summaryrefslogtreecommitdiff
path: root/libgo
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2015-04-22 10:21:45 +0000
committer <>2015-04-25 21:44:09 +0000
commitf80b5ea1605c9f9408c5aa386ba71c16d918ebbf (patch)
treebb7eafaa81fc4b8c5c215bc08d517fd158db234a /libgo
parentc27a97d04853380f1e80525391b3f0d156ed4c84 (diff)
downloadgcc-tarball-f80b5ea1605c9f9408c5aa386ba71c16d918ebbf.tar.gz
Imported from /home/lorry/working-area/delta_gcc-tarball/gcc-5.1.0.tar.bz2.gcc-5.1.0
Diffstat (limited to 'libgo')
-rw-r--r--libgo/MERGE4
-rw-r--r--libgo/Makefile.am274
-rw-r--r--libgo/Makefile.in545
-rw-r--r--libgo/README17
-rw-r--r--libgo/VERSION1
-rw-r--r--libgo/config.h.in6
-rw-r--r--libgo/config/libtool.m438
-rw-r--r--libgo/config/ltmain.sh2
-rwxr-xr-xlibgo/configure249
-rw-r--r--libgo/configure.ac118
-rw-r--r--libgo/go/archive/tar/common.go3
-rw-r--r--libgo/go/archive/tar/reader.go470
-rw-r--r--libgo/go/archive/tar/reader_test.go368
-rw-r--r--libgo/go/archive/tar/stat_atim.go2
-rw-r--r--libgo/go/archive/tar/stat_unix.go2
-rw-r--r--libgo/go/archive/tar/tar_test.go4
-rw-r--r--libgo/go/archive/tar/testdata/sparse-formats.tarbin0 -> 17920 bytes
-rw-r--r--libgo/go/archive/tar/testdata/writer-big-long.tarbin0 -> 4096 bytes
-rw-r--r--libgo/go/archive/tar/testdata/xattrs.tarbin0 -> 5120 bytes
-rw-r--r--libgo/go/archive/tar/writer.go29
-rw-r--r--libgo/go/archive/tar/writer_test.go98
-rw-r--r--libgo/go/archive/zip/reader.go11
-rw-r--r--libgo/go/archive/zip/reader_test.go51
-rw-r--r--libgo/go/archive/zip/register.go41
-rw-r--r--libgo/go/archive/zip/struct.go4
-rw-r--r--libgo/go/archive/zip/testdata/zip64-2.zipbin0 -> 266 bytes
-rw-r--r--libgo/go/archive/zip/writer.go6
-rw-r--r--libgo/go/archive/zip/writer_test.go37
-rw-r--r--libgo/go/bufio/bufio.go171
-rw-r--r--libgo/go/bufio/bufio_test.go362
-rw-r--r--libgo/go/bufio/scan.go33
-rw-r--r--libgo/go/bufio/scan_test.go134
-rw-r--r--libgo/go/bytes/bytes.go22
-rw-r--r--libgo/go/bytes/bytes_test.go42
-rw-r--r--libgo/go/bytes/compare_test.go4
-rw-r--r--libgo/go/bytes/reader.go52
-rw-r--r--libgo/go/bytes/reader_test.go82
-rw-r--r--libgo/go/cmd/cgo/ast.go463
-rw-r--r--libgo/go/cmd/cgo/doc.go748
-rw-r--r--libgo/go/cmd/cgo/gcc.go1753
-rw-r--r--libgo/go/cmd/cgo/godefs.go294
-rw-r--r--libgo/go/cmd/cgo/main.go382
-rw-r--r--libgo/go/cmd/cgo/out.go1334
-rw-r--r--libgo/go/cmd/cgo/util.go84
-rw-r--r--libgo/go/cmd/go/bootstrap.go30
-rw-r--r--libgo/go/cmd/go/build.go2691
-rw-r--r--libgo/go/cmd/go/clean.go248
-rw-r--r--libgo/go/cmd/go/context.go36
-rw-r--r--libgo/go/cmd/go/discovery.go83
-rw-r--r--libgo/go/cmd/go/doc.go1131
-rw-r--r--libgo/go/cmd/go/env.go112
-rw-r--r--libgo/go/cmd/go/fix.go30
-rw-r--r--libgo/go/cmd/go/fmt.go38
-rw-r--r--libgo/go/cmd/go/generate.go403
-rw-r--r--libgo/go/cmd/go/generate_test.go54
-rw-r--r--libgo/go/cmd/go/get.go460
-rw-r--r--libgo/go/cmd/go/go11.go (renamed from libgo/go/reflect/makefunc_dummy.c)10
-rw-r--r--libgo/go/cmd/go/go_windows_test.go55
-rw-r--r--libgo/go/cmd/go/help.go362
-rw-r--r--libgo/go/cmd/go/http.go87
-rw-r--r--libgo/go/cmd/go/list.go209
-rw-r--r--libgo/go/cmd/go/main.go723
-rw-r--r--libgo/go/cmd/go/match_test.go88
-rw-r--r--libgo/go/cmd/go/mkdoc.sh9
-rw-r--r--libgo/go/cmd/go/pkg.go969
-rw-r--r--libgo/go/cmd/go/pkg_test.go73
-rw-r--r--libgo/go/cmd/go/run.go143
-rw-r--r--libgo/go/cmd/go/script23
-rw-r--r--libgo/go/cmd/go/script.txt352
-rw-r--r--libgo/go/cmd/go/signal.go31
-rw-r--r--libgo/go/cmd/go/signal_notunix.go17
-rw-r--r--libgo/go/cmd/go/signal_unix.go18
-rw-r--r--libgo/go/cmd/go/tag_test.go100
-rw-r--r--libgo/go/cmd/go/test.bash820
-rw-r--r--libgo/go/cmd/go/test.go1412
-rw-r--r--libgo/go/cmd/go/testdata/cgocover/p.go19
-rw-r--r--libgo/go/cmd/go/testdata/cgocover/p_test.go7
-rw-r--r--libgo/go/cmd/go/testdata/dep_test.go (renamed from libgo/go/go/types/testdata/expr1.src)6
-rw-r--r--libgo/go/cmd/go/testdata/example1_test.go23
-rw-r--r--libgo/go/cmd/go/testdata/example2_test.go21
-rw-r--r--libgo/go/cmd/go/testdata/generate/test1.go13
-rw-r--r--libgo/go/cmd/go/testdata/generate/test2.go10
-rw-r--r--libgo/go/cmd/go/testdata/generate/test3.go9
-rw-r--r--libgo/go/cmd/go/testdata/importcom/bad.go3
-rw-r--r--libgo/go/cmd/go/testdata/importcom/conflict.go3
-rw-r--r--libgo/go/cmd/go/testdata/importcom/src/bad/bad.go1
-rw-r--r--libgo/go/cmd/go/testdata/importcom/src/conflict/a.go1
-rw-r--r--libgo/go/cmd/go/testdata/importcom/src/conflict/b.go1
-rw-r--r--libgo/go/cmd/go/testdata/importcom/src/works/x/x.go1
-rw-r--r--libgo/go/cmd/go/testdata/importcom/src/works/x/x1.go1
-rw-r--r--libgo/go/cmd/go/testdata/importcom/src/wrongplace/x.go1
-rw-r--r--libgo/go/cmd/go/testdata/importcom/works.go3
-rw-r--r--libgo/go/cmd/go/testdata/importcom/wrongplace.go3
-rw-r--r--libgo/go/cmd/go/testdata/local/easy.go7
-rw-r--r--libgo/go/cmd/go/testdata/local/easysub/easysub.go7
-rw-r--r--libgo/go/cmd/go/testdata/local/easysub/main.go9
-rw-r--r--libgo/go/cmd/go/testdata/local/hard.go7
-rw-r--r--libgo/go/cmd/go/testdata/local/sub/sub.go12
-rw-r--r--libgo/go/cmd/go/testdata/local/sub/sub/subsub.go7
-rw-r--r--libgo/go/cmd/go/testdata/norunexample/example_test.go11
-rw-r--r--libgo/go/cmd/go/testdata/norunexample/test_test.go10
-rw-r--r--libgo/go/cmd/go/testdata/shadow/root1/src/foo/foo.go1
-rw-r--r--libgo/go/cmd/go/testdata/shadow/root1/src/math/math.go1
-rw-r--r--libgo/go/cmd/go/testdata/shadow/root2/src/foo/foo.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/badc/x.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/badpkg/x.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/badtest/badexec/x_test.go5
-rw-r--r--libgo/go/cmd/go/testdata/src/badtest/badsyntax/x.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/badtest/badsyntax/x_test.go3
-rw-r--r--libgo/go/cmd/go/testdata/src/badtest/badvar/x.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/badtest/badvar/x_test.go5
-rw-r--r--libgo/go/cmd/go/testdata/src/cgotest/m.go5
-rw-r--r--libgo/go/cmd/go/testdata/src/go-cmd-test/helloworld.go5
-rw-r--r--libgo/go/cmd/go/testdata/src/main_test/m.go4
-rw-r--r--libgo/go/cmd/go/testdata/src/main_test/m_test.go10
-rw-r--r--libgo/go/cmd/go/testdata/src/notest/hello.go6
-rw-r--r--libgo/go/cmd/go/testdata/src/syntaxerror/x.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/syntaxerror/x_test.go4
-rw-r--r--libgo/go/cmd/go/testdata/src/testcycle/p1/p1.go7
-rw-r--r--libgo/go/cmd/go/testdata/src/testcycle/p1/p1_test.go6
-rw-r--r--libgo/go/cmd/go/testdata/src/testcycle/p2/p2.go7
-rw-r--r--libgo/go/cmd/go/testdata/src/testcycle/p3/p3.go5
-rw-r--r--libgo/go/cmd/go/testdata/src/testcycle/p3/p3_test.go10
-rw-r--r--libgo/go/cmd/go/testdata/src/vetpkg/a_test.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/vetpkg/b.go7
-rw-r--r--libgo/go/cmd/go/testdata/src/xtestonly/f.go3
-rw-r--r--libgo/go/cmd/go/testdata/src/xtestonly/f_test.go12
-rw-r--r--libgo/go/cmd/go/testdata/standalone_test.go6
-rw-r--r--libgo/go/cmd/go/testdata/testimport/p.go3
-rw-r--r--libgo/go/cmd/go/testdata/testimport/p1/p1.go3
-rw-r--r--libgo/go/cmd/go/testdata/testimport/p2/p2.go3
-rw-r--r--libgo/go/cmd/go/testdata/testimport/p_test.go13
-rw-r--r--libgo/go/cmd/go/testdata/testimport/x_test.go15
-rw-r--r--libgo/go/cmd/go/testdata/testinternal/p.go3
-rw-r--r--libgo/go/cmd/go/testdata/testinternal2/p.go3
-rw-r--r--libgo/go/cmd/go/testdata/testinternal2/x/y/z/internal/w/w.go1
-rw-r--r--libgo/go/cmd/go/testdata/testonly/p_test.go1
-rw-r--r--libgo/go/cmd/go/testflag.go319
-rw-r--r--libgo/go/cmd/go/testgo.go21
-rw-r--r--libgo/go/cmd/go/tool.go146
-rw-r--r--libgo/go/cmd/go/vcs.go855
-rw-r--r--libgo/go/cmd/go/vcs_test.go124
-rw-r--r--libgo/go/cmd/go/version.go25
-rw-r--r--libgo/go/cmd/go/vet.go50
-rw-r--r--libgo/go/cmd/gofmt/doc.go93
-rw-r--r--libgo/go/cmd/gofmt/gofmt.go387
-rw-r--r--libgo/go/cmd/gofmt/gofmt_test.go173
-rw-r--r--libgo/go/cmd/gofmt/long_test.go159
-rw-r--r--libgo/go/cmd/gofmt/rewrite.go303
-rw-r--r--libgo/go/cmd/gofmt/simplify.go161
-rw-r--r--libgo/go/cmd/gofmt/testdata/comments.golden9
-rw-r--r--libgo/go/cmd/gofmt/testdata/comments.input9
-rw-r--r--libgo/go/cmd/gofmt/testdata/composites.golden204
-rw-r--r--libgo/go/cmd/gofmt/testdata/composites.input204
-rw-r--r--libgo/go/cmd/gofmt/testdata/crlf.golden13
-rw-r--r--libgo/go/cmd/gofmt/testdata/crlf.input13
-rw-r--r--libgo/go/cmd/gofmt/testdata/import.golden126
-rw-r--r--libgo/go/cmd/gofmt/testdata/import.input131
-rw-r--r--libgo/go/cmd/gofmt/testdata/old.golden9
-rw-r--r--libgo/go/cmd/gofmt/testdata/old.input8
-rw-r--r--libgo/go/cmd/gofmt/testdata/rewrite1.golden14
-rw-r--r--libgo/go/cmd/gofmt/testdata/rewrite1.input14
-rw-r--r--libgo/go/cmd/gofmt/testdata/rewrite2.golden12
-rw-r--r--libgo/go/cmd/gofmt/testdata/rewrite2.input12
-rw-r--r--libgo/go/cmd/gofmt/testdata/rewrite3.golden14
-rw-r--r--libgo/go/cmd/gofmt/testdata/rewrite3.input14
-rw-r--r--libgo/go/cmd/gofmt/testdata/rewrite4.golden76
-rw-r--r--libgo/go/cmd/gofmt/testdata/rewrite4.input76
-rw-r--r--libgo/go/cmd/gofmt/testdata/rewrite5.golden17
-rw-r--r--libgo/go/cmd/gofmt/testdata/rewrite5.input17
-rw-r--r--libgo/go/cmd/gofmt/testdata/rewrite6.golden17
-rw-r--r--libgo/go/cmd/gofmt/testdata/rewrite6.input17
-rw-r--r--libgo/go/cmd/gofmt/testdata/rewrite7.golden17
-rw-r--r--libgo/go/cmd/gofmt/testdata/rewrite7.input17
-rw-r--r--libgo/go/cmd/gofmt/testdata/rewrite8.golden12
-rw-r--r--libgo/go/cmd/gofmt/testdata/rewrite8.input12
-rw-r--r--libgo/go/cmd/gofmt/testdata/slices1.golden66
-rw-r--r--libgo/go/cmd/gofmt/testdata/slices1.input66
-rw-r--r--libgo/go/cmd/gofmt/testdata/slices2.golden63
-rw-r--r--libgo/go/cmd/gofmt/testdata/slices2.input63
-rw-r--r--libgo/go/cmd/gofmt/testdata/stdin1.golden5
-rw-r--r--libgo/go/cmd/gofmt/testdata/stdin1.input5
-rw-r--r--libgo/go/cmd/gofmt/testdata/stdin2.golden11
-rw-r--r--libgo/go/cmd/gofmt/testdata/stdin2.input11
-rw-r--r--libgo/go/cmd/gofmt/testdata/stdin3.golden7
-rw-r--r--libgo/go/cmd/gofmt/testdata/stdin3.input5
-rw-r--r--libgo/go/cmd/gofmt/testdata/stdin4.golden5
-rw-r--r--libgo/go/cmd/gofmt/testdata/stdin4.input5
-rw-r--r--libgo/go/cmd/gofmt/testdata/typeswitch.golden60
-rw-r--r--libgo/go/cmd/gofmt/testdata/typeswitch.input60
-rw-r--r--libgo/go/compress/bzip2/bzip2.go23
-rw-r--r--libgo/go/compress/bzip2/bzip2_test.go68
-rw-r--r--libgo/go/compress/bzip2/huffman.go32
-rw-r--r--libgo/go/compress/bzip2/move_to_front.go79
-rw-r--r--libgo/go/compress/bzip2/testdata/Mark.Twain-Tom.Sawyer.txt.bz2bin0 -> 124744 bytes
-rw-r--r--libgo/go/compress/bzip2/testdata/e.txt.bz2bin0 -> 43149 bytes
-rw-r--r--libgo/go/compress/flate/fixedhuff.go6
-rw-r--r--libgo/go/compress/flate/flate_test.go2
-rw-r--r--libgo/go/compress/flate/gen.go55
-rw-r--r--libgo/go/compress/flate/inflate.go41
-rw-r--r--libgo/go/compress/flate/inflate_test.go39
-rw-r--r--libgo/go/compress/flate/reader_test.go2
-rw-r--r--libgo/go/compress/gzip/gunzip.go51
-rw-r--r--libgo/go/compress/gzip/gunzip_test.go77
-rw-r--r--libgo/go/compress/gzip/gzip.go11
-rw-r--r--libgo/go/compress/gzip/gzip_test.go2
-rw-r--r--libgo/go/compress/lzw/reader.go14
-rw-r--r--libgo/go/compress/lzw/reader_test.go4
-rw-r--r--libgo/go/compress/lzw/writer.go4
-rw-r--r--libgo/go/compress/zlib/reader.go80
-rw-r--r--libgo/go/compress/zlib/reader_test.go2
-rw-r--r--libgo/go/compress/zlib/writer.go7
-rw-r--r--libgo/go/compress/zlib/writer_test.go2
-rw-r--r--libgo/go/container/heap/heap.go4
-rwxr-xr-xlibgo/go/container/list/list.go10
-rwxr-xr-xlibgo/go/container/list/list_test.go56
-rw-r--r--libgo/go/container/ring/ring_test.go8
-rw-r--r--libgo/go/crypto/aes/aes_test.go28
-rw-r--r--libgo/go/crypto/aes/cipher.go12
-rw-r--r--libgo/go/crypto/aes/cipher_asm.go2
-rw-r--r--libgo/go/crypto/cipher/benchmark_test.go139
-rw-r--r--libgo/go/crypto/cipher/cbc.go55
-rw-r--r--libgo/go/crypto/cipher/cbc_aes_test.go46
-rw-r--r--libgo/go/crypto/cipher/cfb.go60
-rw-r--r--libgo/go/crypto/cipher/cfb_test.go85
-rw-r--r--libgo/go/crypto/cipher/cipher.go10
-rw-r--r--libgo/go/crypto/cipher/ctr.go55
-rw-r--r--libgo/go/crypto/cipher/example_test.go4
-rw-r--r--libgo/go/crypto/cipher/gcm.go27
-rw-r--r--libgo/go/crypto/cipher/gcm_test.go16
-rw-r--r--libgo/go/crypto/cipher/ofb.go42
-rw-r--r--libgo/go/crypto/cipher/xor.go84
-rw-r--r--libgo/go/crypto/cipher/xor_test.go28
-rw-r--r--libgo/go/crypto/crypto.go45
-rw-r--r--libgo/go/crypto/dsa/dsa.go12
-rw-r--r--libgo/go/crypto/ecdsa/ecdsa.go36
-rw-r--r--libgo/go/crypto/hmac/hmac_test.go66
-rw-r--r--libgo/go/crypto/md5/gen.go32
-rw-r--r--libgo/go/crypto/md5/md5.go2
-rw-r--r--libgo/go/crypto/md5/md5_test.go13
-rw-r--r--libgo/go/crypto/md5/md5block.go10
-rw-r--r--libgo/go/crypto/md5/md5block_decl.go2
-rw-r--r--libgo/go/crypto/md5/md5block_generic.go9
-rw-r--r--libgo/go/crypto/rand/rand_linux.go39
-rw-r--r--libgo/go/crypto/rand/rand_unix.go13
-rw-r--r--libgo/go/crypto/rand/util.go8
-rw-r--r--libgo/go/crypto/rand/util_test.go65
-rw-r--r--libgo/go/crypto/rc4/rc4.go17
-rw-r--r--libgo/go/crypto/rc4/rc4_asm.go2
-rw-r--r--libgo/go/crypto/rc4/rc4_ref.go11
-rw-r--r--libgo/go/crypto/rc4/rc4_test.go19
-rw-r--r--libgo/go/crypto/rsa/pkcs1v15.go55
-rw-r--r--libgo/go/crypto/rsa/pkcs1v15_test.go42
-rw-r--r--libgo/go/crypto/rsa/pss.go21
-rw-r--r--libgo/go/crypto/rsa/rsa.go33
-rw-r--r--libgo/go/crypto/rsa/rsa_test.go2
-rw-r--r--libgo/go/crypto/sha1/sha1.go10
-rw-r--r--libgo/go/crypto/sha1/sha1_test.go27
-rw-r--r--libgo/go/crypto/sha1/sha1block.go10
-rw-r--r--libgo/go/crypto/sha1/sha1block_decl.go2
-rw-r--r--libgo/go/crypto/sha1/sha1block_generic.go9
-rw-r--r--libgo/go/crypto/sha256/sha256.go12
-rw-r--r--libgo/go/crypto/sha256/sha256_test.go18
-rw-r--r--libgo/go/crypto/sha256/sha256block.go2
-rw-r--r--libgo/go/crypto/sha256/sha256block_decl.go11
-rw-r--r--libgo/go/crypto/sha512/sha512.go10
-rw-r--r--libgo/go/crypto/sha512/sha512_test.go18
-rw-r--r--libgo/go/crypto/sha512/sha512block.go2
-rw-r--r--libgo/go/crypto/sha512/sha512block_decl.go11
-rw-r--r--libgo/go/crypto/subtle/constant_time.go16
-rw-r--r--libgo/go/crypto/subtle/constant_time_test.go2
-rw-r--r--libgo/go/crypto/tls/alert.go2
-rw-r--r--libgo/go/crypto/tls/cipher_suites.go5
-rw-r--r--libgo/go/crypto/tls/common.go226
-rw-r--r--libgo/go/crypto/tls/conn.go175
-rw-r--r--libgo/go/crypto/tls/conn_test.go22
-rw-r--r--libgo/go/crypto/tls/generate_cert.go75
-rw-r--r--libgo/go/crypto/tls/handshake_client.go439
-rw-r--r--libgo/go/crypto/tls/handshake_client_test.go3400
-rw-r--r--libgo/go/crypto/tls/handshake_messages.go209
-rw-r--r--libgo/go/crypto/tls/handshake_messages_test.go9
-rw-r--r--libgo/go/crypto/tls/handshake_server.go123
-rw-r--r--libgo/go/crypto/tls/handshake_server_test.go3972
-rw-r--r--libgo/go/crypto/tls/handshake_test.go167
-rw-r--r--libgo/go/crypto/tls/key_agreement.go85
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA129
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA125
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA128
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA124
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES87
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES97
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv10-RSA-RC483
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES89
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES99
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv11-RSA-RC483
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-ALPN97
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch95
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA134
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA127
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA133
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA126
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES89
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM84
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES99
-rw-r--r--libgo/go/crypto/tls/testdata/Client-TLSv12-RSA-RC483
-rw-r--r--libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-3DES83
-rw-r--r--libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-AES84
-rw-r--r--libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-RC479
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES84
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-3DES79
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-AES82
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-RC476
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv11-FallbackSCSV17
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv11-RSA-RC476
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN122
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch121
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA91
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA101
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven122
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven121
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven81
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES89
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-IssueTicket87
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable87
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-3DES83
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES87
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM93
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-RC479
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-Resume36
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-ResumeDisabled87
-rw-r--r--libgo/go/crypto/tls/testdata/Server-TLSv12-SNI76
-rw-r--r--libgo/go/crypto/tls/ticket.go3
-rw-r--r--libgo/go/crypto/tls/tls.go86
-rw-r--r--libgo/go/crypto/tls/tls_test.go175
-rw-r--r--libgo/go/crypto/x509/pem_decrypt_test.go4
-rw-r--r--libgo/go/crypto/x509/pkix/pkix.go9
-rw-r--r--libgo/go/crypto/x509/root_cgo_darwin.go79
-rw-r--r--libgo/go/crypto/x509/root_darwin.go78
-rw-r--r--libgo/go/crypto/x509/root_nocgo_darwin.go11
-rw-r--r--libgo/go/crypto/x509/root_stub.go14
-rw-r--r--libgo/go/crypto/x509/root_unix.go29
-rw-r--r--libgo/go/crypto/x509/verify.go11
-rw-r--r--libgo/go/crypto/x509/verify_test.go367
-rw-r--r--libgo/go/crypto/x509/x509.go619
-rw-r--r--libgo/go/crypto/x509/x509_test.go317
-rw-r--r--libgo/go/crypto/x509/x509_test_import.go53
-rw-r--r--libgo/go/database/sql/convert.go50
-rw-r--r--libgo/go/database/sql/convert_test.go67
-rw-r--r--libgo/go/database/sql/driver/driver.go2
-rw-r--r--libgo/go/database/sql/fakedb_test.go56
-rw-r--r--libgo/go/database/sql/sql.go354
-rw-r--r--libgo/go/database/sql/sql_test.go209
-rw-r--r--libgo/go/debug/dwarf/const.go35
-rw-r--r--libgo/go/debug/dwarf/entry.go16
-rw-r--r--libgo/go/debug/dwarf/open.go10
-rw-r--r--libgo/go/debug/dwarf/testdata/typedef.elf4bin0 -> 9496 bytes
-rw-r--r--libgo/go/debug/dwarf/type.go160
-rw-r--r--libgo/go/debug/dwarf/type_test.go2
-rw-r--r--libgo/go/debug/dwarf/typeunit.go166
-rw-r--r--libgo/go/debug/dwarf/unit.go2
-rw-r--r--libgo/go/debug/elf/elf.go246
-rw-r--r--libgo/go/debug/elf/elf_test.go2
-rw-r--r--libgo/go/debug/elf/file.go273
-rw-r--r--libgo/go/debug/elf/file_test.go26
-rw-r--r--libgo/go/debug/elf/symbols_test.go834
-rw-r--r--libgo/go/debug/elf/testdata/go-relocation-test-clang-x86.objbin0 -> 1900 bytes
-rw-r--r--libgo/go/debug/elf/testdata/go-relocation-test-gcc482-aarch64.objbin0 -> 3392 bytes
-rw-r--r--libgo/go/debug/elf/testdata/go-relocation-test-gcc482-ppc64le.objbin0 -> 3016 bytes
-rw-r--r--libgo/go/debug/elf/testdata/go-relocation-test-gcc5-ppc.objbin0 -> 2356 bytes
-rw-r--r--libgo/go/debug/elf/testdata/hello.c7
-rw-r--r--libgo/go/debug/gosym/pclntab.go27
-rw-r--r--libgo/go/debug/gosym/symtab.go9
-rw-r--r--libgo/go/debug/macho/fat.go146
-rw-r--r--libgo/go/debug/macho/file.go23
-rw-r--r--libgo/go/debug/macho/file_test.go43
-rw-r--r--libgo/go/debug/macho/macho.go23
-rw-r--r--libgo/go/debug/macho/testdata/fat-gcc-386-amd64-darwin-execbin0 -> 28992 bytes
-rw-r--r--libgo/go/debug/pe/file.go60
-rw-r--r--libgo/go/debug/pe/file_test.go146
-rw-r--r--libgo/go/debug/pe/pe.go72
-rw-r--r--libgo/go/debug/pe/testdata/gcc-amd64-mingw-execbin0 -> 273083 bytes
-rw-r--r--libgo/go/debug/pe/testdata/gcc-amd64-mingw-objbin0 -> 736 bytes
-rw-r--r--libgo/go/debug/plan9obj/file.go328
-rw-r--r--libgo/go/debug/plan9obj/file_test.go81
-rw-r--r--libgo/go/debug/plan9obj/plan9obj.go36
-rw-r--r--libgo/go/debug/plan9obj/testdata/386-plan9-execbin0 -> 37232 bytes
-rw-r--r--libgo/go/debug/plan9obj/testdata/amd64-plan9-execbin0 -> 34279 bytes
-rw-r--r--libgo/go/debug/plan9obj/testdata/hello.c8
-rw-r--r--libgo/go/encoding/ascii85/ascii85.go13
-rw-r--r--libgo/go/encoding/ascii85/ascii85_test.go21
-rw-r--r--libgo/go/encoding/asn1/asn1.go73
-rw-r--r--libgo/go/encoding/asn1/asn1_test.go128
-rw-r--r--libgo/go/encoding/asn1/marshal.go75
-rw-r--r--libgo/go/encoding/asn1/marshal_test.go16
-rw-r--r--libgo/go/encoding/base32/base32.go58
-rw-r--r--libgo/go/encoding/base32/base32_test.go24
-rw-r--r--libgo/go/encoding/base64/base64.go65
-rw-r--r--libgo/go/encoding/base64/base64_test.go43
-rw-r--r--libgo/go/encoding/binary/binary.go78
-rw-r--r--libgo/go/encoding/binary/binary_test.go51
-rw-r--r--libgo/go/encoding/binary/varint_test.go8
-rw-r--r--libgo/go/encoding/csv/reader.go6
-rw-r--r--libgo/go/encoding/csv/writer.go16
-rw-r--r--libgo/go/encoding/csv/writer_test.go13
-rw-r--r--libgo/go/encoding/gob/codec_test.go389
-rw-r--r--libgo/go/encoding/gob/debug.go6
-rw-r--r--libgo/go/encoding/gob/dec_helpers.go468
-rw-r--r--libgo/go/encoding/gob/decgen.go240
-rw-r--r--libgo/go/encoding/gob/decode.go731
-rw-r--r--libgo/go/encoding/gob/decoder.go57
-rw-r--r--libgo/go/encoding/gob/enc_helpers.go414
-rw-r--r--libgo/go/encoding/gob/encgen.go218
-rw-r--r--libgo/go/encoding/gob/encode.go484
-rw-r--r--libgo/go/encoding/gob/encoder.go11
-rw-r--r--libgo/go/encoding/gob/encoder_test.go102
-rw-r--r--libgo/go/encoding/gob/gobencdec_test.go26
-rw-r--r--libgo/go/encoding/gob/timing_test.go258
-rw-r--r--libgo/go/encoding/gob/type.go76
-rw-r--r--libgo/go/encoding/hex/hex.go3
-rw-r--r--libgo/go/encoding/hex/hex_test.go6
-rw-r--r--libgo/go/encoding/json/decode.go60
-rw-r--r--libgo/go/encoding/json/decode_test.go61
-rw-r--r--libgo/go/encoding/json/encode.go59
-rw-r--r--libgo/go/encoding/json/encode_test.go109
-rw-r--r--libgo/go/encoding/json/fold.go143
-rw-r--r--libgo/go/encoding/json/fold_test.go116
-rw-r--r--libgo/go/encoding/json/indent.go5
-rw-r--r--libgo/go/encoding/json/scanner_test.go22
-rw-r--r--libgo/go/encoding/json/stream.go6
-rw-r--r--libgo/go/encoding/xml/marshal.go11
-rw-r--r--libgo/go/encoding/xml/marshal_test.go115
-rw-r--r--libgo/go/encoding/xml/read.go11
-rw-r--r--libgo/go/encoding/xml/read_test.go27
-rw-r--r--libgo/go/encoding/xml/typeinfo.go3
-rw-r--r--libgo/go/encoding/xml/xml.go12
-rw-r--r--libgo/go/encoding/xml/xml_test.go31
-rw-r--r--libgo/go/expvar/expvar.go62
-rw-r--r--libgo/go/expvar/expvar_test.go32
-rw-r--r--libgo/go/flag/flag.go33
-rw-r--r--libgo/go/flag/flag_test.go10
-rw-r--r--libgo/go/fmt/doc.go95
-rw-r--r--libgo/go/fmt/fmt_test.go411
-rw-r--r--libgo/go/fmt/format.go223
-rw-r--r--libgo/go/fmt/print.go279
-rw-r--r--libgo/go/fmt/scan.go11
-rw-r--r--libgo/go/fmt/scan_test.go32
-rw-r--r--libgo/go/go/ast/ast.go6
-rw-r--r--libgo/go/go/ast/commentmap.go2
-rw-r--r--libgo/go/go/ast/scope.go2
-rw-r--r--libgo/go/go/ast/walk.go4
-rw-r--r--libgo/go/go/build/build.go263
-rw-r--r--libgo/go/go/build/build_test.go52
-rw-r--r--libgo/go/go/build/deps_test.go26
-rw-r--r--libgo/go/go/build/doc.go23
-rw-r--r--libgo/go/go/build/syslist.go4
-rw-r--r--libgo/go/go/build/testdata/multi/file.go5
-rw-r--r--libgo/go/go/build/testdata/multi/file_appengine.go5
-rw-r--r--libgo/go/go/doc/comment.go49
-rw-r--r--libgo/go/go/doc/comment_test.go106
-rw-r--r--libgo/go/go/doc/example.go15
-rw-r--r--libgo/go/go/doc/exports.go26
-rw-r--r--libgo/go/go/doc/headscan.go15
-rw-r--r--libgo/go/go/doc/testdata/blank.0.golden37
-rw-r--r--libgo/go/go/doc/testdata/blank.1.golden46
-rw-r--r--libgo/go/go/doc/testdata/blank.2.golden37
-rw-r--r--libgo/go/go/doc/testdata/blank.go38
-rw-r--r--libgo/go/go/format/format.go221
-rw-r--r--libgo/go/go/format/format_test.go6
-rw-r--r--libgo/go/go/parser/error_test.go24
-rw-r--r--libgo/go/go/parser/interface.go7
-rw-r--r--libgo/go/go/parser/parser.go145
-rw-r--r--libgo/go/go/parser/parser_test.go41
-rw-r--r--libgo/go/go/parser/short_test.go31
-rw-r--r--libgo/go/go/printer/nodes.go109
-rw-r--r--libgo/go/go/printer/printer.go125
-rw-r--r--libgo/go/go/printer/printer_test.go19
-rw-r--r--libgo/go/go/printer/testdata/comments.golden13
-rw-r--r--libgo/go/go/printer/testdata/comments.input12
-rw-r--r--libgo/go/go/printer/testdata/comments2.golden26
-rw-r--r--libgo/go/go/printer/testdata/comments2.input28
-rw-r--r--libgo/go/go/printer/testdata/declarations.golden43
-rw-r--r--libgo/go/go/printer/testdata/declarations.input46
-rw-r--r--libgo/go/go/printer/testdata/expressions.golden5
-rw-r--r--libgo/go/go/printer/testdata/expressions.input5
-rw-r--r--libgo/go/go/printer/testdata/expressions.raw5
-rw-r--r--libgo/go/go/printer/testdata/statements.golden11
-rw-r--r--libgo/go/go/printer/testdata/statements.input5
-rw-r--r--libgo/go/go/scanner/scanner.go118
-rw-r--r--libgo/go/go/scanner/scanner_test.go103
-rw-r--r--libgo/go/go/token/position.go51
-rw-r--r--libgo/go/go/token/position_test.go101
-rw-r--r--libgo/go/go/types/testdata/builtins.src302
-rw-r--r--libgo/go/go/types/testdata/const0.src215
-rw-r--r--libgo/go/go/types/testdata/conversions.src18
-rw-r--r--libgo/go/go/types/testdata/decls0.src177
-rw-r--r--libgo/go/go/types/testdata/decls1.src132
-rw-r--r--libgo/go/go/types/testdata/decls2a.src67
-rw-r--r--libgo/go/go/types/testdata/decls2b.src28
-rw-r--r--libgo/go/go/types/testdata/decls3.src231
-rw-r--r--libgo/go/go/types/testdata/expr0.src151
-rw-r--r--libgo/go/go/types/testdata/expr2.src23
-rw-r--r--libgo/go/go/types/testdata/expr3.src367
-rw-r--r--libgo/go/go/types/testdata/stmt0.src274
-rw-r--r--libgo/go/hash/crc32/crc32.go4
-rw-r--r--libgo/go/hash/crc32/crc32_amd64x.go (renamed from libgo/go/hash/crc32/crc32_amd64.go)2
-rw-r--r--libgo/go/hash/fnv/fnv.go3
-rw-r--r--libgo/go/html/escape_test.go18
-rw-r--r--libgo/go/html/template/attr.go4
-rw-r--r--libgo/go/html/template/content.go3
-rw-r--r--libgo/go/html/template/context.go4
-rw-r--r--libgo/go/html/template/error.go16
-rw-r--r--libgo/go/html/template/escape.go116
-rw-r--r--libgo/go/html/template/escape_test.go55
-rw-r--r--libgo/go/html/template/html.go4
-rw-r--r--libgo/go/html/template/js.go2
-rw-r--r--libgo/go/html/template/js_test.go2
-rw-r--r--libgo/go/html/template/template.go48
-rw-r--r--libgo/go/html/template/transition.go12
-rw-r--r--libgo/go/image/color/palette/gen.go96
-rw-r--r--libgo/go/image/color/palette/generate.go8
-rw-r--r--libgo/go/image/color/palette/palette.go7
-rw-r--r--libgo/go/image/gif/reader.go29
-rw-r--r--libgo/go/image/gif/reader_test.go68
-rw-r--r--libgo/go/image/gif/writer.go18
-rw-r--r--libgo/go/image/gif/writer_test.go25
-rw-r--r--libgo/go/image/image.go32
-rw-r--r--libgo/go/image/jpeg/huffman.go253
-rw-r--r--libgo/go/image/jpeg/reader.go210
-rw-r--r--libgo/go/image/jpeg/reader_test.go72
-rw-r--r--libgo/go/image/jpeg/scan.go78
-rw-r--r--libgo/go/image/jpeg/writer.go133
-rw-r--r--libgo/go/image/jpeg/writer_test.go28
-rw-r--r--libgo/go/image/png/paeth.go41
-rw-r--r--libgo/go/image/png/paeth_test.go8
-rw-r--r--libgo/go/image/png/reader.go215
-rw-r--r--libgo/go/image/png/reader_test.go16
-rw-r--r--libgo/go/image/png/testdata/benchGray.pngbin0 -> 14709 bytes
-rw-r--r--libgo/go/image/png/testdata/benchNRGBA-gradient.pngbin0 -> 58831 bytes
-rw-r--r--libgo/go/image/png/testdata/benchNRGBA-opaque.pngbin0 -> 44237 bytes
-rw-r--r--libgo/go/image/png/testdata/benchPaletted.pngbin0 -> 13397 bytes
-rw-r--r--libgo/go/image/png/testdata/benchRGB.pngbin0 -> 39571 bytes
-rw-r--r--libgo/go/image/png/writer.go62
-rw-r--r--libgo/go/image/png/writer_test.go29
-rw-r--r--libgo/go/image/testdata/video-001.separate.dc.progression.jpegbin0 -> 14288 bytes
-rw-r--r--libgo/go/image/testdata/video-001.separate.dc.progression.progressive.jpegbin0 -> 14312 bytes
-rw-r--r--libgo/go/image/testdata/video-005.gray.gifbin0 -> 14505 bytes
-rw-r--r--libgo/go/image/ycbcr.go4
-rw-r--r--libgo/go/index/suffixarray/suffixarray_test.go2
-rw-r--r--libgo/go/internal/syscall/dummy.go5
-rw-r--r--libgo/go/internal/syscall/getrandom_linux.go56
-rw-r--r--libgo/go/io/io.go14
-rw-r--r--libgo/go/io/io_test.go20
-rw-r--r--libgo/go/io/ioutil/blackhole.go23
-rw-r--r--libgo/go/io/ioutil/ioutil.go14
-rw-r--r--libgo/go/io/multi.go11
-rw-r--r--libgo/go/io/multi_test.go27
-rw-r--r--libgo/go/log/syslog/syslog.go5
-rw-r--r--libgo/go/log/syslog/syslog_test.go4
-rw-r--r--libgo/go/log/syslog/syslog_unix.go4
-rw-r--r--libgo/go/math/all_test.go77
-rw-r--r--libgo/go/math/big/arith.go14
-rw-r--r--libgo/go/math/big/int.go91
-rw-r--r--libgo/go/math/big/int_test.go117
-rw-r--r--libgo/go/math/big/nat.go11
-rw-r--r--libgo/go/math/big/nat_test.go27
-rw-r--r--libgo/go/math/big/rat.go201
-rw-r--r--libgo/go/math/big/rat_test.go261
-rw-r--r--libgo/go/math/cmplx/cmath_test.go13
-rw-r--r--libgo/go/math/cmplx/pow.go18
-rw-r--r--libgo/go/math/cmplx/sqrt.go1
-rw-r--r--libgo/go/math/ldexp.go10
-rw-r--r--libgo/go/math/nextafter.go32
-rw-r--r--libgo/go/math/rand/rand.go52
-rw-r--r--libgo/go/math/rand/rand_test.go39
-rw-r--r--libgo/go/math/rand/regress_test.go355
-rw-r--r--libgo/go/math/sqrt.go2
-rw-r--r--libgo/go/mime/mediatype.go10
-rw-r--r--libgo/go/mime/mediatype_test.go1
-rw-r--r--libgo/go/mime/multipart/formdata_test.go3
-rw-r--r--libgo/go/mime/multipart/multipart.go11
-rw-r--r--libgo/go/mime/multipart/quotedprintable_test.go2
-rw-r--r--libgo/go/mime/multipart/writer_test.go15
-rw-r--r--libgo/go/mime/type.go84
-rw-r--r--libgo/go/mime/type_plan9.go2
-rw-r--r--libgo/go/mime/type_test.go42
-rw-r--r--libgo/go/mime/type_unix.go4
-rw-r--r--libgo/go/mime/type_windows.go2
-rw-r--r--libgo/go/net/cgo_android.go14
-rw-r--r--libgo/go/net/cgo_bsd.go2
-rw-r--r--libgo/go/net/cgo_linux.go2
-rw-r--r--libgo/go/net/cgo_unix_test.go24
-rw-r--r--libgo/go/net/conn_test.go39
-rw-r--r--libgo/go/net/dial.go42
-rw-r--r--libgo/go/net/dial_test.go105
-rw-r--r--libgo/go/net/dialgoogle_test.go26
-rw-r--r--libgo/go/net/dnsclient.go8
-rw-r--r--libgo/go/net/dnsclient_test.go69
-rw-r--r--libgo/go/net/dnsclient_unix.go392
-rw-r--r--libgo/go/net/dnsclient_unix_test.go235
-rw-r--r--libgo/go/net/dnsconfig_unix.go54
-rw-r--r--libgo/go/net/dnsconfig_unix_test.go69
-rw-r--r--libgo/go/net/fd_mutex_test.go27
-rw-r--r--libgo/go/net/fd_plan9.go115
-rw-r--r--libgo/go/net/fd_poll_nacl.go94
-rw-r--r--libgo/go/net/fd_poll_runtime.go7
-rw-r--r--libgo/go/net/fd_unix.go80
-rw-r--r--libgo/go/net/fd_unix_test.go2
-rw-r--r--libgo/go/net/fd_windows.go43
-rw-r--r--libgo/go/net/file_plan9.go10
-rw-r--r--libgo/go/net/file_stub.go38
-rw-r--r--libgo/go/net/file_test.go10
-rw-r--r--libgo/go/net/file_unix.go4
-rw-r--r--libgo/go/net/hosts.go2
-rw-r--r--libgo/go/net/hosts_test.go2
-rw-r--r--libgo/go/net/http/cgi/host.go27
-rw-r--r--libgo/go/net/http/cgi/matryoshka_test.go137
-rw-r--r--libgo/go/net/http/chunked.go183
-rw-r--r--libgo/go/net/http/chunked_test.go93
-rw-r--r--libgo/go/net/http/client.go137
-rw-r--r--libgo/go/net/http/client_test.go312
-rw-r--r--libgo/go/net/http/cookie.go62
-rw-r--r--libgo/go/net/http/cookie_test.go139
-rw-r--r--libgo/go/net/http/cookiejar/jar.go2
-rw-r--r--libgo/go/net/http/export_test.go54
-rw-r--r--libgo/go/net/http/fcgi/child.go19
-rw-r--r--libgo/go/net/http/fs.go61
-rw-r--r--libgo/go/net/http/fs_test.go129
-rw-r--r--libgo/go/net/http/header.go19
-rw-r--r--libgo/go/net/http/header_test.go9
-rw-r--r--libgo/go/net/http/httptest/server.go2
-rw-r--r--libgo/go/net/http/httputil/chunked_test.go95
-rw-r--r--libgo/go/net/http/httputil/dump.go45
-rw-r--r--libgo/go/net/http/httputil/dump_test.go115
-rw-r--r--libgo/go/net/http/httputil/httputil.go39
-rw-r--r--libgo/go/net/http/httputil/persist.go21
-rw-r--r--libgo/go/net/http/httputil/reverseproxy.go20
-rw-r--r--libgo/go/net/http/httputil/reverseproxy_test.go16
-rw-r--r--libgo/go/net/http/internal/chunked.go (renamed from libgo/go/net/http/httputil/chunked.go)67
-rw-r--r--libgo/go/net/http/internal/chunked_test.go156
-rw-r--r--libgo/go/net/http/main_test.go (renamed from libgo/go/net/http/z_last_test.go)30
-rw-r--r--libgo/go/net/http/pprof/pprof.go4
-rw-r--r--libgo/go/net/http/proxy_test.go19
-rw-r--r--libgo/go/net/http/race.go11
-rw-r--r--libgo/go/net/http/readrequest_test.go41
-rw-r--r--libgo/go/net/http/request.go199
-rw-r--r--libgo/go/net/http/request_test.go203
-rw-r--r--libgo/go/net/http/requestwrite_test.go104
-rw-r--r--libgo/go/net/http/response.go68
-rw-r--r--libgo/go/net/http/response_test.go51
-rw-r--r--libgo/go/net/http/responsewrite_test.go123
-rw-r--r--libgo/go/net/http/serve_test.go838
-rw-r--r--libgo/go/net/http/server.go348
-rw-r--r--libgo/go/net/http/transfer.go172
-rw-r--r--libgo/go/net/http/transfer_test.go33
-rw-r--r--libgo/go/net/http/transport.go506
-rw-r--r--libgo/go/net/http/transport_test.go716
-rw-r--r--libgo/go/net/interface.go10
-rw-r--r--libgo/go/net/interface_linux.go58
-rw-r--r--libgo/go/net/interface_stub.go2
-rw-r--r--libgo/go/net/ip.go41
-rw-r--r--libgo/go/net/ip_test.go27
-rw-r--r--libgo/go/net/ipraw_test.go9
-rw-r--r--libgo/go/net/iprawsock_posix.go22
-rw-r--r--libgo/go/net/ipsock.go6
-rw-r--r--libgo/go/net/ipsock_plan9.go66
-rw-r--r--libgo/go/net/ipsock_posix.go13
-rw-r--r--libgo/go/net/lookup.go51
-rw-r--r--libgo/go/net/lookup_plan9.go46
-rw-r--r--libgo/go/net/lookup_stub.go49
-rw-r--r--libgo/go/net/lookup_test.go164
-rw-r--r--libgo/go/net/lookup_unix.go2
-rw-r--r--libgo/go/net/lookup_windows.go79
-rw-r--r--libgo/go/net/mail/message.go33
-rw-r--r--libgo/go/net/mail/message_test.go27
-rw-r--r--libgo/go/net/multicast_test.go8
-rw-r--r--libgo/go/net/net.go16
-rw-r--r--libgo/go/net/net_test.go25
-rw-r--r--libgo/go/net/packetconn_test.go32
-rw-r--r--libgo/go/net/parse.go24
-rw-r--r--libgo/go/net/parse_test.go4
-rw-r--r--libgo/go/net/port_test.go6
-rw-r--r--libgo/go/net/port_unix.go12
-rw-r--r--libgo/go/net/protoconn_test.go6
-rw-r--r--libgo/go/net/rpc/client.go22
-rw-r--r--libgo/go/net/rpc/client_test.go91
-rw-r--r--libgo/go/net/rpc/debug.go2
-rw-r--r--libgo/go/net/rpc/jsonrpc/all_test.go35
-rw-r--r--libgo/go/net/rpc/jsonrpc/server.go6
-rw-r--r--libgo/go/net/rpc/server.go30
-rw-r--r--libgo/go/net/rpc/server_test.go38
-rw-r--r--libgo/go/net/sendfile_dragonfly.go2
-rw-r--r--libgo/go/net/sendfile_freebsd.go2
-rw-r--r--libgo/go/net/sendfile_stub.go2
-rw-r--r--libgo/go/net/server_test.go86
-rw-r--r--libgo/go/net/singleflight.go66
-rw-r--r--libgo/go/net/smtp/smtp.go8
-rw-r--r--libgo/go/net/smtp/smtp_test.go144
-rw-r--r--libgo/go/net/sock_cloexec.go47
-rw-r--r--libgo/go/net/sock_posix.go70
-rw-r--r--libgo/go/net/sock_solaris.go18
-rw-r--r--libgo/go/net/sock_stub.go15
-rw-r--r--libgo/go/net/sockopt_bsd.go13
-rw-r--r--libgo/go/net/sockopt_plan9.go13
-rw-r--r--libgo/go/net/sockopt_posix.go2
-rw-r--r--libgo/go/net/sockopt_solaris.go32
-rw-r--r--libgo/go/net/sockopt_stub.go37
-rw-r--r--libgo/go/net/sockoptip_stub.go39
-rw-r--r--libgo/go/net/sys_cloexec.go18
-rw-r--r--libgo/go/net/tcp_test.go53
-rw-r--r--libgo/go/net/tcpsock_plan9.go29
-rw-r--r--libgo/go/net/tcpsock_posix.go29
-rw-r--r--libgo/go/net/tcpsockopt_darwin.go12
-rw-r--r--libgo/go/net/tcpsockopt_dragonfly.go26
-rw-r--r--libgo/go/net/tcpsockopt_openbsd.go17
-rw-r--r--libgo/go/net/tcpsockopt_plan9.go18
-rw-r--r--libgo/go/net/tcpsockopt_posix.go2
-rw-r--r--libgo/go/net/tcpsockopt_solaris.go27
-rw-r--r--libgo/go/net/tcpsockopt_stub.go20
-rw-r--r--libgo/go/net/tcpsockopt_unix.go10
-rw-r--r--libgo/go/net/tcpsockopt_windows.go21
-rw-r--r--libgo/go/net/testdata/domain-resolv.conf5
-rw-r--r--libgo/go/net/testdata/empty-resolv.conf1
-rw-r--r--libgo/go/net/testdata/resolv.conf8
-rw-r--r--libgo/go/net/testdata/search-resolv.conf5
-rw-r--r--libgo/go/net/textproto/reader.go112
-rw-r--r--libgo/go/net/textproto/reader_test.go29
-rw-r--r--libgo/go/net/timeout_test.go25
-rw-r--r--libgo/go/net/udp_test.go45
-rw-r--r--libgo/go/net/udpsock.go4
-rw-r--r--libgo/go/net/udpsock_plan9.go3
-rw-r--r--libgo/go/net/udpsock_posix.go16
-rw-r--r--libgo/go/net/unicast_posix_test.go10
-rw-r--r--libgo/go/net/unix_test.go84
-rw-r--r--libgo/go/net/unixsock_posix.go33
-rw-r--r--libgo/go/net/url/url.go31
-rw-r--r--libgo/go/net/url/url_test.go67
-rw-r--r--libgo/go/net/z_last_test.go99
-rw-r--r--libgo/go/os/dir_unix.go4
-rw-r--r--libgo/go/os/doc.go3
-rw-r--r--libgo/go/os/env.go5
-rw-r--r--libgo/go/os/env_test.go26
-rw-r--r--libgo/go/os/env_unix_test.go2
-rw-r--r--libgo/go/os/error_plan9.go3
-rw-r--r--libgo/go/os/error_unix.go2
-rw-r--r--libgo/go/os/exec/exec.go101
-rw-r--r--libgo/go/os/exec/exec_test.go166
-rw-r--r--libgo/go/os/exec/lp_unix.go2
-rw-r--r--libgo/go/os/exec/lp_unix_test.go2
-rw-r--r--libgo/go/os/exec_plan9.go9
-rw-r--r--libgo/go/os/exec_posix.go2
-rw-r--r--libgo/go/os/exec_unix.go15
-rw-r--r--libgo/go/os/exec_windows.go3
-rw-r--r--libgo/go/os/file.go17
-rw-r--r--libgo/go/os/file_plan9.go44
-rw-r--r--libgo/go/os/file_posix.go29
-rw-r--r--libgo/go/os/file_unix.go92
-rw-r--r--libgo/go/os/getwd.go52
-rw-r--r--libgo/go/os/os_test.go337
-rw-r--r--libgo/go/os/os_unix_test.go40
-rw-r--r--libgo/go/os/path.go16
-rw-r--r--libgo/go/os/path_test.go14
-rw-r--r--libgo/go/os/path_unix.go2
-rw-r--r--libgo/go/os/pipe_bsd.go2
-rw-r--r--libgo/go/os/proc.go15
-rw-r--r--libgo/go/os/signal/signal_test.go8
-rw-r--r--libgo/go/os/signal/signal_unix.go2
-rw-r--r--libgo/go/os/stat_nacl.go62
-rw-r--r--libgo/go/os/stat_solaris.go7
-rw-r--r--libgo/go/os/sys_bsd.go2
-rw-r--r--libgo/go/os/sys_darwin.go31
-rw-r--r--libgo/go/os/sys_freebsd.go23
-rw-r--r--libgo/go/os/sys_nacl.go9
-rw-r--r--libgo/go/os/sys_unix.go11
-rw-r--r--libgo/go/os/types_windows.go3
-rw-r--r--libgo/go/os/user/lookup_stubs.go2
-rw-r--r--libgo/go/os/user/lookup_unix.go2
-rw-r--r--libgo/go/path/filepath/export_test.go7
-rw-r--r--libgo/go/path/filepath/match.go10
-rw-r--r--libgo/go/path/filepath/match_test.go58
-rw-r--r--libgo/go/path/filepath/path.go49
-rw-r--r--libgo/go/path/filepath/path_plan9.go4
-rw-r--r--libgo/go/path/filepath/path_test.go96
-rw-r--r--libgo/go/path/filepath/path_unix.go6
-rw-r--r--libgo/go/path/filepath/path_windows.go5
-rw-r--r--libgo/go/path/filepath/symlink.go19
-rw-r--r--libgo/go/path/filepath/symlink_unix.go7
-rw-r--r--libgo/go/path/filepath/symlink_windows.go5
-rw-r--r--libgo/go/path/path.go10
-rw-r--r--libgo/go/reflect/all_test.go541
-rw-r--r--libgo/go/reflect/deepequal.go3
-rw-r--r--libgo/go/reflect/export_test.go9
-rw-r--r--libgo/go/reflect/makefunc.go87
-rw-r--r--libgo/go/reflect/makefunc_386.S230
-rw-r--r--libgo/go/reflect/makefunc_amd64.S177
-rw-r--r--libgo/go/reflect/makefunc_ffi.go63
-rw-r--r--libgo/go/reflect/makefunc_ffi_c.c93
-rw-r--r--libgo/go/reflect/makefuncgo_386.go143
-rw-r--r--libgo/go/reflect/makefuncgo_amd64.go493
-rw-r--r--libgo/go/reflect/type.go356
-rw-r--r--libgo/go/reflect/value.go1061
-rw-r--r--libgo/go/regexp/all_test.go76
-rw-r--r--libgo/go/regexp/exec.go121
-rw-r--r--libgo/go/regexp/onepass.go581
-rw-r--r--libgo/go/regexp/onepass_test.go208
-rw-r--r--libgo/go/regexp/regexp.go22
-rw-r--r--libgo/go/regexp/syntax/doc.go46
-rw-r--r--libgo/go/regexp/syntax/parse.go44
-rw-r--r--libgo/go/regexp/syntax/parse_test.go17
-rw-r--r--libgo/go/regexp/syntax/perl_groups.go4
-rw-r--r--libgo/go/regexp/syntax/prog.go54
-rw-r--r--libgo/go/regexp/syntax/prog_test.go4
-rw-r--r--libgo/go/regexp/syntax/regexp.go2
-rw-r--r--libgo/go/runtime/append_test.go19
-rw-r--r--libgo/go/runtime/arch_386.go8
-rw-r--r--libgo/go/runtime/arch_amd64.go8
-rw-r--r--libgo/go/runtime/arch_amd64p32.go8
-rw-r--r--libgo/go/runtime/arch_arm.go8
-rw-r--r--libgo/go/runtime/atomic.go51
-rw-r--r--libgo/go/runtime/cgocall.go279
-rw-r--r--libgo/go/runtime/cgocallback.go40
-rw-r--r--libgo/go/runtime/chan.go655
-rw-r--r--libgo/go/runtime/chan_test.go747
-rw-r--r--libgo/go/runtime/complex.go52
-rw-r--r--libgo/go/runtime/cpuprof.go425
-rw-r--r--libgo/go/runtime/crash_cgo_test.go146
-rw-r--r--libgo/go/runtime/crash_test.go249
-rw-r--r--libgo/go/runtime/debug/garbage.go20
-rw-r--r--libgo/go/runtime/debug/heapdump_test.go33
-rw-r--r--libgo/go/runtime/debug/stack.go6
-rw-r--r--libgo/go/runtime/env_posix.go58
-rw-r--r--libgo/go/runtime/error.go7
-rw-r--r--libgo/go/runtime/export_test.go34
-rw-r--r--libgo/go/runtime/extern.go37
-rw-r--r--libgo/go/runtime/gc_test.go139
-rw-r--r--libgo/go/runtime/gcinfo_test.go194
-rw-r--r--libgo/go/runtime/hashmap.go960
-rw-r--r--libgo/go/runtime/hashmap_fast.go379
-rw-r--r--libgo/go/runtime/lfstack_test.go12
-rw-r--r--libgo/go/runtime/lock_futex.go205
-rw-r--r--libgo/go/runtime/lock_sema.go270
-rw-r--r--libgo/go/runtime/malloc.go837
-rw-r--r--libgo/go/runtime/malloc1.go26
-rw-r--r--libgo/go/runtime/mallocrand.go93
-rw-r--r--libgo/go/runtime/mallocrep.go72
-rw-r--r--libgo/go/runtime/mallocrep1.go144
-rw-r--r--libgo/go/runtime/map_test.go145
-rw-r--r--libgo/go/runtime/mapspeed_test.go34
-rw-r--r--libgo/go/runtime/mem.go7
-rw-r--r--libgo/go/runtime/memmove_test.go231
-rw-r--r--libgo/go/runtime/mfinal_test.go201
-rw-r--r--libgo/go/runtime/mgc0.go137
-rw-r--r--libgo/go/runtime/mprof.go668
-rw-r--r--libgo/go/runtime/netpoll.go455
-rw-r--r--libgo/go/runtime/netpoll_epoll.go97
-rw-r--r--libgo/go/runtime/netpoll_kqueue.go101
-rw-r--r--libgo/go/runtime/netpoll_nacl.go26
-rw-r--r--libgo/go/runtime/noasm_arm.go54
-rw-r--r--libgo/go/runtime/norace_test.go36
-rw-r--r--libgo/go/runtime/os_darwin.go24
-rw-r--r--libgo/go/runtime/os_dragonfly.go20
-rw-r--r--libgo/go/runtime/os_freebsd.go17
-rw-r--r--libgo/go/runtime/os_linux.go17
-rw-r--r--libgo/go/runtime/os_nacl.go39
-rw-r--r--libgo/go/runtime/os_netbsd.go20
-rw-r--r--libgo/go/runtime/os_openbsd.go17
-rw-r--r--libgo/go/runtime/os_plan9.go105
-rw-r--r--libgo/go/runtime/os_solaris.go100
-rw-r--r--libgo/go/runtime/os_windows.go58
-rw-r--r--libgo/go/runtime/os_windows_386.go11
-rw-r--r--libgo/go/runtime/os_windows_amd64.go11
-rw-r--r--libgo/go/runtime/panic.go505
-rw-r--r--libgo/go/runtime/pprof/mprof_test.go101
-rw-r--r--libgo/go/runtime/pprof/pprof.go22
-rw-r--r--libgo/go/runtime/pprof/pprof_test.go147
-rw-r--r--libgo/go/runtime/print1.go323
-rw-r--r--libgo/go/runtime/proc.go246
-rw-r--r--libgo/go/runtime/proc_test.go66
-rw-r--r--libgo/go/runtime/race0.go37
-rw-r--r--libgo/go/runtime/rdebug.go37
-rw-r--r--libgo/go/runtime/rune.go219
-rw-r--r--libgo/go/runtime/runtime.go60
-rw-r--r--libgo/go/runtime/runtime_test.go131
-rw-r--r--libgo/go/runtime/runtime_unix_test.go56
-rw-r--r--libgo/go/runtime/select.go651
-rw-r--r--libgo/go/runtime/sema.go275
-rw-r--r--libgo/go/runtime/signal_unix.go13
-rw-r--r--libgo/go/runtime/sigpanic_unix.go40
-rw-r--r--libgo/go/runtime/sigqueue.go182
-rw-r--r--libgo/go/runtime/slice.go139
-rw-r--r--libgo/go/runtime/stack.go13
-rw-r--r--libgo/go/runtime/string.go298
-rw-r--r--libgo/go/runtime/stubs.go316
-rw-r--r--libgo/go/runtime/syscall_windows.go174
-rw-r--r--libgo/go/runtime/time.go289
-rw-r--r--libgo/go/runtime/type.go55
-rw-r--r--libgo/go/runtime/typekind.go44
-rw-r--r--libgo/go/runtime/vlrt.go258
-rw-r--r--libgo/go/sort/sort.go6
-rw-r--r--libgo/go/strconv/atob_test.go34
-rw-r--r--libgo/go/strconv/atof.go11
-rw-r--r--libgo/go/strconv/atoi.go10
-rw-r--r--libgo/go/strconv/isprint.go202
-rw-r--r--libgo/go/strconv/makeisprint.go69
-rw-r--r--libgo/go/strconv/quote.go19
-rw-r--r--libgo/go/strconv/quote_example_test.go35
-rw-r--r--libgo/go/strconv/quote_test.go5
-rw-r--r--libgo/go/strings/example_test.go32
-rw-r--r--libgo/go/strings/reader.go52
-rw-r--r--libgo/go/strings/reader_test.go56
-rw-r--r--libgo/go/strings/replace.go149
-rw-r--r--libgo/go/strings/replace_test.go60
-rw-r--r--libgo/go/strings/strings.go81
-rw-r--r--libgo/go/strings/strings_test.go60
-rw-r--r--libgo/go/sync/atomic/64bit_arm.go12
-rw-r--r--libgo/go/sync/atomic/atomic_test.go23
-rw-r--r--libgo/go/sync/atomic/doc.go2
-rw-r--r--libgo/go/sync/atomic/race.go276
-rw-r--r--libgo/go/sync/atomic/value.go85
-rw-r--r--libgo/go/sync/atomic/value_test.go195
-rw-r--r--libgo/go/sync/mutex_test.go72
-rw-r--r--libgo/go/sync/once.go7
-rw-r--r--libgo/go/sync/once_test.go51
-rw-r--r--libgo/go/sync/pool.go225
-rw-r--r--libgo/go/sync/pool_test.go164
-rw-r--r--libgo/go/sync/runtime.go8
-rw-r--r--libgo/go/sync/runtime_sema_test.go85
-rw-r--r--libgo/go/sync/rwmutex.go10
-rw-r--r--libgo/go/sync/rwmutex_test.go121
-rw-r--r--libgo/go/sync/waitgroup.go21
-rw-r--r--libgo/go/sync/waitgroup_test.go125
-rw-r--r--libgo/go/syscall/consistency_unix_test.go34
-rw-r--r--libgo/go/syscall/dir_plan9.go9
-rw-r--r--libgo/go/syscall/env_plan9.go86
-rw-r--r--libgo/go/syscall/env_unix.go62
-rw-r--r--libgo/go/syscall/env_windows.go8
-rw-r--r--libgo/go/syscall/exec_linux.go130
-rw-r--r--libgo/go/syscall/exec_unix.go5
-rw-r--r--libgo/go/syscall/exec_windows.go15
-rw-r--r--libgo/go/syscall/export_test.go7
-rw-r--r--libgo/go/syscall/libcall_linux_s390.go7
-rw-r--r--libgo/go/syscall/libcall_linux_s390x.go7
-rw-r--r--libgo/go/syscall/libcall_posix.go11
-rw-r--r--libgo/go/syscall/libcall_posix_largefile.go6
-rw-r--r--libgo/go/syscall/libcall_posix_regfile.go6
-rw-r--r--libgo/go/syscall/lsf_linux.go4
-rw-r--r--libgo/go/syscall/mksyscall.awk9
-rw-r--r--libgo/go/syscall/mmap_unix_test.go22
-rw-r--r--libgo/go/syscall/netlink_linux.go3
-rw-r--r--libgo/go/syscall/rlimit_linux_test.go41
-rw-r--r--libgo/go/syscall/route_bsd.go11
-rw-r--r--libgo/go/syscall/route_dragonfly.go2
-rw-r--r--libgo/go/syscall/route_freebsd.go12
-rw-r--r--libgo/go/syscall/route_freebsd_32bit.go24
-rw-r--r--libgo/go/syscall/route_freebsd_64bit.go14
-rw-r--r--libgo/go/syscall/route_netbsd.go2
-rw-r--r--libgo/go/syscall/route_openbsd.go8
-rw-r--r--libgo/go/syscall/sockcmsg_unix.go8
-rw-r--r--libgo/go/syscall/socket.go50
-rw-r--r--libgo/go/syscall/socket_posix.go4
-rw-r--r--libgo/go/syscall/socket_xnet.go4
-rw-r--r--libgo/go/syscall/str.go6
-rw-r--r--libgo/go/syscall/syscall.go12
-rw-r--r--libgo/go/syscall/syscall_errno.go2
-rw-r--r--libgo/go/syscall/syscall_linux_386.go3
-rw-r--r--libgo/go/syscall/syscall_linux_s390.go21
-rw-r--r--libgo/go/syscall/syscall_linux_s390x.go21
-rw-r--r--libgo/go/syscall/syscall_test.go17
-rw-r--r--libgo/go/syscall/syscall_unix.go9
-rw-r--r--libgo/go/syscall/syscall_unix_test.go (renamed from libgo/go/syscall/passfd_test.go)120
-rw-r--r--libgo/go/testing/allocs_test.go29
-rw-r--r--libgo/go/testing/benchmark.go118
-rw-r--r--libgo/go/testing/benchmark_test.go55
-rw-r--r--libgo/go/testing/cover.go28
-rw-r--r--libgo/go/testing/example.go6
-rw-r--r--libgo/go/testing/quick/quick.go6
-rw-r--r--libgo/go/testing/quick/quick_test.go11
-rw-r--r--libgo/go/testing/testing.go121
-rw-r--r--libgo/go/testing/testing_test.go18
-rw-r--r--libgo/go/text/scanner/scanner.go37
-rw-r--r--libgo/go/text/scanner/scanner_test.go63
-rw-r--r--libgo/go/text/tabwriter/tabwriter.go12
-rw-r--r--libgo/go/text/tabwriter/tabwriter_test.go39
-rw-r--r--libgo/go/text/template/doc.go11
-rw-r--r--libgo/go/text/template/exec.go21
-rw-r--r--libgo/go/text/template/exec_test.go121
-rw-r--r--libgo/go/text/template/funcs.go86
-rw-r--r--libgo/go/text/template/multi_test.go12
-rw-r--r--libgo/go/text/template/parse/node.go248
-rw-r--r--libgo/go/text/template/parse/parse.go62
-rw-r--r--libgo/go/text/template/parse/parse_test.go5
-rw-r--r--libgo/go/text/template/template.go2
-rw-r--r--libgo/go/time/example_test.go4
-rw-r--r--libgo/go/time/format.go18
-rw-r--r--libgo/go/time/format_test.go520
-rw-r--r--libgo/go/time/genzabbrs.go20
-rw-r--r--libgo/go/time/internal_test.go43
-rw-r--r--libgo/go/time/sleep.go28
-rw-r--r--libgo/go/time/sleep_test.go78
-rw-r--r--libgo/go/time/sys_unix.go2
-rw-r--r--libgo/go/time/tick.go3
-rw-r--r--libgo/go/time/tick_test.go18
-rw-r--r--libgo/go/time/time.go45
-rw-r--r--libgo/go/time/time_test.go557
-rw-r--r--libgo/go/time/zoneinfo.go87
-rw-r--r--libgo/go/time/zoneinfo_abbrs_windows.go3
-rw-r--r--libgo/go/time/zoneinfo_plan9.go2
-rw-r--r--libgo/go/time/zoneinfo_read.go8
-rw-r--r--libgo/go/time/zoneinfo_test.go66
-rw-r--r--libgo/go/time/zoneinfo_unix.go2
-rw-r--r--libgo/go/time/zoneinfo_windows.go10
-rw-r--r--libgo/go/unicode/letter.go7
-rw-r--r--libgo/go/unicode/letter_test.go16
-rw-r--r--libgo/go/unicode/script_test.go29
-rw-r--r--libgo/go/unicode/tables.go1297
-rw-r--r--libgo/go/unicode/utf16/utf16.go2
-rw-r--r--libgo/go/unicode/utf16/utf16_test.go48
-rw-r--r--libgo/go/unicode/utf8/example_test.go4
-rw-r--r--libgo/go/unicode/utf8/utf8.go60
-rwxr-xr-xlibgo/merge.sh85
-rwxr-xr-xlibgo/mksysinfo.sh99
-rw-r--r--libgo/mvifdiff.sh15
-rw-r--r--libgo/runtime/chan.goc (renamed from libgo/runtime/chan.c)612
-rw-r--r--libgo/runtime/chan.h75
-rw-r--r--libgo/runtime/cpuprof.goc (renamed from libgo/runtime/cpuprof.c)15
-rw-r--r--libgo/runtime/env_posix.c10
-rw-r--r--libgo/runtime/go-append.c5
-rw-r--r--libgo/runtime/go-assert-interface.c2
-rw-r--r--libgo/runtime/go-caller.c40
-rw-r--r--libgo/runtime/go-callers.c54
-rw-r--r--libgo/runtime/go-can-convert-interface.c2
-rw-r--r--libgo/runtime/go-cdiv.c31
-rw-r--r--libgo/runtime/go-cgo.c16
-rw-r--r--libgo/runtime/go-check-interface.c4
-rw-r--r--libgo/runtime/go-convert-interface.c2
-rw-r--r--libgo/runtime/go-defer.c12
-rw-r--r--libgo/runtime/go-defer.h10
-rw-r--r--libgo/runtime/go-eface-compare.c4
-rw-r--r--libgo/runtime/go-eface-val-compare.c2
-rw-r--r--libgo/runtime/go-ffi.c346
-rw-r--r--libgo/runtime/go-ffi.h16
-rw-r--r--libgo/runtime/go-getgoroot.c26
-rw-r--r--libgo/runtime/go-iface.goc (renamed from libgo/runtime/iface.goc)8
-rw-r--r--libgo/runtime/go-interface-eface-compare.c2
-rw-r--r--libgo/runtime/go-make-slice.c2
-rw-r--r--libgo/runtime/go-map-delete.c9
-rw-r--r--libgo/runtime/go-map-index.c4
-rw-r--r--libgo/runtime/go-new.c12
-rw-r--r--libgo/runtime/go-now.c10
-rw-r--r--libgo/runtime/go-panic.c6
-rw-r--r--libgo/runtime/go-panic.h9
-rw-r--r--libgo/runtime/go-recover.c228
-rw-r--r--libgo/runtime/go-reflect-call.c332
-rw-r--r--libgo/runtime/go-reflect-map.c184
-rw-r--r--libgo/runtime/go-setenv.c20
-rw-r--r--libgo/runtime/go-signal.c25
-rw-r--r--libgo/runtime/go-string-to-byte-array.c9
-rw-r--r--libgo/runtime/go-string-to-int-array.c13
-rw-r--r--libgo/runtime/go-traceback.c2
-rw-r--r--libgo/runtime/go-type-complex.c110
-rw-r--r--libgo/runtime/go-type-eface.c3
-rw-r--r--libgo/runtime/go-type-float.c88
-rw-r--r--libgo/runtime/go-type.h26
-rw-r--r--libgo/runtime/go-typestring.c17
-rw-r--r--libgo/runtime/go-unsafe-pointer.c25
-rw-r--r--libgo/runtime/go-unsetenv.c54
-rw-r--r--libgo/runtime/go-unwind.c12
-rw-r--r--libgo/runtime/go-varargs.c6
-rw-r--r--libgo/runtime/goc2c.c17
-rw-r--r--libgo/runtime/heapdump.c776
-rw-r--r--libgo/runtime/lfstack.goc (renamed from libgo/runtime/lfstack.c)12
-rw-r--r--libgo/runtime/lock_futex.c16
-rw-r--r--libgo/runtime/lock_sema.c11
-rw-r--r--libgo/runtime/malloc.goc626
-rw-r--r--libgo/runtime/malloc.h224
-rw-r--r--libgo/runtime/mcache.c124
-rw-r--r--libgo/runtime/mcentral.c205
-rw-r--r--libgo/runtime/mem.c55
-rw-r--r--libgo/runtime/mfinal.c218
-rw-r--r--libgo/runtime/mgc0.c1762
-rw-r--r--libgo/runtime/mgc0.h41
-rw-r--r--libgo/runtime/mheap.c482
-rw-r--r--libgo/runtime/mprof.goc280
-rw-r--r--libgo/runtime/msize.c27
-rw-r--r--libgo/runtime/netpoll.goc205
-rw-r--r--libgo/runtime/netpoll_epoll.c13
-rw-r--r--libgo/runtime/netpoll_kqueue.c12
-rw-r--r--libgo/runtime/netpoll_select.c4
-rw-r--r--libgo/runtime/netpoll_stub.c3
-rw-r--r--libgo/runtime/panic.c113
-rw-r--r--libgo/runtime/parfor.c47
-rw-r--r--libgo/runtime/print.c77
-rw-r--r--libgo/runtime/proc.c707
-rw-r--r--libgo/runtime/race.h33
-rw-r--r--libgo/runtime/rdebug.goc26
-rw-r--r--libgo/runtime/reflect.goc2
-rw-r--r--libgo/runtime/runtime.c138
-rw-r--r--libgo/runtime/runtime.h158
-rw-r--r--libgo/runtime/runtime1.goc75
-rw-r--r--libgo/runtime/sema.goc6
-rw-r--r--libgo/runtime/signal_unix.c11
-rw-r--r--libgo/runtime/string.goc14
-rw-r--r--libgo/runtime/time.goc55
-rw-r--r--libgo/runtime/yield.c6
-rw-r--r--libgo/testsuite/Makefile.in1
-rwxr-xr-xlibgo/testsuite/gotest77
-rw-r--r--libgo/testsuite/lib/libgo.exp2
1106 files changed, 79826 insertions, 23852 deletions
diff --git a/libgo/MERGE b/libgo/MERGE
index cc27a79977..260f8cf8e5 100644
--- a/libgo/MERGE
+++ b/libgo/MERGE
@@ -1,4 +1,4 @@
-0ddbdc3c7ce2
+883bc6ed0ea815293fe6309d66f967ea60630e87
-The first line of this file holds the Mercurial revision number of the
+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 4f09bc30bf..00fbaabae3 100644
--- a/libgo/Makefile.am
+++ b/libgo/Makefile.am
@@ -15,7 +15,7 @@ endif
SUBDIRS = ${subdirs}
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell $(GOC) -dumpversion)
MAINT_CHARSET = latin1
@@ -26,10 +26,13 @@ STAMP = echo timestamp >
toolexecdir = $(glibgo_toolexecdir)
toolexeclibdir = $(glibgo_toolexeclibdir)
toolexeclibgodir = $(nover_glibgo_toolexeclibdir)/go/$(gcc_version)/$(target_alias)
+libexecsubdir = $(libexecdir)/gcc/$(target_alias)/$(gcc_version)
LIBFFI = @LIBFFI@
LIBFFIINCS = @LIBFFIINCS@
+LIBATOMIC = @LIBATOMIC@
+
WARN_CFLAGS = $(WARN_FLAGS) $(WERROR)
# -I/-D flags to pass when compiling.
@@ -97,8 +100,13 @@ AM_MAKEFLAGS = \
# Subdir rules rely on $(FLAGS_TO_PASS)
FLAGS_TO_PASS = $(AM_MAKEFLAGS)
+if GOC_IS_LLGO
+toolexeclib_LTLIBRARIES = libgo-llgo.la
+toolexeclib_LIBRARIES = libgobegin-llgo.a
+else
toolexeclib_LTLIBRARIES = libgo.la
-toolexeclib_LIBRARIES = libgobegin.a
+toolexeclib_LIBRARIES = libgobegin.a libnetgo.a
+endif
toolexeclibgo_DATA = \
bufio.gox \
@@ -196,7 +204,8 @@ toolexeclibgodebug_DATA = \
debug/elf.gox \
debug/gosym.gox \
debug/macho.gox \
- debug/pe.gox
+ debug/pe.gox \
+ debug/plan9obj.gox
toolexeclibgoencodingdir = $(toolexeclibgodir)/encoding
@@ -441,8 +450,8 @@ runtime_files = \
runtime/go-deferred-recover.c \
runtime/go-eface-compare.c \
runtime/go-eface-val-compare.c \
+ runtime/go-ffi.c \
runtime/go-fieldtrack.c \
- runtime/go-getgoroot.c \
runtime/go-int-array-to-string.c \
runtime/go-int-to-string.c \
runtime/go-interface-compare.c \
@@ -483,21 +492,18 @@ runtime_files = \
runtime/go-type-interface.c \
runtime/go-type-string.c \
runtime/go-typedesc-equal.c \
- runtime/go-typestring.c \
runtime/go-unsafe-new.c \
runtime/go-unsafe-newarray.c \
runtime/go-unsafe-pointer.c \
+ runtime/go-unsetenv.c \
runtime/go-unwind.c \
runtime/go-varargs.c \
- runtime/chan.c \
- runtime/cpuprof.c \
runtime/env_posix.c \
- runtime/lfstack.c \
+ runtime/heapdump.c \
$(runtime_lock_files) \
runtime/mcache.c \
runtime/mcentral.c \
$(runtime_mem_file) \
- runtime/mfinal.c \
runtime/mfixalloc.c \
runtime/mgc0.c \
runtime/mheap.c \
@@ -512,11 +518,15 @@ runtime_files = \
runtime/thread.c \
runtime/yield.c \
$(rtems_task_variable_add_file) \
- iface.c \
+ chan.c \
+ cpuprof.c \
+ go-iface.c \
+ lfstack.c \
malloc.c \
map.c \
mprof.c \
netpoll.c \
+ rdebug.c \
reflect.c \
runtime1.c \
sema.c \
@@ -686,9 +696,9 @@ go_net_sockoptip_file = go/net/sockoptip_linux.go go/net/sockoptip_posix.go
else
if LIBGO_IS_SOLARIS
go_net_cgo_file = go/net/cgo_linux.go
-go_net_sock_file = go/net/sock_solaris.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_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
else
if LIBGO_IS_FREEBSD
go_net_cgo_file = go/net/cgo_bsd.go
@@ -753,16 +763,18 @@ if LIBGO_IS_DARWIN
go_net_tcpsockopt_file = go/net/tcpsockopt_darwin.go
else
if LIBGO_IS_SOLARIS
-go_net_tcpsockopt_file = go/net/tcpsockopt_darwin.go
+go_net_tcpsockopt_file = go/net/tcpsockopt_solaris.go
+else
+if LIBGO_IS_DRAGONFLY
+go_net_tcpsockopt_file = go/net/tcpsockopt_dragonfly.go
else
-go_net_tcpsockopt_file = go/net/tcpsockopt_unix.go
+go_net_tcpsockopt_file = go/net/tcpsockopt_unix.go
+endif
endif
endif
endif
-go_net_files = \
- go/net/cgo_unix.go \
- $(go_net_cgo_file) \
+go_net_common_files = \
$(go_net_cloexec_file) \
go/net/dial.go \
go/net/dnsclient.go \
@@ -806,6 +818,15 @@ go_net_files = \
go/net/unixsock.go \
go/net/unixsock_posix.go
+go_net_files = \
+ go/net/cgo_unix.go \
+ $(go_net_cgo_file) \
+ $(go_net_common_files)
+
+go_netgo_files = \
+ go/net/cgo_stub.go \
+ $(go_net_common_files)
+
if LIBGO_IS_SOLARIS
if LIBGO_IS_386
go_os_dir_file = go/os/dir_largefile.go
@@ -848,6 +869,16 @@ endif
endif
endif
+if LIBGO_IS_FREEBSD
+go_os_cloexec_file = go/os/sys_freebsd.go
+else
+if LIBGO_IS_DARWIN
+go_os_cloexec_file = go/os/sys_darwin.go
+else
+go_os_cloexec_file = go/os/sys_unix.go
+endif
+endif
+
if LIBGO_IS_SOLARIS
go_os_stat_file = go/os/stat_solaris.go
else
@@ -906,6 +937,7 @@ go_os_files = \
$(go_os_stat_file) \
go/os/str.go \
$(go_os_sys_file) \
+ $(go_os_cloexec_file) \
go/os/types.go \
go/os/types_notwin.go
@@ -913,33 +945,18 @@ go_path_files = \
go/path/match.go \
go/path/path.go
-if LIBGO_IS_X86_64
-go_reflect_makefunc_file = \
- go/reflect/makefuncgo_amd64.go
-go_reflect_makefunc_s_file = \
- go/reflect/makefunc_amd64.S
-else
-if LIBGO_IS_386
-go_reflect_makefunc_file = \
- go/reflect/makefuncgo_386.go
-go_reflect_makefunc_s_file = \
- go/reflect/makefunc_386.S
-else
-go_reflect_makefunc_file =
-go_reflect_makefunc_s_file = \
- go/reflect/makefunc_dummy.c
-endif
-endif
-
go_reflect_files = \
go/reflect/deepequal.go \
go/reflect/makefunc.go \
- $(go_reflect_makefunc_file) \
+ go/reflect/makefunc_ffi.go \
go/reflect/type.go \
go/reflect/value.go
+go_reflect_makefunc_c_file = \
+ go/reflect/makefunc_ffi_c.c
go_regexp_files = \
go/regexp/exec.go \
+ go/regexp/onepass.go \
go/regexp/regexp.go
go_net_rpc_files = \
@@ -954,7 +971,6 @@ go_runtime_files = \
go/runtime/extern.go \
go/runtime/mem.go \
go/runtime/softfloat64.go \
- go/runtime/type.go \
version.go
version.go: s-version; @true
@@ -962,10 +978,25 @@ s-version: Makefile
rm -f version.go.tmp
echo "package runtime" > version.go.tmp
echo 'const defaultGoroot = "$(prefix)"' >> version.go.tmp
- echo 'const theVersion = "'`$(CC) --version | sed 1q`'"' >> version.go.tmp
+ echo 'const theVersion = "'`cat $(srcdir)/VERSION | sed 1q`' '`$(GOC) --version | sed 1q`'"' >> version.go.tmp
echo 'const theGoarch = "'$(GOARCH)'"' >> version.go.tmp
echo 'const theGoos = "'$(GOOS)'"' >> version.go.tmp
- $(SHELL) $(srcdir)/../move-if-change version.go.tmp version.go
+ echo 'const theGccgoToolDir = "$(libexecsubdir)"' >> version.go.tmp
+ $(SHELL) $(srcdir)/mvifdiff.sh version.go.tmp version.go
+ $(STAMP) $@
+
+noinst_DATA = zstdpkglist.go
+
+# Generate the list of go std packages that were included in libgo
+zstdpkglist.go: s-zstdpkglist; @true
+s-zstdpkglist: Makefile
+ rm -f zstdpkglist.go.tmp
+ echo 'package main' > zstdpkglist.go.tmp
+ echo "" >> zstdpkglist.go.tmp
+ echo 'var stdpkg = map[string]bool{' >> zstdpkglist.go.tmp
+ echo $(libgo_go_objs) 'unsafe.lo' 'runtime/cgo.lo' | sed 's/\.lo /\": true,\n/g' | sed 's/\.lo/\": true,/' | sed 's/-go//' | grep -v _c | sed 's/^/\t\"/' | sort | uniq >> zstdpkglist.go.tmp
+ echo '}' >> zstdpkglist.go.tmp
+ $(SHELL) $(srcdir)/mvifdiff.sh zstdpkglist.go.tmp zstdpkglist.go
$(STAMP) $@
go_sort_files = \
@@ -996,6 +1027,7 @@ go_sync_files = \
go/sync/cond.go \
go/sync/mutex.go \
go/sync/once.go \
+ go/sync/pool.go \
go/sync/race0.go \
go/sync/runtime.go \
go/sync/rwmutex.go \
@@ -1122,7 +1154,8 @@ go_crypto_cipher_files = \
go/crypto/cipher/ctr.go \
go/crypto/cipher/gcm.go \
go/crypto/cipher/io.go \
- go/crypto/cipher/ofb.go
+ go/crypto/cipher/ofb.go \
+ go/crypto/cipher/xor.go
go_crypto_des_files = \
go/crypto/des/block.go \
go/crypto/des/cipher.go \
@@ -1139,11 +1172,21 @@ go_crypto_hmac_files = \
go/crypto/hmac/hmac.go
go_crypto_md5_files = \
go/crypto/md5/md5.go \
- go/crypto/md5/md5block.go
+ go/crypto/md5/md5block.go \
+ go/crypto/md5/md5block_generic.go
+
+if LIBGO_IS_LINUX
+crypto_rand_file = go/crypto/rand/rand_linux.go
+else
+crypto_rand_file =
+endif
+
go_crypto_rand_files = \
go/crypto/rand/rand.go \
go/crypto/rand/rand_unix.go \
+ $(crypto_rand_file) \
go/crypto/rand/util.go
+
go_crypto_rc4_files = \
go/crypto/rc4/rc4.go \
go/crypto/rc4/rc4_ref.go
@@ -1153,7 +1196,8 @@ go_crypto_rsa_files = \
go/crypto/rsa/rsa.go
go_crypto_sha1_files = \
go/crypto/sha1/sha1.go \
- go/crypto/sha1/sha1block.go
+ go/crypto/sha1/sha1block.go \
+ go/crypto/sha1/sha1block_generic.go
go_crypto_sha256_files = \
go/crypto/sha256/sha256.go \
go/crypto/sha256/sha256block.go
@@ -1203,6 +1247,7 @@ go_debug_dwarf_files = \
go/debug/dwarf/line.go \
go/debug/dwarf/open.go \
go/debug/dwarf/type.go \
+ go/debug/dwarf/typeunit.go \
go/debug/dwarf/unit.go
go_debug_elf_files = \
go/debug/elf/elf.go \
@@ -1211,11 +1256,15 @@ go_debug_gosym_files = \
go/debug/gosym/pclntab.go \
go/debug/gosym/symtab.go
go_debug_macho_files = \
+ go/debug/macho/fat.go \
go/debug/macho/file.go \
go/debug/macho/macho.go
go_debug_pe_files = \
go/debug/pe/file.go \
go/debug/pe/pe.go
+go_debug_plan9obj_files = \
+ go/debug/plan9obj/file.go \
+ go/debug/plan9obj/plan9obj.go
go_encoding_ascii85_files = \
go/encoding/ascii85/ascii85.go
@@ -1236,9 +1285,11 @@ go_encoding_csv_files = \
go_encoding_gob_files = \
go/encoding/gob/decode.go \
go/encoding/gob/decoder.go \
+ go/encoding/gob/dec_helpers.go \
go/encoding/gob/doc.go \
go/encoding/gob/encode.go \
go/encoding/gob/encoder.go \
+ go/encoding/gob/enc_helpers.go \
go/encoding/gob/error.go \
go/encoding/gob/type.go
go_encoding_hex_files = \
@@ -1246,6 +1297,7 @@ go_encoding_hex_files = \
go_encoding_json_files = \
go/encoding/json/decode.go \
go/encoding/json/encode.go \
+ go/encoding/json/fold.go \
go/encoding/json/indent.go \
go/encoding/json/scanner.go \
go/encoding/json/stream.go \
@@ -1361,7 +1413,6 @@ go_index_suffixarray_files = \
go/index/suffixarray/suffixarray.go
go_io_ioutil_files = \
- go/io/ioutil/blackhole.go \
go/io/ioutil/ioutil.go \
go/io/ioutil/tempfile.go
@@ -1399,7 +1450,6 @@ go_mime_multipart_files = \
go/mime/multipart/writer.go
go_net_http_files = \
- go/net/http/chunked.go \
go/net/http/client.go \
go/net/http/cookie.go \
go/net/http/filetransport.go \
@@ -1443,11 +1493,12 @@ go_net_http_httptest_files = \
go_net_http_pprof_files = \
go/net/http/pprof/pprof.go
go_net_http_httputil_files = \
- go/net/http/httputil/chunked.go \
go/net/http/httputil/dump.go \
+ go/net/http/httputil/httputil.go \
go/net/http/httputil/persist.go \
go/net/http/httputil/reverseproxy.go
-
+go_net_http_internal_files = \
+ go/net/http/internal/chunked.go
go_old_regexp_files = \
go/old/regexp/regexp.go
@@ -1481,7 +1532,8 @@ go_path_filepath_files = \
go/path/filepath/match.go \
go/path/filepath/path.go \
go/path/filepath/path_unix.go \
- go/path/filepath/symlink.go
+ go/path/filepath/symlink.go \
+ go/path/filepath/symlink_unix.go
go_regexp_syntax_files = \
go/regexp/syntax/compile.go \
@@ -1516,7 +1568,8 @@ go_text_template_parse_files = \
go/text/template/parse/parse.go
go_sync_atomic_files = \
- go/sync/atomic/doc.go
+ go/sync/atomic/doc.go \
+ go/sync/atomic/value.go
go_sync_atomic_c_files = \
go/sync/atomic/atomic.c
@@ -1730,21 +1783,34 @@ go_syscall_c_files = \
go_syscall_test_files = \
$(syscall_creds_test_file) \
- go/syscall/passfd_test.go
+ go/syscall/export_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
files=`echo $^ | sed -e 's/libcalls-list//' -e 's|[^ ]*go/syscall/mksyscall.awk||'`; \
$(AWK) -f $(srcdir)/go/syscall/mksyscall.awk $${files} > libcalls.go.tmp
- $(SHELL) $(srcdir)/../move-if-change libcalls.go.tmp libcalls.go
+ $(SHELL) $(srcdir)/mvifdiff.sh libcalls.go.tmp libcalls.go
$(STAMP) $@
libcalls-list: s-libcalls-list; @true
s-libcalls-list: Makefile
rm -f libcalls-list.tmp
echo $(go_base_syscall_files) > libcalls-list.tmp
- $(SHELL) $(srcdir)/../move-if-change libcalls-list.tmp libcalls-list
+ $(SHELL) $(srcdir)/mvifdiff.sh libcalls-list.tmp libcalls-list
$(STAMP) $@
syscall_arch.go: s-syscall_arch; @true
@@ -1753,13 +1819,13 @@ s-syscall_arch: Makefile
echo "package syscall" > syscall_arch.go.tmp
echo 'const ARCH = "'$(GOARCH)'"' >> syscall_arch.go.tmp
echo 'const OS = "'$(GOOS)'"' >> syscall_arch.go.tmp
- $(SHELL) $(srcdir)/../move-if-change syscall_arch.go.tmp syscall_arch.go
+ $(SHELL) $(srcdir)/mvifdiff.sh syscall_arch.go.tmp syscall_arch.go
$(STAMP) $@
sysinfo.go: s-sysinfo; @true
s-sysinfo: $(srcdir)/mksysinfo.sh config.h
- CC="$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(OSCFLAGS)" $(SHELL) $(srcdir)/mksysinfo.sh
- $(SHELL) $(srcdir)/../move-if-change tmp-sysinfo.go sysinfo.go
+ CC="$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(OSCFLAGS) -O" $(SHELL) $(srcdir)/mksysinfo.sh
+ $(SHELL) $(srcdir)/mvifdiff.sh tmp-sysinfo.go sysinfo.go
$(STAMP) $@
# The epoll struct has an embedded union and is packed on x86_64,
@@ -1787,7 +1853,7 @@ s-epoll: Makefile
exit 1; ;; \
esac
echo '}' >> epoll.go.tmp
- $(SHELL) $(srcdir)/../move-if-change epoll.go.tmp epoll.go
+ $(SHELL) $(srcdir)/mvifdiff.sh epoll.go.tmp epoll.go
$(STAMP) $@
if LIBGO_IS_LINUX
@@ -1818,7 +1884,7 @@ libgo_go_objs = \
os.lo \
path.lo \
reflect-go.lo \
- reflect/makefunc.lo \
+ reflect/makefunc_ffi_c.lo \
regexp.lo \
runtime-go.lo \
sort.lo \
@@ -1868,6 +1934,7 @@ libgo_go_objs = \
debug/gosym.lo \
debug/macho.lo \
debug/pe.lo \
+ debug/plan9obj.lo \
encoding/ascii85.lo \
encoding/asn1.lo \
encoding/base32.lo \
@@ -1899,6 +1966,7 @@ libgo_go_objs = \
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 \
@@ -1907,6 +1975,7 @@ libgo_go_objs = \
image/jpeg.lo \
image/png.lo \
index/suffixarray.lo \
+ internal/syscall.lo \
io/ioutil.lo \
log/syslog.lo \
log/syslog/syslog_c.lo \
@@ -1942,19 +2011,30 @@ libgo_go_objs = \
unicode/utf16.lo \
unicode/utf8.lo
-libgo_la_SOURCES = $(runtime_files)
-
-libgo_la_LDFLAGS = \
+libgo_ldflags = \
-version-info $(libtool_VERSION) $(PTHREAD_CFLAGS) $(AM_LDFLAGS)
-libgo_la_LIBADD = \
+libgo_libadd = \
$(libgo_go_objs) ../libbacktrace/libbacktrace.la \
- ../libatomic/libatomic_convenience.la \
- $(LIBFFI) $(PTHREAD_LIBS) $(MATH_LIBS) $(NET_LIBS)
+ $(LIBATOMIC) $(LIBFFI) $(PTHREAD_LIBS) $(MATH_LIBS) $(NET_LIBS)
+
+libgo_la_SOURCES = $(runtime_files)
+libgo_la_LDFLAGS = $(libgo_ldflags)
+libgo_la_LIBADD = $(libgo_libadd)
+
+libgo_llgo_la_SOURCES = $(runtime_files)
+libgo_llgo_la_LDFLAGS = $(libgo_ldflags)
+libgo_llgo_la_LIBADD = $(libgo_libadd)
libgobegin_a_SOURCES = \
runtime/go-main.c
+libgobegin_llgo_a_SOURCES = \
+ runtime/go-main.c
+
+libnetgo_a_SOURCES = $(go_netgo_files)
+libnetgo_a_LIBADD = netgo.o
+
LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS))
GOCFLAGS = $(CFLAGS)
@@ -1979,7 +2059,14 @@ BUILDPACKAGE = \
files=`echo $^ | sed -e 's/[^ ]*\.gox//g'`; \
$(LTGOCOMPILE) -I . -c -fgo-pkgpath=`echo $@ | sed -e 's/.lo$$//' -e 's/-go$$//'` -o $@ $$files
+# Build netgo.o.
+BUILDNETGO = \
+ $(MKDIR_P) $(@D); \
+ files=`echo $^ | sed -e 's/[^ ]*\.gox//g'`; \
+ $(GOCOMPILE) -I . -c -fgo-pkgpath=net -o $@ $$files
+
GOTESTFLAGS =
+GOBENCH =
# Check a package.
CHECK = \
@@ -1999,6 +2086,8 @@ CHECK = \
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); \
+ 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); \
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 \
echo "PASS: $(@D)" >> $@-testlog; \
@@ -2013,7 +2102,7 @@ CHECK = \
fi
# Build all packages before checking any.
-CHECK_DEPS = libgo.la libgobegin.a \
+CHECK_DEPS = \
$(toolexeclibgo_DATA) \
$(toolexeclibgoarchive_DATA) \
$(toolexeclibgocompress_DATA) \
@@ -2042,6 +2131,12 @@ CHECK_DEPS = libgo.la libgobegin.a \
$(toolexeclibgotexttemplate_DATA) \
$(toolexeclibgounicode_DATA)
+if GOC_IS_LLGO
+CHECK_DEPS += libgo-llgo.la libgobegin-llgo.a
+else
+CHECK_DEPS += libgo.la libgobegin.a
+endif
+
@go_include@ bufio.lo.dep
bufio.lo.dep: $(go_bufio_files)
$(BUILDDEPS)
@@ -2191,6 +2286,12 @@ net/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: net/check
+@go_include@ netgo.o.dep
+netgo.o.dep: $(go_netgo_files)
+ $(BUILDDEPS)
+netgo.o: $(go_netgo_files)
+ $(BUILDNETGO)
+
@go_include@ os.lo.dep
os.lo.dep: $(go_os_files)
$(BUILDDEPS)
@@ -2216,7 +2317,7 @@ reflect-go.lo: $(go_reflect_files)
$(BUILDPACKAGE)
reflect/check: $(CHECK_DEPS)
@$(CHECK)
-reflect/makefunc.lo: $(go_reflect_makefunc_s_file)
+reflect/makefunc_ffi_c.lo: $(go_reflect_makefunc_c_file)
@$(MKDIR_P) reflect
$(LTCOMPILE) -c -o $@ $<
.PHONY: reflect/check
@@ -2620,6 +2721,15 @@ debug/pe/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: debug/pe/check
+@go_include@ debug/plan9obj.lo.dep
+debug/plan9obj.lo.dep: $(go_debug_plan9obj_files)
+ $(BUILDDEPS)
+debug/plan9obj.lo: $(go_debug_plan9obj_files)
+ $(BUILDPACKAGE)
+debug/plan9obj/check: $(CHECK_DEPS)
+ @$(CHECK)
+.PHONY: debug/plan9obj/check
+
@go_include@ encoding/asn1.lo.dep
encoding/asn1.lo.dep: $(go_encoding_asn1_files)
$(BUILDDEPS)
@@ -3073,6 +3183,15 @@ net/http/httputil/check: $(check_deps)
@$(CHECK)
.PHONY: net/http/httputil/check
+@go_include@ net/http/internal.lo.dep
+net/http/internal.lo.dep: $(go_net_http_internal_files)
+ $(BUILDDEPS)
+net/http/internal.lo: $(go_net_http_internal_files)
+ $(BUILDPACKAGE)
+net/http/internal/check: $(CHECK_DEPS)
+ @$(CHECK)
+.PHONY: net/http/internal/check
+
@go_include@ net/http/pprof.lo.dep
net/http/pprof.lo.dep: $(go_net_http_pprof_files)
$(BUILDDEPS)
@@ -3173,7 +3292,8 @@ runtime/pprof/check: $(CHECK_DEPS)
.PHONY: runtime/pprof/check
# At least for now, we need -static-libgo for this test, because
# otherwise we can't get the line numbers.
-runtime_pprof_check_GOCFLAGS = -static-libgo
+# Also use -fno-inline to get better results from the memory profiler.
+runtime_pprof_check_GOCFLAGS = -static-libgo -fno-inline
@go_include@ sync/atomic.lo.dep
sync/atomic.lo.dep: $(go_sync_atomic_files)
@@ -3276,6 +3396,15 @@ 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/'`; \
@@ -3417,6 +3546,8 @@ debug/macho.gox: debug/macho.lo
$(BUILDGOX)
debug/pe.gox: debug/pe.lo
$(BUILDGOX)
+debug/plan9obj.gox: debug/plan9obj.lo
+ $(BUILDGOX)
encoding/ascii85.gox: encoding/ascii85.lo
$(BUILDGOX)
@@ -3534,6 +3665,9 @@ net/http/httputil.gox: net/http/httputil.lo
net/http/pprof.gox: net/http/pprof.lo
$(BUILDGOX)
+net/http/internal.gox: net/http/internal.lo
+ $(BUILDGOX)
+
net/rpc/jsonrpc.gox: net/rpc/jsonrpc.lo
$(BUILDGOX)
@@ -3563,6 +3697,9 @@ 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
@@ -3641,6 +3778,7 @@ TEST_PACKAGES = \
debug/elf/check \
debug/macho/check \
debug/pe/check \
+ debug/plan9obj/check \
encoding/ascii85/check \
encoding/asn1/check \
encoding/base32/check \
@@ -3684,6 +3822,7 @@ TEST_PACKAGES = \
net/http/fcgi/check \
net/http/httptest/check \
net/http/httputil/check \
+ net/http/internal/check \
net/mail/check \
net/rpc/check \
net/smtp/check \
@@ -3806,6 +3945,9 @@ check-am:
check-multi:
$(MULTIDO) $(AM_MAKEFLAGS) DO=check-am multi-do # $(MAKE)
+bench:
+ -@$(MAKE) -k $(TEST_PACKAGES) GOBENCH=.
+
MOSTLYCLEAN_FILES = libgo.head libgo.sum.sep libgo.log.sep
mostlyclean-local:
diff --git a/libgo/Makefile.in b/libgo/Makefile.in
index cf93938379..8ecc339012 100644
--- a/libgo/Makefile.in
+++ b/libgo/Makefile.in
@@ -45,6 +45,8 @@ POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
target_triplet = @target@
+@GOC_IS_LLGO_TRUE@am__append_1 = libgo-llgo.la libgobegin-llgo.a
+@GOC_IS_LLGO_FALSE@am__append_2 = libgo.la libgobegin.a
subdir = .
DIST_COMMON = README $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
$(top_srcdir)/configure $(am__configure_deps) \
@@ -126,78 +128,93 @@ am__installdirs = "$(DESTDIR)$(toolexeclibdir)" \
"$(DESTDIR)$(toolexeclibgounicodedir)"
LIBRARIES = $(toolexeclib_LIBRARIES)
ARFLAGS = cru
+libgobegin_llgo_a_AR = $(AR) $(ARFLAGS)
+libgobegin_llgo_a_LIBADD =
+am_libgobegin_llgo_a_OBJECTS = go-main.$(OBJEXT)
+libgobegin_llgo_a_OBJECTS = $(am_libgobegin_llgo_a_OBJECTS)
libgobegin_a_AR = $(AR) $(ARFLAGS)
libgobegin_a_LIBADD =
am_libgobegin_a_OBJECTS = go-main.$(OBJEXT)
libgobegin_a_OBJECTS = $(am_libgobegin_a_OBJECTS)
+libnetgo_a_AR = $(AR) $(ARFLAGS)
+libnetgo_a_DEPENDENCIES = netgo.o
+am__objects_1 =
+am__objects_2 = $(am__objects_1) $(am__objects_1) $(am__objects_1) \
+ $(am__objects_1) $(am__objects_1) $(am__objects_1) \
+ $(am__objects_1)
+am__objects_3 = $(am__objects_2)
+am_libnetgo_a_OBJECTS = $(am__objects_3)
+libnetgo_a_OBJECTS = $(am_libnetgo_a_OBJECTS)
LTLIBRARIES = $(toolexeclib_LTLIBRARIES)
am__DEPENDENCIES_1 =
am__DEPENDENCIES_2 = bufio.lo bytes.lo bytes/index.lo crypto.lo \
encoding.lo errors.lo expvar.lo flag.lo fmt.lo hash.lo html.lo \
image.lo io.lo log.lo math.lo mime.lo net.lo os.lo path.lo \
- reflect-go.lo reflect/makefunc.lo regexp.lo runtime-go.lo \
- sort.lo strconv.lo strings.lo strings/index.lo sync.lo \
- syscall.lo syscall/errno.lo syscall/signame.lo syscall/wait.lo \
- testing.lo time-go.lo unicode.lo archive/tar.lo archive/zip.lo \
- compress/bzip2.lo compress/flate.lo compress/gzip.lo \
- compress/lzw.lo compress/zlib.lo container/heap.lo \
- container/list.lo container/ring.lo crypto/aes.lo \
- crypto/cipher.lo crypto/des.lo crypto/dsa.lo crypto/ecdsa.lo \
- crypto/elliptic.lo crypto/hmac.lo crypto/md5.lo crypto/rand.lo \
- crypto/rc4.lo crypto/rsa.lo crypto/sha1.lo crypto/sha256.lo \
- crypto/sha512.lo crypto/subtle.lo crypto/tls.lo crypto/x509.lo \
+ reflect-go.lo reflect/makefunc_ffi_c.lo regexp.lo \
+ runtime-go.lo sort.lo strconv.lo strings.lo strings/index.lo \
+ sync.lo syscall.lo syscall/errno.lo syscall/signame.lo \
+ syscall/wait.lo testing.lo time-go.lo unicode.lo \
+ archive/tar.lo archive/zip.lo compress/bzip2.lo \
+ compress/flate.lo compress/gzip.lo compress/lzw.lo \
+ compress/zlib.lo container/heap.lo container/list.lo \
+ container/ring.lo crypto/aes.lo crypto/cipher.lo crypto/des.lo \
+ crypto/dsa.lo crypto/ecdsa.lo crypto/elliptic.lo \
+ crypto/hmac.lo crypto/md5.lo crypto/rand.lo crypto/rc4.lo \
+ crypto/rsa.lo crypto/sha1.lo crypto/sha256.lo crypto/sha512.lo \
+ crypto/subtle.lo crypto/tls.lo crypto/x509.lo \
crypto/x509/pkix.lo database/sql.lo database/sql/driver.lo \
debug/dwarf.lo debug/elf.lo debug/gosym.lo debug/macho.lo \
- debug/pe.lo encoding/ascii85.lo encoding/asn1.lo \
- encoding/base32.lo encoding/base64.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 hash/crc32.lo \
- hash/crc64.lo hash/fnv.lo net/http/cgi.lo \
+ debug/pe.lo debug/plan9obj.lo encoding/ascii85.lo \
+ encoding/asn1.lo encoding/base32.lo encoding/base64.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 \
+ 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/pprof.lo image/color.lo \
- image/color/palette.lo image/draw.lo image/gif.lo \
- image/jpeg.lo image/png.lo index/suffixarray.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 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 \
+ 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 \
+ 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 \
net/rpc/jsonrpc.lo runtime/debug.lo runtime/pprof.lo \
sync/atomic.lo sync/atomic_c.lo text/scanner.lo \
text/tabwriter.lo text/template.lo text/template/parse.lo \
testing/iotest.lo testing/quick.lo unicode/utf16.lo \
unicode/utf8.lo
-libgo_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \
- ../libbacktrace/libbacktrace.la \
- ../libatomic/libatomic_convenience.la $(am__DEPENDENCIES_1) \
+am__DEPENDENCIES_3 = $(am__DEPENDENCIES_2) \
+ ../libbacktrace/libbacktrace.la $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
- $(am__DEPENDENCIES_1)
-@LIBGO_IS_LINUX_FALSE@am__objects_1 = lock_sema.lo thread-sema.lo
-@LIBGO_IS_LINUX_TRUE@am__objects_1 = lock_futex.lo thread-linux.lo
-@HAVE_SYS_MMAN_H_FALSE@am__objects_2 = mem_posix_memalign.lo
-@HAVE_SYS_MMAN_H_TRUE@am__objects_2 = mem.lo
-@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@am__objects_3 = netpoll_kqueue.lo
-@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@am__objects_3 = netpoll_select.lo
-@LIBGO_IS_LINUX_TRUE@am__objects_3 = netpoll_epoll.lo
-@LIBGO_IS_RTEMS_TRUE@am__objects_4 = rtems-task-variable-add.lo
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@am__objects_5 = getncpu-none.lo
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@am__objects_5 = getncpu-bsd.lo
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@am__objects_5 = getncpu-bsd.lo
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@am__objects_5 = getncpu-solaris.lo
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@am__objects_5 = getncpu-irix.lo
-@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@am__objects_5 = \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+libgo_llgo_la_DEPENDENCIES = $(am__DEPENDENCIES_3)
+@LIBGO_IS_LINUX_FALSE@am__objects_4 = lock_sema.lo thread-sema.lo
+@LIBGO_IS_LINUX_TRUE@am__objects_4 = lock_futex.lo thread-linux.lo
+@HAVE_SYS_MMAN_H_FALSE@am__objects_5 = mem_posix_memalign.lo
+@HAVE_SYS_MMAN_H_TRUE@am__objects_5 = mem.lo
+@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@am__objects_6 = netpoll_kqueue.lo
+@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@am__objects_6 = netpoll_select.lo
+@LIBGO_IS_LINUX_TRUE@am__objects_6 = netpoll_epoll.lo
+@LIBGO_IS_RTEMS_TRUE@am__objects_7 = rtems-task-variable-add.lo
+@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@am__objects_8 = getncpu-none.lo
+@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@am__objects_8 = getncpu-bsd.lo
+@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@am__objects_8 = getncpu-bsd.lo
+@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@am__objects_8 = getncpu-solaris.lo
+@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@am__objects_8 = getncpu-irix.lo
+@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@am__objects_8 = \
@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@ getncpu-bsd.lo
-@LIBGO_IS_LINUX_TRUE@am__objects_5 = getncpu-linux.lo
-am__objects_6 = go-append.lo go-assert.lo go-assert-interface.lo \
+@LIBGO_IS_LINUX_TRUE@am__objects_8 = getncpu-linux.lo
+am__objects_9 = go-append.lo go-assert.lo go-assert-interface.lo \
go-byte-array-to-string.lo go-breakpoint.lo go-caller.lo \
go-callers.lo go-can-convert-interface.lo go-cdiv.lo go-cgo.lo \
go-check-interface.lo go-construct-map.lo \
go-convert-interface.lo go-copy.lo go-defer.lo \
go-deferred-recover.lo go-eface-compare.lo \
- go-eface-val-compare.lo go-fieldtrack.lo go-getgoroot.lo \
+ go-eface-val-compare.lo go-ffi.lo go-fieldtrack.lo \
go-int-array-to-string.lo go-int-to-string.lo \
go-interface-compare.lo go-interface-eface-compare.lo \
go-interface-val-compare.lo go-make-slice.lo go-map-delete.lo \
@@ -210,21 +227,29 @@ am__objects_6 = go-append.lo go-assert.lo go-assert-interface.lo \
go-strplus.lo go-strslice.lo go-traceback.lo \
go-type-complex.lo go-type-eface.lo go-type-error.lo \
go-type-float.lo go-type-identity.lo go-type-interface.lo \
- go-type-string.lo go-typedesc-equal.lo go-typestring.lo \
- go-unsafe-new.lo go-unsafe-newarray.lo go-unsafe-pointer.lo \
- go-unwind.lo go-varargs.lo chan.lo cpuprof.lo env_posix.lo \
- lfstack.lo $(am__objects_1) mcache.lo mcentral.lo \
- $(am__objects_2) mfinal.lo mfixalloc.lo mgc0.lo mheap.lo \
- msize.lo $(am__objects_3) panic.lo parfor.lo print.lo proc.lo \
- runtime.lo signal_unix.lo thread.lo yield.lo $(am__objects_4) \
- iface.lo malloc.lo map.lo mprof.lo netpoll.lo reflect.lo \
- runtime1.lo sema.lo sigqueue.lo string.lo time.lo \
- $(am__objects_5)
-am_libgo_la_OBJECTS = $(am__objects_6)
+ go-type-string.lo go-typedesc-equal.lo go-unsafe-new.lo \
+ go-unsafe-newarray.lo go-unsafe-pointer.lo go-unsetenv.lo \
+ go-unwind.lo go-varargs.lo env_posix.lo heapdump.lo \
+ $(am__objects_4) mcache.lo mcentral.lo $(am__objects_5) \
+ mfixalloc.lo mgc0.lo mheap.lo msize.lo $(am__objects_6) \
+ panic.lo parfor.lo print.lo proc.lo runtime.lo signal_unix.lo \
+ thread.lo yield.lo $(am__objects_7) chan.lo cpuprof.lo \
+ go-iface.lo lfstack.lo malloc.lo map.lo mprof.lo netpoll.lo \
+ rdebug.lo reflect.lo runtime1.lo sema.lo sigqueue.lo string.lo \
+ time.lo $(am__objects_8)
+am_libgo_llgo_la_OBJECTS = $(am__objects_9)
+libgo_llgo_la_OBJECTS = $(am_libgo_llgo_la_OBJECTS)
+libgo_llgo_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(libgo_llgo_la_LDFLAGS) $(LDFLAGS) -o $@
+@GOC_IS_LLGO_TRUE@am_libgo_llgo_la_rpath = -rpath $(toolexeclibdir)
+libgo_la_DEPENDENCIES = $(am__DEPENDENCIES_3)
+am_libgo_la_OBJECTS = $(am__objects_9)
libgo_la_OBJECTS = $(am_libgo_la_OBJECTS)
libgo_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(libgo_la_LDFLAGS) \
$(LDFLAGS) -o $@
+@GOC_IS_LLGO_FALSE@am_libgo_la_rpath = -rpath $(toolexeclibdir)
DEFAULT_INCLUDES = -I.@am__isrc@
depcomp = $(SHELL) $(top_srcdir)/../depcomp
am__depfiles_maybe = depfiles
@@ -238,7 +263,9 @@ CCLD = $(CC)
LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
$(LDFLAGS) -o $@
-SOURCES = $(libgobegin_a_SOURCES) $(libgo_la_SOURCES)
+SOURCES = $(libgobegin_llgo_a_SOURCES) $(libgobegin_a_SOURCES) \
+ $(libnetgo_a_SOURCES) $(libgo_llgo_la_SOURCES) \
+ $(libgo_la_SOURCES)
MULTISRCTOP =
MULTIBUILDTOP =
MULTIDIRS =
@@ -252,23 +279,24 @@ RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
install-pdf-recursive install-ps-recursive install-recursive \
installcheck-recursive installdirs-recursive pdf-recursive \
ps-recursive uninstall-recursive
-DATA = $(toolexeclibgo_DATA) $(toolexeclibgoarchive_DATA) \
- $(toolexeclibgocompress_DATA) $(toolexeclibgocontainer_DATA) \
- $(toolexeclibgocrypto_DATA) $(toolexeclibgocryptox509_DATA) \
- $(toolexeclibgodatabase_DATA) $(toolexeclibgodatabasesql_DATA) \
- $(toolexeclibgodebug_DATA) $(toolexeclibgoencoding_DATA) \
- $(toolexeclibgoexp_DATA) $(toolexeclibgogo_DATA) \
- $(toolexeclibgohash_DATA) $(toolexeclibgohtml_DATA) \
- $(toolexeclibgoimage_DATA) $(toolexeclibgoimagecolor_DATA) \
- $(toolexeclibgoindex_DATA) $(toolexeclibgoio_DATA) \
- $(toolexeclibgolog_DATA) $(toolexeclibgomath_DATA) \
- $(toolexeclibgomime_DATA) $(toolexeclibgonet_DATA) \
- $(toolexeclibgonethttp_DATA) $(toolexeclibgonetrpc_DATA) \
- $(toolexeclibgoold_DATA) $(toolexeclibgoos_DATA) \
- $(toolexeclibgopath_DATA) $(toolexeclibgoregexp_DATA) \
- $(toolexeclibgoruntime_DATA) $(toolexeclibgosync_DATA) \
- $(toolexeclibgotesting_DATA) $(toolexeclibgotext_DATA) \
- $(toolexeclibgotexttemplate_DATA) $(toolexeclibgounicode_DATA)
+DATA = $(noinst_DATA) $(toolexeclibgo_DATA) \
+ $(toolexeclibgoarchive_DATA) $(toolexeclibgocompress_DATA) \
+ $(toolexeclibgocontainer_DATA) $(toolexeclibgocrypto_DATA) \
+ $(toolexeclibgocryptox509_DATA) $(toolexeclibgodatabase_DATA) \
+ $(toolexeclibgodatabasesql_DATA) $(toolexeclibgodebug_DATA) \
+ $(toolexeclibgoencoding_DATA) $(toolexeclibgoexp_DATA) \
+ $(toolexeclibgogo_DATA) $(toolexeclibgohash_DATA) \
+ $(toolexeclibgohtml_DATA) $(toolexeclibgoimage_DATA) \
+ $(toolexeclibgoimagecolor_DATA) $(toolexeclibgoindex_DATA) \
+ $(toolexeclibgoio_DATA) $(toolexeclibgolog_DATA) \
+ $(toolexeclibgomath_DATA) $(toolexeclibgomime_DATA) \
+ $(toolexeclibgonet_DATA) $(toolexeclibgonethttp_DATA) \
+ $(toolexeclibgonetrpc_DATA) $(toolexeclibgoold_DATA) \
+ $(toolexeclibgoos_DATA) $(toolexeclibgopath_DATA) \
+ $(toolexeclibgoregexp_DATA) $(toolexeclibgoruntime_DATA) \
+ $(toolexeclibgosync_DATA) $(toolexeclibgotesting_DATA) \
+ $(toolexeclibgotext_DATA) $(toolexeclibgotexttemplate_DATA) \
+ $(toolexeclibgounicode_DATA)
RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
distclean-recursive maintainer-clean-recursive
AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
@@ -316,6 +344,7 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LD = @LD@
LDFLAGS = @LDFLAGS@
+LIBATOMIC = @LIBATOMIC@
LIBFFI = @LIBFFI@
LIBFFIINCS = @LIBFFIINCS@
LIBOBJS = @LIBOBJS@
@@ -429,7 +458,7 @@ top_srcdir = @top_srcdir@
SUFFIXES = .c .go .gox .o .obj .lo .a
@LIBGO_IS_RTEMS_TRUE@subdirs = testsuite
SUBDIRS = ${subdirs}
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell $(GOC) -dumpversion)
MAINT_CHARSET = latin1
mkinstalldirs = $(SHELL) $(toplevel_srcdir)/mkinstalldirs
PWD_COMMAND = $${PWDCMD-pwd}
@@ -437,6 +466,7 @@ STAMP = echo timestamp >
toolexecdir = $(glibgo_toolexecdir)
toolexeclibdir = $(glibgo_toolexeclibdir)
toolexeclibgodir = $(nover_glibgo_toolexeclibdir)/go/$(gcc_version)/$(target_alias)
+libexecsubdir = $(libexecdir)/gcc/$(target_alias)/$(gcc_version)
WARN_CFLAGS = $(WARN_FLAGS) $(WERROR)
# -I/-D flags to pass when compiling.
@@ -500,8 +530,10 @@ AM_MAKEFLAGS = \
# Subdir rules rely on $(FLAGS_TO_PASS)
FLAGS_TO_PASS = $(AM_MAKEFLAGS)
-toolexeclib_LTLIBRARIES = libgo.la
-toolexeclib_LIBRARIES = libgobegin.a
+@GOC_IS_LLGO_FALSE@toolexeclib_LTLIBRARIES = libgo.la
+@GOC_IS_LLGO_TRUE@toolexeclib_LTLIBRARIES = libgo-llgo.la
+@GOC_IS_LLGO_FALSE@toolexeclib_LIBRARIES = libgobegin.a libnetgo.a
+@GOC_IS_LLGO_TRUE@toolexeclib_LIBRARIES = libgobegin-llgo.a
toolexeclibgo_DATA = \
bufio.gox \
bytes.gox \
@@ -590,7 +622,8 @@ toolexeclibgodebug_DATA = \
debug/elf.gox \
debug/gosym.gox \
debug/macho.gox \
- debug/pe.gox
+ debug/pe.gox \
+ debug/plan9obj.gox
toolexeclibgoencodingdir = $(toolexeclibgodir)/encoding
toolexeclibgoencoding_DATA = \
@@ -772,8 +805,8 @@ runtime_files = \
runtime/go-deferred-recover.c \
runtime/go-eface-compare.c \
runtime/go-eface-val-compare.c \
+ runtime/go-ffi.c \
runtime/go-fieldtrack.c \
- runtime/go-getgoroot.c \
runtime/go-int-array-to-string.c \
runtime/go-int-to-string.c \
runtime/go-interface-compare.c \
@@ -814,21 +847,18 @@ runtime_files = \
runtime/go-type-interface.c \
runtime/go-type-string.c \
runtime/go-typedesc-equal.c \
- runtime/go-typestring.c \
runtime/go-unsafe-new.c \
runtime/go-unsafe-newarray.c \
runtime/go-unsafe-pointer.c \
+ runtime/go-unsetenv.c \
runtime/go-unwind.c \
runtime/go-varargs.c \
- runtime/chan.c \
- runtime/cpuprof.c \
runtime/env_posix.c \
- runtime/lfstack.c \
+ runtime/heapdump.c \
$(runtime_lock_files) \
runtime/mcache.c \
runtime/mcentral.c \
$(runtime_mem_file) \
- runtime/mfinal.c \
runtime/mfixalloc.c \
runtime/mgc0.c \
runtime/mheap.c \
@@ -843,11 +873,15 @@ runtime_files = \
runtime/thread.c \
runtime/yield.c \
$(rtems_task_variable_add_file) \
- iface.c \
+ chan.c \
+ cpuprof.c \
+ go-iface.c \
+ lfstack.c \
malloc.c \
map.c \
mprof.c \
netpoll.c \
+ rdebug.c \
reflect.c \
runtime1.c \
sema.c \
@@ -971,19 +1005,19 @@ go_mime_files = \
@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
@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@go_net_sock_file = go/net/sock_bsd.go
@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sock_file = go/net/sock_bsd.go
-@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_sock_file = go/net/sock_solaris.go
+@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_sock_file = go/net/sock_stub.go
@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@go_net_sock_file = go/net/sock_linux.go
@LIBGO_IS_LINUX_TRUE@go_net_sock_file = go/net/sock_linux.go
@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sockopt_file = go/net/sockopt_bsd.go
@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@go_net_sockopt_file = go/net/sockopt_bsd.go
@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sockopt_file = go/net/sockopt_bsd.go
-@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_sockopt_file = go/net/sockopt_bsd.go
+@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_sockopt_file = go/net/sockopt_solaris.go
@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@go_net_sockopt_file = go/net/sockopt_linux.go
@LIBGO_IS_LINUX_TRUE@go_net_sockopt_file = go/net/sockopt_linux.go
@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sockoptip_file = go/net/sockoptip_bsd.go go/net/sockoptip_posix.go
@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@go_net_sockoptip_file = go/net/sockoptip_bsd.go go/net/sockoptip_posix.go
@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sockoptip_file = go/net/sockoptip_bsd.go go/net/sockoptip_posix.go
-@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_sockoptip_file = go/net/sockoptip_bsd.go go/net/sockoptip_posix.go
+@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
@@ -996,13 +1030,12 @@ go_mime_files = \
@LIBGO_IS_LINUX_TRUE@go_net_interface_file = go/net/interface_linux.go
@LIBGO_IS_LINUX_FALSE@go_net_cloexec_file = go/net/sys_cloexec.go
@LIBGO_IS_LINUX_TRUE@go_net_cloexec_file = go/net/sock_cloexec.go
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_OPENBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_tcpsockopt_file = go/net/tcpsockopt_unix.go
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_OPENBSD_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_tcpsockopt_file = go/net/tcpsockopt_darwin.go
+@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_OPENBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_tcpsockopt_file = go/net/tcpsockopt_unix.go
+@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_DRAGONFLY_TRUE@@LIBGO_IS_OPENBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_tcpsockopt_file = go/net/tcpsockopt_dragonfly.go
+@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_OPENBSD_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_tcpsockopt_file = go/net/tcpsockopt_solaris.go
@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_files = \
- go/net/cgo_unix.go \
- $(go_net_cgo_file) \
+go_net_common_files = \
$(go_net_cloexec_file) \
go/net/dial.go \
go/net/dnsclient.go \
@@ -1046,6 +1079,15 @@ go_net_files = \
go/net/unixsock.go \
go/net/unixsock_posix.go
+go_net_files = \
+ go/net/cgo_unix.go \
+ $(go_net_cgo_file) \
+ $(go_net_common_files)
+
+go_netgo_files = \
+ go/net/cgo_stub.go \
+ $(go_net_common_files)
+
@LIBGO_IS_386_FALSE@@LIBGO_IS_SOLARIS_TRUE@@LIBGO_IS_SPARC_FALSE@go_os_dir_file = go/os/dir_regfile.go
@LIBGO_IS_386_FALSE@@LIBGO_IS_SOLARIS_TRUE@@LIBGO_IS_SPARC_TRUE@go_os_dir_file = go/os/dir_largefile.go
@LIBGO_IS_386_TRUE@@LIBGO_IS_SOLARIS_TRUE@go_os_dir_file = go/os/dir_largefile.go
@@ -1058,6 +1100,9 @@ go_net_files = \
@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_os_sys_file = go/os/sys_uname.go
@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_os_sys_file = go/os/sys_uname.go
@LIBGO_IS_LINUX_TRUE@go_os_sys_file = go/os/sys_linux.go
+@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_FALSE@go_os_cloexec_file = go/os/sys_unix.go
+@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_FREEBSD_FALSE@go_os_cloexec_file = go/os/sys_darwin.go
+@LIBGO_IS_FREEBSD_TRUE@go_os_cloexec_file = go/os/sys_freebsd.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_os_stat_file = go/os/stat.go
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_DRAGONFLY_TRUE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_OPENBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_os_stat_file = go/os/stat_dragonfly.go
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_OPENBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_os_stat_file = go/os/stat_atimespec.go
@@ -1090,6 +1135,7 @@ go_os_files = \
$(go_os_stat_file) \
go/os/str.go \
$(go_os_sys_file) \
+ $(go_os_cloexec_file) \
go/os/types.go \
go/os/types_notwin.go
@@ -1097,31 +1143,19 @@ go_path_files = \
go/path/match.go \
go/path/path.go
-@LIBGO_IS_386_FALSE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_file =
-@LIBGO_IS_386_TRUE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_file = \
-@LIBGO_IS_386_TRUE@@LIBGO_IS_X86_64_FALSE@ go/reflect/makefuncgo_386.go
-
-@LIBGO_IS_X86_64_TRUE@go_reflect_makefunc_file = \
-@LIBGO_IS_X86_64_TRUE@ go/reflect/makefuncgo_amd64.go
-
-@LIBGO_IS_386_FALSE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_s_file = \
-@LIBGO_IS_386_FALSE@@LIBGO_IS_X86_64_FALSE@ go/reflect/makefunc_dummy.c
-
-@LIBGO_IS_386_TRUE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_s_file = \
-@LIBGO_IS_386_TRUE@@LIBGO_IS_X86_64_FALSE@ go/reflect/makefunc_386.S
-
-@LIBGO_IS_X86_64_TRUE@go_reflect_makefunc_s_file = \
-@LIBGO_IS_X86_64_TRUE@ go/reflect/makefunc_amd64.S
-
go_reflect_files = \
go/reflect/deepequal.go \
go/reflect/makefunc.go \
- $(go_reflect_makefunc_file) \
+ go/reflect/makefunc_ffi.go \
go/reflect/type.go \
go/reflect/value.go
+go_reflect_makefunc_c_file = \
+ go/reflect/makefunc_ffi_c.c
+
go_regexp_files = \
go/regexp/exec.go \
+ go/regexp/onepass.go \
go/regexp/regexp.go
go_net_rpc_files = \
@@ -1136,9 +1170,9 @@ go_runtime_files = \
go/runtime/extern.go \
go/runtime/mem.go \
go/runtime/softfloat64.go \
- go/runtime/type.go \
version.go
+noinst_DATA = zstdpkglist.go
go_sort_files = \
go/sort/search.go \
go/sort/sort.go
@@ -1168,6 +1202,7 @@ go_sync_files = \
go/sync/cond.go \
go/sync/mutex.go \
go/sync/once.go \
+ go/sync/pool.go \
go/sync/race0.go \
go/sync/runtime.go \
go/sync/rwmutex.go \
@@ -1276,7 +1311,8 @@ go_crypto_cipher_files = \
go/crypto/cipher/ctr.go \
go/crypto/cipher/gcm.go \
go/crypto/cipher/io.go \
- go/crypto/cipher/ofb.go
+ go/crypto/cipher/ofb.go \
+ go/crypto/cipher/xor.go
go_crypto_des_files = \
go/crypto/des/block.go \
@@ -1299,11 +1335,15 @@ go_crypto_hmac_files = \
go_crypto_md5_files = \
go/crypto/md5/md5.go \
- go/crypto/md5/md5block.go
+ go/crypto/md5/md5block.go \
+ go/crypto/md5/md5block_generic.go
+@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/rand.go \
go/crypto/rand/rand_unix.go \
+ $(crypto_rand_file) \
go/crypto/rand/util.go
go_crypto_rc4_files = \
@@ -1317,7 +1357,8 @@ go_crypto_rsa_files = \
go_crypto_sha1_files = \
go/crypto/sha1/sha1.go \
- go/crypto/sha1/sha1block.go
+ go/crypto/sha1/sha1block.go \
+ go/crypto/sha1/sha1block_generic.go
go_crypto_sha256_files = \
go/crypto/sha256/sha256.go \
@@ -1372,6 +1413,7 @@ go_debug_dwarf_files = \
go/debug/dwarf/line.go \
go/debug/dwarf/open.go \
go/debug/dwarf/type.go \
+ go/debug/dwarf/typeunit.go \
go/debug/dwarf/unit.go
go_debug_elf_files = \
@@ -1383,6 +1425,7 @@ go_debug_gosym_files = \
go/debug/gosym/symtab.go
go_debug_macho_files = \
+ go/debug/macho/fat.go \
go/debug/macho/file.go \
go/debug/macho/macho.go
@@ -1390,6 +1433,10 @@ go_debug_pe_files = \
go/debug/pe/file.go \
go/debug/pe/pe.go
+go_debug_plan9obj_files = \
+ go/debug/plan9obj/file.go \
+ go/debug/plan9obj/plan9obj.go
+
go_encoding_ascii85_files = \
go/encoding/ascii85/ascii85.go
@@ -1415,9 +1462,11 @@ go_encoding_csv_files = \
go_encoding_gob_files = \
go/encoding/gob/decode.go \
go/encoding/gob/decoder.go \
+ go/encoding/gob/dec_helpers.go \
go/encoding/gob/doc.go \
go/encoding/gob/encode.go \
go/encoding/gob/encoder.go \
+ go/encoding/gob/enc_helpers.go \
go/encoding/gob/error.go \
go/encoding/gob/type.go
@@ -1427,6 +1476,7 @@ go_encoding_hex_files = \
go_encoding_json_files = \
go/encoding/json/decode.go \
go/encoding/json/encode.go \
+ go/encoding/json/fold.go \
go/encoding/json/indent.go \
go/encoding/json/scanner.go \
go/encoding/json/stream.go \
@@ -1555,7 +1605,6 @@ go_index_suffixarray_files = \
go/index/suffixarray/suffixarray.go
go_io_ioutil_files = \
- go/io/ioutil/blackhole.go \
go/io/ioutil/ioutil.go \
go/io/ioutil/tempfile.go
@@ -1595,7 +1644,6 @@ go_mime_multipart_files = \
go/mime/multipart/writer.go
go_net_http_files = \
- go/net/http/chunked.go \
go/net/http/client.go \
go/net/http/cookie.go \
go/net/http/filetransport.go \
@@ -1648,11 +1696,14 @@ go_net_http_pprof_files = \
go/net/http/pprof/pprof.go
go_net_http_httputil_files = \
- go/net/http/httputil/chunked.go \
go/net/http/httputil/dump.go \
+ go/net/http/httputil/httputil.go \
go/net/http/httputil/persist.go \
go/net/http/httputil/reverseproxy.go
+go_net_http_internal_files = \
+ go/net/http/internal/chunked.go
+
go_old_regexp_files = \
go/old/regexp/regexp.go
@@ -1682,7 +1733,8 @@ go_path_filepath_files = \
go/path/filepath/match.go \
go/path/filepath/path.go \
go/path/filepath/path_unix.go \
- go/path/filepath/symlink.go
+ go/path/filepath/symlink.go \
+ go/path/filepath/symlink_unix.go
go_regexp_syntax_files = \
go/regexp/syntax/compile.go \
@@ -1720,7 +1772,8 @@ go_text_template_parse_files = \
go/text/template/parse/parse.go
go_sync_atomic_files = \
- go/sync/atomic/doc.go
+ go/sync/atomic/doc.go \
+ go/sync/atomic/value.go
go_sync_atomic_c_files = \
go/sync/atomic/atomic.c
@@ -1863,7 +1916,16 @@ go_syscall_c_files = \
go_syscall_test_files = \
$(syscall_creds_test_file) \
- go/syscall/passfd_test.go
+ go/syscall/export_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 =
@@ -1890,7 +1952,7 @@ libgo_go_objs = \
os.lo \
path.lo \
reflect-go.lo \
- reflect/makefunc.lo \
+ reflect/makefunc_ffi_c.lo \
regexp.lo \
runtime-go.lo \
sort.lo \
@@ -1940,6 +2002,7 @@ libgo_go_objs = \
debug/gosym.lo \
debug/macho.lo \
debug/pe.lo \
+ debug/plan9obj.lo \
encoding/ascii85.lo \
encoding/asn1.lo \
encoding/base32.lo \
@@ -1971,6 +2034,7 @@ libgo_go_objs = \
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 \
@@ -1979,6 +2043,7 @@ libgo_go_objs = \
image/jpeg.lo \
image/png.lo \
index/suffixarray.lo \
+ internal/syscall.lo \
io/ioutil.lo \
log/syslog.lo \
log/syslog/syslog_c.lo \
@@ -2014,18 +2079,27 @@ libgo_go_objs = \
unicode/utf16.lo \
unicode/utf8.lo
-libgo_la_SOURCES = $(runtime_files)
-libgo_la_LDFLAGS = \
+libgo_ldflags = \
-version-info $(libtool_VERSION) $(PTHREAD_CFLAGS) $(AM_LDFLAGS)
-libgo_la_LIBADD = \
+libgo_libadd = \
$(libgo_go_objs) ../libbacktrace/libbacktrace.la \
- ../libatomic/libatomic_convenience.la \
- $(LIBFFI) $(PTHREAD_LIBS) $(MATH_LIBS) $(NET_LIBS)
+ $(LIBATOMIC) $(LIBFFI) $(PTHREAD_LIBS) $(MATH_LIBS) $(NET_LIBS)
+libgo_la_SOURCES = $(runtime_files)
+libgo_la_LDFLAGS = $(libgo_ldflags)
+libgo_la_LIBADD = $(libgo_libadd)
+libgo_llgo_la_SOURCES = $(runtime_files)
+libgo_llgo_la_LDFLAGS = $(libgo_ldflags)
+libgo_llgo_la_LIBADD = $(libgo_libadd)
libgobegin_a_SOURCES = \
runtime/go-main.c
+libgobegin_llgo_a_SOURCES = \
+ runtime/go-main.c
+
+libnetgo_a_SOURCES = $(go_netgo_files)
+libnetgo_a_LIBADD = netgo.o
LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS))
AM_GOCFLAGS = $(STRINGOPS_FLAG)
GOCOMPILE = $(GOC) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_GOCFLAGS) $(GOCFLAGS)
@@ -2049,7 +2123,15 @@ BUILDPACKAGE = \
files=`echo $^ | sed -e 's/[^ ]*\.gox//g'`; \
$(LTGOCOMPILE) -I . -c -fgo-pkgpath=`echo $@ | sed -e 's/.lo$$//' -e 's/-go$$//'` -o $@ $$files
+
+# Build netgo.o.
+BUILDNETGO = \
+ $(MKDIR_P) $(@D); \
+ files=`echo $^ | sed -e 's/[^ ]*\.gox//g'`; \
+ $(GOCOMPILE) -I . -c -fgo-pkgpath=net -o $@ $$files
+
GOTESTFLAGS =
+GOBENCH =
# Check a package.
CHECK = \
@@ -2069,6 +2151,8 @@ CHECK = \
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); \
+ 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); \
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 \
echo "PASS: $(@D)" >> $@-testlog; \
@@ -2084,38 +2168,24 @@ CHECK = \
# Build all packages before checking any.
-CHECK_DEPS = libgo.la libgobegin.a \
- $(toolexeclibgo_DATA) \
- $(toolexeclibgoarchive_DATA) \
- $(toolexeclibgocompress_DATA) \
- $(toolexeclibgocontainer_DATA) \
- $(toolexeclibgocrypto_DATA) \
- $(toolexeclibgodebug_DATA) \
- $(toolexeclibgoencoding_DATA) \
- $(toolexeclibgoexp_DATA) \
- $(toolexeclibgogo_DATA) \
- $(toolexeclibgohash_DATA) \
- $(toolexeclibgoimage_DATA) \
- $(toolexeclibgoindex_DATA) \
- $(toolexeclibgoio_DATA) \
- $(toolexeclibgolog_DATA) \
- $(toolexeclibgomath_DATA) \
- $(toolexeclibgomime_DATA) \
- $(toolexeclibgonet_DATA) \
- $(toolexeclibgonethttp_DATA) \
- $(toolexeclibgoos_DATA) \
- $(toolexeclibgopath_DATA) \
- $(toolexeclibgorpc_DATA) \
- $(toolexeclibgoruntime_DATA) \
- $(toolexeclibgosync_DATA) \
- $(toolexeclibgotesting_DATA) \
- $(toolexeclibgotext_DATA) \
- $(toolexeclibgotexttemplate_DATA) \
- $(toolexeclibgounicode_DATA)
-
+CHECK_DEPS = $(toolexeclibgo_DATA) $(toolexeclibgoarchive_DATA) \
+ $(toolexeclibgocompress_DATA) $(toolexeclibgocontainer_DATA) \
+ $(toolexeclibgocrypto_DATA) $(toolexeclibgodebug_DATA) \
+ $(toolexeclibgoencoding_DATA) $(toolexeclibgoexp_DATA) \
+ $(toolexeclibgogo_DATA) $(toolexeclibgohash_DATA) \
+ $(toolexeclibgoimage_DATA) $(toolexeclibgoindex_DATA) \
+ $(toolexeclibgoio_DATA) $(toolexeclibgolog_DATA) \
+ $(toolexeclibgomath_DATA) $(toolexeclibgomime_DATA) \
+ $(toolexeclibgonet_DATA) $(toolexeclibgonethttp_DATA) \
+ $(toolexeclibgoos_DATA) $(toolexeclibgopath_DATA) \
+ $(toolexeclibgorpc_DATA) $(toolexeclibgoruntime_DATA) \
+ $(toolexeclibgosync_DATA) $(toolexeclibgotesting_DATA) \
+ $(toolexeclibgotext_DATA) $(toolexeclibgotexttemplate_DATA) \
+ $(toolexeclibgounicode_DATA) $(am__append_1) $(am__append_2)
# At least for now, we need -static-libgo for this test, because
# otherwise we can't get the line numbers.
-runtime_pprof_check_GOCFLAGS = -static-libgo
+# Also use -fno-inline to get better results from the memory profiler.
+runtime_pprof_check_GOCFLAGS = -static-libgo -fno-inline
# How to build a .gox file from a .lo file.
BUILDGOX = \
@@ -2181,6 +2251,7 @@ TEST_PACKAGES = \
debug/elf/check \
debug/macho/check \
debug/pe/check \
+ debug/plan9obj/check \
encoding/ascii85/check \
encoding/asn1/check \
encoding/base32/check \
@@ -2224,6 +2295,7 @@ TEST_PACKAGES = \
net/http/fcgi/check \
net/http/httptest/check \
net/http/httputil/check \
+ net/http/internal/check \
net/mail/check \
net/rpc/check \
net/smtp/check \
@@ -2337,10 +2409,18 @@ uninstall-toolexeclibLIBRARIES:
clean-toolexeclibLIBRARIES:
-test -z "$(toolexeclib_LIBRARIES)" || rm -f $(toolexeclib_LIBRARIES)
+libgobegin-llgo.a: $(libgobegin_llgo_a_OBJECTS) $(libgobegin_llgo_a_DEPENDENCIES)
+ -rm -f libgobegin-llgo.a
+ $(libgobegin_llgo_a_AR) libgobegin-llgo.a $(libgobegin_llgo_a_OBJECTS) $(libgobegin_llgo_a_LIBADD)
+ $(RANLIB) libgobegin-llgo.a
libgobegin.a: $(libgobegin_a_OBJECTS) $(libgobegin_a_DEPENDENCIES)
-rm -f libgobegin.a
$(libgobegin_a_AR) libgobegin.a $(libgobegin_a_OBJECTS) $(libgobegin_a_LIBADD)
$(RANLIB) libgobegin.a
+libnetgo.a: $(libnetgo_a_OBJECTS) $(libnetgo_a_DEPENDENCIES)
+ -rm -f libnetgo.a
+ $(libnetgo_a_AR) libnetgo.a $(libnetgo_a_OBJECTS) $(libnetgo_a_LIBADD)
+ $(RANLIB) libnetgo.a
install-toolexeclibLTLIBRARIES: $(toolexeclib_LTLIBRARIES)
@$(NORMAL_INSTALL)
test -z "$(toolexeclibdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibdir)"
@@ -2372,8 +2452,10 @@ clean-toolexeclibLTLIBRARIES:
echo "rm -f \"$${dir}/so_locations\""; \
rm -f "$${dir}/so_locations"; \
done
+libgo-llgo.la: $(libgo_llgo_la_OBJECTS) $(libgo_llgo_la_DEPENDENCIES)
+ $(libgo_llgo_la_LINK) $(am_libgo_llgo_la_rpath) $(libgo_llgo_la_OBJECTS) $(libgo_llgo_la_LIBADD) $(LIBS)
libgo.la: $(libgo_la_OBJECTS) $(libgo_la_DEPENDENCIES)
- $(libgo_la_LINK) -rpath $(toolexeclibdir) $(libgo_la_OBJECTS) $(libgo_la_LIBADD) $(LIBS)
+ $(libgo_la_LINK) $(am_libgo_la_rpath) $(libgo_la_OBJECTS) $(libgo_la_LIBADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@@ -2407,8 +2489,9 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-deferred-recover.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-eface-compare.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-eface-val-compare.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-ffi.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-fieldtrack.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-getgoroot.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-iface.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-int-array-to-string.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-int-to-string.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-interface-compare.Plo@am__quote@
@@ -2450,13 +2533,13 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-interface.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-string.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-typedesc-equal.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-typestring.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unsafe-new.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unsafe-newarray.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unsafe-pointer.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unsetenv.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unwind.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-varargs.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iface.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/heapdump.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lfstack.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lock_futex.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lock_sema.Plo@am__quote@
@@ -2466,7 +2549,6 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mcentral.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mem.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mem_posix_memalign.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mfinal.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mfixalloc.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mgc0.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mheap.Plo@am__quote@
@@ -2480,6 +2562,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parfor.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/print.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rdebug.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reflect.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtems-task-variable-add.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/runtime.Plo@am__quote@
@@ -2655,6 +2738,13 @@ go-eface-val-compare.lo: runtime/go-eface-val-compare.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-eface-val-compare.lo `test -f 'runtime/go-eface-val-compare.c' || echo '$(srcdir)/'`runtime/go-eface-val-compare.c
+go-ffi.lo: runtime/go-ffi.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-ffi.lo -MD -MP -MF $(DEPDIR)/go-ffi.Tpo -c -o go-ffi.lo `test -f 'runtime/go-ffi.c' || echo '$(srcdir)/'`runtime/go-ffi.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-ffi.Tpo $(DEPDIR)/go-ffi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-ffi.c' object='go-ffi.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-ffi.lo `test -f 'runtime/go-ffi.c' || echo '$(srcdir)/'`runtime/go-ffi.c
+
go-fieldtrack.lo: runtime/go-fieldtrack.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-fieldtrack.lo -MD -MP -MF $(DEPDIR)/go-fieldtrack.Tpo -c -o go-fieldtrack.lo `test -f 'runtime/go-fieldtrack.c' || echo '$(srcdir)/'`runtime/go-fieldtrack.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-fieldtrack.Tpo $(DEPDIR)/go-fieldtrack.Plo
@@ -2662,13 +2752,6 @@ go-fieldtrack.lo: runtime/go-fieldtrack.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-fieldtrack.lo `test -f 'runtime/go-fieldtrack.c' || echo '$(srcdir)/'`runtime/go-fieldtrack.c
-go-getgoroot.lo: runtime/go-getgoroot.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-getgoroot.lo -MD -MP -MF $(DEPDIR)/go-getgoroot.Tpo -c -o go-getgoroot.lo `test -f 'runtime/go-getgoroot.c' || echo '$(srcdir)/'`runtime/go-getgoroot.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-getgoroot.Tpo $(DEPDIR)/go-getgoroot.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-getgoroot.c' object='go-getgoroot.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-getgoroot.lo `test -f 'runtime/go-getgoroot.c' || echo '$(srcdir)/'`runtime/go-getgoroot.c
-
go-int-array-to-string.lo: runtime/go-int-array-to-string.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-int-array-to-string.lo -MD -MP -MF $(DEPDIR)/go-int-array-to-string.Tpo -c -o go-int-array-to-string.lo `test -f 'runtime/go-int-array-to-string.c' || echo '$(srcdir)/'`runtime/go-int-array-to-string.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-int-array-to-string.Tpo $(DEPDIR)/go-int-array-to-string.Plo
@@ -2949,13 +3032,6 @@ go-typedesc-equal.lo: runtime/go-typedesc-equal.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-typedesc-equal.lo `test -f 'runtime/go-typedesc-equal.c' || echo '$(srcdir)/'`runtime/go-typedesc-equal.c
-go-typestring.lo: runtime/go-typestring.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-typestring.lo -MD -MP -MF $(DEPDIR)/go-typestring.Tpo -c -o go-typestring.lo `test -f 'runtime/go-typestring.c' || echo '$(srcdir)/'`runtime/go-typestring.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-typestring.Tpo $(DEPDIR)/go-typestring.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-typestring.c' object='go-typestring.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-typestring.lo `test -f 'runtime/go-typestring.c' || echo '$(srcdir)/'`runtime/go-typestring.c
-
go-unsafe-new.lo: runtime/go-unsafe-new.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-unsafe-new.lo -MD -MP -MF $(DEPDIR)/go-unsafe-new.Tpo -c -o go-unsafe-new.lo `test -f 'runtime/go-unsafe-new.c' || echo '$(srcdir)/'`runtime/go-unsafe-new.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-unsafe-new.Tpo $(DEPDIR)/go-unsafe-new.Plo
@@ -2977,6 +3053,13 @@ go-unsafe-pointer.lo: runtime/go-unsafe-pointer.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-unsafe-pointer.lo `test -f 'runtime/go-unsafe-pointer.c' || echo '$(srcdir)/'`runtime/go-unsafe-pointer.c
+go-unsetenv.lo: runtime/go-unsetenv.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-unsetenv.lo -MD -MP -MF $(DEPDIR)/go-unsetenv.Tpo -c -o go-unsetenv.lo `test -f 'runtime/go-unsetenv.c' || echo '$(srcdir)/'`runtime/go-unsetenv.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-unsetenv.Tpo $(DEPDIR)/go-unsetenv.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-unsetenv.c' object='go-unsetenv.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-unsetenv.lo `test -f 'runtime/go-unsetenv.c' || echo '$(srcdir)/'`runtime/go-unsetenv.c
+
go-unwind.lo: runtime/go-unwind.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-unwind.lo -MD -MP -MF $(DEPDIR)/go-unwind.Tpo -c -o go-unwind.lo `test -f 'runtime/go-unwind.c' || echo '$(srcdir)/'`runtime/go-unwind.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-unwind.Tpo $(DEPDIR)/go-unwind.Plo
@@ -2991,20 +3074,6 @@ go-varargs.lo: runtime/go-varargs.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-varargs.lo `test -f 'runtime/go-varargs.c' || echo '$(srcdir)/'`runtime/go-varargs.c
-chan.lo: runtime/chan.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT chan.lo -MD -MP -MF $(DEPDIR)/chan.Tpo -c -o chan.lo `test -f 'runtime/chan.c' || echo '$(srcdir)/'`runtime/chan.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/chan.Tpo $(DEPDIR)/chan.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/chan.c' object='chan.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o chan.lo `test -f 'runtime/chan.c' || echo '$(srcdir)/'`runtime/chan.c
-
-cpuprof.lo: runtime/cpuprof.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cpuprof.lo -MD -MP -MF $(DEPDIR)/cpuprof.Tpo -c -o cpuprof.lo `test -f 'runtime/cpuprof.c' || echo '$(srcdir)/'`runtime/cpuprof.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/cpuprof.Tpo $(DEPDIR)/cpuprof.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/cpuprof.c' object='cpuprof.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cpuprof.lo `test -f 'runtime/cpuprof.c' || echo '$(srcdir)/'`runtime/cpuprof.c
-
env_posix.lo: runtime/env_posix.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT env_posix.lo -MD -MP -MF $(DEPDIR)/env_posix.Tpo -c -o env_posix.lo `test -f 'runtime/env_posix.c' || echo '$(srcdir)/'`runtime/env_posix.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/env_posix.Tpo $(DEPDIR)/env_posix.Plo
@@ -3012,12 +3081,12 @@ env_posix.lo: runtime/env_posix.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o env_posix.lo `test -f 'runtime/env_posix.c' || echo '$(srcdir)/'`runtime/env_posix.c
-lfstack.lo: runtime/lfstack.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lfstack.lo -MD -MP -MF $(DEPDIR)/lfstack.Tpo -c -o lfstack.lo `test -f 'runtime/lfstack.c' || echo '$(srcdir)/'`runtime/lfstack.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/lfstack.Tpo $(DEPDIR)/lfstack.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/lfstack.c' object='lfstack.lo' libtool=yes @AMDEPBACKSLASH@
+heapdump.lo: runtime/heapdump.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT heapdump.lo -MD -MP -MF $(DEPDIR)/heapdump.Tpo -c -o heapdump.lo `test -f 'runtime/heapdump.c' || echo '$(srcdir)/'`runtime/heapdump.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/heapdump.Tpo $(DEPDIR)/heapdump.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/heapdump.c' object='heapdump.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lfstack.lo `test -f 'runtime/lfstack.c' || echo '$(srcdir)/'`runtime/lfstack.c
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o heapdump.lo `test -f 'runtime/heapdump.c' || echo '$(srcdir)/'`runtime/heapdump.c
lock_sema.lo: runtime/lock_sema.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lock_sema.lo -MD -MP -MF $(DEPDIR)/lock_sema.Tpo -c -o lock_sema.lo `test -f 'runtime/lock_sema.c' || echo '$(srcdir)/'`runtime/lock_sema.c
@@ -3075,13 +3144,6 @@ mem.lo: runtime/mem.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mem.lo `test -f 'runtime/mem.c' || echo '$(srcdir)/'`runtime/mem.c
-mfinal.lo: runtime/mfinal.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mfinal.lo -MD -MP -MF $(DEPDIR)/mfinal.Tpo -c -o mfinal.lo `test -f 'runtime/mfinal.c' || echo '$(srcdir)/'`runtime/mfinal.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/mfinal.Tpo $(DEPDIR)/mfinal.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/mfinal.c' object='mfinal.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mfinal.lo `test -f 'runtime/mfinal.c' || echo '$(srcdir)/'`runtime/mfinal.c
-
mfixalloc.lo: runtime/mfixalloc.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mfixalloc.lo -MD -MP -MF $(DEPDIR)/mfixalloc.Tpo -c -o mfixalloc.lo `test -f 'runtime/mfixalloc.c' || echo '$(srcdir)/'`runtime/mfixalloc.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/mfixalloc.Tpo $(DEPDIR)/mfixalloc.Plo
@@ -4357,10 +4419,23 @@ s-version: Makefile
rm -f version.go.tmp
echo "package runtime" > version.go.tmp
echo 'const defaultGoroot = "$(prefix)"' >> version.go.tmp
- echo 'const theVersion = "'`$(CC) --version | sed 1q`'"' >> version.go.tmp
+ echo 'const theVersion = "'`cat $(srcdir)/VERSION | sed 1q`' '`$(GOC) --version | sed 1q`'"' >> version.go.tmp
echo 'const theGoarch = "'$(GOARCH)'"' >> version.go.tmp
echo 'const theGoos = "'$(GOOS)'"' >> version.go.tmp
- $(SHELL) $(srcdir)/../move-if-change version.go.tmp version.go
+ echo 'const theGccgoToolDir = "$(libexecsubdir)"' >> version.go.tmp
+ $(SHELL) $(srcdir)/mvifdiff.sh version.go.tmp version.go
+ $(STAMP) $@
+
+# Generate the list of go std packages that were included in libgo
+zstdpkglist.go: s-zstdpkglist; @true
+s-zstdpkglist: Makefile
+ rm -f zstdpkglist.go.tmp
+ echo 'package main' > zstdpkglist.go.tmp
+ echo "" >> zstdpkglist.go.tmp
+ echo 'var stdpkg = map[string]bool{' >> zstdpkglist.go.tmp
+ echo $(libgo_go_objs) 'unsafe.lo' 'runtime/cgo.lo' | sed 's/\.lo /\": true,\n/g' | sed 's/\.lo/\": true,/' | sed 's/-go//' | grep -v _c | sed 's/^/\t\"/' | sort | uniq >> zstdpkglist.go.tmp
+ echo '}' >> zstdpkglist.go.tmp
+ $(SHELL) $(srcdir)/mvifdiff.sh zstdpkglist.go.tmp zstdpkglist.go
$(STAMP) $@
libcalls.go: s-libcalls; @true
@@ -4368,14 +4443,14 @@ s-libcalls: libcalls-list go/syscall/mksyscall.awk $(go_base_syscall_files)
rm -f libcalls.go.tmp
files=`echo $^ | sed -e 's/libcalls-list//' -e 's|[^ ]*go/syscall/mksyscall.awk||'`; \
$(AWK) -f $(srcdir)/go/syscall/mksyscall.awk $${files} > libcalls.go.tmp
- $(SHELL) $(srcdir)/../move-if-change libcalls.go.tmp libcalls.go
+ $(SHELL) $(srcdir)/mvifdiff.sh libcalls.go.tmp libcalls.go
$(STAMP) $@
libcalls-list: s-libcalls-list; @true
s-libcalls-list: Makefile
rm -f libcalls-list.tmp
echo $(go_base_syscall_files) > libcalls-list.tmp
- $(SHELL) $(srcdir)/../move-if-change libcalls-list.tmp libcalls-list
+ $(SHELL) $(srcdir)/mvifdiff.sh libcalls-list.tmp libcalls-list
$(STAMP) $@
syscall_arch.go: s-syscall_arch; @true
@@ -4384,13 +4459,13 @@ s-syscall_arch: Makefile
echo "package syscall" > syscall_arch.go.tmp
echo 'const ARCH = "'$(GOARCH)'"' >> syscall_arch.go.tmp
echo 'const OS = "'$(GOOS)'"' >> syscall_arch.go.tmp
- $(SHELL) $(srcdir)/../move-if-change syscall_arch.go.tmp syscall_arch.go
+ $(SHELL) $(srcdir)/mvifdiff.sh syscall_arch.go.tmp syscall_arch.go
$(STAMP) $@
sysinfo.go: s-sysinfo; @true
s-sysinfo: $(srcdir)/mksysinfo.sh config.h
- CC="$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(OSCFLAGS)" $(SHELL) $(srcdir)/mksysinfo.sh
- $(SHELL) $(srcdir)/../move-if-change tmp-sysinfo.go sysinfo.go
+ CC="$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(OSCFLAGS) -O" $(SHELL) $(srcdir)/mksysinfo.sh
+ $(SHELL) $(srcdir)/mvifdiff.sh tmp-sysinfo.go sysinfo.go
$(STAMP) $@
# The epoll struct has an embedded union and is packed on x86_64,
@@ -4418,7 +4493,7 @@ s-epoll: Makefile
exit 1; ;; \
esac
echo '}' >> epoll.go.tmp
- $(SHELL) $(srcdir)/../move-if-change epoll.go.tmp epoll.go
+ $(SHELL) $(srcdir)/mvifdiff.sh epoll.go.tmp epoll.go
$(STAMP) $@
@go_include@ bufio.lo.dep
@@ -4570,6 +4645,12 @@ net/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: net/check
+@go_include@ netgo.o.dep
+netgo.o.dep: $(go_netgo_files)
+ $(BUILDDEPS)
+netgo.o: $(go_netgo_files)
+ $(BUILDNETGO)
+
@go_include@ os.lo.dep
os.lo.dep: $(go_os_files)
$(BUILDDEPS)
@@ -4595,7 +4676,7 @@ reflect-go.lo: $(go_reflect_files)
$(BUILDPACKAGE)
reflect/check: $(CHECK_DEPS)
@$(CHECK)
-reflect/makefunc.lo: $(go_reflect_makefunc_s_file)
+reflect/makefunc_ffi_c.lo: $(go_reflect_makefunc_c_file)
@$(MKDIR_P) reflect
$(LTCOMPILE) -c -o $@ $<
.PHONY: reflect/check
@@ -4999,6 +5080,15 @@ debug/pe/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: debug/pe/check
+@go_include@ debug/plan9obj.lo.dep
+debug/plan9obj.lo.dep: $(go_debug_plan9obj_files)
+ $(BUILDDEPS)
+debug/plan9obj.lo: $(go_debug_plan9obj_files)
+ $(BUILDPACKAGE)
+debug/plan9obj/check: $(CHECK_DEPS)
+ @$(CHECK)
+.PHONY: debug/plan9obj/check
+
@go_include@ encoding/asn1.lo.dep
encoding/asn1.lo.dep: $(go_encoding_asn1_files)
$(BUILDDEPS)
@@ -5452,6 +5542,15 @@ net/http/httputil/check: $(check_deps)
@$(CHECK)
.PHONY: net/http/httputil/check
+@go_include@ net/http/internal.lo.dep
+net/http/internal.lo.dep: $(go_net_http_internal_files)
+ $(BUILDDEPS)
+net/http/internal.lo: $(go_net_http_internal_files)
+ $(BUILDPACKAGE)
+net/http/internal/check: $(CHECK_DEPS)
+ @$(CHECK)
+.PHONY: net/http/internal/check
+
@go_include@ net/http/pprof.lo.dep
net/http/pprof.lo.dep: $(go_net_http_pprof_files)
$(BUILDDEPS)
@@ -5652,6 +5751,15 @@ 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
@@ -5788,6 +5896,8 @@ debug/macho.gox: debug/macho.lo
$(BUILDGOX)
debug/pe.gox: debug/pe.lo
$(BUILDGOX)
+debug/plan9obj.gox: debug/plan9obj.lo
+ $(BUILDGOX)
encoding/ascii85.gox: encoding/ascii85.lo
$(BUILDGOX)
@@ -5905,6 +6015,9 @@ net/http/httputil.gox: net/http/httputil.lo
net/http/pprof.gox: net/http/pprof.lo
$(BUILDGOX)
+net/http/internal.gox: net/http/internal.lo
+ $(BUILDGOX)
+
net/rpc/jsonrpc.gox: net/rpc/jsonrpc.lo
$(BUILDGOX)
@@ -5934,6 +6047,9 @@ 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
@@ -6052,6 +6168,9 @@ check-am:
check-multi:
$(MULTIDO) $(AM_MAKEFLAGS) DO=check-am multi-do # $(MAKE)
+bench:
+ -@$(MAKE) -k $(TEST_PACKAGES) GOBENCH=.
+
mostlyclean-local:
find . -name '*.lo' -print | xargs $(LIBTOOL) --mode=clean rm -f
find . -name '*.$(OBJEXT)' -print | xargs rm -f
diff --git a/libgo/README b/libgo/README
index 732c3526c4..d5af7e2fd1 100644
--- a/libgo/README
+++ b/libgo/README
@@ -3,25 +3,24 @@ See ../README.
This is the runtime support library for the Go programming language.
This library is intended for use with the Go frontend.
-The library has only been tested on GNU/Linux using glibc. It should
-not be difficult to port to other operating systems.
+This library should not be stripped when it is installed. Go code
+relies on being able to look up file/line information, which comes
+from the debugging info using the libbacktrace library.
-The library has only been tested on x86/x86_64 systems. It should not
-be difficult to port to other architectures.
+The library has only been tested on GNU/Linux using glibc, and on
+Solaris. It should not be difficult to port to other operating
+systems.
Directories:
go
- A copy of the Go library from http://golang.org/, with a few
- changes for gccgo. Notably, the reflection interface is different.
+ A copy of the Go library from http://golang.org/, with several
+ changes for gccgo.
runtime
Runtime functions, written in C, which are called directly by the
compiler or by the library.
-syscalls
- System call support.
-
Contributing
============
diff --git a/libgo/VERSION b/libgo/VERSION
new file mode 100644
index 0000000000..bcab27e8d3
--- /dev/null
+++ b/libgo/VERSION
@@ -0,0 +1 @@
+go1.4.2 \ No newline at end of file
diff --git a/libgo/config.h.in b/libgo/config.h.in
index 2ee0cfc243..629c603e38 100644
--- a/libgo/config.h.in
+++ b/libgo/config.h.in
@@ -319,6 +319,9 @@
/* Define to 1 if you have the `unlinkat' function. */
#undef HAVE_UNLINKAT
+/* Define to 1 if you have the `unsetenv' function. */
+#undef HAVE_UNSETENV
+
/* Define to 1 if you have the `unshare' function. */
#undef HAVE_UNSHARE
@@ -344,9 +347,6 @@
*/
#undef LT_OBJDIR
-/* Define if makecontext expects top of stack in uc_stack. */
-#undef MAKECONTEXT_STACK_TOP
-
/* Name of package */
#undef PACKAGE
diff --git a/libgo/config/libtool.m4 b/libgo/config/libtool.m4
index f1ffebf99c..f700594745 100644
--- a/libgo/config/libtool.m4
+++ b/libgo/config/libtool.m4
@@ -1011,7 +1011,7 @@ _LT_EOF
case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
_lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
- 10.[[012]]*)
+ 10.[[012]][[,.]]*)
_lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
10.*)
_lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
@@ -1237,7 +1237,14 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
LD="${LD-ld} -m elf_i386_fbsd"
;;
x86_64-*linux*)
- LD="${LD-ld} -m elf_i386"
+ case `/usr/bin/file conftest.o` in
+ *x86-64*)
+ LD="${LD-ld} -m elf32_x86_64"
+ ;;
+ *)
+ LD="${LD-ld} -m elf_i386"
+ ;;
+ esac
;;
powerpc64le-*linux*)
LD="${LD-ld} -m elf32lppclinux"
@@ -1293,27 +1300,14 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
CFLAGS="$SAVE_CFLAGS"
fi
;;
-*-*solaris*)
+sparc*-*solaris*)
# Find out which ABI we are using.
echo 'int i;' > conftest.$ac_ext
if AC_TRY_EVAL(ac_compile); then
case `/usr/bin/file conftest.o` in
*64-bit*)
case $lt_cv_prog_gnu_ld in
- yes*)
- case $host in
- i?86-*-solaris* | x86_64-*-solaris2.1[[0-9]]*)
- LD="${LD-ld} -m elf_x86_64"
- ;;
- sparc*-*-solaris*)
- LD="${LD-ld} -m elf64_sparc"
- ;;
- esac
- # GNU ld 2.21 introduced _sol2 emulations. Use them if available.
- if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
- LD="${LD-ld}_sol2"
- fi
- ;;
+ yes*) LD="${LD-ld} -m elf64_sparc" ;;
*)
if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
LD="${LD-ld} -64"
@@ -2297,7 +2291,7 @@ freebsd* | dragonfly*)
objformat=`/usr/bin/objformat`
else
case $host_os in
- freebsd[[123]]*) objformat=aout ;;
+ freebsd[[23]].*) objformat=aout ;;
*) objformat=elf ;;
esac
fi
@@ -2315,7 +2309,7 @@ freebsd* | dragonfly*)
esac
shlibpath_var=LD_LIBRARY_PATH
case $host_os in
- freebsd2*)
+ freebsd2.*)
shlibpath_overrides_runpath=yes
;;
freebsd3.[[01]]* | freebsdelf3.[[01]]*)
@@ -3597,6 +3591,7 @@ m4_if([$1], [CXX], [
# AIX 5 now supports IA64 processor
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
fi
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
;;
amigaos*)
@@ -3908,6 +3903,7 @@ m4_if([$1], [CXX], [
# AIX 5 now supports IA64 processor
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
fi
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
;;
amigaos*)
@@ -4828,7 +4824,7 @@ _LT_EOF
;;
# Unfortunately, older versions of FreeBSD 2 do not have this feature.
- freebsd2*)
+ freebsd2.*)
_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
_LT_TAGVAR(hardcode_direct, $1)=yes
_LT_TAGVAR(hardcode_minus_L, $1)=yes
@@ -5775,7 +5771,7 @@ if test "$_lt_caught_CXX_error" != yes; then
esac
;;
- freebsd[[12]]*)
+ freebsd2.*)
# C++ shared libraries reported to be fairly broken before
# switch to ELF
_LT_TAGVAR(ld_shlibs, $1)=no
diff --git a/libgo/config/ltmain.sh b/libgo/config/ltmain.sh
index 17f19d888b..ce66b44906 100644
--- a/libgo/config/ltmain.sh
+++ b/libgo/config/ltmain.sh
@@ -5928,7 +5928,7 @@ func_mode_link ()
test "$hardcode_direct_absolute" = no; then
add="$dir/$linklib"
elif test "$hardcode_minus_L" = yes; then
- add_dir="-L$dir"
+ add_dir="-L$absdir"
# Try looking first in the location we're being installed to.
if test -n "$inst_prefix_dir"; then
case $libdir in
diff --git a/libgo/configure b/libgo/configure
index 1223204a25..377179d2c3 100755
--- a/libgo/configure
+++ b/libgo/configure
@@ -616,6 +616,8 @@ PTHREAD_LIBS
PTHREAD_CFLAGS
NET_LIBS
MATH_LIBS
+GOC_IS_LLGO_FALSE
+GOC_IS_LLGO_TRUE
USING_SPLIT_STACK_FALSE
USING_SPLIT_STACK_TRUE
SPLIT_STACK
@@ -631,6 +633,12 @@ LIBGO_IS_SPARC64_FALSE
LIBGO_IS_SPARC64_TRUE
LIBGO_IS_SPARC_FALSE
LIBGO_IS_SPARC_TRUE
+LIBGO_IS_S390X_FALSE
+LIBGO_IS_S390X_TRUE
+LIBGO_IS_S390_FALSE
+LIBGO_IS_S390_TRUE
+LIBGO_IS_PPC64LE_FALSE
+LIBGO_IS_PPC64LE_TRUE
LIBGO_IS_PPC64_FALSE
LIBGO_IS_PPC64_TRUE
LIBGO_IS_PPC_FALSE
@@ -676,6 +684,7 @@ LIBGO_IS_FREEBSD_TRUE
LIBGO_IS_DARWIN_FALSE
LIBGO_IS_DARWIN_TRUE
go_include
+LIBATOMIC
LIBFFIINCS
LIBFFI
nover_glibgo_toolexeclibdir
@@ -817,6 +826,7 @@ enable_libtool_lock
enable_werror
enable_version_specific_runtime_libs
with_libffi
+with_libatomic
with_system_libunwind
enable_sjlj_exceptions
'
@@ -1469,6 +1479,7 @@ Optional Packages:
--with-pic try to use only PIC/non-PIC objects [default=use
both]
--without-libffi don't use libffi
+ --without-libatomic don't use libatomic
--with-system-libunwind use installed libunwind
Some influential environment variables:
@@ -2500,7 +2511,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
ac_config_headers="$ac_config_headers config.h"
-libtool_VERSION=5:0:0
+libtool_VERSION=7:0:0
# Default to --enable-multilib
@@ -6521,7 +6532,14 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
LD="${LD-ld} -m elf_i386_fbsd"
;;
x86_64-*linux*)
- LD="${LD-ld} -m elf_i386"
+ case `/usr/bin/file conftest.o` in
+ *x86-64*)
+ LD="${LD-ld} -m elf32_x86_64"
+ ;;
+ *)
+ LD="${LD-ld} -m elf_i386"
+ ;;
+ esac
;;
powerpc64le-*linux*)
LD="${LD-ld} -m elf32lppclinux"
@@ -6611,7 +6629,7 @@ $as_echo "$lt_cv_cc_needs_belf" >&6; }
CFLAGS="$SAVE_CFLAGS"
fi
;;
-*-*solaris*)
+sparc*-*solaris*)
# Find out which ABI we are using.
echo 'int i;' > conftest.$ac_ext
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
@@ -6622,20 +6640,7 @@ $as_echo "$lt_cv_cc_needs_belf" >&6; }
case `/usr/bin/file conftest.o` in
*64-bit*)
case $lt_cv_prog_gnu_ld in
- yes*)
- case $host in
- i?86-*-solaris* | x86_64-*-solaris2.1[0-9]*)
- LD="${LD-ld} -m elf_x86_64"
- ;;
- sparc*-*-solaris*)
- LD="${LD-ld} -m elf64_sparc"
- ;;
- esac
- # GNU ld 2.21 introduced _sol2 emulations. Use them if available.
- if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
- LD="${LD-ld}_sol2"
- fi
- ;;
+ yes*) LD="${LD-ld} -m elf64_sparc" ;;
*)
if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
LD="${LD-ld} -64"
@@ -7243,7 +7248,7 @@ $as_echo "$lt_cv_ld_force_load" >&6; }
case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
10.0,*86*-darwin8*|10.0,*-darwin[91]*)
_lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
- 10.[012]*)
+ 10.[012][,.]*)
_lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
10.*)
_lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
@@ -8169,6 +8174,7 @@ $as_echo_n "checking for $compiler option to produce PIC... " >&6; }
# AIX 5 now supports IA64 processor
lt_prog_compiler_static='-Bstatic'
fi
+ lt_prog_compiler_pic='-fPIC'
;;
amigaos*)
@@ -9350,7 +9356,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
;;
# Unfortunately, older versions of FreeBSD 2 do not have this feature.
- freebsd2*)
+ freebsd2.*)
archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
hardcode_direct=yes
hardcode_minus_L=yes
@@ -10263,7 +10269,7 @@ freebsd* | dragonfly*)
objformat=`/usr/bin/objformat`
else
case $host_os in
- freebsd[123]*) objformat=aout ;;
+ freebsd[23].*) objformat=aout ;;
*) objformat=elf ;;
esac
fi
@@ -10281,7 +10287,7 @@ freebsd* | dragonfly*)
esac
shlibpath_var=LD_LIBRARY_PATH
case $host_os in
- freebsd2*)
+ freebsd2.*)
shlibpath_overrides_runpath=yes
;;
freebsd3.[01]* | freebsdelf3.[01]*)
@@ -11115,7 +11121,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11118 "configure"
+#line 11124 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -11221,7 +11227,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11224 "configure"
+#line 11230 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -11600,6 +11606,7 @@ $as_echo_n "checking for $compiler option to produce PIC... " >&6; }
# AIX 5 now supports IA64 processor
lt_prog_compiler_static_GO='-Bstatic'
fi
+ lt_prog_compiler_pic_GO='-fPIC'
;;
amigaos*)
@@ -12766,7 +12773,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
;;
# Unfortunately, older versions of FreeBSD 2 do not have this feature.
- freebsd2*)
+ freebsd2.*)
archive_cmds_GO='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
hardcode_direct_GO=yes
hardcode_minus_L_GO=yes
@@ -13444,7 +13451,7 @@ else
nover_glibgo_toolexecdir='${libdir}/gcc/${host_alias}'
nover_glibgo_toolexeclibdir='${libdir}'
fi
-multi_os_directory=`$CC -print-multi-os-directory`
+multi_os_directory=`$GOC -print-multi-os-directory`
case $multi_os_directory in
.) ;; # Avoid trailing /.
*) nover_glibgo_toolexeclibdir=${nover_glibgo_toolexeclibdir}/${multi_os_directory} ;;
@@ -13483,6 +13490,24 @@ fi
+# See if the user wants to configure without libatomic. This is useful if we are
+# on an architecture for which libgo does not need an atomic support library and
+# libatomic does not support our C compiler.
+
+# Check whether --with-libatomic was given.
+if test "${with_libatomic+set}" = set; then :
+ withval=$with_libatomic; :
+else
+ with_libatomic=${with_libatomic_default-yes}
+fi
+
+
+LIBATOMIC=
+if test "$with_libatomic" != no; then
+ LIBATOMIC=../libatomic/libatomic_convenience.la
+fi
+
+
# Used to tell GNU make to include a file without telling automake to
# include it.
go_include="-include"
@@ -13599,6 +13624,9 @@ is_m68k=no
mips_abi=unknown
is_ppc=no
is_ppc64=no
+is_ppc64le=no
+is_s390=no
+is_s390x=no
is_sparc=no
is_sparc64=no
is_x86_64=no
@@ -13709,13 +13737,47 @@ _ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
is_ppc=yes
else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#if defined(_BIG_ENDIAN) || defined(__BIG_ENDIAN__)
+#error 64be
+#endif
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ is_ppc64le=yes
+else
is_ppc64=yes
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
if test "$is_ppc" = "yes"; then
GOARCH=ppc
- else
+ elif test "$is_ppc64" = "yes"; then
GOARCH=ppc64
+ else
+ GOARCH=ppc64le
+ fi
+ ;;
+ s390*-*-*)
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#if defined(__s390x__)
+#error 64-bit
+#endif
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ is_s390=yes
+else
+ is_s390x=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ if test "$is_s390" = "yes"; then
+ GOARCH=s390
+ else
+ GOARCH=s390x
fi
;;
sparc*-*-*)
@@ -13835,6 +13897,30 @@ else
LIBGO_IS_PPC64_FALSE=
fi
+ if test $is_ppc64le = yes; then
+ LIBGO_IS_PPC64LE_TRUE=
+ LIBGO_IS_PPC64LE_FALSE='#'
+else
+ LIBGO_IS_PPC64LE_TRUE='#'
+ LIBGO_IS_PPC64LE_FALSE=
+fi
+
+ if test $is_s390 = yes; then
+ LIBGO_IS_S390_TRUE=
+ LIBGO_IS_S390_FALSE='#'
+else
+ LIBGO_IS_S390_TRUE='#'
+ LIBGO_IS_S390_FALSE=
+fi
+
+ if test $is_s390x = yes; then
+ LIBGO_IS_S390X_TRUE=
+ LIBGO_IS_S390X_FALSE='#'
+else
+ LIBGO_IS_S390X_TRUE='#'
+ LIBGO_IS_S390X_FALSE=
+fi
+
if test $is_sparc = yes; then
LIBGO_IS_SPARC_TRUE=
LIBGO_IS_SPARC_FALSE='#'
@@ -13865,17 +13951,17 @@ GO_LIBCALL_OS_FILE=
GO_LIBCALL_OS_ARCH_FILE=
GO_SYSCALL_OS_FILE=
GO_SYSCALL_OS_ARCH_FILE=
-if test -f ${srcdir}/go/syscall/libcall_${GOOS}.go; then
- GO_LIBCALL_OS_FILE=go/syscall/libcall_${GOOS}.go
+if test -f "${srcdir}/go/syscall/libcall_${GOOS}.go"; then
+ GO_LIBCALL_OS_FILE="go/syscall/libcall_${GOOS}.go"
fi
-if test -f ${srcdir}/go/syscall/libcall_${GOOS}_${GOARCH}.go; then
- GO_LIBCALL_OS_ARCH_FILE=go/syscall/libcall_${GOOS}_${GOARCH}.go
+if test -f "${srcdir}/go/syscall/libcall_${GOOS}_${GOARCH}.go"; then
+ GO_LIBCALL_OS_ARCH_FILE="go/syscall/libcall_${GOOS}_${GOARCH}.go"
fi
-if test -f ${srcdir}/go/syscall/syscall_${GOOS}.go; then
- GO_SYSCALL_OS_FILE=go/syscall/syscall_${GOOS}.go
+if test -f "${srcdir}/go/syscall/syscall_${GOOS}.go"; then
+ GO_SYSCALL_OS_FILE="go/syscall/syscall_${GOOS}.go"
fi
-if test -f ${srcdir}/go/syscall/syscall_${GOOS}_${GOARCH}.go; then
- GO_SYSCALL_OS_ARCH_FILE=go/syscall/syscall_${GOOS}_${GOARCH}.go
+if test -f "${srcdir}/go/syscall/syscall_${GOOS}_${GOARCH}.go"; then
+ GO_SYSCALL_OS_ARCH_FILE="go/syscall/syscall_${GOOS}_${GOARCH}.go"
fi
@@ -13889,11 +13975,6 @@ case "$target" in
# msghdr in <sys/socket.h>.
OSCFLAGS="$OSCFLAGS -D_XOPEN_SOURCE=500"
;;
- *-*-solaris2.[89])
- # Solaris 8/9 need this so struct msghdr gets the msg_control
- # etc. fields in <sys/socket.h> (_XPG4_2).
- OSCFLAGS="$OSCFLAGS -D_XOPEN_SOURCE=500 -D_XOPEN_SOURCE_EXTENDED -D__EXTENSIONS__"
- ;;
*-*-solaris2.1[01])
# Solaris 10+ needs this so struct msghdr gets the msg_control
# etc. fields in <sys/socket.h> (_XPG4_2). _XOPEN_SOURCE=600 as
@@ -13960,6 +14041,27 @@ $as_echo "#define LINKER_SUPPORTS_SPLIT_STACK 1" >>confdefs.h
fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler is llgo" >&5
+$as_echo_n "checking whether compiler is llgo... " >&6; }
+if test "${libgo_cv_c_goc_is_llgo+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ libgo_cv_c_goc_is_llgo=no
+if $GOC -dumpversion 2>/dev/null | grep llgo >/dev/null 2>&1; then
+ libgo_cv_c_goc_is_llgo=yes
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgo_cv_c_goc_is_llgo" >&5
+$as_echo "$libgo_cv_c_goc_is_llgo" >&6; }
+ if test "$libgo_cv_c_goc_is_llgo" = yes; then
+ GOC_IS_LLGO_TRUE=
+ GOC_IS_LLGO_FALSE='#'
+else
+ GOC_IS_LLGO_TRUE='#'
+ GOC_IS_LLGO_FALSE=
+fi
+
+
MATH_LIBS=
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrt in -lm" >&5
$as_echo_n "checking for sqrt in -lm... " >&6; }
@@ -14703,7 +14805,7 @@ else
fi
-for ac_func in strerror_r strsignal wait4 mincore setenv dl_iterate_phdr
+for ac_func in strerror_r strsignal wait4 mincore setenv unsetenv dl_iterate_phdr
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@@ -15053,20 +15155,6 @@ $as_echo "#define HAVE_STRUCT_EXCEPTION 1" >>confdefs.h
fi
-case "$target" in
- sparc*-*-solaris2.[89]*)
- libgo_cv_lib_makecontext_stack_top=yes
- ;;
- *)
- libgo_cv_lib_makecontext_stack_top=no
- ;;
-esac
-if test "$libgo_cv_lib_makecontext_stack_top" = "yes"; then
-
-$as_echo "#define MAKECONTEXT_STACK_TOP 1" >>confdefs.h
-
-fi
-
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether setcontext clobbers TLS variables" >&5
$as_echo_n "checking whether setcontext clobbers TLS variables... " >&6; }
if test "${libgo_cv_lib_setcontext_clobbers_tls+set}" = set; then :
@@ -15239,6 +15327,28 @@ $as_echo "#define EH_FRAME_FLAGS \"aw\"" >>confdefs.h
fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler supports -Qunused-arguments" >&5
+$as_echo_n "checking if compiler supports -Qunused-arguments... " >&6; }
+if test "${libgo_cv_c_unused_arguments+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ CFLAGS_hold=$CFLAGS
+CFLAGS="$CFLAGS -Qunused-arguments"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int i;
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ libgo_cv_c_unused_arguments=yes
+else
+ libgo_cv_c_unused_arguments=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+CFLAGS=$CFLAGS_hold
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgo_cv_c_unused_arguments" >&5
+$as_echo "$libgo_cv_c_unused_arguments" >&6; }
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if assembler supports GNU comdat group syntax" >&5
$as_echo_n "checking if assembler supports GNU comdat group syntax... " >&6; }
if test "${libgo_cv_as_comdat_gnu+set}" = set; then :
@@ -15246,11 +15356,16 @@ if test "${libgo_cv_as_comdat_gnu+set}" = set; then :
else
echo '.section .text,"axG",@progbits,.foo,comdat' > conftest.s
+CFLAGS_hold=$CFLAGS
+if test "$libgo_cv_c_unused_arguments" = yes; then
+ CFLAGS="$CFLAGS -Qunused-arguments"
+fi
if $CC $CFLAGS -c conftest.s > /dev/null 2>&1; then
libgo_cv_as_comdat_gnu=yes
else
libgo_cv_as_comdat_gnu=no
fi
+CFLAGS=$CFLAGS_hold
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgo_cv_as_comdat_gnu" >&5
@@ -15269,9 +15384,14 @@ else
libgo_cv_as_x86_pcrel=yes
echo '.text; foo: nop; .data; .long foo-.; .text' > conftest.s
+CFLAGS_hold=$CFLAGS
+if test "$libgo_cv_c_unused_arguments" = yes; then
+ CFLAGS="$CFLAGS -Qunused-arguments"
+fi
if $CC $CFLAGS -c conftest.s 2>&1 | $EGREP -i 'illegal|warning' > /dev/null; then
libgo_cv_as_x86_pcrel=no
fi
+CFLAGS=$CFLAGS_hold
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgo_cv_as_x86_pcrel" >&5
@@ -15290,9 +15410,14 @@ else
libgo_cv_as_x86_64_unwind_section_type=yes
echo '.section .eh_frame,"a",@unwind' > conftest.s
+CFLAGS_hold=$CFLAGS
+if test "$libgo_cv_c_unused_arguments" = yes; then
+ CFLAGS="$CFLAGS -Qunused-arguments"
+fi
if $CC $CFLAGS -c conftest.s 2>&1 | grep -i warning > /dev/null; then
libgo_cv_as_x86_64_unwind_section_type=no
fi
+CFLAGS=$CFLAGS_hold
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgo_cv_as_x86_64_unwind_section_type" >&5
@@ -15591,6 +15716,18 @@ if test -z "${LIBGO_IS_PPC64_TRUE}" && test -z "${LIBGO_IS_PPC64_FALSE}"; then
as_fn_error "conditional \"LIBGO_IS_PPC64\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
+if test -z "${LIBGO_IS_PPC64LE_TRUE}" && test -z "${LIBGO_IS_PPC64LE_FALSE}"; then
+ as_fn_error "conditional \"LIBGO_IS_PPC64LE\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${LIBGO_IS_S390_TRUE}" && test -z "${LIBGO_IS_S390_FALSE}"; then
+ as_fn_error "conditional \"LIBGO_IS_S390\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${LIBGO_IS_S390X_TRUE}" && test -z "${LIBGO_IS_S390X_FALSE}"; then
+ as_fn_error "conditional \"LIBGO_IS_S390X\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
if test -z "${LIBGO_IS_SPARC_TRUE}" && test -z "${LIBGO_IS_SPARC_FALSE}"; then
as_fn_error "conditional \"LIBGO_IS_SPARC\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
@@ -15607,6 +15744,10 @@ if test -z "${USING_SPLIT_STACK_TRUE}" && test -z "${USING_SPLIT_STACK_FALSE}";
as_fn_error "conditional \"USING_SPLIT_STACK\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
+if test -z "${GOC_IS_LLGO_TRUE}" && test -z "${GOC_IS_LLGO_FALSE}"; then
+ as_fn_error "conditional \"GOC_IS_LLGO\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
if test -z "${HAVE_SYS_MMAN_H_TRUE}" && test -z "${HAVE_SYS_MMAN_H_FALSE}"; then
as_fn_error "conditional \"HAVE_SYS_MMAN_H\" was never defined.
diff --git a/libgo/configure.ac b/libgo/configure.ac
index 754e1906c6..0baff412de 100644
--- a/libgo/configure.ac
+++ b/libgo/configure.ac
@@ -11,7 +11,7 @@ AC_INIT(package-unused, version-unused,, libgo)
AC_CONFIG_SRCDIR(Makefile.am)
AC_CONFIG_HEADER(config.h)
-libtool_VERSION=5:0:0
+libtool_VERSION=7:0:0
AC_SUBST(libtool_VERSION)
AM_ENABLE_MULTILIB(, ..)
@@ -88,7 +88,7 @@ else
nover_glibgo_toolexecdir='${libdir}/gcc/${host_alias}'
nover_glibgo_toolexeclibdir='${libdir}'
fi
-multi_os_directory=`$CC -print-multi-os-directory`
+multi_os_directory=`$GOC -print-multi-os-directory`
case $multi_os_directory in
.) ;; # Avoid trailing /.
*) nover_glibgo_toolexeclibdir=${nover_glibgo_toolexeclibdir}/${multi_os_directory} ;;
@@ -122,6 +122,21 @@ fi
AC_SUBST(LIBFFI)
AC_SUBST(LIBFFIINCS)
+# See if the user wants to configure without libatomic. This is useful if we are
+# on an architecture for which libgo does not need an atomic support library and
+# libatomic does not support our C compiler.
+AC_ARG_WITH(libatomic,
+ AS_HELP_STRING([--without-libatomic],
+ [don't use libatomic]),
+ [:],
+ [with_libatomic=${with_libatomic_default-yes}])
+
+LIBATOMIC=
+if test "$with_libatomic" != no; then
+ LIBATOMIC=../libatomic/libatomic_convenience.la
+fi
+AC_SUBST(LIBATOMIC)
+
# Used to tell GNU make to include a file without telling automake to
# include it.
go_include="-include"
@@ -179,6 +194,9 @@ is_m68k=no
mips_abi=unknown
is_ppc=no
is_ppc64=no
+is_ppc64le=no
+is_s390=no
+is_s390x=no
is_sparc=no
is_sparc64=no
is_x86_64=no
@@ -249,11 +267,30 @@ changequote([,])dnl
#ifdef _ARCH_PPC64
#error 64-bit
#endif],
-[is_ppc=yes], [is_ppc64=yes])
+[is_ppc=yes],
+ [AC_COMPILE_IFELSE([
+#if defined(_BIG_ENDIAN) || defined(__BIG_ENDIAN__)
+#error 64be
+#endif],
+[is_ppc64le=yes],[is_ppc64=yes])])
if test "$is_ppc" = "yes"; then
GOARCH=ppc
- else
+ elif test "$is_ppc64" = "yes"; then
GOARCH=ppc64
+ else
+ GOARCH=ppc64le
+ fi
+ ;;
+ s390*-*-*)
+ AC_COMPILE_IFELSE([
+#if defined(__s390x__)
+#error 64-bit
+#endif],
+[is_s390=yes], [is_s390x=yes])
+ if test "$is_s390" = "yes"; then
+ GOARCH=s390
+ else
+ GOARCH=s390x
fi
;;
sparc*-*-*)
@@ -281,6 +318,9 @@ AM_CONDITIONAL(LIBGO_IS_MIPSN64, test $mips_abi = n64)
AM_CONDITIONAL(LIBGO_IS_MIPSO64, test $mips_abi = o64)
AM_CONDITIONAL(LIBGO_IS_PPC, test $is_ppc = yes)
AM_CONDITIONAL(LIBGO_IS_PPC64, test $is_ppc64 = yes)
+AM_CONDITIONAL(LIBGO_IS_PPC64LE, test $is_ppc64le = yes)
+AM_CONDITIONAL(LIBGO_IS_S390, test $is_s390 = yes)
+AM_CONDITIONAL(LIBGO_IS_S390X, test $is_s390x = yes)
AM_CONDITIONAL(LIBGO_IS_SPARC, test $is_sparc = yes)
AM_CONDITIONAL(LIBGO_IS_SPARC64, test $is_sparc64 = yes)
AM_CONDITIONAL(LIBGO_IS_X86_64, test $is_x86_64 = yes)
@@ -291,17 +331,17 @@ GO_LIBCALL_OS_FILE=
GO_LIBCALL_OS_ARCH_FILE=
GO_SYSCALL_OS_FILE=
GO_SYSCALL_OS_ARCH_FILE=
-if test -f ${srcdir}/go/syscall/libcall_${GOOS}.go; then
- GO_LIBCALL_OS_FILE=go/syscall/libcall_${GOOS}.go
+if test -f "${srcdir}/go/syscall/libcall_${GOOS}.go"; then
+ GO_LIBCALL_OS_FILE="go/syscall/libcall_${GOOS}.go"
fi
-if test -f ${srcdir}/go/syscall/libcall_${GOOS}_${GOARCH}.go; then
- GO_LIBCALL_OS_ARCH_FILE=go/syscall/libcall_${GOOS}_${GOARCH}.go
+if test -f "${srcdir}/go/syscall/libcall_${GOOS}_${GOARCH}.go"; then
+ GO_LIBCALL_OS_ARCH_FILE="go/syscall/libcall_${GOOS}_${GOARCH}.go"
fi
-if test -f ${srcdir}/go/syscall/syscall_${GOOS}.go; then
- GO_SYSCALL_OS_FILE=go/syscall/syscall_${GOOS}.go
+if test -f "${srcdir}/go/syscall/syscall_${GOOS}.go"; then
+ GO_SYSCALL_OS_FILE="go/syscall/syscall_${GOOS}.go"
fi
-if test -f ${srcdir}/go/syscall/syscall_${GOOS}_${GOARCH}.go; then
- GO_SYSCALL_OS_ARCH_FILE=go/syscall/syscall_${GOOS}_${GOARCH}.go
+if test -f "${srcdir}/go/syscall/syscall_${GOOS}_${GOARCH}.go"; then
+ GO_SYSCALL_OS_ARCH_FILE="go/syscall/syscall_${GOOS}_${GOARCH}.go"
fi
AC_SUBST(GO_LIBCALL_OS_FILE)
AC_SUBST(GO_LIBCALL_OS_ARCH_FILE)
@@ -316,11 +356,6 @@ case "$target" in
# msghdr in <sys/socket.h>.
OSCFLAGS="$OSCFLAGS -D_XOPEN_SOURCE=500"
;;
- *-*-solaris2.[[89]])
- # Solaris 8/9 need this so struct msghdr gets the msg_control
- # etc. fields in <sys/socket.h> (_XPG4_2).
- OSCFLAGS="$OSCFLAGS -D_XOPEN_SOURCE=500 -D_XOPEN_SOURCE_EXTENDED -D__EXTENSIONS__"
- ;;
*-*-solaris2.1[[01]])
# Solaris 10+ needs this so struct msghdr gets the msg_control
# etc. fields in <sys/socket.h> (_XPG4_2). _XOPEN_SOURCE=600 as
@@ -366,6 +401,14 @@ if test "$libgo_cv_c_linker_supports_split_stack" = yes; then
[Define if the linker support split stack adjustments])
fi
+AC_CACHE_CHECK([whether compiler is llgo],
+[libgo_cv_c_goc_is_llgo],
+[libgo_cv_c_goc_is_llgo=no
+if $GOC -dumpversion 2>/dev/null | grep llgo >/dev/null 2>&1; then
+ libgo_cv_c_goc_is_llgo=yes
+fi])
+AM_CONDITIONAL(GOC_IS_LLGO, test "$libgo_cv_c_goc_is_llgo" = yes)
+
dnl Test for the -lm library.
MATH_LIBS=
AC_CHECK_LIB([m], [sqrt], MATH_LIBS=-lm)
@@ -508,7 +551,7 @@ fi
AM_CONDITIONAL(HAVE_SYS_MMAN_H, test "$ac_cv_header_sys_mman_h" = yes)
-AC_CHECK_FUNCS(strerror_r strsignal wait4 mincore setenv dl_iterate_phdr)
+AC_CHECK_FUNCS(strerror_r strsignal wait4 mincore setenv unsetenv dl_iterate_phdr)
AM_CONDITIONAL(HAVE_STRERROR_R, test "$ac_cv_func_strerror_r" = yes)
AM_CONDITIONAL(HAVE_WAIT4, test "$ac_cv_func_wait4" = yes)
@@ -662,21 +705,6 @@ if test "$libgo_has_struct_exception" = "yes"; then
[Define to 1 if <math.h> defines struct exception])
fi
-dnl Check if makecontext expects the uc_stack member of ucontext to point
-dnl to the top of the stack.
-case "$target" in
- sparc*-*-solaris2.[[89]]*)
- libgo_cv_lib_makecontext_stack_top=yes
- ;;
- *)
- libgo_cv_lib_makecontext_stack_top=no
- ;;
-esac
-if test "$libgo_cv_lib_makecontext_stack_top" = "yes"; then
- AC_DEFINE(MAKECONTEXT_STACK_TOP, 1,
- [Define if makecontext expects top of stack in uc_stack.])
-fi
-
dnl See whether setcontext changes the value of TLS variables.
AC_CACHE_CHECK([whether setcontext clobbers TLS variables],
[libgo_cv_lib_setcontext_clobbers_tls],
@@ -790,14 +818,28 @@ else
[Define to the flags needed for the .section .eh_frame directive.])
fi
+AC_CACHE_CHECK([if compiler supports -Qunused-arguments],
+[libgo_cv_c_unused_arguments],
+[CFLAGS_hold=$CFLAGS
+CFLAGS="$CFLAGS -Qunused-arguments"
+AC_COMPILE_IFELSE([[int i;]],
+[libgo_cv_c_unused_arguments=yes],
+[libgo_cv_c_unused_arguments=no])
+CFLAGS=$CFLAGS_hold])
+
AC_CACHE_CHECK([if assembler supports GNU comdat group syntax],
libgo_cv_as_comdat_gnu, [
echo '.section .text,"axG",@progbits,.foo,comdat' > conftest.s
+CFLAGS_hold=$CFLAGS
+if test "$libgo_cv_c_unused_arguments" = yes; then
+ CFLAGS="$CFLAGS -Qunused-arguments"
+fi
if $CC $CFLAGS -c conftest.s > /dev/null 2>&1; then
libgo_cv_as_comdat_gnu=yes
else
libgo_cv_as_comdat_gnu=no
fi
+CFLAGS=$CFLAGS_hold
])
if test "x$libgo_cv_as_comdat_gnu" = xyes; then
AC_DEFINE(HAVE_AS_COMDAT_GAS, 1,
@@ -808,9 +850,14 @@ AC_CACHE_CHECK([assembler supports pc related relocs],
libgo_cv_as_x86_pcrel, [
libgo_cv_as_x86_pcrel=yes
echo '.text; foo: nop; .data; .long foo-.; .text' > conftest.s
+CFLAGS_hold=$CFLAGS
+if test "$libgo_cv_c_unused_arguments" = yes; then
+ CFLAGS="$CFLAGS -Qunused-arguments"
+fi
if $CC $CFLAGS -c conftest.s 2>&1 | $EGREP -i 'illegal|warning' > /dev/null; then
libgo_cv_as_x86_pcrel=no
fi
+CFLAGS=$CFLAGS_hold
])
if test "x$libgo_cv_as_x86_pcrel" = xyes; then
AC_DEFINE(HAVE_AS_X86_PCREL, 1,
@@ -821,9 +868,14 @@ AC_CACHE_CHECK([assembler supports unwind section type],
libgo_cv_as_x86_64_unwind_section_type, [
libgo_cv_as_x86_64_unwind_section_type=yes
echo '.section .eh_frame,"a",@unwind' > conftest.s
+CFLAGS_hold=$CFLAGS
+if test "$libgo_cv_c_unused_arguments" = yes; then
+ CFLAGS="$CFLAGS -Qunused-arguments"
+fi
if $CC $CFLAGS -c conftest.s 2>&1 | grep -i warning > /dev/null; then
libgo_cv_as_x86_64_unwind_section_type=no
fi
+CFLAGS=$CFLAGS_hold
])
if test "x$libgo_cv_as_x86_64_unwind_section_type" = xyes; then
AC_DEFINE(HAVE_AS_X86_64_UNWIND_SECTION_TYPE, 1,
diff --git a/libgo/go/archive/tar/common.go b/libgo/go/archive/tar/common.go
index 1b961e3ec6..e363aa793e 100644
--- a/libgo/go/archive/tar/common.go
+++ b/libgo/go/archive/tar/common.go
@@ -38,6 +38,7 @@ const (
TypeXGlobalHeader = 'g' // global extended header
TypeGNULongName = 'L' // Next file has a long name
TypeGNULongLink = 'K' // Next file symlinks to a file w/ a long name
+ TypeGNUSparse = 'S' // sparse file
)
// A Header represents a single header in a tar archive.
@@ -57,6 +58,7 @@ type Header struct {
Devminor int64 // minor number of character or block device
AccessTime time.Time // access time
ChangeTime time.Time // status change time
+ Xattrs map[string]string
}
// File name constants from the tar spec.
@@ -189,6 +191,7 @@ const (
paxSize = "size"
paxUid = "uid"
paxUname = "uname"
+ paxXattr = "SCHILY.xattr."
paxNone = ""
)
diff --git a/libgo/go/archive/tar/reader.go b/libgo/go/archive/tar/reader.go
index b2d62f3c51..a27559d0f0 100644
--- a/libgo/go/archive/tar/reader.go
+++ b/libgo/go/archive/tar/reader.go
@@ -29,12 +29,58 @@ const maxNanoSecondIntSize = 9
// The Next method advances to the next file in the archive (including the first),
// and then it can be treated as an io.Reader to access the file's data.
type Reader struct {
- r io.Reader
- err error
- nb int64 // number of unread bytes for current file entry
- pad int64 // amount of padding (ignored) after current file entry
+ r io.Reader
+ err error
+ pad int64 // amount of padding (ignored) after current file entry
+ curr numBytesReader // reader for current file entry
+ hdrBuff [blockSize]byte // buffer to use in readHeader
}
+// A numBytesReader is an io.Reader with a numBytes method, returning the number
+// of bytes remaining in the underlying encoded data.
+type numBytesReader interface {
+ io.Reader
+ numBytes() int64
+}
+
+// A regFileReader is a numBytesReader for reading file data from a tar archive.
+type regFileReader struct {
+ r io.Reader // underlying reader
+ nb int64 // number of unread bytes for current file entry
+}
+
+// A sparseFileReader is a numBytesReader for reading sparse file data from a tar archive.
+type sparseFileReader struct {
+ rfr *regFileReader // reads the sparse-encoded file data
+ sp []sparseEntry // the sparse map for the file
+ pos int64 // keeps track of file position
+ tot int64 // total size of the file
+}
+
+// Keywords for GNU sparse files in a PAX extended header
+const (
+ paxGNUSparseNumBlocks = "GNU.sparse.numblocks"
+ paxGNUSparseOffset = "GNU.sparse.offset"
+ paxGNUSparseNumBytes = "GNU.sparse.numbytes"
+ paxGNUSparseMap = "GNU.sparse.map"
+ paxGNUSparseName = "GNU.sparse.name"
+ paxGNUSparseMajor = "GNU.sparse.major"
+ paxGNUSparseMinor = "GNU.sparse.minor"
+ paxGNUSparseSize = "GNU.sparse.size"
+ paxGNUSparseRealSize = "GNU.sparse.realsize"
+)
+
+// Keywords for old GNU sparse headers
+const (
+ oldGNUSparseMainHeaderOffset = 386
+ oldGNUSparseMainHeaderIsExtendedOffset = 482
+ oldGNUSparseMainHeaderNumEntries = 4
+ oldGNUSparseExtendedHeaderIsExtendedOffset = 504
+ oldGNUSparseExtendedHeaderNumEntries = 21
+ oldGNUSparseOffsetSize = 12
+ oldGNUSparseNumBytesSize = 12
+)
+
// NewReader creates a new Reader reading from r.
func NewReader(r io.Reader) *Reader { return &Reader{r: r} }
@@ -64,6 +110,18 @@ func (tr *Reader) Next() (*Header, error) {
tr.skipUnread()
hdr = tr.readHeader()
mergePAX(hdr, headers)
+
+ // Check for a PAX format sparse file
+ sp, err := tr.checkForGNUSparsePAXHeaders(hdr, headers)
+ if err != nil {
+ tr.err = err
+ return nil, err
+ }
+ if sp != nil {
+ // Current file is a PAX format GNU sparse file.
+ // Set the current file reader to a sparse file reader.
+ tr.curr = &sparseFileReader{rfr: tr.curr.(*regFileReader), sp: sp, tot: hdr.Size}
+ }
return hdr, nil
case TypeGNULongName:
// We have a GNU long name header. Its contents are the real file name.
@@ -87,6 +145,67 @@ func (tr *Reader) Next() (*Header, error) {
return hdr, tr.err
}
+// checkForGNUSparsePAXHeaders checks the PAX headers for GNU sparse headers. If they are found, then
+// this function reads the sparse map and returns it. Unknown sparse formats are ignored, causing the file to
+// be treated as a regular file.
+func (tr *Reader) checkForGNUSparsePAXHeaders(hdr *Header, headers map[string]string) ([]sparseEntry, error) {
+ var sparseFormat string
+
+ // Check for sparse format indicators
+ major, majorOk := headers[paxGNUSparseMajor]
+ minor, minorOk := headers[paxGNUSparseMinor]
+ sparseName, sparseNameOk := headers[paxGNUSparseName]
+ _, sparseMapOk := headers[paxGNUSparseMap]
+ sparseSize, sparseSizeOk := headers[paxGNUSparseSize]
+ sparseRealSize, sparseRealSizeOk := headers[paxGNUSparseRealSize]
+
+ // Identify which, if any, sparse format applies from which PAX headers are set
+ if majorOk && minorOk {
+ sparseFormat = major + "." + minor
+ } else if sparseNameOk && sparseMapOk {
+ sparseFormat = "0.1"
+ } else if sparseSizeOk {
+ sparseFormat = "0.0"
+ } else {
+ // Not a PAX format GNU sparse file.
+ return nil, nil
+ }
+
+ // Check for unknown sparse format
+ if sparseFormat != "0.0" && sparseFormat != "0.1" && sparseFormat != "1.0" {
+ return nil, nil
+ }
+
+ // Update hdr from GNU sparse PAX headers
+ if sparseNameOk {
+ hdr.Name = sparseName
+ }
+ if sparseSizeOk {
+ realSize, err := strconv.ParseInt(sparseSize, 10, 0)
+ if err != nil {
+ return nil, ErrHeader
+ }
+ hdr.Size = realSize
+ } else if sparseRealSizeOk {
+ realSize, err := strconv.ParseInt(sparseRealSize, 10, 0)
+ if err != nil {
+ return nil, ErrHeader
+ }
+ hdr.Size = realSize
+ }
+
+ // Set up the sparse map, according to the particular sparse format in use
+ var sp []sparseEntry
+ var err error
+ switch sparseFormat {
+ case "0.0", "0.1":
+ sp, err = readGNUSparseMap0x1(headers)
+ case "1.0":
+ sp, err = readGNUSparseMap1x0(tr.curr)
+ }
+ return sp, err
+}
+
// mergePAX merges well known headers according to PAX standard.
// In general headers with the same name as those found
// in the header struct overwrite those found in the header
@@ -139,8 +258,14 @@ func mergePAX(hdr *Header, headers map[string]string) error {
return err
}
hdr.Size = int64(size)
+ default:
+ if strings.HasPrefix(k, paxXattr) {
+ if hdr.Xattrs == nil {
+ hdr.Xattrs = make(map[string]string)
+ }
+ hdr.Xattrs[k[len(paxXattr):]] = v
+ }
}
-
}
return nil
}
@@ -188,6 +313,11 @@ func parsePAX(r io.Reader) (map[string]string, error) {
if err != nil {
return nil, err
}
+
+ // For GNU PAX sparse format 0.0 support.
+ // This function transforms the sparse format 0.0 headers into sparse format 0.1 headers.
+ var sparseMap bytes.Buffer
+
headers := make(map[string]string)
// Each record is constructed as
// "%d %s=%s\n", length, keyword, value
@@ -205,7 +335,7 @@ func parsePAX(r io.Reader) (map[string]string, error) {
return nil, ErrHeader
}
// Extract everything between the decimal and the n -1 on the
- // beginning to to eat the ' ', -1 on the end to skip the newline.
+ // beginning to eat the ' ', -1 on the end to skip the newline.
var record []byte
record, buf = buf[sp+1:n-1], buf[n:]
// The first equals is guaranteed to mark the end of the key.
@@ -215,7 +345,21 @@ func parsePAX(r io.Reader) (map[string]string, error) {
return nil, ErrHeader
}
key, value := record[:eq], record[eq+1:]
- headers[string(key)] = string(value)
+
+ keyStr := string(key)
+ if keyStr == paxGNUSparseOffset || keyStr == paxGNUSparseNumBytes {
+ // GNU sparse format 0.0 special key. Write to sparseMap instead of using the headers map.
+ sparseMap.Write(value)
+ sparseMap.Write([]byte{','})
+ } else {
+ // Normal key. Set the value in the headers map.
+ headers[keyStr] = string(value)
+ }
+ }
+ if sparseMap.Len() != 0 {
+ // Add sparse info to headers, chopping off the extra comma
+ sparseMap.Truncate(sparseMap.Len() - 1)
+ headers[paxGNUSparseMap] = sparseMap.String()
}
return headers, nil
}
@@ -262,8 +406,8 @@ func (tr *Reader) octal(b []byte) int64 {
// skipUnread skips any unread bytes in the existing file entry, as well as any alignment padding.
func (tr *Reader) skipUnread() {
- nr := tr.nb + tr.pad // number of bytes to skip
- tr.nb, tr.pad = 0, 0
+ nr := tr.numBytes() + tr.pad // number of bytes to skip
+ tr.curr, tr.pad = nil, 0
if sr, ok := tr.r.(io.Seeker); ok {
if _, err := sr.Seek(nr, os.SEEK_CUR); err == nil {
return
@@ -283,7 +427,9 @@ func (tr *Reader) verifyChecksum(header []byte) bool {
}
func (tr *Reader) readHeader() *Header {
- header := make([]byte, blockSize)
+ header := tr.hdrBuff[:]
+ copy(header, zeroBlock)
+
if _, tr.err = io.ReadFull(tr.r, header); tr.err != nil {
return nil
}
@@ -325,14 +471,14 @@ func (tr *Reader) readHeader() *Header {
// so its magic bytes, like the rest of the block, are NULs.
magic := string(s.next(8)) // contains version field as well.
var format string
- switch magic {
- case "ustar\x0000": // POSIX tar (1003.1-1988)
+ switch {
+ case magic[:6] == "ustar\x00": // POSIX tar (1003.1-1988)
if string(header[508:512]) == "tar\x00" {
format = "star"
} else {
format = "posix"
}
- case "ustar \x00": // old GNU tar
+ case magic == "ustar \x00": // old GNU tar
format = "gnu"
}
@@ -367,30 +513,308 @@ func (tr *Reader) readHeader() *Header {
// Maximum value of hdr.Size is 64 GB (12 octal digits),
// so there's no risk of int64 overflowing.
- tr.nb = int64(hdr.Size)
- tr.pad = -tr.nb & (blockSize - 1) // blockSize is a power of two
+ nb := int64(hdr.Size)
+ tr.pad = -nb & (blockSize - 1) // blockSize is a power of two
+
+ // Set the current file reader.
+ tr.curr = &regFileReader{r: tr.r, nb: nb}
+
+ // Check for old GNU sparse format entry.
+ if hdr.Typeflag == TypeGNUSparse {
+ // Get the real size of the file.
+ hdr.Size = tr.octal(header[483:495])
+
+ // Read the sparse map.
+ sp := tr.readOldGNUSparseMap(header)
+ if tr.err != nil {
+ return nil
+ }
+ // Current file is a GNU sparse file. Update the current file reader.
+ tr.curr = &sparseFileReader{rfr: tr.curr.(*regFileReader), sp: sp, tot: hdr.Size}
+ }
return hdr
}
+// A sparseEntry holds a single entry in a sparse file's sparse map.
+// A sparse entry indicates the offset and size in a sparse file of a
+// block of data.
+type sparseEntry struct {
+ offset int64
+ numBytes int64
+}
+
+// readOldGNUSparseMap reads the sparse map as stored in the old GNU sparse format.
+// The sparse map is stored in the tar header if it's small enough. If it's larger than four entries,
+// then one or more extension headers are used to store the rest of the sparse map.
+func (tr *Reader) readOldGNUSparseMap(header []byte) []sparseEntry {
+ isExtended := header[oldGNUSparseMainHeaderIsExtendedOffset] != 0
+ spCap := oldGNUSparseMainHeaderNumEntries
+ if isExtended {
+ spCap += oldGNUSparseExtendedHeaderNumEntries
+ }
+ sp := make([]sparseEntry, 0, spCap)
+ s := slicer(header[oldGNUSparseMainHeaderOffset:])
+
+ // Read the four entries from the main tar header
+ for i := 0; i < oldGNUSparseMainHeaderNumEntries; i++ {
+ offset := tr.octal(s.next(oldGNUSparseOffsetSize))
+ numBytes := tr.octal(s.next(oldGNUSparseNumBytesSize))
+ if tr.err != nil {
+ tr.err = ErrHeader
+ return nil
+ }
+ if offset == 0 && numBytes == 0 {
+ break
+ }
+ sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
+ }
+
+ for isExtended {
+ // There are more entries. Read an extension header and parse its entries.
+ sparseHeader := make([]byte, blockSize)
+ if _, tr.err = io.ReadFull(tr.r, sparseHeader); tr.err != nil {
+ return nil
+ }
+ isExtended = sparseHeader[oldGNUSparseExtendedHeaderIsExtendedOffset] != 0
+ s = slicer(sparseHeader)
+ for i := 0; i < oldGNUSparseExtendedHeaderNumEntries; i++ {
+ offset := tr.octal(s.next(oldGNUSparseOffsetSize))
+ numBytes := tr.octal(s.next(oldGNUSparseNumBytesSize))
+ if tr.err != nil {
+ tr.err = ErrHeader
+ return nil
+ }
+ if offset == 0 && numBytes == 0 {
+ break
+ }
+ sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
+ }
+ }
+ return sp
+}
+
+// readGNUSparseMap1x0 reads the sparse map as stored in GNU's PAX sparse format version 1.0.
+// The sparse map is stored just before the file data and padded out to the nearest block boundary.
+func readGNUSparseMap1x0(r io.Reader) ([]sparseEntry, error) {
+ buf := make([]byte, 2*blockSize)
+ sparseHeader := buf[:blockSize]
+
+ // readDecimal is a helper function to read a decimal integer from the sparse map
+ // while making sure to read from the file in blocks of size blockSize
+ readDecimal := func() (int64, error) {
+ // Look for newline
+ nl := bytes.IndexByte(sparseHeader, '\n')
+ if nl == -1 {
+ if len(sparseHeader) >= blockSize {
+ // This is an error
+ return 0, ErrHeader
+ }
+ oldLen := len(sparseHeader)
+ newLen := oldLen + blockSize
+ if cap(sparseHeader) < newLen {
+ // There's more header, but we need to make room for the next block
+ copy(buf, sparseHeader)
+ sparseHeader = buf[:newLen]
+ } else {
+ // There's more header, and we can just reslice
+ sparseHeader = sparseHeader[:newLen]
+ }
+
+ // Now that sparseHeader is large enough, read next block
+ if _, err := io.ReadFull(r, sparseHeader[oldLen:newLen]); err != nil {
+ return 0, err
+ }
+
+ // Look for a newline in the new data
+ nl = bytes.IndexByte(sparseHeader[oldLen:newLen], '\n')
+ if nl == -1 {
+ // This is an error
+ return 0, ErrHeader
+ }
+ nl += oldLen // We want the position from the beginning
+ }
+ // Now that we've found a newline, read a number
+ n, err := strconv.ParseInt(string(sparseHeader[:nl]), 10, 0)
+ if err != nil {
+ return 0, ErrHeader
+ }
+
+ // Update sparseHeader to consume this number
+ sparseHeader = sparseHeader[nl+1:]
+ return n, nil
+ }
+
+ // Read the first block
+ if _, err := io.ReadFull(r, sparseHeader); err != nil {
+ return nil, err
+ }
+
+ // The first line contains the number of entries
+ numEntries, err := readDecimal()
+ if err != nil {
+ return nil, err
+ }
+
+ // Read all the entries
+ sp := make([]sparseEntry, 0, numEntries)
+ for i := int64(0); i < numEntries; i++ {
+ // Read the offset
+ offset, err := readDecimal()
+ if err != nil {
+ return nil, err
+ }
+ // Read numBytes
+ numBytes, err := readDecimal()
+ if err != nil {
+ return nil, err
+ }
+
+ sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
+ }
+
+ return sp, nil
+}
+
+// readGNUSparseMap0x1 reads the sparse map as stored in GNU's PAX sparse format version 0.1.
+// The sparse map is stored in the PAX headers.
+func readGNUSparseMap0x1(headers map[string]string) ([]sparseEntry, error) {
+ // Get number of entries
+ numEntriesStr, ok := headers[paxGNUSparseNumBlocks]
+ if !ok {
+ return nil, ErrHeader
+ }
+ numEntries, err := strconv.ParseInt(numEntriesStr, 10, 0)
+ if err != nil {
+ return nil, ErrHeader
+ }
+
+ sparseMap := strings.Split(headers[paxGNUSparseMap], ",")
+
+ // There should be two numbers in sparseMap for each entry
+ if int64(len(sparseMap)) != 2*numEntries {
+ return nil, ErrHeader
+ }
+
+ // Loop through the entries in the sparse map
+ sp := make([]sparseEntry, 0, numEntries)
+ for i := int64(0); i < numEntries; i++ {
+ offset, err := strconv.ParseInt(sparseMap[2*i], 10, 0)
+ if err != nil {
+ return nil, ErrHeader
+ }
+ numBytes, err := strconv.ParseInt(sparseMap[2*i+1], 10, 0)
+ if err != nil {
+ return nil, ErrHeader
+ }
+ sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
+ }
+
+ return sp, nil
+}
+
+// numBytes returns the number of bytes left to read in the current file's entry
+// in the tar archive, or 0 if there is no current file.
+func (tr *Reader) numBytes() int64 {
+ if tr.curr == nil {
+ // No current file, so no bytes
+ return 0
+ }
+ return tr.curr.numBytes()
+}
+
// Read reads from the current entry in the tar archive.
// It returns 0, io.EOF when it reaches the end of that entry,
// until Next is called to advance to the next entry.
func (tr *Reader) Read(b []byte) (n int, err error) {
- if tr.nb == 0 {
- // file consumed
+ if tr.curr == nil {
return 0, io.EOF
}
+ n, err = tr.curr.Read(b)
+ if err != nil && err != io.EOF {
+ tr.err = err
+ }
+ return
+}
- if int64(len(b)) > tr.nb {
- b = b[0:tr.nb]
+func (rfr *regFileReader) Read(b []byte) (n int, err error) {
+ if rfr.nb == 0 {
+ // file consumed
+ return 0, io.EOF
}
- n, err = tr.r.Read(b)
- tr.nb -= int64(n)
+ if int64(len(b)) > rfr.nb {
+ b = b[0:rfr.nb]
+ }
+ n, err = rfr.r.Read(b)
+ rfr.nb -= int64(n)
- if err == io.EOF && tr.nb > 0 {
+ if err == io.EOF && rfr.nb > 0 {
err = io.ErrUnexpectedEOF
}
- tr.err = err
return
}
+
+// numBytes returns the number of bytes left to read in the file's data in the tar archive.
+func (rfr *regFileReader) numBytes() int64 {
+ return rfr.nb
+}
+
+// readHole reads a sparse file hole ending at offset toOffset
+func (sfr *sparseFileReader) readHole(b []byte, toOffset int64) int {
+ n64 := toOffset - sfr.pos
+ if n64 > int64(len(b)) {
+ n64 = int64(len(b))
+ }
+ n := int(n64)
+ for i := 0; i < n; i++ {
+ b[i] = 0
+ }
+ sfr.pos += n64
+ return n
+}
+
+// Read reads the sparse file data in expanded form.
+func (sfr *sparseFileReader) Read(b []byte) (n int, err error) {
+ if len(sfr.sp) == 0 {
+ // No more data fragments to read from.
+ if sfr.pos < sfr.tot {
+ // We're in the last hole
+ n = sfr.readHole(b, sfr.tot)
+ return
+ }
+ // Otherwise, we're at the end of the file
+ return 0, io.EOF
+ }
+ if sfr.pos < sfr.sp[0].offset {
+ // We're in a hole
+ n = sfr.readHole(b, sfr.sp[0].offset)
+ return
+ }
+
+ // We're not in a hole, so we'll read from the next data fragment
+ posInFragment := sfr.pos - sfr.sp[0].offset
+ bytesLeft := sfr.sp[0].numBytes - posInFragment
+ if int64(len(b)) > bytesLeft {
+ b = b[0:bytesLeft]
+ }
+
+ n, err = sfr.rfr.Read(b)
+ sfr.pos += int64(n)
+
+ if int64(n) == bytesLeft {
+ // We're done with this fragment
+ sfr.sp = sfr.sp[1:]
+ }
+
+ if err == io.EOF && sfr.pos < sfr.tot {
+ // We reached the end of the last fragment's data, but there's a final hole
+ err = nil
+ }
+ return
+}
+
+// numBytes returns the number of bytes left to read in the sparse file's
+// sparse-encoded data in the tar archive.
+func (sfr *sparseFileReader) numBytes() int64 {
+ return sfr.rfr.nb
+}
diff --git a/libgo/go/archive/tar/reader_test.go b/libgo/go/archive/tar/reader_test.go
index 1285616565..9601ffe459 100644
--- a/libgo/go/archive/tar/reader_test.go
+++ b/libgo/go/archive/tar/reader_test.go
@@ -9,6 +9,7 @@ import (
"crypto/md5"
"fmt"
"io"
+ "io/ioutil"
"os"
"reflect"
"strings"
@@ -54,8 +55,92 @@ var gnuTarTest = &untarTest{
},
}
+var sparseTarTest = &untarTest{
+ file: "testdata/sparse-formats.tar",
+ headers: []*Header{
+ {
+ Name: "sparse-gnu",
+ Mode: 420,
+ Uid: 1000,
+ Gid: 1000,
+ Size: 200,
+ ModTime: time.Unix(1392395740, 0),
+ Typeflag: 0x53,
+ Linkname: "",
+ Uname: "david",
+ Gname: "david",
+ Devmajor: 0,
+ Devminor: 0,
+ },
+ {
+ Name: "sparse-posix-0.0",
+ Mode: 420,
+ Uid: 1000,
+ Gid: 1000,
+ Size: 200,
+ ModTime: time.Unix(1392342187, 0),
+ Typeflag: 0x30,
+ Linkname: "",
+ Uname: "david",
+ Gname: "david",
+ Devmajor: 0,
+ Devminor: 0,
+ },
+ {
+ Name: "sparse-posix-0.1",
+ Mode: 420,
+ Uid: 1000,
+ Gid: 1000,
+ Size: 200,
+ ModTime: time.Unix(1392340456, 0),
+ Typeflag: 0x30,
+ Linkname: "",
+ Uname: "david",
+ Gname: "david",
+ Devmajor: 0,
+ Devminor: 0,
+ },
+ {
+ Name: "sparse-posix-1.0",
+ Mode: 420,
+ Uid: 1000,
+ Gid: 1000,
+ Size: 200,
+ ModTime: time.Unix(1392337404, 0),
+ Typeflag: 0x30,
+ Linkname: "",
+ Uname: "david",
+ Gname: "david",
+ Devmajor: 0,
+ Devminor: 0,
+ },
+ {
+ Name: "end",
+ Mode: 420,
+ Uid: 1000,
+ Gid: 1000,
+ Size: 4,
+ ModTime: time.Unix(1392398319, 0),
+ Typeflag: 0x30,
+ Linkname: "",
+ Uname: "david",
+ Gname: "david",
+ Devmajor: 0,
+ Devminor: 0,
+ },
+ },
+ cksums: []string{
+ "6f53234398c2449fe67c1812d993012f",
+ "6f53234398c2449fe67c1812d993012f",
+ "6f53234398c2449fe67c1812d993012f",
+ "6f53234398c2449fe67c1812d993012f",
+ "b0061974914468de549a2af8ced10316",
+ },
+}
+
var untarTests = []*untarTest{
gnuTarTest,
+ sparseTarTest,
{
file: "testdata/star.tar",
headers: []*Header{
@@ -161,6 +246,46 @@ var untarTests = []*untarTest{
},
},
},
+ {
+ file: "testdata/xattrs.tar",
+ headers: []*Header{
+ {
+ Name: "small.txt",
+ Mode: 0644,
+ Uid: 1000,
+ Gid: 10,
+ Size: 5,
+ ModTime: time.Unix(1386065770, 448252320),
+ Typeflag: '0',
+ Uname: "alex",
+ Gname: "wheel",
+ AccessTime: time.Unix(1389782991, 419875220),
+ ChangeTime: time.Unix(1389782956, 794414986),
+ Xattrs: map[string]string{
+ "user.key": "value",
+ "user.key2": "value2",
+ // Interestingly, selinux encodes the terminating null inside the xattr
+ "security.selinux": "unconfined_u:object_r:default_t:s0\x00",
+ },
+ },
+ {
+ Name: "small2.txt",
+ Mode: 0644,
+ Uid: 1000,
+ Gid: 10,
+ Size: 11,
+ ModTime: time.Unix(1386065770, 449252304),
+ Typeflag: '0',
+ Uname: "alex",
+ Gname: "wheel",
+ AccessTime: time.Unix(1389782991, 419875220),
+ ChangeTime: time.Unix(1386065770, 449252304),
+ Xattrs: map[string]string{
+ "security.selinux": "unconfined_u:object_r:default_t:s0\x00",
+ },
+ },
+ },
+ },
}
func TestReader(t *testing.T) {
@@ -180,7 +305,7 @@ testLoop:
f.Close()
continue testLoop
}
- if *hdr != *header {
+ if !reflect.DeepEqual(*hdr, *header) {
t.Errorf("test %d, entry %d: Incorrect header:\nhave %+v\nwant %+v",
i, j, *hdr, *header)
}
@@ -253,7 +378,7 @@ func TestIncrementalRead(t *testing.T) {
}
// check the header
- if *hdr != *headers[nread] {
+ if !reflect.DeepEqual(*hdr, *headers[nread]) {
t.Errorf("Incorrect header:\nhave %+v\nwant %+v",
*hdr, headers[nread])
}
@@ -321,7 +446,7 @@ func TestParsePAXHeader(t *testing.T) {
{"mtime", "mtime=1350244992.023960108", "30 mtime=1350244992.023960108\n"}}
for _, test := range paxTests {
key, expected, raw := test[0], test[1], test[2]
- reader := bytes.NewBuffer([]byte(raw))
+ reader := bytes.NewReader([]byte(raw))
headers, err := parsePAX(reader)
if err != nil {
t.Errorf("Couldn't parse correctly formatted headers: %v", err)
@@ -337,7 +462,7 @@ func TestParsePAXHeader(t *testing.T) {
t.Error("Buffer wasn't consumed")
}
}
- badHeader := bytes.NewBuffer([]byte("3 somelongkey="))
+ badHeader := bytes.NewReader([]byte("3 somelongkey="))
if _, err := parsePAX(badHeader); err != ErrHeader {
t.Fatal("Unexpected success when parsing bad header")
}
@@ -346,7 +471,7 @@ func TestParsePAXHeader(t *testing.T) {
func TestParsePAXTime(t *testing.T) {
// Some valid PAX time values
timestamps := map[string]time.Time{
- "1350244992.023960108": time.Unix(1350244992, 23960108), // The commoon case
+ "1350244992.023960108": time.Unix(1350244992, 23960108), // The common case
"1350244992.02396010": time.Unix(1350244992, 23960100), // Lower precision value
"1350244992.0239601089": time.Unix(1350244992, 23960108), // Higher precision value
"1350244992": time.Unix(1350244992, 0), // Low precision value
@@ -383,3 +508,236 @@ func TestMergePAX(t *testing.T) {
t.Errorf("incorrect merge: got %+v, want %+v", hdr, want)
}
}
+
+func TestSparseEndToEnd(t *testing.T) {
+ test := sparseTarTest
+ f, err := os.Open(test.file)
+ if err != nil {
+ t.Fatalf("Unexpected error: %v", err)
+ }
+ defer f.Close()
+
+ tr := NewReader(f)
+
+ headers := test.headers
+ cksums := test.cksums
+ nread := 0
+
+ // loop over all files
+ for ; ; nread++ {
+ hdr, err := tr.Next()
+ if hdr == nil || err == io.EOF {
+ break
+ }
+
+ // check the header
+ if !reflect.DeepEqual(*hdr, *headers[nread]) {
+ t.Errorf("Incorrect header:\nhave %+v\nwant %+v",
+ *hdr, headers[nread])
+ }
+
+ // read and checksum the file data
+ h := md5.New()
+ _, err = io.Copy(h, tr)
+ if err != nil {
+ t.Fatalf("Unexpected error: %v", err)
+ }
+
+ // verify checksum
+ have := fmt.Sprintf("%x", h.Sum(nil))
+ want := cksums[nread]
+ if want != have {
+ t.Errorf("Bad checksum on file %s:\nhave %+v\nwant %+v", hdr.Name, have, want)
+ }
+ }
+ if nread != len(headers) {
+ t.Errorf("Didn't process all files\nexpected: %d\nprocessed %d\n", len(headers), nread)
+ }
+}
+
+type sparseFileReadTest struct {
+ sparseData []byte
+ sparseMap []sparseEntry
+ realSize int64
+ expected []byte
+}
+
+var sparseFileReadTests = []sparseFileReadTest{
+ {
+ sparseData: []byte("abcde"),
+ sparseMap: []sparseEntry{
+ {offset: 0, numBytes: 2},
+ {offset: 5, numBytes: 3},
+ },
+ realSize: 8,
+ expected: []byte("ab\x00\x00\x00cde"),
+ },
+ {
+ sparseData: []byte("abcde"),
+ sparseMap: []sparseEntry{
+ {offset: 0, numBytes: 2},
+ {offset: 5, numBytes: 3},
+ },
+ realSize: 10,
+ expected: []byte("ab\x00\x00\x00cde\x00\x00"),
+ },
+ {
+ sparseData: []byte("abcde"),
+ sparseMap: []sparseEntry{
+ {offset: 1, numBytes: 3},
+ {offset: 6, numBytes: 2},
+ },
+ realSize: 8,
+ expected: []byte("\x00abc\x00\x00de"),
+ },
+ {
+ sparseData: []byte("abcde"),
+ sparseMap: []sparseEntry{
+ {offset: 1, numBytes: 3},
+ {offset: 6, numBytes: 2},
+ },
+ realSize: 10,
+ expected: []byte("\x00abc\x00\x00de\x00\x00"),
+ },
+ {
+ sparseData: []byte(""),
+ sparseMap: nil,
+ realSize: 2,
+ expected: []byte("\x00\x00"),
+ },
+}
+
+func TestSparseFileReader(t *testing.T) {
+ for i, test := range sparseFileReadTests {
+ r := bytes.NewReader(test.sparseData)
+ nb := int64(r.Len())
+ sfr := &sparseFileReader{
+ rfr: &regFileReader{r: r, nb: nb},
+ sp: test.sparseMap,
+ pos: 0,
+ tot: test.realSize,
+ }
+ if sfr.numBytes() != nb {
+ t.Errorf("test %d: Before reading, sfr.numBytes() = %d, want %d", i, sfr.numBytes(), nb)
+ }
+ buf, err := ioutil.ReadAll(sfr)
+ if err != nil {
+ t.Errorf("test %d: Unexpected error: %v", i, err)
+ }
+ if e := test.expected; !bytes.Equal(buf, e) {
+ t.Errorf("test %d: Contents = %v, want %v", i, buf, e)
+ }
+ if sfr.numBytes() != 0 {
+ t.Errorf("test %d: After draining the reader, numBytes() was nonzero", i)
+ }
+ }
+}
+
+func TestSparseIncrementalRead(t *testing.T) {
+ sparseMap := []sparseEntry{{10, 2}}
+ sparseData := []byte("Go")
+ expected := "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Go\x00\x00\x00\x00\x00\x00\x00\x00"
+
+ r := bytes.NewReader(sparseData)
+ nb := int64(r.Len())
+ sfr := &sparseFileReader{
+ rfr: &regFileReader{r: r, nb: nb},
+ sp: sparseMap,
+ pos: 0,
+ tot: int64(len(expected)),
+ }
+
+ // We'll read the data 6 bytes at a time, with a hole of size 10 at
+ // the beginning and one of size 8 at the end.
+ var outputBuf bytes.Buffer
+ buf := make([]byte, 6)
+ for {
+ n, err := sfr.Read(buf)
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ t.Errorf("Read: unexpected error %v\n", err)
+ }
+ if n > 0 {
+ _, err := outputBuf.Write(buf[:n])
+ if err != nil {
+ t.Errorf("Write: unexpected error %v\n", err)
+ }
+ }
+ }
+ got := outputBuf.String()
+ if got != expected {
+ t.Errorf("Contents = %v, want %v", got, expected)
+ }
+}
+
+func TestReadGNUSparseMap0x1(t *testing.T) {
+ headers := map[string]string{
+ paxGNUSparseNumBlocks: "4",
+ paxGNUSparseMap: "0,5,10,5,20,5,30,5",
+ }
+ expected := []sparseEntry{
+ {offset: 0, numBytes: 5},
+ {offset: 10, numBytes: 5},
+ {offset: 20, numBytes: 5},
+ {offset: 30, numBytes: 5},
+ }
+
+ sp, err := readGNUSparseMap0x1(headers)
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+ if !reflect.DeepEqual(sp, expected) {
+ t.Errorf("Incorrect sparse map: got %v, wanted %v", sp, expected)
+ }
+}
+
+func TestReadGNUSparseMap1x0(t *testing.T) {
+ // This test uses lots of holes so the sparse header takes up more than two blocks
+ numEntries := 100
+ expected := make([]sparseEntry, 0, numEntries)
+ sparseMap := new(bytes.Buffer)
+
+ fmt.Fprintf(sparseMap, "%d\n", numEntries)
+ for i := 0; i < numEntries; i++ {
+ offset := int64(2048 * i)
+ numBytes := int64(1024)
+ expected = append(expected, sparseEntry{offset: offset, numBytes: numBytes})
+ fmt.Fprintf(sparseMap, "%d\n%d\n", offset, numBytes)
+ }
+
+ // Make the header the smallest multiple of blockSize that fits the sparseMap
+ headerBlocks := (sparseMap.Len() + blockSize - 1) / blockSize
+ bufLen := blockSize * headerBlocks
+ buf := make([]byte, bufLen)
+ copy(buf, sparseMap.Bytes())
+
+ // Get an reader to read the sparse map
+ r := bytes.NewReader(buf)
+
+ // Read the sparse map
+ sp, err := readGNUSparseMap1x0(r)
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+ if !reflect.DeepEqual(sp, expected) {
+ t.Errorf("Incorrect sparse map: got %v, wanted %v", sp, expected)
+ }
+}
+
+func TestUninitializedRead(t *testing.T) {
+ test := gnuTarTest
+ f, err := os.Open(test.file)
+ if err != nil {
+ t.Fatalf("Unexpected error: %v", err)
+ }
+ defer f.Close()
+
+ tr := NewReader(f)
+ _, err = tr.Read([]byte{})
+ if err == nil || err != io.EOF {
+ t.Errorf("Unexpected error: %v, wanted %v", err, io.EOF)
+ }
+
+}
diff --git a/libgo/go/archive/tar/stat_atim.go b/libgo/go/archive/tar/stat_atim.go
index 6029b08712..cf9cc79c59 100644
--- a/libgo/go/archive/tar/stat_atim.go
+++ b/libgo/go/archive/tar/stat_atim.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 linux openbsd
+// +build linux dragonfly openbsd solaris
package tar
diff --git a/libgo/go/archive/tar/stat_unix.go b/libgo/go/archive/tar/stat_unix.go
index 92bc924242..cb843db4cf 100644
--- a/libgo/go/archive/tar/stat_unix.go
+++ b/libgo/go/archive/tar/stat_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 linux darwin freebsd openbsd netbsd
+// +build linux darwin dragonfly freebsd openbsd netbsd solaris
package tar
diff --git a/libgo/go/archive/tar/tar_test.go b/libgo/go/archive/tar/tar_test.go
index 616a9cc57e..ed333f3ea4 100644
--- a/libgo/go/archive/tar/tar_test.go
+++ b/libgo/go/archive/tar/tar_test.go
@@ -36,6 +36,10 @@ func TestFileInfoHeader(t *testing.T) {
if g, e := h.ModTime, fi.ModTime(); !g.Equal(e) {
t.Errorf("ModTime = %v; want %v", g, e)
}
+ // FileInfoHeader should error when passing nil FileInfo
+ if _, err := FileInfoHeader(nil, ""); err == nil {
+ t.Fatalf("Expected error when passing nil to FileInfoHeader")
+ }
}
func TestFileInfoHeaderDir(t *testing.T) {
diff --git a/libgo/go/archive/tar/testdata/sparse-formats.tar b/libgo/go/archive/tar/testdata/sparse-formats.tar
new file mode 100644
index 0000000000..8bd4e74d50
--- /dev/null
+++ b/libgo/go/archive/tar/testdata/sparse-formats.tar
Binary files differ
diff --git a/libgo/go/archive/tar/testdata/writer-big-long.tar b/libgo/go/archive/tar/testdata/writer-big-long.tar
new file mode 100644
index 0000000000..5960ee8247
--- /dev/null
+++ b/libgo/go/archive/tar/testdata/writer-big-long.tar
Binary files differ
diff --git a/libgo/go/archive/tar/testdata/xattrs.tar b/libgo/go/archive/tar/testdata/xattrs.tar
new file mode 100644
index 0000000000..9701950edd
--- /dev/null
+++ b/libgo/go/archive/tar/testdata/xattrs.tar
Binary files differ
diff --git a/libgo/go/archive/tar/writer.go b/libgo/go/archive/tar/writer.go
index 549f1464c3..dafb2cabf3 100644
--- a/libgo/go/archive/tar/writer.go
+++ b/libgo/go/archive/tar/writer.go
@@ -37,8 +37,10 @@ type Writer struct {
nb int64 // number of unwritten bytes for current file entry
pad int64 // amount of padding to write after current file entry
closed bool
- usedBinary bool // whether the binary numeric field extension was used
- preferPax bool // use pax header instead of binary numeric header
+ usedBinary bool // whether the binary numeric field extension was used
+ preferPax bool // use pax header instead of binary numeric header
+ hdrBuff [blockSize]byte // buffer to use in writeHeader when writing a regular header
+ paxHdrBuff [blockSize]byte // buffer to use in writeHeader when writing a pax header
}
// NewWriter creates a new Writer writing to w.
@@ -160,7 +162,18 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
// subsecond time resolution, but for now let's just capture
// too long fields or non ascii characters
- header := make([]byte, blockSize)
+ var header []byte
+
+ // We need to select which scratch buffer to use carefully,
+ // since this method is called recursively to write PAX headers.
+ // If allowPax is true, this is the non-recursive call, and we will use hdrBuff.
+ // If allowPax is false, we are being called by writePAXHeader, and hdrBuff is
+ // already being used by the non-recursive call, so we must use paxHdrBuff.
+ header = tw.hdrBuff[:]
+ if !allowPax {
+ header = tw.paxHdrBuff[:]
+ }
+ copy(header, zeroBlock)
s := slicer(header)
// keep a reference to the filename to allow to overwrite it later if we detect that we can use ustar longnames instead of pax
@@ -218,8 +231,8 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
tw.cString(prefixHeaderBytes, prefix, false, paxNone, nil)
// Use the ustar magic if we used ustar long names.
- if len(prefix) > 0 {
- copy(header[257:265], []byte("ustar\000"))
+ if len(prefix) > 0 && !tw.usedBinary {
+ copy(header[257:265], []byte("ustar\x00"))
}
}
}
@@ -236,6 +249,12 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
return tw.err
}
+ if allowPax {
+ for k, v := range hdr.Xattrs {
+ paxHeaders[paxXattr+k] = v
+ }
+ }
+
if len(paxHeaders) > 0 {
if !allowPax {
return errInvalidHeader
diff --git a/libgo/go/archive/tar/writer_test.go b/libgo/go/archive/tar/writer_test.go
index 30ebf977ac..5e42e322f9 100644
--- a/libgo/go/archive/tar/writer_test.go
+++ b/libgo/go/archive/tar/writer_test.go
@@ -10,6 +10,7 @@ import (
"io"
"io/ioutil"
"os"
+ "reflect"
"strings"
"testing"
"testing/iotest"
@@ -102,6 +103,29 @@ var writerTests = []*writerTest{
},
},
},
+ // The truncated test file was produced using these commands:
+ // dd if=/dev/zero bs=1048576 count=16384 > (longname/)*15 /16gig.txt
+ // tar -b 1 -c -f- (longname/)*15 /16gig.txt | dd bs=512 count=8 > writer-big-long.tar
+ {
+ file: "testdata/writer-big-long.tar",
+ entries: []*writerTestEntry{
+ {
+ header: &Header{
+ Name: strings.Repeat("longname/", 15) + "16gig.txt",
+ Mode: 0644,
+ Uid: 1000,
+ Gid: 1000,
+ Size: 16 << 30,
+ ModTime: time.Unix(1399583047, 0),
+ Typeflag: '0',
+ Uname: "guillaume",
+ Gname: "guillaume",
+ },
+ // fake contents
+ contents: strings.Repeat("\x00", 4<<10),
+ },
+ },
+ },
// This file was produced using gnu tar 1.17
// gnutar -b 4 --format=ustar (longname/)*15 + file.txt
{
@@ -338,6 +362,45 @@ func TestPaxNonAscii(t *testing.T) {
}
}
+func TestPaxXattrs(t *testing.T) {
+ xattrs := map[string]string{
+ "user.key": "value",
+ }
+
+ // Create an archive with an xattr
+ fileinfo, err := os.Stat("testdata/small.txt")
+ if err != nil {
+ t.Fatal(err)
+ }
+ hdr, err := FileInfoHeader(fileinfo, "")
+ if err != nil {
+ t.Fatalf("os.Stat: %v", err)
+ }
+ contents := "Kilts"
+ hdr.Xattrs = xattrs
+ var buf bytes.Buffer
+ writer := NewWriter(&buf)
+ if err := writer.WriteHeader(hdr); err != nil {
+ t.Fatal(err)
+ }
+ if _, err = writer.Write([]byte(contents)); err != nil {
+ t.Fatal(err)
+ }
+ if err := writer.Close(); err != nil {
+ t.Fatal(err)
+ }
+ // Test that we can get the xattrs back out of the archive.
+ reader := NewReader(&buf)
+ hdr, err = reader.Next()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !reflect.DeepEqual(hdr.Xattrs, xattrs) {
+ t.Fatalf("xattrs did not survive round trip: got %+v, want %+v",
+ hdr.Xattrs, xattrs)
+ }
+}
+
func TestPAXHeader(t *testing.T) {
medName := strings.Repeat("CD", 50)
longName := strings.Repeat("AB", 100)
@@ -391,3 +454,38 @@ func TestUSTARLongName(t *testing.T) {
t.Fatal("Couldn't recover long name")
}
}
+
+func TestValidTypeflagWithPAXHeader(t *testing.T) {
+ var buffer bytes.Buffer
+ tw := NewWriter(&buffer)
+
+ fileName := strings.Repeat("ab", 100)
+
+ hdr := &Header{
+ Name: fileName,
+ Size: 4,
+ Typeflag: 0,
+ }
+ if err := tw.WriteHeader(hdr); err != nil {
+ t.Fatalf("Failed to write header: %s", err)
+ }
+ if _, err := tw.Write([]byte("fooo")); err != nil {
+ t.Fatalf("Failed to write the file's data: %s", err)
+ }
+ tw.Close()
+
+ tr := NewReader(&buffer)
+
+ for {
+ header, err := tr.Next()
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ t.Fatalf("Failed to read header: %s", err)
+ }
+ if header.Typeflag != 0 {
+ t.Fatalf("Typeflag should've been 0, found %d", header.Typeflag)
+ }
+ }
+}
diff --git a/libgo/go/archive/zip/reader.go b/libgo/go/archive/zip/reader.go
index 116737337f..8136b840d4 100644
--- a/libgo/go/archive/zip/reader.go
+++ b/libgo/go/archive/zip/reader.go
@@ -253,7 +253,7 @@ func readDirectoryHeader(f *File, r io.Reader) error {
}
if tag == zip64ExtraId {
// update directory values from the zip64 extra block
- eb := readBuf(b)
+ eb := readBuf(b[:size])
if len(eb) >= 8 {
f.UncompressedSize64 = eb.uint64()
}
@@ -267,8 +267,13 @@ func readDirectoryHeader(f *File, r io.Reader) error {
b = b[size:]
}
// Should have consumed the whole header.
- if len(b) != 0 {
- return ErrFormat
+ // But popular zip & JAR creation tools are broken and
+ // may pad extra zeros at the end, so accept those
+ // too. See golang.org/issue/8186.
+ for _, v := range b {
+ if v != 0 {
+ return ErrFormat
+ }
}
}
return nil
diff --git a/libgo/go/archive/zip/reader_test.go b/libgo/go/archive/zip/reader_test.go
index 78875ecbf0..29d0652dcc 100644
--- a/libgo/go/archive/zip/reader_test.go
+++ b/libgo/go/archive/zip/reader_test.go
@@ -13,6 +13,7 @@ import (
"os"
"path/filepath"
"regexp"
+ "strings"
"testing"
"time"
)
@@ -235,6 +236,18 @@ var tests = []ZipTest{
},
},
},
+ // Another zip64 file with different Extras fields. (golang.org/issue/7069)
+ {
+ Name: "zip64-2.zip",
+ File: []ZipTestFile{
+ {
+ Name: "README",
+ Content: []byte("This small file is in ZIP64 format.\n"),
+ Mtime: "08-10-12 14:33:32",
+ Mode: 0644,
+ },
+ },
+ },
}
var crossPlatform = []ZipTestFile{
@@ -343,19 +356,13 @@ func readTestFile(t *testing.T, zt ZipTest, ft ZipTestFile, f *File) {
testFileMode(t, zt.Name, f, ft.Mode)
- size0 := f.UncompressedSize
-
var b bytes.Buffer
r, err := f.Open()
if err != nil {
- t.Error(err)
+ t.Errorf("%s: %v", zt.Name, err)
return
}
- if size1 := f.UncompressedSize; size0 != size1 {
- t.Errorf("file %q changed f.UncompressedSize from %d to %d", f.Name, size0, size1)
- }
-
_, err = io.Copy(&b, r)
if err != ft.ContentErr {
t.Errorf("%s: copying contents: %v (want %v)", zt.Name, err, ft.ContentErr)
@@ -365,6 +372,14 @@ func readTestFile(t *testing.T, zt ZipTest, ft ZipTestFile, f *File) {
}
r.Close()
+ size := uint64(f.UncompressedSize)
+ if size == uint32max {
+ size = f.UncompressedSize64
+ }
+ if g := uint64(b.Len()); g != size {
+ t.Errorf("%v: read %v bytes but f.UncompressedSize == %v", f.Name, g, size)
+ }
+
var c []byte
if ft.Content != nil {
c = ft.Content
@@ -494,3 +509,25 @@ func returnRecursiveZip() (r io.ReaderAt, size int64) {
b := rZipBytes()
return bytes.NewReader(b), int64(len(b))
}
+
+func TestIssue8186(t *testing.T) {
+ // Directory headers & data found in the TOC of a JAR file.
+ dirEnts := []string{
+ "PK\x01\x02\n\x00\n\x00\x00\b\x00\x004\x9d3?\xaa\x1b\x06\xf0\x81\x02\x00\x00\x81\x02\x00\x00-\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00res/drawable-xhdpi-v4/ic_actionbar_accept.png\xfe\xca\x00\x00\x00",
+ "PK\x01\x02\n\x00\n\x00\x00\b\x00\x004\x9d3?\x90K\x89\xc7t\n\x00\x00t\n\x00\x00\x0e\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd1\x02\x00\x00resources.arsc\x00\x00\x00",
+ "PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?\xff$\x18\xed3\x03\x00\x00\xb4\b\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00t\r\x00\x00AndroidManifest.xml",
+ "PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?\x14\xc5K\xab\x192\x02\x00\xc8\xcd\x04\x00\v\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe8\x10\x00\x00classes.dex",
+ "PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?E\x96\nD\xac\x01\x00\x00P\x03\x00\x00&\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00:C\x02\x00res/layout/actionbar_set_wallpaper.xml",
+ "PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?Ļ\x14\xe3\xd8\x01\x00\x00\xd8\x03\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00:E\x02\x00res/layout/wallpaper_cropper.xml",
+ "PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?}\xc1\x15\x9eZ\x01\x00\x00!\x02\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`G\x02\x00META-INF/MANIFEST.MF",
+ "PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?\xe6\x98Ьo\x01\x00\x00\x84\x02\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfcH\x02\x00META-INF/CERT.SF",
+ "PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?\xbfP\x96b\x86\x04\x00\x00\xb2\x06\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa9J\x02\x00META-INF/CERT.RSA",
+ }
+ for i, s := range dirEnts {
+ var f File
+ err := readDirectoryHeader(&f, strings.NewReader(s))
+ if err != nil {
+ t.Errorf("error reading #%d: %v", i, err)
+ }
+ }
+}
diff --git a/libgo/go/archive/zip/register.go b/libgo/go/archive/zip/register.go
index c046f081b7..4211ec7af7 100644
--- a/libgo/go/archive/zip/register.go
+++ b/libgo/go/archive/zip/register.go
@@ -6,6 +6,7 @@ package zip
import (
"compress/flate"
+ "errors"
"io"
"io/ioutil"
"sync"
@@ -21,12 +22,50 @@ type Compressor func(io.Writer) (io.WriteCloser, error)
// when they're finished reading.
type Decompressor func(io.Reader) io.ReadCloser
+var flateWriterPool sync.Pool
+
+func newFlateWriter(w io.Writer) io.WriteCloser {
+ fw, ok := flateWriterPool.Get().(*flate.Writer)
+ if ok {
+ fw.Reset(w)
+ } else {
+ fw, _ = flate.NewWriter(w, 5)
+ }
+ return &pooledFlateWriter{fw: fw}
+}
+
+type pooledFlateWriter struct {
+ mu sync.Mutex // guards Close and Write
+ fw *flate.Writer
+}
+
+func (w *pooledFlateWriter) Write(p []byte) (n int, err error) {
+ w.mu.Lock()
+ defer w.mu.Unlock()
+ if w.fw == nil {
+ return 0, errors.New("Write after Close")
+ }
+ return w.fw.Write(p)
+}
+
+func (w *pooledFlateWriter) Close() error {
+ w.mu.Lock()
+ defer w.mu.Unlock()
+ var err error
+ if w.fw != nil {
+ err = w.fw.Close()
+ flateWriterPool.Put(w.fw)
+ w.fw = nil
+ }
+ return err
+}
+
var (
mu sync.RWMutex // guards compressor and decompressor maps
compressors = map[uint16]Compressor{
Store: func(w io.Writer) (io.WriteCloser, error) { return &nopCloser{w}, nil },
- Deflate: func(w io.Writer) (io.WriteCloser, error) { return flate.NewWriter(w, 5) },
+ Deflate: func(w io.Writer) (io.WriteCloser, error) { return newFlateWriter(w), nil },
}
decompressors = map[uint16]Decompressor{
diff --git a/libgo/go/archive/zip/struct.go b/libgo/go/archive/zip/struct.go
index 65e5238c3b..cb28e83242 100644
--- a/libgo/go/archive/zip/struct.go
+++ b/libgo/go/archive/zip/struct.go
@@ -174,13 +174,13 @@ func timeToMsDosTime(t time.Time) (fDate uint16, fTime uint16) {
return
}
-// ModTime returns the modification time.
+// ModTime returns the modification time in UTC.
// The resolution is 2s.
func (h *FileHeader) ModTime() time.Time {
return msDosTimeToTime(h.ModifiedDate, h.ModifiedTime)
}
-// SetModTime sets the ModifiedTime and ModifiedDate fields to the given time.
+// SetModTime sets the ModifiedTime and ModifiedDate fields to the given time in UTC.
// The resolution is 2s.
func (h *FileHeader) SetModTime(t time.Time) {
h.ModifiedDate, h.ModifiedTime = timeToMsDosTime(t)
diff --git a/libgo/go/archive/zip/testdata/zip64-2.zip b/libgo/go/archive/zip/testdata/zip64-2.zip
new file mode 100644
index 0000000000..f844e35373
--- /dev/null
+++ b/libgo/go/archive/zip/testdata/zip64-2.zip
Binary files differ
diff --git a/libgo/go/archive/zip/writer.go b/libgo/go/archive/zip/writer.go
index 6c9800a78f..170beec0ee 100644
--- a/libgo/go/archive/zip/writer.go
+++ b/libgo/go/archive/zip/writer.go
@@ -34,6 +34,12 @@ func NewWriter(w io.Writer) *Writer {
return &Writer{cw: &countWriter{w: bufio.NewWriter(w)}}
}
+// Flush flushes any buffered data to the underlying writer.
+// Calling Flush is not normally necessary; calling Close is sufficient.
+func (w *Writer) Flush() error {
+ return w.cw.w.(*bufio.Writer).Flush()
+}
+
// Close finishes writing the zip file by writing the central directory.
// It does not (and can not) close the underlying writer.
func (w *Writer) Close() error {
diff --git a/libgo/go/archive/zip/writer_test.go b/libgo/go/archive/zip/writer_test.go
index 8b1c4dfd26..184a7d96a7 100644
--- a/libgo/go/archive/zip/writer_test.go
+++ b/libgo/go/archive/zip/writer_test.go
@@ -6,6 +6,7 @@ package zip
import (
"bytes"
+ "io"
"io/ioutil"
"math/rand"
"os"
@@ -86,6 +87,24 @@ func TestWriter(t *testing.T) {
}
}
+func TestWriterFlush(t *testing.T) {
+ var buf bytes.Buffer
+ w := NewWriter(struct{ io.Writer }{&buf})
+ _, err := w.Create("foo")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if buf.Len() > 0 {
+ t.Fatalf("Unexpected %d bytes already in buffer", buf.Len())
+ }
+ if err := w.Flush(); err != nil {
+ t.Fatal(err)
+ }
+ if buf.Len() == 0 {
+ t.Fatal("No bytes written after Flush")
+ }
+}
+
func testCreate(t *testing.T, w *Writer, wt *WriteTest) {
header := &FileHeader{
Name: wt.Name,
@@ -125,3 +144,21 @@ func testReadFile(t *testing.T, f *File, wt *WriteTest) {
t.Errorf("File contents %q, want %q", b, wt.Data)
}
}
+
+func BenchmarkCompressedZipGarbage(b *testing.B) {
+ b.ReportAllocs()
+ var buf bytes.Buffer
+ bigBuf := bytes.Repeat([]byte("a"), 1<<20)
+ for i := 0; i < b.N; i++ {
+ buf.Reset()
+ zw := NewWriter(&buf)
+ for j := 0; j < 3; j++ {
+ w, _ := zw.CreateHeader(&FileHeader{
+ Name: "foo",
+ Method: Deflate,
+ })
+ w.Write(bigBuf)
+ }
+ zw.Close()
+ }
+}
diff --git a/libgo/go/bufio/bufio.go b/libgo/go/bufio/bufio.go
index d1ff3c9edc..d3c68fe6fe 100644
--- a/libgo/go/bufio/bufio.go
+++ b/libgo/go/bufio/bufio.go
@@ -30,14 +30,15 @@ var (
// Reader implements buffering for an io.Reader object.
type Reader struct {
buf []byte
- rd io.Reader
- r, w int
+ rd io.Reader // reader provided by the client
+ r, w int // buf read and write positions
err error
lastByte int
lastRuneSize int
}
const minReadBufferSize = 16
+const maxConsecutiveEmptyReads = 100
// NewReaderSize returns a new Reader whose buffer has at least the specified
// size. If the argument io.Reader is already a Reader with large enough
@@ -87,15 +88,26 @@ func (b *Reader) fill() {
b.r = 0
}
- // Read new data.
- n, err := b.rd.Read(b.buf[b.w:])
- if n < 0 {
- panic(errNegativeRead)
+ if b.w >= len(b.buf) {
+ panic("bufio: tried to fill full buffer")
}
- b.w += n
- if err != nil {
- b.err = err
+
+ // Read new data: try a limited number of times.
+ for i := maxConsecutiveEmptyReads; i > 0; i-- {
+ n, err := b.rd.Read(b.buf[b.w:])
+ if n < 0 {
+ panic(errNegativeRead)
+ }
+ b.w += n
+ if err != nil {
+ b.err = err
+ return
+ }
+ if n > 0 {
+ return
+ }
}
+ b.err = io.ErrNoProgress
}
func (b *Reader) readErr() error {
@@ -115,21 +127,21 @@ func (b *Reader) Peek(n int) ([]byte, error) {
if n > len(b.buf) {
return nil, ErrBufferFull
}
+ // 0 <= n <= len(b.buf)
for b.w-b.r < n && b.err == nil {
- b.fill()
- }
- m := b.w - b.r
- if m > n {
- m = n
+ b.fill() // b.w-b.r < len(b.buf) => buffer is not full
}
+
var err error
- if m < n {
+ if avail := b.w - b.r; avail < n {
+ // not enough data in buffer
+ n = avail
err = b.readErr()
if err == nil {
err = ErrBufferFull
}
}
- return b.buf[b.r : b.r+m], err
+ return b.buf[b.r : b.r+n], err
}
// Read reads data into p.
@@ -142,7 +154,7 @@ func (b *Reader) Read(p []byte) (n int, err error) {
if n == 0 {
return 0, b.readErr()
}
- if b.w == b.r {
+ if b.r == b.w {
if b.err != nil {
return 0, b.readErr()
}
@@ -150,22 +162,23 @@ func (b *Reader) Read(p []byte) (n int, err error) {
// Large read, empty buffer.
// Read directly into p to avoid copy.
n, b.err = b.rd.Read(p)
+ if n < 0 {
+ panic(errNegativeRead)
+ }
if n > 0 {
b.lastByte = int(p[n-1])
b.lastRuneSize = -1
}
return n, b.readErr()
}
- b.fill()
- if b.w == b.r {
+ b.fill() // buffer is empty
+ if b.r == b.w {
return 0, b.readErr()
}
}
- if n > b.w-b.r {
- n = b.w - b.r
- }
- copy(p[0:n], b.buf[b.r:])
+ // copy as much as we can
+ n = copy(p, b.buf[b.r:b.w])
b.r += n
b.lastByte = int(b.buf[b.r-1])
b.lastRuneSize = -1
@@ -176,11 +189,11 @@ func (b *Reader) Read(p []byte) (n int, err error) {
// If no byte is available, returns an error.
func (b *Reader) ReadByte() (c byte, err error) {
b.lastRuneSize = -1
- for b.w == b.r {
+ for b.r == b.w {
if b.err != nil {
return 0, b.readErr()
}
- b.fill()
+ b.fill() // buffer is empty
}
c = b.buf[b.r]
b.r++
@@ -190,19 +203,19 @@ func (b *Reader) ReadByte() (c byte, err error) {
// UnreadByte unreads the last byte. Only the most recently read byte can be unread.
func (b *Reader) UnreadByte() error {
- b.lastRuneSize = -1
- if b.r == b.w && b.lastByte >= 0 {
- b.w = 1
- b.r = 0
- b.buf[0] = byte(b.lastByte)
- b.lastByte = -1
- return nil
- }
- if b.r <= 0 {
+ if b.lastByte < 0 || b.r == 0 && b.w > 0 {
return ErrInvalidUnreadByte
}
- b.r--
+ // b.r > 0 || b.w == 0
+ if b.r > 0 {
+ b.r--
+ } else {
+ // b.r == 0 && b.w == 0
+ b.w = 1
+ }
+ b.buf[b.r] = byte(b.lastByte)
b.lastByte = -1
+ b.lastRuneSize = -1
return nil
}
@@ -210,8 +223,8 @@ func (b *Reader) UnreadByte() error {
// rune and its size in bytes. If the encoded rune is invalid, it consumes one byte
// and returns unicode.ReplacementChar (U+FFFD) with a size of 1.
func (b *Reader) ReadRune() (r rune, size int, err error) {
- for b.r+utf8.UTFMax > b.w && !utf8.FullRune(b.buf[b.r:b.w]) && b.err == nil {
- b.fill()
+ for b.r+utf8.UTFMax > b.w && !utf8.FullRune(b.buf[b.r:b.w]) && b.err == nil && b.w-b.r < len(b.buf) {
+ b.fill() // b.w-b.r < len(buf) => buffer is not full
}
b.lastRuneSize = -1
if b.r == b.w {
@@ -232,7 +245,7 @@ func (b *Reader) ReadRune() (r rune, size int, err error) {
// regard it is stricter than UnreadByte, which will unread the last byte
// from any read operation.)
func (b *Reader) UnreadRune() error {
- if b.lastRuneSize < 0 || b.r == 0 {
+ if b.lastRuneSize < 0 || b.r < b.lastRuneSize {
return ErrInvalidUnreadRune
}
b.r -= b.lastRuneSize
@@ -255,37 +268,40 @@ func (b *Reader) Buffered() int { return b.w - b.r }
// ReadBytes or ReadString instead.
// ReadSlice returns err != nil if and only if line does not end in delim.
func (b *Reader) ReadSlice(delim byte) (line []byte, err error) {
- // Look in buffer.
- if i := bytes.IndexByte(b.buf[b.r:b.w], delim); i >= 0 {
- line1 := b.buf[b.r : b.r+i+1]
- b.r += i + 1
- return line1, nil
- }
-
- // Read more into buffer, until buffer fills or we find delim.
for {
- if b.err != nil {
- line := b.buf[b.r:b.w]
- b.r = b.w
- return line, b.readErr()
+ // Search buffer.
+ if i := bytes.IndexByte(b.buf[b.r:b.w], delim); i >= 0 {
+ line = b.buf[b.r : b.r+i+1]
+ b.r += i + 1
+ break
}
- n := b.Buffered()
- b.fill()
-
- // Search new part of buffer
- if i := bytes.IndexByte(b.buf[n:b.w], delim); i >= 0 {
- line := b.buf[0 : n+i+1]
- b.r = n + i + 1
- return line, nil
+ // Pending error?
+ if b.err != nil {
+ line = b.buf[b.r:b.w]
+ b.r = b.w
+ err = b.readErr()
+ break
}
- // Buffer is full?
+ // Buffer full?
if b.Buffered() >= len(b.buf) {
b.r = b.w
- return b.buf, ErrBufferFull
+ line = b.buf
+ err = ErrBufferFull
+ break
}
+
+ b.fill() // buffer is not full
+ }
+
+ // Handle last byte, if any.
+ if i := len(line) - 1; i >= 0 {
+ b.lastByte = int(line[i])
+ b.lastRuneSize = -1
}
+
+ return
}
// ReadLine is a low-level line-reading primitive. Most callers should use
@@ -301,6 +317,9 @@ func (b *Reader) ReadSlice(delim byte) (line []byte, err error) {
//
// The text returned from ReadLine does not include the line end ("\r\n" or "\n").
// No indication or error is given if the input ends without a final line end.
+// Calling UnreadByte after ReadLine will always unread the last byte read
+// (possibly a character belonging to the line end) even if that byte is not
+// part of the line returned by ReadLine.
func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error) {
line, err = b.ReadSlice('\n')
if err == ErrBufferFull {
@@ -410,12 +429,24 @@ func (b *Reader) WriteTo(w io.Writer) (n int64, err error) {
return n, err
}
- for b.fill(); b.r < b.w; b.fill() {
+ if w, ok := w.(io.ReaderFrom); ok {
+ m, err := w.ReadFrom(b.rd)
+ n += m
+ return n, err
+ }
+
+ if b.w-b.r < len(b.buf) {
+ b.fill() // buffer not full
+ }
+
+ for b.r < b.w {
+ // b.r < b.w => buffer is not empty
m, err := b.writeBuf(w)
n += m
if err != nil {
return n, err
}
+ b.fill() // buffer is empty
}
if b.err == io.EOF {
@@ -425,9 +456,14 @@ func (b *Reader) WriteTo(w io.Writer) (n int64, err error) {
return n, b.readErr()
}
+var errNegativeWrite = errors.New("bufio: writer returned negative count from Write")
+
// writeBuf writes the Reader's buffer to the writer.
func (b *Reader) writeBuf(w io.Writer) (int64, error) {
n, err := w.Write(b.buf[b.r:b.w])
+ if n < 0 {
+ panic(errNegativeWrite)
+ }
b.r += n
return int64(n), err
}
@@ -619,9 +655,16 @@ func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) {
return n, err1
}
}
- m, err = r.Read(b.buf[b.n:])
- if m == 0 {
- break
+ nr := 0
+ for nr < maxConsecutiveEmptyReads {
+ m, err = r.Read(b.buf[b.n:])
+ if m != 0 || err != nil {
+ break
+ }
+ nr++
+ }
+ if nr == maxConsecutiveEmptyReads {
+ return n, io.ErrNoProgress
}
b.n += m
n += int64(m)
diff --git a/libgo/go/bufio/bufio_test.go b/libgo/go/bufio/bufio_test.go
index 41bd3d4563..550dac9173 100644
--- a/libgo/go/bufio/bufio_test.go
+++ b/libgo/go/bufio/bufio_test.go
@@ -14,6 +14,7 @@ import (
"strings"
"testing"
"testing/iotest"
+ "time"
"unicode/utf8"
)
@@ -30,9 +31,6 @@ func newRot13Reader(r io.Reader) *rot13Reader {
func (r13 *rot13Reader) Read(p []byte) (int, error) {
n, err := r13.r.Read(p)
- if err != nil {
- return n, err
- }
for i := 0; i < n; i++ {
c := p[i] | 0x20 // lowercase byte
if 'a' <= c && c <= 'm' {
@@ -41,7 +39,7 @@ func (r13 *rot13Reader) Read(p []byte) (int, error) {
p[i] -= 13
}
}
- return n, nil
+ return n, err
}
// Call ReadByte to accumulate the text of a file
@@ -65,12 +63,12 @@ func readBytes(buf *Reader) string {
func TestReaderSimple(t *testing.T) {
data := "hello world"
- b := NewReader(bytes.NewBufferString(data))
+ b := NewReader(strings.NewReader(data))
if s := readBytes(b); s != "hello world" {
t.Errorf("simple hello world test failed: got %q", s)
}
- b = NewReader(newRot13Reader(bytes.NewBufferString(data)))
+ b = NewReader(newRot13Reader(strings.NewReader(data)))
if s := readBytes(b); s != "uryyb jbeyq" {
t.Errorf("rot13 hello world test failed: got %q", s)
}
@@ -139,7 +137,7 @@ var bufreaders = []bufReader{
const minReadBufferSize = 16
var bufsizes = []int{
- minReadBufferSize, 23, 32, 46, 64, 93, 128, 1024, 4096,
+ 0, minReadBufferSize, 23, 32, 46, 64, 93, 128, 1024, 4096,
}
func TestReader(t *testing.T) {
@@ -161,7 +159,7 @@ func TestReader(t *testing.T) {
readmaker := readMakers[i]
bufreader := bufreaders[j]
bufsize := bufsizes[k]
- read := readmaker.fn(bytes.NewBufferString(text))
+ read := readmaker.fn(strings.NewReader(text))
buf := NewReaderSize(read, bufsize)
s := bufreader.fn(buf)
if s != text {
@@ -174,6 +172,34 @@ func TestReader(t *testing.T) {
}
}
+type zeroReader struct{}
+
+func (zeroReader) Read(p []byte) (int, error) {
+ return 0, nil
+}
+
+func TestZeroReader(t *testing.T) {
+ var z zeroReader
+ r := NewReader(z)
+
+ c := make(chan error)
+ go func() {
+ _, err := r.ReadByte()
+ c <- err
+ }()
+
+ select {
+ case err := <-c:
+ if err == nil {
+ t.Error("error expected")
+ } else if err != io.ErrNoProgress {
+ t.Error("unexpected error:", err)
+ }
+ case <-time.After(time.Second):
+ t.Error("test timed out (endless loop in ReadByte?)")
+ }
+}
+
// A StringReader delivers its data one string segment at a time via Read.
type StringReader struct {
data []string
@@ -228,34 +254,150 @@ func TestReadRune(t *testing.T) {
}
func TestUnreadRune(t *testing.T) {
- got := ""
segments := []string{"Hello, world:", "日本語"}
- data := strings.Join(segments, "")
r := NewReader(&StringReader{data: segments})
+ got := ""
+ want := strings.Join(segments, "")
// Normal execution.
for {
r1, _, err := r.ReadRune()
if err != nil {
if err != io.EOF {
- t.Error("unexpected EOF")
+ t.Error("unexpected error on ReadRune:", err)
}
break
}
got += string(r1)
- // Put it back and read it again
+ // Put it back and read it again.
if err = r.UnreadRune(); err != nil {
- t.Error("unexpected error on UnreadRune:", err)
+ t.Fatal("unexpected error on UnreadRune:", err)
}
r2, _, err := r.ReadRune()
if err != nil {
- t.Error("unexpected error reading after unreading:", err)
+ t.Fatal("unexpected error reading after unreading:", err)
}
if r1 != r2 {
- t.Errorf("incorrect rune after unread: got %c wanted %c", r1, r2)
+ t.Fatalf("incorrect rune after unread: got %c, want %c", r1, r2)
}
}
- if got != data {
- t.Errorf("want=%q got=%q", data, got)
+ if got != want {
+ t.Errorf("got %q, want %q", got, want)
+ }
+}
+
+func TestUnreadByte(t *testing.T) {
+ segments := []string{"Hello, ", "world"}
+ r := NewReader(&StringReader{data: segments})
+ got := ""
+ want := strings.Join(segments, "")
+ // Normal execution.
+ for {
+ b1, err := r.ReadByte()
+ if err != nil {
+ if err != io.EOF {
+ t.Error("unexpected error on ReadByte:", err)
+ }
+ break
+ }
+ got += string(b1)
+ // Put it back and read it again.
+ if err = r.UnreadByte(); err != nil {
+ t.Fatal("unexpected error on UnreadByte:", err)
+ }
+ b2, err := r.ReadByte()
+ if err != nil {
+ t.Fatal("unexpected error reading after unreading:", err)
+ }
+ if b1 != b2 {
+ t.Fatalf("incorrect byte after unread: got %q, want %q", b1, b2)
+ }
+ }
+ if got != want {
+ t.Errorf("got %q, want %q", got, want)
+ }
+}
+
+func TestUnreadByteMultiple(t *testing.T) {
+ segments := []string{"Hello, ", "world"}
+ data := strings.Join(segments, "")
+ for n := 0; n <= len(data); n++ {
+ r := NewReader(&StringReader{data: segments})
+ // Read n bytes.
+ for i := 0; i < n; i++ {
+ b, err := r.ReadByte()
+ if err != nil {
+ t.Fatalf("n = %d: unexpected error on ReadByte: %v", n, err)
+ }
+ if b != data[i] {
+ t.Fatalf("n = %d: incorrect byte returned from ReadByte: got %q, want %q", n, b, data[i])
+ }
+ }
+ // Unread one byte if there is one.
+ if n > 0 {
+ if err := r.UnreadByte(); err != nil {
+ t.Errorf("n = %d: unexpected error on UnreadByte: %v", n, err)
+ }
+ }
+ // Test that we cannot unread any further.
+ if err := r.UnreadByte(); err == nil {
+ t.Errorf("n = %d: expected error on UnreadByte", n)
+ }
+ }
+}
+
+func TestUnreadByteOthers(t *testing.T) {
+ // A list of readers to use in conjunction with UnreadByte.
+ var readers = []func(*Reader, byte) ([]byte, error){
+ (*Reader).ReadBytes,
+ (*Reader).ReadSlice,
+ func(r *Reader, delim byte) ([]byte, error) {
+ data, err := r.ReadString(delim)
+ return []byte(data), err
+ },
+ // ReadLine doesn't fit the data/pattern easily
+ // so we leave it out. It should be covered via
+ // the ReadSlice test since ReadLine simply calls
+ // ReadSlice, and it's that function that handles
+ // the last byte.
+ }
+
+ // Try all readers with UnreadByte.
+ for rno, read := range readers {
+ // Some input data that is longer than the minimum reader buffer size.
+ const n = 10
+ var buf bytes.Buffer
+ for i := 0; i < n; i++ {
+ buf.WriteString("abcdefg")
+ }
+
+ r := NewReaderSize(&buf, minReadBufferSize)
+ readTo := func(delim byte, want string) {
+ data, err := read(r, delim)
+ if err != nil {
+ t.Fatalf("#%d: unexpected error reading to %c: %v", rno, delim, err)
+ }
+ if got := string(data); got != want {
+ t.Fatalf("#%d: got %q, want %q", rno, got, want)
+ }
+ }
+
+ // Read the data with occasional UnreadByte calls.
+ for i := 0; i < n; i++ {
+ readTo('d', "abcd")
+ for j := 0; j < 3; j++ {
+ if err := r.UnreadByte(); err != nil {
+ t.Fatalf("#%d: unexpected error on UnreadByte: %v", rno, err)
+ }
+ readTo('d', "d")
+ }
+ readTo('g', "efg")
+ }
+
+ // All data should have been read.
+ _, err := r.ReadByte()
+ if err != io.EOF {
+ t.Errorf("#%d: got error %v; want EOF", rno, err)
+ }
}
}
@@ -293,7 +435,7 @@ func TestUnreadRuneError(t *testing.T) {
if err != nil {
t.Error("unexpected error on ReadRune (2):", err)
}
- for _ = range buf {
+ for range buf {
_, err = r.ReadByte()
if err != nil {
t.Error("unexpected error on ReadByte (2):", err)
@@ -318,6 +460,18 @@ func TestUnreadRuneError(t *testing.T) {
if r.UnreadRune() == nil {
t.Error("expected error after UnreadByte (3)")
}
+ // Test error after ReadSlice.
+ _, _, err = r.ReadRune() // reset state
+ if err != nil {
+ t.Error("unexpected error on ReadRune (4):", err)
+ }
+ _, err = r.ReadSlice(0)
+ if err != io.EOF {
+ t.Error("unexpected error on ReadSlice (4):", err)
+ }
+ if r.UnreadRune() == nil {
+ t.Error("expected error after ReadSlice (4)")
+ }
}
func TestUnreadRuneAtEOF(t *testing.T) {
@@ -447,7 +601,7 @@ func TestWriteErrors(t *testing.T) {
func TestNewReaderSizeIdempotent(t *testing.T) {
const BufSize = 1000
- b := NewReaderSize(bytes.NewBufferString("hello world"), BufSize)
+ b := NewReaderSize(strings.NewReader("hello world"), BufSize)
// Does it recognize itself?
b1 := NewReaderSize(b, BufSize)
if b1 != b {
@@ -516,6 +670,9 @@ func TestPeek(t *testing.T) {
if s, err := buf.Peek(4); string(s) != "abcd" || err != nil {
t.Fatalf("want %q got %q, err=%v", "abcd", string(s), err)
}
+ if _, err := buf.Peek(-1); err != ErrNegativeCount {
+ t.Fatalf("want ErrNegativeCount got %v", err)
+ }
if _, err := buf.Peek(32); err != ErrBufferFull {
t.Fatalf("want ErrBufFull got %v", err)
}
@@ -642,7 +799,7 @@ func TestLineTooLong(t *testing.T) {
for i := 0; i < minReadBufferSize*5/2; i++ {
data = append(data, '0'+byte(i%10))
}
- buf := bytes.NewBuffer(data)
+ buf := bytes.NewReader(data)
l := NewReaderSize(buf, minReadBufferSize)
line, isPrefix, err := l.ReadLine()
if !isPrefix || !bytes.Equal(line, data[:minReadBufferSize]) || err != nil {
@@ -667,7 +824,7 @@ func TestLineTooLong(t *testing.T) {
func TestReadAfterLines(t *testing.T) {
line1 := "this is line1"
restData := "this is line2\nthis is line 3\n"
- inbuf := bytes.NewBuffer([]byte(line1 + "\n" + restData))
+ inbuf := bytes.NewReader([]byte(line1 + "\n" + restData))
outbuf := new(bytes.Buffer)
maxLineLength := len(line1) + len(restData)/2
l := NewReaderSize(inbuf, maxLineLength)
@@ -693,7 +850,7 @@ func TestReadEmptyBuffer(t *testing.T) {
}
func TestLinesAfterRead(t *testing.T) {
- l := NewReaderSize(bytes.NewBuffer([]byte("foo")), minReadBufferSize)
+ l := NewReaderSize(bytes.NewReader([]byte("foo")), minReadBufferSize)
_, err := ioutil.ReadAll(l)
if err != nil {
t.Error(err)
@@ -783,7 +940,7 @@ func createTestInput(n int) []byte {
func TestReaderWriteTo(t *testing.T) {
input := createTestInput(8192)
- r := NewReader(onlyReader{bytes.NewBuffer(input)})
+ r := NewReader(onlyReader{bytes.NewReader(input)})
w := new(bytes.Buffer)
if n, err := r.WriteTo(w); err != nil || n != int64(len(input)) {
t.Fatalf("r.WriteTo(w) = %d, %v, want %d, nil", n, err, len(input))
@@ -842,7 +999,7 @@ func TestWriterReadFrom(t *testing.T) {
input := createTestInput(8192)
b := new(bytes.Buffer)
w := NewWriter(wfunc(b))
- r := rfunc(bytes.NewBuffer(input))
+ r := rfunc(bytes.NewReader(input))
if n, err := w.ReadFrom(r); err != nil || n != int64(len(input)) {
t.Errorf("ws[%d],rs[%d]: w.ReadFrom(r) = %d, %v, want %d, nil", wi, ri, n, err, len(input))
continue
@@ -1021,7 +1178,61 @@ func TestWriterReadFromWhileFull(t *testing.T) {
// Use ReadFrom to read in some data.
n2, err := w.ReadFrom(strings.NewReader("abcdef"))
if n2 != 6 || err != nil {
- t.Fatalf("ReadFrom returned (%v, %v), want (6, nil)", n, err)
+ t.Fatalf("ReadFrom returned (%v, %v), want (6, nil)", n2, err)
+ }
+}
+
+type emptyThenNonEmptyReader struct {
+ r io.Reader
+ n int
+}
+
+func (r *emptyThenNonEmptyReader) Read(p []byte) (int, error) {
+ if r.n <= 0 {
+ return r.r.Read(p)
+ }
+ r.n--
+ return 0, nil
+}
+
+// Test for golang.org/issue/7611
+func TestWriterReadFromUntilEOF(t *testing.T) {
+ buf := new(bytes.Buffer)
+ w := NewWriterSize(buf, 5)
+
+ // Partially fill buffer
+ n, err := w.Write([]byte("0123"))
+ if n != 4 || err != nil {
+ t.Fatalf("Write returned (%v, %v), want (4, nil)", n, err)
+ }
+
+ // Use ReadFrom to read in some data.
+ r := &emptyThenNonEmptyReader{r: strings.NewReader("abcd"), n: 3}
+ n2, err := w.ReadFrom(r)
+ if n2 != 4 || err != nil {
+ t.Fatalf("ReadFrom returned (%v, %v), want (4, nil)", n2, err)
+ }
+ w.Flush()
+ if got, want := string(buf.Bytes()), "0123abcd"; got != want {
+ t.Fatalf("buf.Bytes() returned %q, want %q", got, want)
+ }
+}
+
+func TestWriterReadFromErrNoProgress(t *testing.T) {
+ buf := new(bytes.Buffer)
+ w := NewWriterSize(buf, 5)
+
+ // Partially fill buffer
+ n, err := w.Write([]byte("0123"))
+ if n != 4 || err != nil {
+ t.Fatalf("Write returned (%v, %v), want (4, nil)", n, err)
+ }
+
+ // Use ReadFrom to read in some data.
+ r := &emptyThenNonEmptyReader{r: strings.NewReader("abcd"), n: 100}
+ n2, err := w.ReadFrom(r)
+ if n2 != 0 || err != io.ErrNoProgress {
+ t.Fatalf("buf.Bytes() returned (%v, %v), want (0, io.ErrNoProgress)", n2, err)
}
}
@@ -1059,81 +1270,114 @@ func TestWriterReset(t *testing.T) {
// An onlyReader only implements io.Reader, no matter what other methods the underlying implementation may have.
type onlyReader struct {
- r io.Reader
-}
-
-func (r onlyReader) Read(b []byte) (int, error) {
- return r.r.Read(b)
+ io.Reader
}
// An onlyWriter only implements io.Writer, no matter what other methods the underlying implementation may have.
type onlyWriter struct {
- w io.Writer
-}
-
-func (w onlyWriter) Write(b []byte) (int, error) {
- return w.w.Write(b)
+ io.Writer
}
func BenchmarkReaderCopyOptimal(b *testing.B) {
// Optimal case is where the underlying reader implements io.WriterTo
+ srcBuf := bytes.NewBuffer(make([]byte, 8192))
+ src := NewReader(srcBuf)
+ dstBuf := new(bytes.Buffer)
+ dst := onlyWriter{dstBuf}
for i := 0; i < b.N; i++ {
- b.StopTimer()
- src := NewReader(bytes.NewBuffer(make([]byte, 8192)))
- dst := onlyWriter{new(bytes.Buffer)}
- b.StartTimer()
+ srcBuf.Reset()
+ src.Reset(srcBuf)
+ dstBuf.Reset()
io.Copy(dst, src)
}
}
func BenchmarkReaderCopyUnoptimal(b *testing.B) {
// Unoptimal case is where the underlying reader doesn't implement io.WriterTo
+ srcBuf := bytes.NewBuffer(make([]byte, 8192))
+ src := NewReader(onlyReader{srcBuf})
+ dstBuf := new(bytes.Buffer)
+ dst := onlyWriter{dstBuf}
for i := 0; i < b.N; i++ {
- b.StopTimer()
- src := NewReader(onlyReader{bytes.NewBuffer(make([]byte, 8192))})
- dst := onlyWriter{new(bytes.Buffer)}
- b.StartTimer()
+ srcBuf.Reset()
+ src.Reset(onlyReader{srcBuf})
+ dstBuf.Reset()
io.Copy(dst, src)
}
}
func BenchmarkReaderCopyNoWriteTo(b *testing.B) {
+ srcBuf := bytes.NewBuffer(make([]byte, 8192))
+ srcReader := NewReader(srcBuf)
+ src := onlyReader{srcReader}
+ dstBuf := new(bytes.Buffer)
+ dst := onlyWriter{dstBuf}
for i := 0; i < b.N; i++ {
- b.StopTimer()
- src := onlyReader{NewReader(bytes.NewBuffer(make([]byte, 8192)))}
- dst := onlyWriter{new(bytes.Buffer)}
- b.StartTimer()
+ srcBuf.Reset()
+ srcReader.Reset(srcBuf)
+ dstBuf.Reset()
io.Copy(dst, src)
}
}
+func BenchmarkReaderWriteToOptimal(b *testing.B) {
+ const bufSize = 16 << 10
+ buf := make([]byte, bufSize)
+ r := bytes.NewReader(buf)
+ srcReader := NewReaderSize(onlyReader{r}, 1<<10)
+ if _, ok := ioutil.Discard.(io.ReaderFrom); !ok {
+ b.Fatal("ioutil.Discard doesn't support ReaderFrom")
+ }
+ for i := 0; i < b.N; i++ {
+ r.Seek(0, 0)
+ srcReader.Reset(onlyReader{r})
+ n, err := srcReader.WriteTo(ioutil.Discard)
+ if err != nil {
+ b.Fatal(err)
+ }
+ if n != bufSize {
+ b.Fatalf("n = %d; want %d", n, bufSize)
+ }
+ }
+}
+
func BenchmarkWriterCopyOptimal(b *testing.B) {
// Optimal case is where the underlying writer implements io.ReaderFrom
+ srcBuf := bytes.NewBuffer(make([]byte, 8192))
+ src := onlyReader{srcBuf}
+ dstBuf := new(bytes.Buffer)
+ dst := NewWriter(dstBuf)
for i := 0; i < b.N; i++ {
- b.StopTimer()
- src := onlyReader{bytes.NewBuffer(make([]byte, 8192))}
- dst := NewWriter(new(bytes.Buffer))
- b.StartTimer()
+ srcBuf.Reset()
+ dstBuf.Reset()
+ dst.Reset(dstBuf)
io.Copy(dst, src)
}
}
func BenchmarkWriterCopyUnoptimal(b *testing.B) {
+ srcBuf := bytes.NewBuffer(make([]byte, 8192))
+ src := onlyReader{srcBuf}
+ dstBuf := new(bytes.Buffer)
+ dst := NewWriter(onlyWriter{dstBuf})
for i := 0; i < b.N; i++ {
- b.StopTimer()
- src := onlyReader{bytes.NewBuffer(make([]byte, 8192))}
- dst := NewWriter(onlyWriter{new(bytes.Buffer)})
- b.StartTimer()
+ srcBuf.Reset()
+ dstBuf.Reset()
+ dst.Reset(onlyWriter{dstBuf})
io.Copy(dst, src)
}
}
func BenchmarkWriterCopyNoReadFrom(b *testing.B) {
+ srcBuf := bytes.NewBuffer(make([]byte, 8192))
+ src := onlyReader{srcBuf}
+ dstBuf := new(bytes.Buffer)
+ dstWriter := NewWriter(dstBuf)
+ dst := onlyWriter{dstWriter}
for i := 0; i < b.N; i++ {
- b.StopTimer()
- src := onlyReader{bytes.NewBuffer(make([]byte, 8192))}
- dst := onlyWriter{NewWriter(new(bytes.Buffer))}
- b.StartTimer()
+ srcBuf.Reset()
+ dstBuf.Reset()
+ dstWriter.Reset(dstBuf)
io.Copy(dst, src)
}
}
diff --git a/libgo/go/bufio/scan.go b/libgo/go/bufio/scan.go
index 423505fbcb..364d159613 100644
--- a/libgo/go/bufio/scan.go
+++ b/libgo/go/bufio/scan.go
@@ -36,6 +36,7 @@ type Scanner struct {
start int // First non-processed byte in buf.
end int // End of data in buf.
err error // Sticky error.
+ empties int // Count of successive empty tokens.
}
// SplitFunc is the signature of the split function used to tokenize the
@@ -64,8 +65,9 @@ var (
)
const (
- // Maximum size used to buffer a token. The actual maximum token size
- // may be smaller as the buffer may need to include, for instance, a newline.
+ // MaxScanTokenSize is the maximum size used to buffer a token.
+ // The actual maximum token size may be smaller as the buffer
+ // may need to include, for instance, a newline.
MaxScanTokenSize = 64 * 1024
)
@@ -107,11 +109,15 @@ 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
+// advancing the input. This is a common error mode for scanners.
func (s *Scanner) Scan() bool {
// Loop until we have a token.
for {
// See if we can get a token with what we already have.
- if s.end > s.start {
+ // If we've run out of data but have an error, give the split function
+ // a chance to recover any remaining, possibly empty token.
+ if s.end > s.start || s.err != nil {
advance, token, err := s.split(s.buf[s.start:s.end], s.err != nil)
if err != nil {
s.setErr(err)
@@ -122,6 +128,15 @@ func (s *Scanner) Scan() bool {
}
s.token = token
if token != nil {
+ if s.err == nil || advance > 0 {
+ s.empties = 0
+ } else {
+ // Returning tokens not advancing input at EOF.
+ s.empties++
+ if s.empties > 100 {
+ panic("bufio.Scan: 100 empty tokens without progressing")
+ }
+ }
return true
}
}
@@ -135,7 +150,7 @@ func (s *Scanner) Scan() bool {
}
// Must read more data.
// First, shift data to beginning of buffer if there's lots of empty space
- // or space is neded.
+ // or space is needed.
if s.start > 0 && (s.end == len(s.buf) || s.start > len(s.buf)/2) {
copy(s.buf, s.buf[s.start:s.end])
s.end -= s.start
@@ -169,10 +184,11 @@ func (s *Scanner) Scan() bool {
break
}
if n > 0 {
+ s.empties = 0
break
}
loop++
- if loop > 100 {
+ if loop > maxConsecutiveEmptyReads {
s.setErr(io.ErrNoProgress)
break
}
@@ -306,7 +322,7 @@ func isSpace(r rune) bool {
return true
}
switch r {
- case '\u1680', '\u180e', '\u2028', '\u2029', '\u202f', '\u205f', '\u3000':
+ case '\u1680', '\u2028', '\u2029', '\u202f', '\u205f', '\u3000':
return true
}
return false
@@ -326,9 +342,6 @@ func ScanWords(data []byte, atEOF bool) (advance int, token []byte, err error) {
break
}
}
- if atEOF && len(data) == 0 {
- return 0, nil, nil
- }
// Scan until space, marking end of word.
for width, i := 0, start; i < len(data); i += width {
var r rune
@@ -342,5 +355,5 @@ func ScanWords(data []byte, atEOF bool) (advance int, token []byte, err error) {
return len(data), data[start:], nil
}
// Request more data.
- return 0, nil, nil
+ return start, nil, nil
}
diff --git a/libgo/go/bufio/scan_test.go b/libgo/go/bufio/scan_test.go
index c1483b2685..eea87cbf7b 100644
--- a/libgo/go/bufio/scan_test.go
+++ b/libgo/go/bufio/scan_test.go
@@ -15,6 +15,8 @@ import (
"unicode/utf8"
)
+const smallMaxTokenSize = 256 // Much smaller for more efficient testing.
+
// Test white space table matches the Unicode definition.
func TestSpace(t *testing.T) {
for r := rune(0); r <= utf8.MaxRune; r++ {
@@ -38,7 +40,7 @@ var scanTests = []string{
func TestScanByte(t *testing.T) {
for n, test := range scanTests {
- buf := bytes.NewBufferString(test)
+ buf := strings.NewReader(test)
s := NewScanner(buf)
s.Split(ScanBytes)
var i int
@@ -60,7 +62,7 @@ func TestScanByte(t *testing.T) {
// Test that the rune splitter returns same sequence of runes (not bytes) as for range string.
func TestScanRune(t *testing.T) {
for n, test := range scanTests {
- buf := bytes.NewBufferString(test)
+ buf := strings.NewReader(test)
s := NewScanner(buf)
s.Split(ScanRunes)
var i, runeCount int
@@ -104,7 +106,7 @@ var wordScanTests = []string{
// Test that the word splitter returns the same data as strings.Fields.
func TestScanWords(t *testing.T) {
for n, test := range wordScanTests {
- buf := bytes.NewBufferString(test)
+ buf := strings.NewReader(test)
s := NewScanner(buf)
s.Split(ScanWords)
words := strings.Fields(test)
@@ -135,7 +137,7 @@ func TestScanWords(t *testing.T) {
// reads in Scanner.Scan.
type slowReader struct {
max int
- buf *bytes.Buffer
+ buf io.Reader
}
func (sr *slowReader) Read(p []byte) (n int, err error) {
@@ -172,7 +174,6 @@ func genLine(buf *bytes.Buffer, lineNum, n int, addNewline bool) {
// Test the line splitter, including some carriage returns but no long lines.
func TestScanLongLines(t *testing.T) {
- const smallMaxTokenSize = 256 // Much smaller for more efficient testing.
// Build a buffer of lots of line lengths up to but not exceeding smallMaxTokenSize.
tmp := new(bytes.Buffer)
buf := new(bytes.Buffer)
@@ -248,7 +249,7 @@ func TestScanLineTooLong(t *testing.T) {
// Test that the line splitter handles a final line without a newline.
func testNoNewline(text string, lines []string, t *testing.T) {
- buf := bytes.NewBufferString(text)
+ buf := strings.NewReader(text)
s := NewScanner(&slowReader{7, buf})
s.Split(ScanLines)
for lineNum := 0; s.Scan(); lineNum++ {
@@ -277,7 +278,7 @@ func TestScanLineNoNewline(t *testing.T) {
testNoNewline(text, lines, t)
}
-// Test that the line splitter handles a final line with a carriage return but nonewline.
+// Test that the line splitter handles a final line with a carriage return but no newline.
func TestScanLineReturnButNoNewline(t *testing.T) {
const text = "abcdefghijklmn\nopqrstuvwxyz\r"
lines := []string{
@@ -328,7 +329,7 @@ func TestSplitError(t *testing.T) {
}
// Read the data.
const text = "abcdefghijklmnopqrstuvwxyz"
- buf := bytes.NewBufferString(text)
+ buf := strings.NewReader(text)
s := NewScanner(&slowReader{1, buf})
s.Split(errorSplit)
var i int
@@ -404,3 +405,120 @@ func TestBadReader(t *testing.T) {
t.Errorf("unexpected error: %v", err)
}
}
+
+func TestScanWordsExcessiveWhiteSpace(t *testing.T) {
+ const word = "ipsum"
+ s := strings.Repeat(" ", 4*smallMaxTokenSize) + word
+ scanner := NewScanner(strings.NewReader(s))
+ scanner.MaxTokenSize(smallMaxTokenSize)
+ scanner.Split(ScanWords)
+ if !scanner.Scan() {
+ t.Fatalf("scan failed: %v", scanner.Err())
+ }
+ if token := scanner.Text(); token != word {
+ t.Fatalf("unexpected token: %v", token)
+ }
+}
+
+// Test that empty tokens, including at end of line or end of file, are found by the scanner.
+// Issue 8672: Could miss final empty token.
+
+func commaSplit(data []byte, atEOF bool) (advance int, token []byte, err error) {
+ for i := 0; i < len(data); i++ {
+ if data[i] == ',' {
+ return i + 1, data[:i], nil
+ }
+ }
+ if !atEOF {
+ return 0, nil, nil
+ }
+ return 0, data, nil
+}
+
+func TestEmptyTokens(t *testing.T) {
+ s := NewScanner(strings.NewReader("1,2,3,"))
+ values := []string{"1", "2", "3", ""}
+ s.Split(commaSplit)
+ var i int
+ for i = 0; i < len(values); i++ {
+ if !s.Scan() {
+ break
+ }
+ if s.Text() != values[i] {
+ t.Errorf("%d: expected %q got %q", i, values[i], s.Text())
+ }
+ }
+ if i != len(values) {
+ t.Errorf("got %d fields, expected %d", i, len(values))
+ }
+ if err := s.Err(); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func loopAtEOFSplit(data []byte, atEOF bool) (advance int, token []byte, err error) {
+ if len(data) > 0 {
+ return 1, data[:1], nil
+ }
+ return 0, data, nil
+}
+
+func TestDontLoopForever(t *testing.T) {
+ s := NewScanner(strings.NewReader("abc"))
+ s.Split(loopAtEOFSplit)
+ // Expect a panic
+ defer func() {
+ err := recover()
+ if err == nil {
+ t.Fatal("should have panicked")
+ }
+ if msg, ok := err.(string); !ok || !strings.Contains(msg, "empty tokens") {
+ panic(err)
+ }
+ }()
+ for count := 0; s.Scan(); count++ {
+ if count > 1000 {
+ t.Fatal("looping")
+ }
+ }
+ if s.Err() != nil {
+ t.Fatal("after scan:", s.Err())
+ }
+}
+
+func TestBlankLines(t *testing.T) {
+ s := NewScanner(strings.NewReader(strings.Repeat("\n", 1000)))
+ for count := 0; s.Scan(); count++ {
+ if count > 2000 {
+ t.Fatal("looping")
+ }
+ }
+ if s.Err() != nil {
+ t.Fatal("after scan:", s.Err())
+ }
+}
+
+type countdown int
+
+func (c *countdown) split(data []byte, atEOF bool) (advance int, token []byte, err error) {
+ if *c > 0 {
+ *c--
+ return 1, data[:1], nil
+ }
+ return 0, nil, nil
+}
+
+// Check that the looping-at-EOF check doesn't trigger for merely empty tokens.
+func TestEmptyLinesOK(t *testing.T) {
+ c := countdown(10000)
+ s := NewScanner(strings.NewReader(strings.Repeat("\n", 10000)))
+ s.Split(c.split)
+ for s.Scan() {
+ }
+ if s.Err() != nil {
+ t.Fatal("after scan:", s.Err())
+ }
+ if c != 0 {
+ t.Fatalf("stopped with %d left to process", c)
+ }
+}
diff --git a/libgo/go/bytes/bytes.go b/libgo/go/bytes/bytes.go
index 01a5d9ae4e..7634707b3c 100644
--- a/libgo/go/bytes/bytes.go
+++ b/libgo/go/bytes/bytes.go
@@ -265,8 +265,10 @@ func Fields(s []byte) [][]byte {
// FieldsFunc interprets s as a sequence of UTF-8-encoded Unicode code points.
// It splits the slice s at each run of code points c satisfying f(c) and
-// returns a slice of subslices of s. If no code points in s satisfy f(c), an
-// empty slice is returned.
+// returns a slice of subslices of s. If all code points in s satisfy f(c), or
+// len(s) == 0, an empty slice is returned.
+// FieldsFunc makes no guarantees about the order in which it calls f(c).
+// If f does not return consistent results for a given c, FieldsFunc may crash.
func FieldsFunc(s []byte, f func(rune) bool) [][]byte {
n := 0
inField := false
@@ -356,7 +358,11 @@ func Map(mapping func(r rune) rune, s []byte) []byte {
}
r = mapping(r)
if r >= 0 {
- if nbytes+utf8.RuneLen(r) > maxbytes {
+ rl := utf8.RuneLen(r)
+ if rl < 0 {
+ rl = len(string(utf8.RuneError))
+ }
+ if nbytes+rl > maxbytes {
// Grow the buffer.
maxbytes = maxbytes*2 + utf8.UTFMax
nb := make([]byte, maxbytes)
@@ -373,9 +379,10 @@ func Map(mapping func(r rune) rune, s []byte) []byte {
// Repeat returns a new byte slice consisting of count copies of b.
func Repeat(b []byte, count int) []byte {
nb := make([]byte, len(b)*count)
- bp := 0
- for i := 0; i < count; i++ {
- bp += copy(nb[bp:], b)
+ bp := copy(nb, b)
+ for bp < len(nb) {
+ copy(nb[bp:], nb[:bp])
+ bp *= 2
}
return nb
}
@@ -600,6 +607,9 @@ func Runes(s []byte) []rune {
// Replace returns a copy of the slice s with the first n
// non-overlapping instances of old replaced by new.
+// If old is empty, it matches at the beginning of the slice
+// and after each UTF-8 sequence, yielding up to k+1 replacements
+// for a k-rune slice.
// If n < 0, there is no limit on the number of replacements.
func Replace(s, old, new []byte, n int) []byte {
m := 0
diff --git a/libgo/go/bytes/bytes_test.go b/libgo/go/bytes/bytes_test.go
index ab5da4fbf0..980c41d754 100644
--- a/libgo/go/bytes/bytes_test.go
+++ b/libgo/go/bytes/bytes_test.go
@@ -785,6 +785,16 @@ func TestMap(t *testing.T) {
if string(m) != expect {
t.Errorf("drop: expected %q got %q", expect, m)
}
+
+ // 6. Invalid rune
+ invalidRune := func(r rune) rune {
+ return utf8.MaxRune + 1
+ }
+ m = Map(invalidRune, []byte("x"))
+ expect = "\uFFFD"
+ if string(m) != expect {
+ t.Errorf("invalidRune: expected %q got %q", expect, m)
+ }
}
func TestToUpper(t *testing.T) { runStringTests(t, ToUpper, "ToUpper", upperTests) }
@@ -1073,6 +1083,8 @@ var TitleTests = []TitleTest{
{"123a456", "123a456"},
{"double-blind", "Double-Blind"},
{"ÿøû", "Ÿøû"},
+ {"with_underscore", "With_underscore"},
+ {"unicode \xe2\x80\xa8 line separator", "Unicode \xe2\x80\xa8 Line Separator"},
}
func TestTitle(t *testing.T) {
@@ -1132,7 +1144,7 @@ func TestEqualFold(t *testing.T) {
func TestBufferGrowNegative(t *testing.T) {
defer func() {
if err := recover(); err == nil {
- t.Fatal("Grow(-1) should have paniced")
+ t.Fatal("Grow(-1) should have panicked")
}
}()
var b Buffer
@@ -1142,7 +1154,7 @@ func TestBufferGrowNegative(t *testing.T) {
func TestBufferTruncateNegative(t *testing.T) {
defer func() {
if err := recover(); err == nil {
- t.Fatal("Truncate(-1) should have paniced")
+ t.Fatal("Truncate(-1) should have panicked")
}
}()
var b Buffer
@@ -1152,7 +1164,7 @@ func TestBufferTruncateNegative(t *testing.T) {
func TestBufferTruncateOutOfRange(t *testing.T) {
defer func() {
if err := recover(); err == nil {
- t.Fatal("Truncate(20) should have paniced")
+ t.Fatal("Truncate(20) should have panicked")
}
}()
var b Buffer
@@ -1160,6 +1172,24 @@ func TestBufferTruncateOutOfRange(t *testing.T) {
b.Truncate(20)
}
+var containsTests = []struct {
+ b, subslice []byte
+ want bool
+}{
+ {[]byte("hello"), []byte("hel"), true},
+ {[]byte("日本語"), []byte("日本"), true},
+ {[]byte("hello"), []byte("Hello, world"), false},
+ {[]byte("東京"), []byte("京東"), false},
+}
+
+func TestContains(t *testing.T) {
+ for _, tt := range containsTests {
+ if got := Contains(tt.b, tt.subslice); got != tt.want {
+ t.Errorf("Contains(%q, %q) = %v, want %v", tt.b, tt.subslice, got, tt.want)
+ }
+ }
+}
+
var makeFieldsInput = func() []byte {
x := make([]byte, 1<<20)
// Input is ~10% space, ~10% 2-byte UTF-8, rest ASCII non-space.
@@ -1202,3 +1232,9 @@ func BenchmarkTrimSpace(b *testing.B) {
TrimSpace(s)
}
}
+
+func BenchmarkRepeat(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Repeat([]byte("-"), 80)
+ }
+}
diff --git a/libgo/go/bytes/compare_test.go b/libgo/go/bytes/compare_test.go
index 0a36f5ad39..63522374ee 100644
--- a/libgo/go/bytes/compare_test.go
+++ b/libgo/go/bytes/compare_test.go
@@ -1,3 +1,7 @@
+// 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 bytes_test
import (
diff --git a/libgo/go/bytes/reader.go b/libgo/go/bytes/reader.go
index 77511b9455..d2d40fa7ca 100644
--- a/libgo/go/bytes/reader.go
+++ b/libgo/go/bytes/reader.go
@@ -16,40 +16,41 @@ import (
// Unlike a Buffer, a Reader is read-only and supports seeking.
type Reader struct {
s []byte
- i int // current reading index
- prevRune int // index of previous rune; or < 0
+ i int64 // current reading index
+ prevRune int // index of previous rune; or < 0
}
// Len returns the number of bytes of the unread portion of the
// slice.
func (r *Reader) Len() int {
- if r.i >= len(r.s) {
+ if r.i >= int64(len(r.s)) {
return 0
}
- return len(r.s) - r.i
+ return int(int64(len(r.s)) - r.i)
}
func (r *Reader) Read(b []byte) (n int, err error) {
if len(b) == 0 {
return 0, nil
}
- if r.i >= len(r.s) {
+ if r.i >= int64(len(r.s)) {
return 0, io.EOF
}
- n = copy(b, r.s[r.i:])
- r.i += n
r.prevRune = -1
+ n = copy(b, r.s[r.i:])
+ r.i += int64(n)
return
}
func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) {
+ // cannot modify state - see io.ReaderAt
if off < 0 {
- return 0, errors.New("bytes: invalid offset")
+ return 0, errors.New("bytes.Reader.ReadAt: negative offset")
}
if off >= int64(len(r.s)) {
return 0, io.EOF
}
- n = copy(b, r.s[int(off):])
+ n = copy(b, r.s[off:])
if n < len(b) {
err = io.EOF
}
@@ -57,49 +58,51 @@ func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) {
}
func (r *Reader) ReadByte() (b byte, err error) {
- if r.i >= len(r.s) {
+ r.prevRune = -1
+ if r.i >= int64(len(r.s)) {
return 0, io.EOF
}
b = r.s[r.i]
r.i++
- r.prevRune = -1
return
}
func (r *Reader) UnreadByte() error {
+ r.prevRune = -1
if r.i <= 0 {
- return errors.New("bytes.Reader: at beginning of slice")
+ return errors.New("bytes.Reader.UnreadByte: at beginning of slice")
}
r.i--
- r.prevRune = -1
return nil
}
func (r *Reader) ReadRune() (ch rune, size int, err error) {
- if r.i >= len(r.s) {
+ if r.i >= int64(len(r.s)) {
+ r.prevRune = -1
return 0, 0, io.EOF
}
- r.prevRune = r.i
+ r.prevRune = int(r.i)
if c := r.s[r.i]; c < utf8.RuneSelf {
r.i++
return rune(c), 1, nil
}
ch, size = utf8.DecodeRune(r.s[r.i:])
- r.i += size
+ r.i += int64(size)
return
}
func (r *Reader) UnreadRune() error {
if r.prevRune < 0 {
- return errors.New("bytes.Reader: previous operation was not ReadRune")
+ return errors.New("bytes.Reader.UnreadRune: previous operation was not ReadRune")
}
- r.i = r.prevRune
+ r.i = int64(r.prevRune)
r.prevRune = -1
return nil
}
// Seek implements the io.Seeker interface.
func (r *Reader) Seek(offset int64, whence int) (int64, error) {
+ r.prevRune = -1
var abs int64
switch whence {
case 0:
@@ -109,22 +112,19 @@ func (r *Reader) Seek(offset int64, whence int) (int64, error) {
case 2:
abs = int64(len(r.s)) + offset
default:
- return 0, errors.New("bytes: invalid whence")
+ return 0, errors.New("bytes.Reader.Seek: invalid whence")
}
if abs < 0 {
- return 0, errors.New("bytes: negative position")
- }
- if abs >= 1<<31 {
- return 0, errors.New("bytes: position out of range")
+ return 0, errors.New("bytes.Reader.Seek: negative position")
}
- r.i = int(abs)
+ r.i = abs
return abs, nil
}
// WriteTo implements the io.WriterTo interface.
func (r *Reader) WriteTo(w io.Writer) (n int64, err error) {
r.prevRune = -1
- if r.i >= len(r.s) {
+ if r.i >= int64(len(r.s)) {
return 0, nil
}
b := r.s[r.i:]
@@ -132,7 +132,7 @@ func (r *Reader) WriteTo(w io.Writer) (n int64, err error) {
if m > len(b) {
panic("bytes.Reader.WriteTo: invalid Write count")
}
- r.i += m
+ r.i += int64(m)
n = int64(m)
if m != len(b) && err == nil {
err = io.ErrShortWrite
diff --git a/libgo/go/bytes/reader_test.go b/libgo/go/bytes/reader_test.go
index 19f014da03..d3dce53499 100644
--- a/libgo/go/bytes/reader_test.go
+++ b/libgo/go/bytes/reader_test.go
@@ -10,6 +10,7 @@ import (
"io"
"io/ioutil"
"os"
+ "sync"
"testing"
)
@@ -26,9 +27,9 @@ func TestReader(t *testing.T) {
{seek: os.SEEK_SET, off: 0, n: 20, want: "0123456789"},
{seek: os.SEEK_SET, off: 1, n: 1, want: "1"},
{seek: os.SEEK_CUR, off: 1, wantpos: 3, n: 2, want: "34"},
- {seek: os.SEEK_SET, off: -1, seekerr: "bytes: negative position"},
- {seek: os.SEEK_SET, off: 1<<31 - 1},
- {seek: os.SEEK_CUR, off: 1, seekerr: "bytes: position out of range"},
+ {seek: os.SEEK_SET, off: -1, seekerr: "bytes.Reader.Seek: negative position"},
+ {seek: os.SEEK_SET, off: 1 << 33, wantpos: 1 << 33},
+ {seek: os.SEEK_CUR, off: 1, wantpos: 1<<33 + 1},
{seek: os.SEEK_SET, n: 5, want: "01234"},
{seek: os.SEEK_CUR, n: 5, want: "56789"},
{seek: os.SEEK_END, off: -1, n: 1, wantpos: 9, want: "9"},
@@ -60,6 +61,16 @@ func TestReader(t *testing.T) {
}
}
+func TestReadAfterBigSeek(t *testing.T) {
+ r := NewReader([]byte("0123456789"))
+ if _, err := r.Seek(1<<31+5, os.SEEK_SET); err != nil {
+ t.Fatal(err)
+ }
+ if n, err := r.Read(make([]byte, 10)); n != 0 || err != io.EOF {
+ t.Errorf("Read = %d, %v; want 0, EOF", n, err)
+ }
+}
+
func TestReaderAt(t *testing.T) {
r := NewReader([]byte("0123456789"))
tests := []struct {
@@ -73,7 +84,7 @@ func TestReaderAt(t *testing.T) {
{1, 9, "123456789", nil},
{11, 10, "", io.EOF},
{0, 0, "", nil},
- {-1, 0, "", "bytes: invalid offset"},
+ {-1, 0, "", "bytes.Reader.ReadAt: negative offset"},
}
for i, tt := range tests {
b := make([]byte, tt.n)
@@ -88,6 +99,43 @@ func TestReaderAt(t *testing.T) {
}
}
+func TestReaderAtConcurrent(t *testing.T) {
+ // Test for the race detector, to verify ReadAt doesn't mutate
+ // any state.
+ r := NewReader([]byte("0123456789"))
+ var wg sync.WaitGroup
+ for i := 0; i < 5; i++ {
+ wg.Add(1)
+ go func(i int) {
+ defer wg.Done()
+ var buf [1]byte
+ r.ReadAt(buf[:], int64(i))
+ }(i)
+ }
+ wg.Wait()
+}
+
+func TestEmptyReaderConcurrent(t *testing.T) {
+ // Test for the race detector, to verify a Read that doesn't yield any bytes
+ // is okay to use from multiple goroutines. This was our historic behavior.
+ // See golang.org/issue/7856
+ r := NewReader([]byte{})
+ var wg sync.WaitGroup
+ for i := 0; i < 5; i++ {
+ wg.Add(2)
+ go func() {
+ defer wg.Done()
+ var buf [1]byte
+ r.Read(buf[:])
+ }()
+ go func() {
+ defer wg.Done()
+ r.Read(nil)
+ }()
+ }
+ wg.Wait()
+}
+
func TestReaderWriteTo(t *testing.T) {
for i := 0; i < 30; i += 3 {
var l int
@@ -133,6 +181,32 @@ func TestReaderLen(t *testing.T) {
}
}
+var UnreadRuneErrorTests = []struct {
+ name string
+ f func(*Reader)
+}{
+ {"Read", func(r *Reader) { r.Read([]byte{0}) }},
+ {"ReadByte", func(r *Reader) { r.ReadByte() }},
+ {"UnreadRune", func(r *Reader) { r.UnreadRune() }},
+ {"Seek", func(r *Reader) { r.Seek(0, 1) }},
+ {"WriteTo", func(r *Reader) { r.WriteTo(&Buffer{}) }},
+}
+
+func TestUnreadRuneError(t *testing.T) {
+ for _, tt := range UnreadRuneErrorTests {
+ reader := NewReader([]byte("0123456789"))
+ if _, _, err := reader.ReadRune(); err != nil {
+ // should not happen
+ t.Fatal(err)
+ }
+ tt.f(reader)
+ err := reader.UnreadRune()
+ if err == nil {
+ t.Errorf("Unreading after %s: expected error", tt.name)
+ }
+ }
+}
+
func TestReaderDoubleUnreadRune(t *testing.T) {
buf := NewBuffer([]byte("groucho"))
if _, _, err := buf.ReadRune(); err != nil {
diff --git a/libgo/go/cmd/cgo/ast.go b/libgo/go/cmd/cgo/ast.go
new file mode 100644
index 0000000000..10e2278a1d
--- /dev/null
+++ b/libgo/go/cmd/cgo/ast.go
@@ -0,0 +1,463 @@
+// 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.
+
+// Parse input AST and prepare Prog structure.
+
+package main
+
+import (
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/scanner"
+ "go/token"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+func parse(name string, flags parser.Mode) *ast.File {
+ ast1, err := parser.ParseFile(fset, name, nil, flags)
+ if err != nil {
+ if list, ok := err.(scanner.ErrorList); ok {
+ // If err is a scanner.ErrorList, its String will print just
+ // the first error and then (+n more errors).
+ // Instead, turn it into a new Error that will return
+ // details for all the errors.
+ for _, e := range list {
+ fmt.Fprintln(os.Stderr, e)
+ }
+ os.Exit(2)
+ }
+ fatalf("parsing %s: %s", name, err)
+ }
+ return ast1
+}
+
+func sourceLine(n ast.Node) int {
+ return fset.Position(n.Pos()).Line
+}
+
+// ReadGo populates f with information learned from reading the
+// Go source file with the given file name. It gathers the C preamble
+// attached to the import "C" comment, a list of references to C.xxx,
+// a list of exported functions, and the actual AST, to be rewritten and
+// printed.
+func (f *File) ReadGo(name string) {
+ // Create absolute path for file, so that it will be used in error
+ // messages and recorded in debug line number information.
+ // This matches the rest of the toolchain. See golang.org/issue/5122.
+ if aname, err := filepath.Abs(name); err == nil {
+ name = aname
+ }
+
+ // Two different parses: once with comments, once without.
+ // The printer is not good enough at printing comments in the
+ // right place when we start editing the AST behind its back,
+ // so we use ast1 to look for the doc comments on import "C"
+ // and on exported functions, and we use ast2 for translating
+ // and reprinting.
+ ast1 := parse(name, parser.ParseComments)
+ ast2 := parse(name, 0)
+
+ f.Package = ast1.Name.Name
+ f.Name = make(map[string]*Name)
+
+ // In ast1, find the import "C" line and get any extra C preamble.
+ sawC := false
+ for _, decl := range ast1.Decls {
+ d, ok := decl.(*ast.GenDecl)
+ if !ok {
+ continue
+ }
+ for _, spec := range d.Specs {
+ s, ok := spec.(*ast.ImportSpec)
+ if !ok || string(s.Path.Value) != `"C"` {
+ continue
+ }
+ sawC = true
+ if s.Name != nil {
+ error_(s.Path.Pos(), `cannot rename import "C"`)
+ }
+ cg := s.Doc
+ if cg == nil && len(d.Specs) == 1 {
+ cg = d.Doc
+ }
+ if cg != nil {
+ f.Preamble += fmt.Sprintf("#line %d %q\n", sourceLine(cg), name)
+ f.Preamble += commentText(cg) + "\n"
+ }
+ }
+ }
+ if !sawC {
+ error_(token.NoPos, `cannot find import "C"`)
+ }
+
+ // In ast2, strip the import "C" line.
+ w := 0
+ for _, decl := range ast2.Decls {
+ d, ok := decl.(*ast.GenDecl)
+ if !ok {
+ ast2.Decls[w] = decl
+ w++
+ continue
+ }
+ ws := 0
+ for _, spec := range d.Specs {
+ s, ok := spec.(*ast.ImportSpec)
+ if !ok || string(s.Path.Value) != `"C"` {
+ d.Specs[ws] = spec
+ ws++
+ }
+ }
+ if ws == 0 {
+ continue
+ }
+ d.Specs = d.Specs[0:ws]
+ ast2.Decls[w] = d
+ w++
+ }
+ ast2.Decls = ast2.Decls[0:w]
+
+ // Accumulate pointers to uses of C.x.
+ if f.Ref == nil {
+ f.Ref = make([]*Ref, 0, 8)
+ }
+ f.walk(ast2, "prog", (*File).saveRef)
+
+ // Accumulate exported functions.
+ // The comments are only on ast1 but we need to
+ // save the function bodies from ast2.
+ // The first walk fills in ExpFunc, and the
+ // second walk changes the entries to
+ // refer to ast2 instead.
+ f.walk(ast1, "prog", (*File).saveExport)
+ f.walk(ast2, "prog", (*File).saveExport2)
+
+ f.Comments = ast1.Comments
+ f.AST = ast2
+}
+
+// Like ast.CommentGroup's Text method but preserves
+// leading blank lines, so that line numbers line up.
+func commentText(g *ast.CommentGroup) string {
+ if g == nil {
+ return ""
+ }
+ var pieces []string
+ for _, com := range g.List {
+ c := string(com.Text)
+ // Remove comment markers.
+ // The parser has given us exactly the comment text.
+ switch c[1] {
+ case '/':
+ //-style comment (no newline at the end)
+ c = c[2:] + "\n"
+ case '*':
+ /*-style comment */
+ c = c[2 : len(c)-2]
+ }
+ pieces = append(pieces, c)
+ }
+ return strings.Join(pieces, "")
+}
+
+// Save references to C.xxx for later processing.
+func (f *File) saveRef(x interface{}, context string) {
+ n, ok := x.(*ast.Expr)
+ if !ok {
+ return
+ }
+ if sel, ok := (*n).(*ast.SelectorExpr); ok {
+ // For now, assume that the only instance of capital C is
+ // when used as the imported package identifier.
+ // The parser should take care of scoping in the future,
+ // so that we will be able to distinguish a "top-level C"
+ // from a local C.
+ if l, ok := sel.X.(*ast.Ident); ok && l.Name == "C" {
+ if context == "as2" {
+ context = "expr"
+ }
+ if context == "embed-type" {
+ error_(sel.Pos(), "cannot embed C type")
+ }
+ goname := sel.Sel.Name
+ if goname == "errno" {
+ error_(sel.Pos(), "cannot refer to errno directly; see documentation")
+ return
+ }
+ if goname == "_CMalloc" {
+ error_(sel.Pos(), "cannot refer to C._CMalloc; use C.malloc")
+ return
+ }
+ if goname == "malloc" {
+ goname = "_CMalloc"
+ }
+ name := f.Name[goname]
+ if name == nil {
+ name = &Name{
+ Go: goname,
+ }
+ f.Name[goname] = name
+ }
+ f.Ref = append(f.Ref, &Ref{
+ Name: name,
+ Expr: n,
+ Context: context,
+ })
+ return
+ }
+ }
+}
+
+// If a function should be exported add it to ExpFunc.
+func (f *File) saveExport(x interface{}, context string) {
+ n, ok := x.(*ast.FuncDecl)
+ if !ok {
+ return
+ }
+
+ if n.Doc == nil {
+ return
+ }
+ for _, c := range n.Doc.List {
+ if !strings.HasPrefix(string(c.Text), "//export ") {
+ continue
+ }
+
+ name := strings.TrimSpace(string(c.Text[9:]))
+ if name == "" {
+ error_(c.Pos(), "export missing name")
+ }
+
+ if name != n.Name.Name {
+ error_(c.Pos(), "export comment has wrong name %q, want %q", name, n.Name.Name)
+ }
+
+ f.ExpFunc = append(f.ExpFunc, &ExpFunc{
+ Func: n,
+ ExpName: name,
+ })
+ break
+ }
+}
+
+// Make f.ExpFunc[i] point at the Func from this AST instead of the other one.
+func (f *File) saveExport2(x interface{}, context string) {
+ n, ok := x.(*ast.FuncDecl)
+ if !ok {
+ return
+ }
+
+ for _, exp := range f.ExpFunc {
+ if exp.Func.Name.Name == n.Name.Name {
+ exp.Func = n
+ break
+ }
+ }
+}
+
+// walk walks the AST x, calling visit(f, x, context) for each node.
+func (f *File) walk(x interface{}, context string, visit func(*File, interface{}, string)) {
+ visit(f, x, context)
+ switch n := x.(type) {
+ case *ast.Expr:
+ f.walk(*n, context, visit)
+
+ // everything else just recurs
+ default:
+ error_(token.NoPos, "unexpected type %T in walk", x, visit)
+ panic("unexpected type")
+
+ case nil:
+
+ // These are ordered and grouped to match ../../go/ast/ast.go
+ case *ast.Field:
+ if len(n.Names) == 0 && context == "field" {
+ f.walk(&n.Type, "embed-type", visit)
+ } else {
+ f.walk(&n.Type, "type", visit)
+ }
+ case *ast.FieldList:
+ for _, field := range n.List {
+ f.walk(field, context, visit)
+ }
+ case *ast.BadExpr:
+ case *ast.Ident:
+ case *ast.Ellipsis:
+ case *ast.BasicLit:
+ case *ast.FuncLit:
+ f.walk(n.Type, "type", visit)
+ f.walk(n.Body, "stmt", visit)
+ case *ast.CompositeLit:
+ f.walk(&n.Type, "type", visit)
+ f.walk(n.Elts, "expr", visit)
+ case *ast.ParenExpr:
+ f.walk(&n.X, context, visit)
+ case *ast.SelectorExpr:
+ f.walk(&n.X, "selector", visit)
+ case *ast.IndexExpr:
+ f.walk(&n.X, "expr", visit)
+ f.walk(&n.Index, "expr", visit)
+ case *ast.SliceExpr:
+ f.walk(&n.X, "expr", visit)
+ if n.Low != nil {
+ f.walk(&n.Low, "expr", visit)
+ }
+ if n.High != nil {
+ f.walk(&n.High, "expr", visit)
+ }
+ if n.Max != nil {
+ f.walk(&n.Max, "expr", visit)
+ }
+ case *ast.TypeAssertExpr:
+ f.walk(&n.X, "expr", visit)
+ f.walk(&n.Type, "type", visit)
+ case *ast.CallExpr:
+ if context == "as2" {
+ f.walk(&n.Fun, "call2", visit)
+ } else {
+ f.walk(&n.Fun, "call", visit)
+ }
+ f.walk(n.Args, "expr", visit)
+ case *ast.StarExpr:
+ f.walk(&n.X, context, visit)
+ case *ast.UnaryExpr:
+ f.walk(&n.X, "expr", visit)
+ case *ast.BinaryExpr:
+ f.walk(&n.X, "expr", visit)
+ f.walk(&n.Y, "expr", visit)
+ case *ast.KeyValueExpr:
+ f.walk(&n.Key, "expr", visit)
+ f.walk(&n.Value, "expr", visit)
+
+ case *ast.ArrayType:
+ f.walk(&n.Len, "expr", visit)
+ f.walk(&n.Elt, "type", visit)
+ case *ast.StructType:
+ f.walk(n.Fields, "field", visit)
+ case *ast.FuncType:
+ f.walk(n.Params, "param", visit)
+ if n.Results != nil {
+ f.walk(n.Results, "param", visit)
+ }
+ case *ast.InterfaceType:
+ f.walk(n.Methods, "field", visit)
+ case *ast.MapType:
+ f.walk(&n.Key, "type", visit)
+ f.walk(&n.Value, "type", visit)
+ case *ast.ChanType:
+ f.walk(&n.Value, "type", visit)
+
+ case *ast.BadStmt:
+ case *ast.DeclStmt:
+ f.walk(n.Decl, "decl", visit)
+ case *ast.EmptyStmt:
+ case *ast.LabeledStmt:
+ f.walk(n.Stmt, "stmt", visit)
+ case *ast.ExprStmt:
+ f.walk(&n.X, "expr", visit)
+ case *ast.SendStmt:
+ f.walk(&n.Chan, "expr", visit)
+ f.walk(&n.Value, "expr", visit)
+ case *ast.IncDecStmt:
+ f.walk(&n.X, "expr", visit)
+ case *ast.AssignStmt:
+ f.walk(n.Lhs, "expr", visit)
+ if len(n.Lhs) == 2 && len(n.Rhs) == 1 {
+ f.walk(n.Rhs, "as2", visit)
+ } else {
+ f.walk(n.Rhs, "expr", visit)
+ }
+ case *ast.GoStmt:
+ f.walk(n.Call, "expr", visit)
+ case *ast.DeferStmt:
+ f.walk(n.Call, "expr", visit)
+ case *ast.ReturnStmt:
+ f.walk(n.Results, "expr", visit)
+ case *ast.BranchStmt:
+ case *ast.BlockStmt:
+ f.walk(n.List, context, visit)
+ case *ast.IfStmt:
+ f.walk(n.Init, "stmt", visit)
+ f.walk(&n.Cond, "expr", visit)
+ f.walk(n.Body, "stmt", visit)
+ f.walk(n.Else, "stmt", visit)
+ case *ast.CaseClause:
+ if context == "typeswitch" {
+ context = "type"
+ } else {
+ context = "expr"
+ }
+ f.walk(n.List, context, visit)
+ f.walk(n.Body, "stmt", visit)
+ case *ast.SwitchStmt:
+ f.walk(n.Init, "stmt", visit)
+ f.walk(&n.Tag, "expr", visit)
+ f.walk(n.Body, "switch", visit)
+ case *ast.TypeSwitchStmt:
+ f.walk(n.Init, "stmt", visit)
+ f.walk(n.Assign, "stmt", visit)
+ f.walk(n.Body, "typeswitch", visit)
+ case *ast.CommClause:
+ f.walk(n.Comm, "stmt", visit)
+ f.walk(n.Body, "stmt", visit)
+ case *ast.SelectStmt:
+ f.walk(n.Body, "stmt", visit)
+ case *ast.ForStmt:
+ f.walk(n.Init, "stmt", visit)
+ f.walk(&n.Cond, "expr", visit)
+ f.walk(n.Post, "stmt", visit)
+ f.walk(n.Body, "stmt", visit)
+ case *ast.RangeStmt:
+ f.walk(&n.Key, "expr", visit)
+ f.walk(&n.Value, "expr", visit)
+ f.walk(&n.X, "expr", visit)
+ f.walk(n.Body, "stmt", visit)
+
+ case *ast.ImportSpec:
+ case *ast.ValueSpec:
+ f.walk(&n.Type, "type", visit)
+ f.walk(n.Values, "expr", visit)
+ case *ast.TypeSpec:
+ f.walk(&n.Type, "type", visit)
+
+ case *ast.BadDecl:
+ case *ast.GenDecl:
+ f.walk(n.Specs, "spec", visit)
+ case *ast.FuncDecl:
+ if n.Recv != nil {
+ f.walk(n.Recv, "param", visit)
+ }
+ f.walk(n.Type, "type", visit)
+ if n.Body != nil {
+ f.walk(n.Body, "stmt", visit)
+ }
+
+ case *ast.File:
+ f.walk(n.Decls, "decl", visit)
+
+ case *ast.Package:
+ for _, file := range n.Files {
+ f.walk(file, "file", visit)
+ }
+
+ case []ast.Decl:
+ for _, d := range n {
+ f.walk(d, context, visit)
+ }
+ case []ast.Expr:
+ for i := range n {
+ f.walk(&n[i], context, visit)
+ }
+ case []ast.Stmt:
+ for _, s := range n {
+ f.walk(s, context, visit)
+ }
+ case []ast.Spec:
+ for _, s := range n {
+ f.walk(s, context, visit)
+ }
+ }
+}
diff --git a/libgo/go/cmd/cgo/doc.go b/libgo/go/cmd/cgo/doc.go
new file mode 100644
index 0000000000..6179c7afd1
--- /dev/null
+++ b/libgo/go/cmd/cgo/doc.go
@@ -0,0 +1,748 @@
+// 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 enables the creation of Go packages that call C code.
+
+Using cgo with the go command
+
+To use cgo write normal Go code that imports a pseudo-package "C".
+The Go code can then refer to types such as C.size_t, variables such
+as C.stdout, or functions such as C.putchar.
+
+If the import of "C" is immediately preceded by a comment, that
+comment, called the preamble, is used as a header when compiling
+the C parts of the package. For example:
+
+ // #include <stdio.h>
+ // #include <errno.h>
+ import "C"
+
+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.
+
+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).
+For example:
+
+ // #cgo CFLAGS: -DPNG_DEBUG=1
+ // #cgo amd64 386 CFLAGS: -DX86=1
+ // #cgo LDFLAGS: -lpng
+ // #include <png.h>
+ import "C"
+
+Alternatively, CPPFLAGS and LDFLAGS may be obtained via the pkg-config
+tool using a '#cgo pkg-config:' directive followed by the package names.
+For example:
+
+ // #cgo pkg-config: png cairo
+ // #include <png.h>
+ import "C"
+
+When building, the CGO_CFLAGS, CGO_CPPFLAGS, CGO_CXXFLAGS and
+CGO_LDFLAGS environment variables are added to the flags derived from
+these directives. Package-specific flags should be set using the
+directives, not the environment variables, so that builds work in
+unmodified environments.
+
+All the cgo CPPFLAGS and CFLAGS directives in a package are concatenated and
+used to compile C files in that package. All the CPPFLAGS and CXXFLAGS
+directives in a package are concatenated and used to compile C++ files in that
+package. All the LDFLAGS directives in any package in the program are
+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 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
+compiled with the C compiler. Any .cc, .cpp, or .cxx files will be
+compiled with the C++ compiler. Any .h, .hh, .hpp, or .hxx files will
+not be compiled separately, but, if these header files are changed,
+the C and C++ files will be recompiled. The default C and C++
+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.
+
+CXX_FOR_TARGET works in a similar way for C++ code.
+
+Go references to C
+
+Within the Go file, C's struct field names that are keywords in Go
+can be accessed by prefixing them with an underscore: if x points at a C
+struct with a field named "type", x._type accesses the field.
+C struct fields that cannot be expressed in Go, such as bit fields
+or misaligned data, are omitted in the Go struct, replaced by
+appropriate padding to reach the next field or the end of the struct.
+
+The standard C numeric types are available under the names
+C.char, C.schar (signed char), C.uchar (unsigned char),
+C.short, C.ushort (unsigned short), C.int, C.uint (unsigned int),
+C.long, C.ulong (unsigned long), C.longlong (long long),
+C.ulonglong (unsigned long long), C.float, C.double.
+The C type void* is represented by Go's unsafe.Pointer.
+
+To access a struct, union, or enum type directly, prefix it with
+struct_, union_, or enum_, as in C.struct_stat.
+
+As Go doesn't have support for C's union type in the general case,
+C's union types are represented as a Go byte array with the same length.
+
+Go structs cannot embed fields with C types.
+
+Cgo translates C types into equivalent unexported Go types.
+Because the translations are unexported, a Go package should not
+expose C types in its exported API: a C type used in one Go package
+is different from the same C type used in another.
+
+Any C function (even void functions) may be called in a multiple
+assignment context to retrieve both the return value (if any) and the
+C errno variable as an error (use _ to skip the result value if the
+function returns void). For example:
+
+ n, err := C.sqrt(-1)
+ _, err := C.voidFunc()
+
+Calling C function pointers is currently not supported, however you can
+declare Go variables which hold C function pointers and pass them
+back and forth between Go and C. C code may call function pointers
+received from Go. For example:
+
+ package main
+
+ // typedef int (*intFunc) ();
+ //
+ // int
+ // bridge_int_func(intFunc f)
+ // {
+ // return f();
+ // }
+ //
+ // int fortytwo()
+ // {
+ // return 42;
+ // }
+ import "C"
+ import "fmt"
+
+ func main() {
+ f := C.intFunc(C.fortytwo)
+ fmt.Println(int(C.bridge_int_func(f)))
+ // Output: 42
+ }
+
+In C, a function argument written as a fixed size array
+actually requires a pointer to the first element of the array.
+C compilers are aware of this calling convention and adjust
+the call accordingly, but Go cannot. In Go, you must pass
+the pointer to the first element explicitly: C.f(&C.x[0]).
+
+A few special functions convert between Go and C types
+by making copies of the data. In pseudo-Go definitions:
+
+ // Go string to C string
+ // The C string is allocated in the C heap using malloc.
+ // It is the caller's responsibility to arrange for it to be
+ // freed, such as by calling C.free (be sure to include stdlib.h
+ // if C.free is needed).
+ func C.CString(string) *C.char
+
+ // C string to Go string
+ func C.GoString(*C.char) string
+
+ // C string, length to Go string
+ func C.GoStringN(*C.char, C.int) string
+
+ // C pointer, length to Go []byte
+ func C.GoBytes(unsafe.Pointer, C.int) []byte
+
+C references to Go
+
+Go functions can be exported for use by C code in the following way:
+
+ //export MyFunction
+ func MyFunction(arg1, arg2 int, arg3 string) int64 {...}
+
+ //export MyFunction2
+ func MyFunction2(arg1, arg2 int, arg3 string) (int64, *C.char) {...}
+
+They will be available in the C code as:
+
+ extern int64 MyFunction(int arg1, int arg2, GoString arg3);
+ extern struct MyFunction2_return MyFunction2(int arg1, int arg2, GoString arg3);
+
+found in the _cgo_export.h generated header, after any preambles
+copied from the cgo input files. Functions with multiple
+return values are mapped to functions returning a struct.
+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.
+
+Using cgo directly
+
+Usage:
+ go tool cgo [cgo options] [-- compiler options] file.go
+
+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.
+
+The compiler options are passed through uninterpreted when
+invoking the C compiler to compile the C parts of the package.
+
+The following options are available when running cgo directly:
+
+ -dynimport file
+ Write list of symbols imported by file. Write to
+ -dynout argument or to standard output. Used by go
+ build when building a cgo package.
+ -dynout file
+ Write -dynimport output to file.
+ -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.
+ -gccgo
+ Generate output for the gccgo compiler rather than the
+ gc compiler.
+ -gccgoprefix prefix
+ The -fgo-prefix option to be used with gccgo.
+ -gccgopkgpath path
+ The -fgo-pkgpath option to be used with gccgo.
+ -import_runtime_cgo
+ If set (which it is by default) import runtime/cgo in
+ generated output.
+ -import_syscall
+ If set (which it is by default) import syscall in
+ generated output.
+ -debug-define
+ Debugging option. Print #defines.
+ -debug-gcc
+ Debugging option. Trace C compiler execution and output.
+*/
+package main
+
+/*
+Implementation details.
+
+Cgo provides a way for Go programs to call C code linked into the same
+address space. This comment explains the operation of cgo.
+
+Cgo reads a set of Go source files and looks for statements saying
+import "C". If the import has a doc comment, that comment is
+taken as literal C code to be used as a preamble to any C code
+generated by cgo. A typical preamble #includes necessary definitions:
+
+ // #include <stdio.h>
+ import "C"
+
+For more details about the usage of cgo, see the documentation
+comment at the top of this file.
+
+Understanding C
+
+Cgo scans the Go source files that import "C" for uses of that
+package, such as C.puts. It collects all such identifiers. The next
+step is to determine each kind of name. In C.xxx the xxx might refer
+to a type, a function, a constant, or a global variable. Cgo must
+decide which.
+
+The obvious thing for cgo to do is to process the preamble, expanding
+#includes and processing the corresponding C code. That would require
+a full C parser and type checker that was also aware of any extensions
+known to the system compiler (for example, all the GNU C extensions) as
+well as the system-specific header locations and system-specific
+pre-#defined macros. This is certainly possible to do, but it is an
+enormous amount of work.
+
+Cgo takes a different approach. It determines the meaning of C
+identifiers not by parsing C code but by feeding carefully constructed
+programs into the system C compiler and interpreting the generated
+error messages, debug information, and object files. In practice,
+parsing these is significantly less work and more robust than parsing
+C source.
+
+Cgo first invokes gcc -E -dM on the preamble, in order to find out
+about simple #defines for constants and the like. These are recorded
+for later use.
+
+Next, cgo needs to identify the kinds for each identifier. For the
+identifiers C.foo and C.bar, cgo generates this C program:
+
+ <preamble>
+ #line 1 "not-declared"
+ void __cgo_f_xxx_1(void) { __typeof__(foo) *__cgo_undefined__; }
+ #line 1 "not-type"
+ void __cgo_f_xxx_2(void) { foo *__cgo_undefined__; }
+ #line 1 "not-const"
+ void __cgo_f_xxx_3(void) { enum { __cgo_undefined__ = (foo)*1 }; }
+ #line 2 "not-declared"
+ void __cgo_f_xxx_1(void) { __typeof__(bar) *__cgo_undefined__; }
+ #line 2 "not-type"
+ void __cgo_f_xxx_2(void) { bar *__cgo_undefined__; }
+ #line 2 "not-const"
+ void __cgo_f_xxx_3(void) { enum { __cgo_undefined__ = (bar)*1 }; }
+
+This program will not compile, but cgo can use the presence or absence
+of an error message on a given line to deduce the information it
+needs. The program is syntactically valid regardless of whether each
+name is a type or an ordinary identifier, so there will be no syntax
+errors that might stop parsing early.
+
+An error on not-declared:1 indicates that foo is undeclared.
+An error on not-type:1 indicates that foo is not a type (if declared at all, it is an identifier).
+An error on not-const:1 indicates that foo is not an integer constant.
+
+The line number specifies the name involved. In the example, 1 is foo and 2 is bar.
+
+Next, cgo must learn the details of each type, variable, function, or
+constant. It can do this by reading object files. If cgo has decided
+that t1 is a type, v2 and v3 are variables or functions, and c4, c5,
+and c6 are constants, it generates:
+
+ <preamble>
+ __typeof__(t1) *__cgo__1;
+ __typeof__(v2) *__cgo__2;
+ __typeof__(v3) *__cgo__3;
+ __typeof__(c4) *__cgo__4;
+ enum { __cgo_enum__4 = c4 };
+ __typeof__(c5) *__cgo__5;
+ enum { __cgo_enum__5 = c5 };
+ __typeof__(c6) *__cgo__6;
+ enum { __cgo_enum__6 = c6 };
+
+ long long __cgo_debug_data[] = {
+ 0, // t1
+ 0, // v2
+ 0, // v3
+ c4,
+ c5,
+ c6,
+ 1
+ };
+
+and again invokes the system C compiler, to produce an object file
+containing debug information. Cgo parses the DWARF debug information
+for __cgo__N to learn the type of each identifier. (The types also
+distinguish functions from global variables.) If using a standard gcc,
+cgo can parse the DWARF debug information for the __cgo_enum__N to
+learn the identifier's value. The LLVM-based gcc on OS X emits
+incomplete DWARF information for enums; in that case cgo reads the
+constant values from the __cgo_debug_data from the object file's data
+segment.
+
+At this point cgo knows the meaning of each C.xxx well enough to start
+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.]
+
+Given the input Go files x.go and y.go, cgo generates these source
+files:
+
+ x.cgo1.go # for 6g
+ y.cgo1.go # for 6g
+ _cgo_gotypes.go # for 6g
+ _cgo_defun.c # for 6c
+ x.cgo2.c # for gcc
+ y.cgo2.c # for gcc
+ _cgo_export.c # for gcc
+ _cgo_main.c # for gcc
+
+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):
+
+ 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.
+
+For example, here is the definition of _Cfunc_puts:
+
+ void _cgo_be59f0f25121_Cfunc_puts(void*);
+
+ void
+ ·_Cfunc_puts(struct{uint8 x[1];}p)
+ {
+ runtime·cgocall(_cgo_be59f0f25121_Cfunc_puts, &p);
+ }
+
+The hexadecimal number is a hash of cgo's input, chosen to be
+deterministic yet unlikely to collide with other uses. The actual
+function _cgo_be59f0f25121_Cfunc_puts is implemented in a C source
+file compiled by gcc, the file x.cgo2.c:
+
+ void
+ _cgo_be59f0f25121_Cfunc_puts(void *v)
+ {
+ struct {
+ char* p0;
+ int r;
+ char __pad12[4];
+ } __attribute__((__packed__, __gcc_struct__)) *a = v;
+ a->r = puts((void*)a->p0);
+ }
+
+It 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.
+
+Linking
+
+Once the _cgo_export.c and *.cgo2.c files have been compiled with gcc,
+they need to be linked into the final binary, along with the libraries
+they might depend on (in the case of puts, stdio). 6l has been
+extended to understand basic ELF files, but it does not understand ELF
+in the full complexity that modern C libraries embrace, so it cannot
+in general generate direct references to the system libraries.
+
+Instead, the build process generates an object file using dynamic
+linkage to the desired libraries. The main function is provided by
+_cgo_main.c:
+
+ int main() { return 0; }
+ void crosscall2(void(*fn)(void*, int), void *a, int c) { }
+ void _cgo_allocate(void *a, int c) { }
+ void _cgo_panic(void *a, int c) { }
+
+The extra functions here are stubs to satisfy the references in the C
+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:
+
+ #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"
+
+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
+ _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
+files generated from C files that cgo writes, and those are much more
+limited in the ELF or other features that they use.
+
+In essence, the _cgo_import.6 file includes the extra linking
+directives that 6l is not sophisticated enough to derive from _all.o
+on its own. Similarly, the _all.o uses dynamic references to real
+system object code because 6l is not sophisticated enough to process
+the real code.
+
+The main benefits of this system are that 6l remains relatively simple
+(it does not need to implement a complete ELF and Mach-O linker) and
+that gcc is not needed after the package is compiled. For example,
+package net uses cgo for access to name resolution functions provided
+by libc. Although gcc is needed to compile package net, gcc is not
+needed to link programs that import package net.
+
+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)
+variables:
+
+ bool runtime·iscgo;
+ void (*libcgo_thread_start)(void*);
+ void (*initcgo)(G*);
+
+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.
+
+Internal and External Linking
+
+The text above describes "internal" linking, in which 6l parses and
+links host object files (ELF, Mach-O, PE, and so on) into the final
+executable itself. Keeping 6l simple means we cannot possibly
+implement the full semantics of the host linker, so the kinds of
+objects that can be linked directly into the binary is limited (other
+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
+requirement but introduces a requirement that the host linker be
+present to create such a binary.
+
+Most builds both compile source code and invoke the linker to create a
+binary. When cgo is involved, the compile step already requires gcc, so
+it is not problematic for the link step to require gcc too.
+
+An important exception is builds using a pre-compiled copy of the
+standard library. In particular, package net uses cgo on most systems,
+and we want to preserve the ability to compile pure Go code that
+imports net without requiring gcc to be present at link time. (In this
+case, the dynamic library requirement is less significant, because the
+only library involved is libc.so, which can usually be assumed
+present.)
+
+This conflict between functionality and the gcc requirement means we
+must support both internal and external linking, depending on the
+circumstances: if net is the only cgo-using package, then internal
+linking is probably fine, but if other packages are involved, so that there
+are dependencies on libraries beyond libc, external linking is likely
+to work better. The compilation of a package records the relevant
+information to support both linking modes, leaving the decision
+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.
+
+The directives are:
+
+#pragma cgo_import_dynamic <local> [<remote> ["<library>"]]
+
+ In internal linking mode, allow an unresolved reference to
+ <local>, assuming it will be resolved by a dynamic library
+ symbol. The optional <remote> specifies the symbol's name and
+ possibly version in the dynamic library, and the optional "<library>"
+ names the specific library where the symbol should be found.
+
+ In the <remote>, # 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"
+
+ A side effect of the cgo_import_dynamic directive with a
+ library is to make the final binary depend on that dynamic
+ library. To get the dependency without importing any specific
+ symbols, use _ for local and remote.
+
+ Example:
+ #pragma cgo_import_dynamic _ _ "libc.so.6"
+
+ For compatibility with current versions of SWIG,
+ #pragma dynimport is an alias for #pragma cgo_import_dynamic.
+
+#pragma cgo_dynamic_linker "<path>"
+
+ In internal linking mode, use "<path>" as the dynamic linker
+ in the final binary. This directive is only needed from one
+ package when constructing a binary; by convention it is
+ supplied by runtime/cgo.
+
+ Example:
+ #pragma cgo_dynamic_linker "/lib/ld-linux.so.2"
+
+#pragma cgo_export_dynamic <local> <remote>
+
+ In internal linking mode, put the Go symbol
+ named <local> into the program's exported symbol table as
+ <remote>, so that C code can refer to it by that name. This
+ mechanism makes it possible for C code to call back into Go or
+ to share Go's data.
+
+ For compatibility with current versions of SWIG,
+ #pragma dynexport is an alias for #pragma cgo_export_dynamic.
+
+#pragma cgo_import_static <local>
+
+ In external linking mode, allow unresolved references to
+ <local> in the go.o object file prepared for the host linker,
+ under the assumption that <local> will be supplied by the
+ other object files that will be linked with go.o.
+
+ Example:
+ #pragma cgo_import_static puts_wrapper
+
+#pragma cgo_export_static <local> <remote>
+
+ In external linking mode, put the Go symbol
+ named <local> into the program's exported symbol table as
+ <remote>, so that C code can refer to it by that name. This
+ mechanism makes it possible for C code to call back into Go or
+ to share Go's data.
+
+#pragma cgo_ldflag "<arg>"
+
+ In external linking mode, invoke the host linker (usually gcc)
+ with "<arg>" 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"
+
+A package compiled with cgo will include directives for both
+internal and external linking; the linker will select the appropriate
+subset for the chosen linking mode.
+
+Example
+
+As a simple example, consider a package that uses cgo to call C.sin.
+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
+
+ #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"
+
+ void _cgo_gcc_Cfunc_sin(void*);
+
+ void
+ ·_Cfunc_sin(struct{uint8 x[16];}p)
+ {
+ runtime·cgocall(_cgo_gcc_Cfunc_sin, &p);
+ }
+
+ // compiled by gcc, into foo.cgo2.o
+
+ void
+ _cgo_gcc_Cfunc_sin(void *v)
+ {
+ struct {
+ double p0;
+ double r;
+ } __attribute__((__packed__)) *a = v;
+ a->r = sin(a->p0);
+ }
+
+What happens at link time depends on whether the final binary is linked
+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.
+
+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
+cgo_dynamic_linker directives to learn that the otherwise undefined
+reference to sin in foo.cgo2.o should be rewritten to refer to the
+symbol sin with version GLIBC_2.2.5 from the dynamic library
+"libm.so.6", and the binary should request "/lib/ld-linux.so.2" as its
+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
+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
+creating go.o. Indeed, the definition for _cgo_gcc_Cfunc_sin will be
+provided to the host linker by foo2.cgo.o, which in turn will need the
+symbol 'sin'. 6l also processes the cgo_ldflag directives, so that it
+knows that the eventual host link command must include the -lm
+argument, so that the host linker will be able to find 'sin' in the
+math library.
+
+6l Command Line Interface
+
+The go command and any other Go-aware build systems invoke 6l
+to link a collection of packages into a single binary. By default, 6l will
+present the same interface it does today:
+
+ 6l main.a
+
+produces a file named 6.out, even if 6l does so by invoking the host
+linker in external linking mode.
+
+By default, 6l will decide the linking mode as follows: if the only
+packages using cgo are those on a whitelist of standard library
+packages (net, os/user, runtime/cgo), 6l will use internal linking
+mode. Otherwise, there are non-standard cgo packages involved, and 6l
+will use external linking mode. The first rule means that a build of
+the godoc binary, which uses net but no other cgo, can run without
+needing gcc available. The second rule means that a build of a
+cgo-wrapped library like sqlite3 can generate a standalone executable
+instead of needing to refer to a dynamic library. The specific choice
+can be overridden using a command line flag: 6l -linkmode=internal or
+6l -linkmode=external.
+
+In an external link, 6l will create a temporary directory, write any
+host object files found in package archives to that directory (renamed
+to avoid conflicts), write the go.o file to that directory, and invoke
+the host linker. The default value for the host linker is $CC, split
+into fields, or else "gcc". The specific host linker command line can
+be overridden using command line flags: 6l -extld=clang
+-extldflags='-ggdb -O3'. If any package in a build includes a .cc or
+other file compiled by the C++ compiler, the go tool will use the
+-extld option to set the host linker to the C++ compiler.
+
+These defaults mean that Go-aware build systems can ignore the linking
+changes and keep running plain '6l' and get reasonable results, but
+they can also control the linking details if desired.
+
+*/
diff --git a/libgo/go/cmd/cgo/gcc.go b/libgo/go/cmd/cgo/gcc.go
new file mode 100644
index 0000000000..abdd369d71
--- /dev/null
+++ b/libgo/go/cmd/cgo/gcc.go
@@ -0,0 +1,1753 @@
+// 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.
+
+// Annotate Ref in Prog with C types by parsing gcc debug output.
+// Conversion of debug output to Go types.
+
+package main
+
+import (
+ "bytes"
+ "debug/dwarf"
+ "debug/elf"
+ "debug/macho"
+ "debug/pe"
+ "encoding/binary"
+ "errors"
+ "flag"
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "os"
+ "strconv"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+)
+
+var debugDefine = flag.Bool("debug-define", false, "print relevant #defines")
+var debugGcc = flag.Bool("debug-gcc", false, "print gcc invocations")
+
+var nameToC = map[string]string{
+ "schar": "signed char",
+ "uchar": "unsigned char",
+ "ushort": "unsigned short",
+ "uint": "unsigned int",
+ "ulong": "unsigned long",
+ "longlong": "long long",
+ "ulonglong": "unsigned long long",
+ "complexfloat": "float complex",
+ "complexdouble": "double complex",
+}
+
+// cname returns the C name to use for C.s.
+// The expansions are listed in nameToC and also
+// struct_foo becomes "struct foo", and similarly for
+// union and enum.
+func cname(s string) string {
+ if t, ok := nameToC[s]; ok {
+ return t
+ }
+
+ if strings.HasPrefix(s, "struct_") {
+ return "struct " + s[len("struct_"):]
+ }
+ if strings.HasPrefix(s, "union_") {
+ return "union " + s[len("union_"):]
+ }
+ if strings.HasPrefix(s, "enum_") {
+ return "enum " + s[len("enum_"):]
+ }
+ if strings.HasPrefix(s, "sizeof_") {
+ return "sizeof(" + cname(s[len("sizeof_"):]) + ")"
+ }
+ return s
+}
+
+// DiscardCgoDirectives processes the import C preamble, and discards
+// all #cgo CFLAGS and LDFLAGS directives, so they don't make their
+// way into _cgo_export.h.
+func (f *File) DiscardCgoDirectives() {
+ linesIn := strings.Split(f.Preamble, "\n")
+ linesOut := make([]string, 0, len(linesIn))
+ for _, line := range linesIn {
+ l := strings.TrimSpace(line)
+ if len(l) < 5 || l[:4] != "#cgo" || !unicode.IsSpace(rune(l[4])) {
+ linesOut = append(linesOut, line)
+ } else {
+ linesOut = append(linesOut, "")
+ }
+ }
+ f.Preamble = strings.Join(linesOut, "\n")
+}
+
+// addToFlag appends args to flag. All flags are later written out onto the
+// _cgo_flags file for the build system to use.
+func (p *Package) addToFlag(flag string, args []string) {
+ p.CgoFlags[flag] = append(p.CgoFlags[flag], args...)
+ if flag == "CFLAGS" {
+ // We'll also need these when preprocessing for dwarf information.
+ p.GccOptions = append(p.GccOptions, args...)
+ }
+}
+
+// splitQuoted splits the string s around each instance of one or more consecutive
+// white space characters while taking into account quotes and escaping, and
+// returns an array of substrings of s or an empty list if s contains only white space.
+// Single quotes and double quotes are recognized to prevent splitting within the
+// quoted region, and are removed from the resulting substrings. If a quote in s
+// isn't closed err will be set and r will have the unclosed argument as the
+// last element. The backslash is used for escaping.
+//
+// For example, the following string:
+//
+// `a b:"c d" 'e''f' "g\""`
+//
+// Would be parsed as:
+//
+// []string{"a", "b:c d", "ef", `g"`}
+//
+func splitQuoted(s string) (r []string, err error) {
+ var args []string
+ arg := make([]rune, len(s))
+ escaped := false
+ quoted := false
+ quote := '\x00'
+ i := 0
+ for _, r := range s {
+ switch {
+ case escaped:
+ escaped = false
+ case r == '\\':
+ escaped = true
+ continue
+ case quote != 0:
+ if r == quote {
+ quote = 0
+ continue
+ }
+ case r == '"' || r == '\'':
+ quoted = true
+ quote = r
+ continue
+ case unicode.IsSpace(r):
+ if quoted || i > 0 {
+ quoted = false
+ args = append(args, string(arg[:i]))
+ i = 0
+ }
+ continue
+ }
+ arg[i] = r
+ i++
+ }
+ if quoted || i > 0 {
+ args = append(args, string(arg[:i]))
+ }
+ if quote != 0 {
+ err = errors.New("unclosed quote")
+ } else if escaped {
+ err = errors.New("unfinished escaping")
+ }
+ 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.
+func (p *Package) Translate(f *File) {
+ for _, cref := range f.Ref {
+ // Convert C.ulong to C.unsigned long, etc.
+ cref.Name.C = cname(cref.Name.Go)
+ }
+ p.loadDefines(f)
+ needType := p.guessKinds(f)
+ if len(needType) > 0 {
+ p.loadDWARF(f, needType)
+ }
+ p.rewriteRef(f)
+}
+
+// loadDefines coerces gcc into spitting out the #defines in use
+// in the file f and saves relevant renamings in f.Name[name].Define.
+func (p *Package) loadDefines(f *File) {
+ var b bytes.Buffer
+ b.WriteString(f.Preamble)
+ b.WriteString(builtinProlog)
+ stdout := p.gccDefines(b.Bytes())
+
+ for _, line := range strings.Split(stdout, "\n") {
+ if len(line) < 9 || line[0:7] != "#define" {
+ continue
+ }
+
+ line = strings.TrimSpace(line[8:])
+
+ var key, val string
+ spaceIndex := strings.Index(line, " ")
+ tabIndex := strings.Index(line, "\t")
+
+ if spaceIndex == -1 && tabIndex == -1 {
+ continue
+ } else if tabIndex == -1 || (spaceIndex != -1 && spaceIndex < tabIndex) {
+ key = line[0:spaceIndex]
+ val = strings.TrimSpace(line[spaceIndex:])
+ } else {
+ key = line[0:tabIndex]
+ val = strings.TrimSpace(line[tabIndex:])
+ }
+
+ if n := f.Name[key]; n != nil {
+ if *debugDefine {
+ fmt.Fprintf(os.Stderr, "#define %s %s\n", key, val)
+ }
+ n.Define = val
+ }
+ }
+}
+
+// guessKinds tricks gcc into revealing the kind of each
+// name xxx for the references C.xxx in the Go input.
+// The kind is either a constant, type, or variable.
+func (p *Package) guessKinds(f *File) []*Name {
+ // Determine kinds for names we already know about,
+ // like #defines or 'struct foo', before bothering with gcc.
+ var names, needType []*Name
+ for _, key := range nameKeys(f.Name) {
+ n := f.Name[key]
+ // If we've already found this name as a #define
+ // and we can translate it as a constant value, do so.
+ if n.Define != "" {
+ isConst := false
+ if _, err := strconv.Atoi(n.Define); err == nil {
+ isConst = true
+ } else if n.Define[0] == '"' || n.Define[0] == '\'' {
+ if _, err := parser.ParseExpr(n.Define); err == nil {
+ isConst = true
+ }
+ }
+ if isConst {
+ n.Kind = "const"
+ // Turn decimal into hex, just for consistency
+ // with enum-derived constants. Otherwise
+ // in the cgo -godefs output half the constants
+ // are in hex and half are in whatever the #define used.
+ i, err := strconv.ParseInt(n.Define, 0, 64)
+ if err == nil {
+ n.Const = fmt.Sprintf("%#x", i)
+ } else {
+ n.Const = n.Define
+ }
+ continue
+ }
+
+ if isName(n.Define) {
+ n.C = n.Define
+ }
+ }
+
+ needType = append(needType, n)
+
+ // If this is a struct, union, or enum type name, no need to guess the kind.
+ if strings.HasPrefix(n.C, "struct ") || strings.HasPrefix(n.C, "union ") || strings.HasPrefix(n.C, "enum ") {
+ n.Kind = "type"
+ continue
+ }
+
+ // Otherwise, we'll need to find out from gcc.
+ names = append(names, n)
+ }
+
+ // Bypass gcc if there's nothing left to find out.
+ if len(names) == 0 {
+ return needType
+ }
+
+ // Coerce gcc into telling us whether each name is a type, a value, or undeclared.
+ // For names, find out whether they are integer constants.
+ // We used to look at specific warning or error messages here, but that tied the
+ // behavior too closely to specific versions of the compilers.
+ // Instead, arrange that we can infer what we need from only the presence or absence
+ // of an error on a specific line.
+ //
+ // For each name, we generate these lines, where xxx is the index in toSniff plus one.
+ //
+ // #line xxx "not-declared"
+ // void __cgo_f_xxx_1(void) { __typeof__(name) *__cgo_undefined__; }
+ // #line xxx "not-type"
+ // void __cgo_f_xxx_2(void) { name *__cgo_undefined__; }
+ // #line xxx "not-const"
+ // void __cgo_f_xxx_3(void) { enum { __cgo_undefined__ = (name)*1 }; }
+ //
+ // If we see an error at not-declared:xxx, the corresponding name is not declared.
+ // If we see an error at not-type:xxx, the corresponding name is a type.
+ // If we see an error at not-const:xxx, the corresponding name is not an integer constant.
+ // If we see no errors, we assume the name is an expression but not a constant
+ // (so a variable or a function).
+ //
+ // The specific input forms are chosen so that they are valid C syntax regardless of
+ // whether name denotes a type or an expression.
+
+ var b bytes.Buffer
+ b.WriteString(f.Preamble)
+ b.WriteString(builtinProlog)
+
+ for i, n := range names {
+ fmt.Fprintf(&b, "#line %d \"not-declared\"\n"+
+ "void __cgo_f_%d_1(void) { __typeof__(%s) *__cgo_undefined__; }\n"+
+ "#line %d \"not-type\"\n"+
+ "void __cgo_f_%d_2(void) { %s *__cgo_undefined__; }\n"+
+ "#line %d \"not-const\"\n"+
+ "void __cgo_f_%d_3(void) { enum { __cgo__undefined__ = (%s)*1 }; }\n",
+ i+1, i+1, n.C,
+ i+1, i+1, n.C,
+ i+1, i+1, n.C)
+ }
+ fmt.Fprintf(&b, "#line 1 \"completed\"\n"+
+ "int __cgo__1 = __cgo__2;\n")
+
+ stderr := p.gccErrors(b.Bytes())
+ if stderr == "" {
+ fatalf("%s produced no output\non input:\n%s", p.gccBaseCmd()[0], b.Bytes())
+ }
+
+ completed := false
+ sniff := make([]int, len(names))
+ const (
+ notType = 1 << iota
+ notConst
+ notDeclared
+ )
+ for _, line := range strings.Split(stderr, "\n") {
+ if !strings.Contains(line, ": error:") {
+ // we only care about errors.
+ // we tried to turn off warnings on the command line, but one never knows.
+ continue
+ }
+
+ c1 := strings.Index(line, ":")
+ if c1 < 0 {
+ continue
+ }
+ c2 := strings.Index(line[c1+1:], ":")
+ if c2 < 0 {
+ continue
+ }
+ c2 += c1 + 1
+
+ filename := line[:c1]
+ i, _ := strconv.Atoi(line[c1+1 : c2])
+ i--
+ if i < 0 || i >= len(names) {
+ continue
+ }
+
+ switch filename {
+ case "completed":
+ // Strictly speaking, there is no guarantee that seeing the error at completed:1
+ // (at the end of the file) means we've seen all the errors from earlier in the file,
+ // but usually it does. Certainly if we don't see the completed:1 error, we did
+ // not get all the errors we expected.
+ completed = true
+
+ case "not-declared":
+ sniff[i] |= notDeclared
+ case "not-type":
+ sniff[i] |= notType
+ case "not-const":
+ sniff[i] |= notConst
+ }
+ }
+
+ if !completed {
+ fatalf("%s did not produce error at completed:1\non input:\n%s\nfull error output:\n%s", p.gccBaseCmd()[0], b.Bytes(), stderr)
+ }
+
+ for i, n := range names {
+ switch sniff[i] {
+ default:
+ error_(token.NoPos, "could not determine kind of name for C.%s", fixGo(n.Go))
+ case notType:
+ n.Kind = "const"
+ case notConst:
+ n.Kind = "type"
+ case notConst | notType:
+ n.Kind = "not-type"
+ }
+ }
+ if nerrors > 0 {
+ // Check if compiling the preamble by itself causes any errors,
+ // because the messages we've printed out so far aren't helpful
+ // to users debugging preamble mistakes. See issue 8442.
+ preambleErrors := p.gccErrors([]byte(f.Preamble))
+ if len(preambleErrors) > 0 {
+ error_(token.NoPos, "\n%s errors for preamble:\n%s", p.gccBaseCmd()[0], preambleErrors)
+ }
+
+ fatalf("unresolved names")
+ }
+
+ needType = append(needType, names...)
+ return needType
+}
+
+// loadDWARF parses the DWARF debug information generated
+// by gcc to learn the details of the constants, variables, and types
+// being referred to as C.xxx.
+func (p *Package) loadDWARF(f *File, names []*Name) {
+ // Extract the types from the DWARF section of an object
+ // from a well-formed C program. Gcc only generates DWARF info
+ // for symbols in the object file, so it is not enough to print the
+ // preamble and hope the symbols we care about will be there.
+ // Instead, emit
+ // __typeof__(names[i]) *__cgo__i;
+ // for each entry in names and then dereference the type we
+ // learn for __cgo__i.
+ var b bytes.Buffer
+ b.WriteString(f.Preamble)
+ b.WriteString(builtinProlog)
+ for i, n := range names {
+ fmt.Fprintf(&b, "__typeof__(%s) *__cgo__%d;\n", n.C, i)
+ if n.Kind == "const" {
+ fmt.Fprintf(&b, "enum { __cgo_enum__%d = %s };\n", i, n.C)
+ }
+ }
+
+ // Apple's LLVM-based gcc does not include the enumeration
+ // names and values in its DWARF debug output. In case we're
+ // using such a gcc, create a data block initialized with the values.
+ // We can read them out of the object file.
+ fmt.Fprintf(&b, "long long __cgodebug_data[] = {\n")
+ for _, n := range names {
+ if n.Kind == "const" {
+ fmt.Fprintf(&b, "\t%s,\n", n.C)
+ } else {
+ fmt.Fprintf(&b, "\t0,\n")
+ }
+ }
+ // for the last entry, we can not use 0, otherwise
+ // in case all __cgodebug_data is zero initialized,
+ // LLVM-based gcc will place the it in the __DATA.__common
+ // zero-filled section (our debug/macho doesn't support
+ // this)
+ fmt.Fprintf(&b, "\t1\n")
+ fmt.Fprintf(&b, "};\n")
+
+ d, bo, debugData := p.gccDebug(b.Bytes())
+ enumVal := make([]int64, len(debugData)/8)
+ for i := range enumVal {
+ enumVal[i] = int64(bo.Uint64(debugData[i*8:]))
+ }
+
+ // Scan DWARF info for top-level TagVariable entries with AttrName __cgo__i.
+ types := make([]dwarf.Type, len(names))
+ enums := make([]dwarf.Offset, len(names))
+ nameToIndex := make(map[*Name]int)
+ for i, n := range names {
+ nameToIndex[n] = i
+ }
+ nameToRef := make(map[*Name]*Ref)
+ for _, ref := range f.Ref {
+ nameToRef[ref.Name] = ref
+ }
+ r := d.Reader()
+ for {
+ e, err := r.Next()
+ if err != nil {
+ fatalf("reading DWARF entry: %s", err)
+ }
+ if e == nil {
+ break
+ }
+ switch e.Tag {
+ case dwarf.TagEnumerationType:
+ offset := e.Offset
+ for {
+ e, err := r.Next()
+ if err != nil {
+ fatalf("reading DWARF entry: %s", err)
+ }
+ if e.Tag == 0 {
+ break
+ }
+ if e.Tag == dwarf.TagEnumerator {
+ entryName := e.Val(dwarf.AttrName).(string)
+ if strings.HasPrefix(entryName, "__cgo_enum__") {
+ n, _ := strconv.Atoi(entryName[len("__cgo_enum__"):])
+ if 0 <= n && n < len(names) {
+ enums[n] = offset
+ }
+ }
+ }
+ }
+ case dwarf.TagVariable:
+ name, _ := e.Val(dwarf.AttrName).(string)
+ typOff, _ := e.Val(dwarf.AttrType).(dwarf.Offset)
+ if name == "" || typOff == 0 {
+ fatalf("malformed DWARF TagVariable entry")
+ }
+ if !strings.HasPrefix(name, "__cgo__") {
+ break
+ }
+ typ, err := d.Type(typOff)
+ if err != nil {
+ fatalf("loading DWARF type: %s", err)
+ }
+ t, ok := typ.(*dwarf.PtrType)
+ if !ok || t == nil {
+ fatalf("internal error: %s has non-pointer type", name)
+ }
+ i, err := strconv.Atoi(name[7:])
+ if err != nil {
+ fatalf("malformed __cgo__ name: %s", name)
+ }
+ if enums[i] != 0 {
+ t, err := d.Type(enums[i])
+ if err != nil {
+ fatalf("loading DWARF type: %s", err)
+ }
+ types[i] = t
+ } else {
+ types[i] = t.Type
+ }
+ }
+ if e.Tag != dwarf.TagCompileUnit {
+ r.SkipChildren()
+ }
+ }
+
+ // Record types and typedef information.
+ var conv typeConv
+ conv.Init(p.PtrSize, p.IntSize)
+ for i, n := range names {
+ if types[i] == nil {
+ continue
+ }
+ pos := token.NoPos
+ if ref, ok := nameToRef[n]; ok {
+ pos = ref.Pos()
+ }
+ f, fok := types[i].(*dwarf.FuncType)
+ if n.Kind != "type" && fok {
+ n.Kind = "func"
+ n.FuncType = conv.FuncType(f, pos)
+ } else {
+ n.Type = conv.Type(types[i], pos)
+ if enums[i] != 0 && n.Type.EnumValues != nil {
+ k := fmt.Sprintf("__cgo_enum__%d", i)
+ n.Kind = "const"
+ n.Const = fmt.Sprintf("%#x", n.Type.EnumValues[k])
+ // Remove injected enum to ensure the value will deep-compare
+ // equally in future loads of the same constant.
+ delete(n.Type.EnumValues, k)
+ }
+ // Prefer debug data over DWARF debug output, if we have it.
+ if n.Kind == "const" && i < len(enumVal) {
+ n.Const = fmt.Sprintf("%#x", enumVal[i])
+ }
+ }
+ conv.FinishType(pos)
+ }
+}
+
+// mangleName does name mangling to translate names
+// from the original Go source files to the names
+// used in the final Go files generated by cgo.
+func (p *Package) mangleName(n *Name) {
+ // When using gccgo variables have to be
+ // exported so that they become global symbols
+ // that the C code can refer to.
+ prefix := "_C"
+ if *gccgo && n.IsVar() {
+ prefix = "C"
+ }
+ n.Mangle = prefix + n.Kind + "_" + n.Go
+}
+
+// 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
+// with full definitions instead of mangled names.
+func (p *Package) rewriteRef(f *File) {
+ // Keep a list of all the functions, to remove the ones
+ // only used as expressions and avoid generating bridge
+ // code for them.
+ functions := make(map[string]bool)
+
+ // Assign mangled names.
+ for _, n := range f.Name {
+ if n.Kind == "not-type" {
+ n.Kind = "var"
+ }
+ if n.Mangle == "" {
+ p.mangleName(n)
+ }
+ if n.Kind == "func" {
+ functions[n.Go] = false
+ }
+ }
+
+ // Now that we have all the name types filled in,
+ // scan through the Refs to identify the ones that
+ // are trying to do a ,err call. Also check that
+ // functions are only used in calls.
+ for _, r := range f.Ref {
+ if r.Name.Kind == "const" && r.Name.Const == "" {
+ error_(r.Pos(), "unable to find value of constant C.%s", fixGo(r.Name.Go))
+ }
+ var expr ast.Expr = ast.NewIdent(r.Name.Mangle) // default
+ switch r.Context {
+ case "call", "call2":
+ if r.Name.Kind != "func" {
+ if r.Name.Kind == "type" {
+ r.Context = "type"
+ expr = r.Name.Type.Go
+ break
+ }
+ error_(r.Pos(), "call of non-function C.%s", fixGo(r.Name.Go))
+ break
+ }
+ functions[r.Name.Go] = true
+ if r.Context == "call2" {
+ if r.Name.Go == "_CMalloc" {
+ error_(r.Pos(), "no two-result form for C.malloc")
+ break
+ }
+ // Invent new Name for the two-result function.
+ n := f.Name["2"+r.Name.Go]
+ if n == nil {
+ n = new(Name)
+ *n = *r.Name
+ n.AddError = true
+ n.Mangle = "_C2func_" + n.Go
+ f.Name["2"+r.Name.Go] = n
+ }
+ expr = ast.NewIdent(n.Mangle)
+ r.Name = n
+ break
+ }
+ case "expr":
+ if r.Name.Kind == "func" {
+ // Function is being used in an expression, to e.g. pass around a C function pointer.
+ // Create a new Name for this Ref which causes the variable to be declared in Go land.
+ fpName := "fp_" + r.Name.Go
+ name := f.Name[fpName]
+ if name == nil {
+ name = &Name{
+ Go: fpName,
+ C: r.Name.C,
+ Kind: "fpvar",
+ Type: &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*"), Go: ast.NewIdent("unsafe.Pointer")},
+ }
+ p.mangleName(name)
+ f.Name[fpName] = name
+ }
+ r.Name = name
+ // Rewrite into call to _Cgo_ptr to prevent assignments. The _Cgo_ptr
+ // function is defined in out.go and simply returns its argument. See
+ // issue 7757.
+ expr = &ast.CallExpr{
+ Fun: &ast.Ident{NamePos: (*r.Expr).Pos(), Name: "_Cgo_ptr"},
+ Args: []ast.Expr{ast.NewIdent(name.Mangle)},
+ }
+ } else if r.Name.Kind == "type" {
+ // Okay - might be new(T)
+ expr = r.Name.Type.Go
+ } else if r.Name.Kind == "var" {
+ expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
+ }
+
+ case "type":
+ if r.Name.Kind != "type" {
+ error_(r.Pos(), "expression C.%s used as type", fixGo(r.Name.Go))
+ } else if r.Name.Type == nil {
+ // Use of C.enum_x, C.struct_x or C.union_x without C definition.
+ // GCC won't raise an error when using pointers to such unknown types.
+ error_(r.Pos(), "type C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
+ } else {
+ expr = r.Name.Type.Go
+ }
+ default:
+ if r.Name.Kind == "func" {
+ error_(r.Pos(), "must call C.%s", fixGo(r.Name.Go))
+ }
+ }
+ if *godefs || *cdefs {
+ // Substitute definition for mangled type name.
+ if id, ok := expr.(*ast.Ident); ok {
+ if t := typedef[id.Name]; t != nil {
+ expr = t.Go
+ }
+ if id.Name == r.Name.Mangle && r.Name.Const != "" {
+ expr = ast.NewIdent(r.Name.Const)
+ }
+ }
+ }
+
+ // Copy position information from old expr into new expr,
+ // in case expression being replaced is first on line.
+ // See golang.org/issue/6563.
+ pos := (*r.Expr).Pos()
+ switch x := expr.(type) {
+ case *ast.Ident:
+ expr = &ast.Ident{NamePos: pos, Name: x.Name}
+ }
+
+ *r.Expr = expr
+ }
+
+ // Remove functions only used as expressions, so their respective
+ // bridge functions are not generated.
+ for name, used := range functions {
+ if !used {
+ delete(f.Name, name)
+ }
+ }
+}
+
+// gccBaseCmd returns the start of the compiler command line.
+// It uses $CC if set, or else $GCC, or else the compiler recorded
+// during the initial build as defaultCC.
+// defaultCC is defined in zdefaultcc.go, written by cmd/dist.
+func (p *Package) gccBaseCmd() []string {
+ // Use $CC if set, since that's what the build uses.
+ if ret := strings.Fields(os.Getenv("CC")); len(ret) > 0 {
+ return ret
+ }
+ // Try $GCC if set, since that's what we used to use.
+ if ret := strings.Fields(os.Getenv("GCC")); len(ret) > 0 {
+ return ret
+ }
+ return strings.Fields(defaultCC)
+}
+
+// gccMachine returns the gcc -m flag to use, either "-m32", "-m64" or "-marm".
+func (p *Package) gccMachine() []string {
+ switch goarch {
+ case "amd64":
+ return []string{"-m64"}
+ case "386":
+ return []string{"-m32"}
+ case "arm":
+ return []string{"-marm"} // not thumb
+ }
+ return nil
+}
+
+func gccTmp() string {
+ return *objDir + "_cgo_.o"
+}
+
+// gccCmd returns the gcc command line to use for compiling
+// the input.
+func (p *Package) gccCmd() []string {
+ c := append(p.gccBaseCmd(),
+ "-w", // no warnings
+ "-Wno-error", // warnings are not errors
+ "-o"+gccTmp(), // write object to tmp
+ "-gdwarf-2", // generate DWARF v2 debugging symbols
+ "-c", // do not link
+ "-xc", // input language is C
+ )
+ if strings.Contains(c[0], "clang") {
+ c = append(c,
+ "-ferror-limit=0",
+ // Apple clang version 1.7 (tags/Apple/clang-77) (based on LLVM 2.9svn)
+ // doesn't have -Wno-unneeded-internal-declaration, so we need yet another
+ // flag to disable the warning. Yes, really good diagnostics, clang.
+ "-Wno-unknown-warning-option",
+ "-Wno-unneeded-internal-declaration",
+ "-Wno-unused-function",
+ "-Qunused-arguments",
+ // Clang embeds prototypes for some builtin functions,
+ // like malloc and calloc, but all size_t parameters are
+ // 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.
+ "-fno-builtin",
+ )
+ }
+
+ c = append(c, p.GccOptions...)
+ c = append(c, p.gccMachine()...)
+ c = append(c, "-") //read input from standard input
+ return c
+}
+
+// gccDebug runs gcc -gdwarf-2 over the C program stdin and
+// returns the corresponding DWARF data and, if present, debug data block.
+func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte) {
+ runGcc(stdin, p.gccCmd())
+
+ isDebugData := func(s string) bool {
+ // Some systems use leading _ to denote non-assembly symbols.
+ return s == "__cgodebug_data" || s == "___cgodebug_data"
+ }
+
+ if f, err := macho.Open(gccTmp()); err == nil {
+ defer f.Close()
+ d, err := f.DWARF()
+ if err != nil {
+ fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
+ }
+ var data []byte
+ if f.Symtab != nil {
+ for i := range f.Symtab.Syms {
+ s := &f.Symtab.Syms[i]
+ if isDebugData(s.Name) {
+ // Found it. Now find data section.
+ if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) {
+ sect := f.Sections[i]
+ if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
+ if sdat, err := sect.Data(); err == nil {
+ data = sdat[s.Value-sect.Addr:]
+ }
+ }
+ }
+ }
+ }
+ }
+ return d, f.ByteOrder, data
+ }
+
+ if f, err := elf.Open(gccTmp()); err == nil {
+ defer f.Close()
+ d, err := f.DWARF()
+ if err != nil {
+ fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
+ }
+ var data []byte
+ symtab, err := f.Symbols()
+ if err == nil {
+ for i := range symtab {
+ s := &symtab[i]
+ if isDebugData(s.Name) {
+ // Found it. Now find data section.
+ if i := int(s.Section); 0 <= i && i < len(f.Sections) {
+ sect := f.Sections[i]
+ if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
+ if sdat, err := sect.Data(); err == nil {
+ data = sdat[s.Value-sect.Addr:]
+ }
+ }
+ }
+ }
+ }
+ }
+ return d, f.ByteOrder, data
+ }
+
+ if f, err := pe.Open(gccTmp()); err == nil {
+ defer f.Close()
+ d, err := f.DWARF()
+ if err != nil {
+ fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
+ }
+ var data []byte
+ for _, s := range f.Symbols {
+ if isDebugData(s.Name) {
+ if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
+ sect := f.Sections[i]
+ if s.Value < sect.Size {
+ if sdat, err := sect.Data(); err == nil {
+ data = sdat[s.Value:]
+ }
+ }
+ }
+ }
+ }
+ return d, binary.LittleEndian, data
+ }
+
+ fatalf("cannot parse gcc output %s as ELF, Mach-O, PE object", gccTmp())
+ panic("not reached")
+}
+
+// gccDefines runs gcc -E -dM -xc - over the C program stdin
+// and returns the corresponding standard output, which is the
+// #defines that gcc encountered while processing the input
+// and its included files.
+func (p *Package) gccDefines(stdin []byte) string {
+ base := append(p.gccBaseCmd(), "-E", "-dM", "-xc")
+ base = append(base, p.gccMachine()...)
+ stdout, _ := runGcc(stdin, append(append(base, p.GccOptions...), "-"))
+ return stdout
+}
+
+// gccErrors runs gcc over the C program stdin and returns
+// the errors that gcc prints. That is, this function expects
+// gcc to fail.
+func (p *Package) gccErrors(stdin []byte) string {
+ // TODO(rsc): require failure
+ args := p.gccCmd()
+
+ if *debugGcc {
+ fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " "))
+ os.Stderr.Write(stdin)
+ fmt.Fprint(os.Stderr, "EOF\n")
+ }
+ stdout, stderr, _ := run(stdin, args)
+ if *debugGcc {
+ os.Stderr.Write(stdout)
+ os.Stderr.Write(stderr)
+ }
+ return string(stderr)
+}
+
+// runGcc runs the gcc command line args with stdin on standard input.
+// If the command exits with a non-zero exit status, runGcc prints
+// details about what was run and exits.
+// Otherwise runGcc returns the data written to standard output and standard error.
+// Note that for some of the uses we expect useful data back
+// on standard error, but for those uses gcc must still exit 0.
+func runGcc(stdin []byte, args []string) (string, string) {
+ if *debugGcc {
+ fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " "))
+ os.Stderr.Write(stdin)
+ fmt.Fprint(os.Stderr, "EOF\n")
+ }
+ stdout, stderr, ok := run(stdin, args)
+ if *debugGcc {
+ os.Stderr.Write(stdout)
+ os.Stderr.Write(stderr)
+ }
+ if !ok {
+ os.Stderr.Write(stderr)
+ os.Exit(2)
+ }
+ return string(stdout), string(stderr)
+}
+
+// A typeConv is a translator from dwarf types to Go types
+// with equivalent memory layout.
+type typeConv struct {
+ // Cache of already-translated or in-progress types.
+ m map[dwarf.Type]*Type
+ typedef map[string]ast.Expr
+
+ // Map from types to incomplete pointers to those types.
+ ptrs map[dwarf.Type][]*Type
+ // Keys of ptrs in insertion order (deterministic worklist)
+ ptrKeys []dwarf.Type
+
+ // Predeclared types.
+ bool ast.Expr
+ byte ast.Expr // denotes padding
+ int8, int16, int32, int64 ast.Expr
+ uint8, uint16, uint32, uint64, uintptr ast.Expr
+ float32, float64 ast.Expr
+ complex64, complex128 ast.Expr
+ void ast.Expr
+ string ast.Expr
+ goVoid ast.Expr // _Ctype_void, denotes C's void
+ goVoidPtr ast.Expr // unsafe.Pointer or *byte
+
+ ptrSize int64
+ intSize int64
+}
+
+var tagGen int
+var typedef = make(map[string]*Type)
+var goIdent = make(map[string]*ast.Ident)
+
+func (c *typeConv) Init(ptrSize, intSize int64) {
+ c.ptrSize = ptrSize
+ c.intSize = intSize
+ c.m = make(map[dwarf.Type]*Type)
+ c.ptrs = make(map[dwarf.Type][]*Type)
+ c.bool = c.Ident("bool")
+ c.byte = c.Ident("byte")
+ c.int8 = c.Ident("int8")
+ c.int16 = c.Ident("int16")
+ c.int32 = c.Ident("int32")
+ c.int64 = c.Ident("int64")
+ c.uint8 = c.Ident("uint8")
+ c.uint16 = c.Ident("uint16")
+ c.uint32 = c.Ident("uint32")
+ c.uint64 = c.Ident("uint64")
+ c.uintptr = c.Ident("uintptr")
+ c.float32 = c.Ident("float32")
+ c.float64 = c.Ident("float64")
+ c.complex64 = c.Ident("complex64")
+ c.complex128 = c.Ident("complex128")
+ c.void = c.Ident("void")
+ c.string = c.Ident("string")
+ 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 {
+ c.goVoidPtr = &ast.StarExpr{X: c.byte}
+ } else {
+ c.goVoidPtr = c.Ident("unsafe.Pointer")
+ }
+}
+
+// base strips away qualifiers and typedefs to get the underlying type
+func base(dt dwarf.Type) dwarf.Type {
+ for {
+ if d, ok := dt.(*dwarf.QualType); ok {
+ dt = d.Type
+ continue
+ }
+ if d, ok := dt.(*dwarf.TypedefType); ok {
+ dt = d.Type
+ continue
+ }
+ break
+ }
+ return dt
+}
+
+// Map from dwarf text names to aliases we use in package "C".
+var dwarfToName = map[string]string{
+ "long int": "long",
+ "long unsigned int": "ulong",
+ "unsigned int": "uint",
+ "short unsigned int": "ushort",
+ "short int": "short",
+ "long long int": "longlong",
+ "long long unsigned int": "ulonglong",
+ "signed char": "schar",
+ "float complex": "complexfloat",
+ "double complex": "complexdouble",
+}
+
+const signedDelta = 64
+
+// String returns the current type representation. Format arguments
+// are assembled within this method so that any changes in mutable
+// values are taken into account.
+func (tr *TypeRepr) String() string {
+ if len(tr.Repr) == 0 {
+ return ""
+ }
+ if len(tr.FormatArgs) == 0 {
+ return tr.Repr
+ }
+ return fmt.Sprintf(tr.Repr, tr.FormatArgs...)
+}
+
+// Empty returns true if the result of String would be "".
+func (tr *TypeRepr) Empty() bool {
+ return len(tr.Repr) == 0
+}
+
+// Set modifies the type representation.
+// If fargs are provided, repr is used as a format for fmt.Sprintf.
+// Otherwise, repr is used unprocessed as the type representation.
+func (tr *TypeRepr) Set(repr string, fargs ...interface{}) {
+ tr.Repr = repr
+ tr.FormatArgs = fargs
+}
+
+// FinishType completes any outstanding type mapping work.
+// In particular, it resolves incomplete pointer types.
+func (c *typeConv) FinishType(pos token.Pos) {
+ // Completing one pointer type might produce more to complete.
+ // Keep looping until they're all done.
+ for len(c.ptrKeys) > 0 {
+ dtype := c.ptrKeys[0]
+ c.ptrKeys = c.ptrKeys[1:]
+
+ // Note Type might invalidate c.ptrs[dtype].
+ t := c.Type(dtype, pos)
+ for _, ptr := range c.ptrs[dtype] {
+ ptr.Go.(*ast.StarExpr).X = t.Go
+ ptr.C.Set("%s*", t.C)
+ }
+ c.ptrs[dtype] = nil // retain the map key
+ }
+}
+
+// Type returns a *Type with the same memory layout as
+// dtype when used as the type of a variable or a struct field.
+func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
+ if t, ok := c.m[dtype]; ok {
+ if t.Go == nil {
+ fatalf("%s: type conversion loop at %s", lineno(pos), dtype)
+ }
+ return t
+ }
+
+ t := new(Type)
+ t.Size = dtype.Size() // note: wrong for array of pointers, corrected below
+ t.Align = -1
+ t.C = &TypeRepr{Repr: dtype.Common().Name}
+ c.m[dtype] = t
+
+ switch dt := dtype.(type) {
+ default:
+ fatalf("%s: unexpected type: %s", lineno(pos), dtype)
+
+ case *dwarf.AddrType:
+ if t.Size != c.ptrSize {
+ fatalf("%s: unexpected: %d-byte address type - %s", lineno(pos), t.Size, dtype)
+ }
+ t.Go = c.uintptr
+ t.Align = t.Size
+
+ case *dwarf.ArrayType:
+ if dt.StrideBitSize > 0 {
+ // Cannot represent bit-sized elements in Go.
+ t.Go = c.Opaque(t.Size)
+ break
+ }
+ count := dt.Count
+ if count == -1 {
+ // Indicates flexible array member, which Go doesn't support.
+ // Translate to zero-length array instead.
+ count = 0
+ }
+ sub := c.Type(dt.Type, pos)
+ t.Align = sub.Align
+ t.Go = &ast.ArrayType{
+ Len: c.intExpr(count),
+ Elt: sub.Go,
+ }
+ // Recalculate t.Size now that we know sub.Size.
+ t.Size = count * sub.Size
+ t.C.Set("__typeof__(%s[%d])", sub.C, dt.Count)
+
+ case *dwarf.BoolType:
+ t.Go = c.bool
+ t.Align = 1
+
+ case *dwarf.CharType:
+ if t.Size != 1 {
+ fatalf("%s: unexpected: %d-byte char type - %s", lineno(pos), t.Size, dtype)
+ }
+ t.Go = c.int8
+ t.Align = 1
+
+ case *dwarf.EnumType:
+ if t.Align = t.Size; t.Align >= c.ptrSize {
+ t.Align = c.ptrSize
+ }
+ t.C.Set("enum " + dt.EnumName)
+ signed := 0
+ t.EnumValues = make(map[string]int64)
+ for _, ev := range dt.Val {
+ t.EnumValues[ev.Name] = ev.Val
+ if ev.Val < 0 {
+ signed = signedDelta
+ }
+ }
+ switch t.Size + int64(signed) {
+ default:
+ fatalf("%s: unexpected: %d-byte enum type - %s", lineno(pos), t.Size, dtype)
+ case 1:
+ t.Go = c.uint8
+ case 2:
+ t.Go = c.uint16
+ case 4:
+ t.Go = c.uint32
+ case 8:
+ t.Go = c.uint64
+ case 1 + signedDelta:
+ t.Go = c.int8
+ case 2 + signedDelta:
+ t.Go = c.int16
+ case 4 + signedDelta:
+ t.Go = c.int32
+ case 8 + signedDelta:
+ t.Go = c.int64
+ }
+
+ case *dwarf.FloatType:
+ switch t.Size {
+ default:
+ fatalf("%s: unexpected: %d-byte float type - %s", lineno(pos), t.Size, dtype)
+ case 4:
+ t.Go = c.float32
+ case 8:
+ t.Go = c.float64
+ }
+ if t.Align = t.Size; t.Align >= c.ptrSize {
+ t.Align = c.ptrSize
+ }
+
+ case *dwarf.ComplexType:
+ switch t.Size {
+ default:
+ fatalf("%s: unexpected: %d-byte complex type - %s", lineno(pos), t.Size, dtype)
+ case 8:
+ t.Go = c.complex64
+ case 16:
+ t.Go = c.complex128
+ }
+ if t.Align = t.Size; t.Align >= c.ptrSize {
+ t.Align = c.ptrSize
+ }
+
+ case *dwarf.FuncType:
+ // No attempt at translation: would enable calls
+ // directly between worlds, but we need to moderate those.
+ t.Go = c.uintptr
+ t.Align = c.ptrSize
+
+ case *dwarf.IntType:
+ if dt.BitSize > 0 {
+ fatalf("%s: unexpected: %d-bit int type - %s", lineno(pos), dt.BitSize, dtype)
+ }
+ switch t.Size {
+ default:
+ fatalf("%s: unexpected: %d-byte int type - %s", lineno(pos), t.Size, dtype)
+ case 1:
+ t.Go = c.int8
+ case 2:
+ t.Go = c.int16
+ case 4:
+ t.Go = c.int32
+ case 8:
+ t.Go = c.int64
+ }
+ if t.Align = t.Size; t.Align >= c.ptrSize {
+ t.Align = c.ptrSize
+ }
+
+ case *dwarf.PtrType:
+ // Clang doesn't emit DW_AT_byte_size for pointer types.
+ if t.Size != c.ptrSize && t.Size != -1 {
+ fatalf("%s: unexpected: %d-byte pointer type - %s", lineno(pos), t.Size, dtype)
+ }
+ t.Size = c.ptrSize
+ t.Align = c.ptrSize
+
+ if _, ok := base(dt.Type).(*dwarf.VoidType); ok {
+ t.Go = c.goVoidPtr
+ t.C.Set("void*")
+ break
+ }
+
+ // Placeholder initialization; completed in FinishType.
+ t.Go = &ast.StarExpr{}
+ t.C.Set("<incomplete>*")
+ if _, ok := c.ptrs[dt.Type]; !ok {
+ c.ptrKeys = append(c.ptrKeys, dt.Type)
+ }
+ c.ptrs[dt.Type] = append(c.ptrs[dt.Type], t)
+
+ case *dwarf.QualType:
+ // Ignore qualifier.
+ t = c.Type(dt.Type, pos)
+ c.m[dtype] = t
+ return t
+
+ case *dwarf.StructType:
+ // Convert to Go struct, being careful about alignment.
+ // Have to give it a name to simulate C "struct foo" references.
+ tag := dt.StructName
+ if dt.ByteSize < 0 && tag == "" { // opaque unnamed struct - should not be possible
+ break
+ }
+ if tag == "" {
+ tag = "__" + strconv.Itoa(tagGen)
+ tagGen++
+ } else if t.C.Empty() {
+ t.C.Set(dt.Kind + " " + tag)
+ }
+ name := c.Ident("_Ctype_" + dt.Kind + "_" + tag)
+ t.Go = name // publish before recursive calls
+ goIdent[name.Name] = name
+ if dt.ByteSize < 0 {
+ // Size calculation in c.Struct/c.Opaque will die with size=-1 (unknown),
+ // so execute the basic things that the struct case would do
+ // other than try to determine a Go representation.
+ tt := *t
+ tt.C = &TypeRepr{"%s %s", []interface{}{dt.Kind, tag}}
+ tt.Go = c.Ident("struct{}")
+ typedef[name.Name] = &tt
+ break
+ }
+ switch dt.Kind {
+ case "class", "union":
+ t.Go = c.Opaque(t.Size)
+ if t.C.Empty() {
+ t.C.Set("__typeof__(unsigned char[%d])", t.Size)
+ }
+ t.Align = 1 // TODO: should probably base this on field alignment.
+ typedef[name.Name] = t
+ case "struct":
+ g, csyntax, align := c.Struct(dt, pos)
+ if t.C.Empty() {
+ t.C.Set(csyntax)
+ }
+ t.Align = align
+ tt := *t
+ if tag != "" {
+ tt.C = &TypeRepr{"struct %s", []interface{}{tag}}
+ }
+ tt.Go = g
+ typedef[name.Name] = &tt
+ }
+
+ case *dwarf.TypedefType:
+ // Record typedef for printing.
+ if dt.Name == "_GoString_" {
+ // Special C name for Go string type.
+ // Knows string layout used by compilers: pointer plus length,
+ // which rounds up to 2 pointers after alignment.
+ t.Go = c.string
+ t.Size = c.ptrSize * 2
+ t.Align = c.ptrSize
+ break
+ }
+ if dt.Name == "_GoBytes_" {
+ // Special C name for Go []byte type.
+ // Knows slice layout used by compilers: pointer, length, cap.
+ t.Go = c.Ident("[]byte")
+ t.Size = c.ptrSize + 4 + 4
+ t.Align = c.ptrSize
+ break
+ }
+ name := c.Ident("_Ctype_" + dt.Name)
+ goIdent[name.Name] = name
+ sub := c.Type(dt.Type, pos)
+ t.Go = name
+ t.Size = sub.Size
+ t.Align = sub.Align
+ oldType := typedef[name.Name]
+ if oldType == nil {
+ tt := *t
+ tt.Go = sub.Go
+ typedef[name.Name] = &tt
+ }
+
+ // 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 {
+ t.Go = sub.Go
+
+ if isStructUnionClass(sub.Go) {
+ // Use the typedef name for C code.
+ typedef[sub.Go.(*ast.Ident).Name].C = t.C
+ }
+
+ // If we've seen this typedef before, and it
+ // was an anonymous struct/union/class before
+ // too, use the old definition.
+ // TODO: it would be safer to only do this if
+ // we verify that the types are the same.
+ if oldType != nil && isStructUnionClass(oldType.Go) {
+ t.Go = oldType.Go
+ }
+ }
+
+ case *dwarf.UcharType:
+ if t.Size != 1 {
+ fatalf("%s: unexpected: %d-byte uchar type - %s", lineno(pos), t.Size, dtype)
+ }
+ t.Go = c.uint8
+ t.Align = 1
+
+ case *dwarf.UintType:
+ if dt.BitSize > 0 {
+ fatalf("%s: unexpected: %d-bit uint type - %s", lineno(pos), dt.BitSize, dtype)
+ }
+ switch t.Size {
+ default:
+ fatalf("%s: unexpected: %d-byte uint type - %s", lineno(pos), t.Size, dtype)
+ case 1:
+ t.Go = c.uint8
+ case 2:
+ t.Go = c.uint16
+ case 4:
+ t.Go = c.uint32
+ case 8:
+ t.Go = c.uint64
+ }
+ if t.Align = t.Size; t.Align >= c.ptrSize {
+ t.Align = c.ptrSize
+ }
+
+ case *dwarf.VoidType:
+ t.Go = c.goVoid
+ t.C.Set("void")
+ t.Align = 1
+ }
+
+ switch dtype.(type) {
+ case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.IntType, *dwarf.FloatType, *dwarf.UcharType, *dwarf.UintType:
+ s := dtype.Common().Name
+ if s != "" {
+ if ss, ok := dwarfToName[s]; ok {
+ s = ss
+ }
+ s = strings.Join(strings.Split(s, " "), "") // strip spaces
+ name := c.Ident("_Ctype_" + s)
+ tt := *t
+ typedef[name.Name] = &tt
+ if !*godefs && !*cdefs {
+ t.Go = name
+ }
+ }
+ }
+
+ if t.Size < 0 {
+ // Unsized types are [0]byte, unless they're typedefs of other types
+ // or structs with tags.
+ // if so, use the name we've already defined.
+ t.Size = 0
+ switch dt := dtype.(type) {
+ case *dwarf.TypedefType:
+ // ok
+ case *dwarf.StructType:
+ if dt.StructName != "" {
+ break
+ }
+ t.Go = c.Opaque(0)
+ default:
+ t.Go = c.Opaque(0)
+ }
+ if t.C.Empty() {
+ t.C.Set("void")
+ }
+ }
+
+ if t.C.Empty() {
+ fatalf("%s: internal error: did not create C name for %s", lineno(pos), dtype)
+ }
+
+ return t
+}
+
+// isStructUnionClass reports whether the type described by the Go syntax x
+// is a struct, union, or class with a tag.
+func isStructUnionClass(x ast.Expr) bool {
+ id, ok := x.(*ast.Ident)
+ if !ok {
+ return false
+ }
+ name := id.Name
+ return strings.HasPrefix(name, "_Ctype_struct_") ||
+ strings.HasPrefix(name, "_Ctype_union_") ||
+ strings.HasPrefix(name, "_Ctype_class_")
+}
+
+// FuncArg returns a Go type with the same memory layout as
+// dtype when used as the type of a C function argument.
+func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type {
+ t := c.Type(dtype, pos)
+ switch dt := dtype.(type) {
+ case *dwarf.ArrayType:
+ // Arrays are passed implicitly as pointers in C.
+ // In Go, we must be explicit.
+ tr := &TypeRepr{}
+ tr.Set("%s*", t.C)
+ return &Type{
+ Size: c.ptrSize,
+ Align: c.ptrSize,
+ Go: &ast.StarExpr{X: t.Go},
+ C: tr,
+ }
+ case *dwarf.TypedefType:
+ // C has much more relaxed rules than Go for
+ // implicit type conversions. When the parameter
+ // is type T defined as *X, simulate a little of the
+ // laxness of C by making the argument *X instead of T.
+ if ptr, ok := base(dt.Type).(*dwarf.PtrType); ok {
+ // Unless the typedef happens to point to void* since
+ // Go has special rules around using unsafe.Pointer.
+ if _, void := base(ptr.Type).(*dwarf.VoidType); void {
+ break
+ }
+
+ t = c.Type(ptr, pos)
+ if t == nil {
+ return nil
+ }
+
+ // Remember the C spelling, in case the struct
+ // has __attribute__((unavailable)) on it. See issue 2888.
+ t.Typedef = dt.Name
+ }
+ }
+ return t
+}
+
+// FuncType returns the Go type analogous to dtype.
+// There is no guarantee about matching memory layout.
+func (c *typeConv) FuncType(dtype *dwarf.FuncType, pos token.Pos) *FuncType {
+ p := make([]*Type, len(dtype.ParamType))
+ gp := make([]*ast.Field, len(dtype.ParamType))
+ for i, f := range dtype.ParamType {
+ // gcc's DWARF generator outputs a single DotDotDotType parameter for
+ // function pointers that specify no parameters (e.g. void
+ // (*__cgo_0)()). Treat this special case as void. This case is
+ // invalid according to ISO C anyway (i.e. void (*__cgo_1)(...) is not
+ // legal).
+ if _, ok := f.(*dwarf.DotDotDotType); ok && i == 0 {
+ p, gp = nil, nil
+ break
+ }
+ p[i] = c.FuncArg(f, pos)
+ gp[i] = &ast.Field{Type: p[i].Go}
+ }
+ var r *Type
+ var gr []*ast.Field
+ if _, ok := dtype.ReturnType.(*dwarf.VoidType); ok {
+ gr = []*ast.Field{{Type: c.goVoid}}
+ } else if dtype.ReturnType != nil {
+ r = c.Type(dtype.ReturnType, pos)
+ gr = []*ast.Field{{Type: r.Go}}
+ }
+ return &FuncType{
+ Params: p,
+ Result: r,
+ Go: &ast.FuncType{
+ Params: &ast.FieldList{List: gp},
+ Results: &ast.FieldList{List: gr},
+ },
+ }
+}
+
+// Identifier
+func (c *typeConv) Ident(s string) *ast.Ident {
+ return ast.NewIdent(s)
+}
+
+// Opaque type of n bytes.
+func (c *typeConv) Opaque(n int64) ast.Expr {
+ return &ast.ArrayType{
+ Len: c.intExpr(n),
+ Elt: c.byte,
+ }
+}
+
+// Expr for integer n.
+func (c *typeConv) intExpr(n int64) ast.Expr {
+ return &ast.BasicLit{
+ Kind: token.INT,
+ Value: strconv.FormatInt(n, 10),
+ }
+}
+
+// Add padding of given size to fld.
+func (c *typeConv) pad(fld []*ast.Field, size int64) []*ast.Field {
+ n := len(fld)
+ fld = fld[0 : n+1]
+ fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident("_")}, Type: c.Opaque(size)}
+ return fld
+}
+
+// Struct conversion: return Go and (6g) 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
+
+ var buf bytes.Buffer
+ buf.WriteString("struct {")
+ fld := make([]*ast.Field, 0, 2*len(dt.Field)+1) // enough for padding around every field
+ off := int64(0)
+
+ // Rename struct fields that happen to be named Go keywords into
+ // _{keyword}. Create a map from C ident -> Go ident. The Go ident will
+ // be mangled. Any existing identifier that already has the same name on
+ // the C-side will cause the Go-mangled version to be prefixed with _.
+ // (e.g. in a struct with fields '_type' and 'type', the latter would be
+ // rendered as '__type' in Go).
+ ident := make(map[string]string)
+ used := make(map[string]bool)
+ for _, f := range dt.Field {
+ ident[f.Name] = f.Name
+ used[f.Name] = true
+ }
+
+ if !*godefs && !*cdefs {
+ for cid, goid := range ident {
+ if token.Lookup(goid).IsKeyword() {
+ // Avoid keyword
+ goid = "_" + goid
+
+ // Also avoid existing fields
+ for _, exist := used[goid]; exist; _, exist = used[goid] {
+ goid = "_" + goid
+ }
+
+ used[goid] = true
+ ident[cid] = goid
+ }
+ }
+ }
+
+ anon := 0
+ for _, f := range dt.Field {
+ if f.ByteOffset > off {
+ fld = c.pad(fld, f.ByteOffset-off)
+ off = f.ByteOffset
+ }
+
+ name := f.Name
+ ft := f.Type
+
+ // In godefs or cdefs 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 <sys/resource.h> file; see
+ // issue 6677.
+ if *godefs || *cdefs {
+ 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
+ ft = st.Field[0].Type
+ }
+ }
+
+ // TODO: Handle fields that are anonymous structs by
+ // promoting the fields of the inner struct.
+
+ t := c.Type(ft, pos)
+ tgo := t.Go
+ size := t.Size
+ talign := t.Align
+ if f.BitSize > 0 {
+ if f.BitSize%8 != 0 {
+ continue
+ }
+ size = f.BitSize / 8
+ name := tgo.(*ast.Ident).String()
+ if strings.HasPrefix(name, "int") {
+ name = "int"
+ } else {
+ name = "uint"
+ }
+ tgo = ast.NewIdent(name + fmt.Sprint(f.BitSize))
+ talign = size
+ }
+
+ if talign > 0 && f.ByteOffset%talign != 0 && !*cdefs {
+ // 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)
+ fld = fld[0 : n+1]
+ if name == "" {
+ name = fmt.Sprintf("anon%d", anon)
+ anon++
+ ident[name] = name
+ }
+ fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident(ident[name])}, Type: tgo}
+ off += size
+ buf.WriteString(t.C.String())
+ buf.WriteString(" ")
+ buf.WriteString(name)
+ buf.WriteString("; ")
+ if talign > align {
+ align = talign
+ }
+ }
+ if off < dt.ByteSize {
+ fld = c.pad(fld, dt.ByteSize-off)
+ off = dt.ByteSize
+ }
+ 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 {
+ godefsFields(fld)
+ }
+ expr = &ast.StructType{Fields: &ast.FieldList{List: fld}}
+ return
+}
+
+func upper(s string) string {
+ if s == "" {
+ return ""
+ }
+ r, size := utf8.DecodeRuneInString(s)
+ if r == '_' {
+ return "X" + s
+ }
+ return string(unicode.ToUpper(r)) + s[size:]
+}
+
+// godefsFields rewrites field names for use in Go or C definitions.
+// It strips leading common prefixes (like tv_ in tv_sec, tv_usec)
+// converts names to upper case, and rewrites _ into Pad_godefs_n,
+// so that all fields are exported.
+func godefsFields(fld []*ast.Field) {
+ prefix := fieldPrefix(fld)
+ npad := 0
+ for _, f := range fld {
+ for _, n := range f.Names {
+ if n.Name != prefix {
+ n.Name = strings.TrimPrefix(n.Name, prefix)
+ }
+ if n.Name == "_" {
+ // Use exported name instead.
+ n.Name = "Pad_cgo_" + strconv.Itoa(npad)
+ npad++
+ }
+ if !*cdefs {
+ n.Name = upper(n.Name)
+ }
+ }
+ }
+}
+
+// fieldPrefix returns the prefix that should be removed from all the
+// field names when generating the C or Go code. For generated
+// C, we leave the names as is (tv_sec, tv_usec), since that's what
+// people are used to seeing in C. For generated Go code, such as
+// 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 {
+ // Ignore field names that don't have the prefix we're
+ // looking for. It is common in C headers to have fields
+ // named, say, _pad in an otherwise prefixed header.
+ // If the struct has 3 fields tv_sec, tv_usec, _pad1, then we
+ // still want to remove the tv_ prefix.
+ // The check for "orig_" here handles orig_eax in the
+ // x86 ptrace register sets, which otherwise have all fields
+ // with reg_ prefixes.
+ if strings.HasPrefix(n.Name, "orig_") || strings.HasPrefix(n.Name, "_") {
+ continue
+ }
+ i := strings.Index(n.Name, "_")
+ if i < 0 {
+ continue
+ }
+ if prefix == "" {
+ prefix = n.Name[:i+1]
+ } else if prefix != n.Name[:i+1] {
+ return ""
+ }
+ }
+ }
+ return prefix
+}
diff --git a/libgo/go/cmd/cgo/godefs.go b/libgo/go/cmd/cgo/godefs.go
new file mode 100644
index 0000000000..ce5ac2736c
--- /dev/null
+++ b/libgo/go/cmd/cgo/godefs.go
@@ -0,0 +1,294 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/printer"
+ "go/token"
+ "os"
+ "strings"
+)
+
+// godefs returns the output for -godefs mode.
+func (p *Package) godefs(f *File, srcfile string) string {
+ var buf bytes.Buffer
+
+ fmt.Fprintf(&buf, "// Created by cgo -godefs - DO NOT EDIT\n")
+ fmt.Fprintf(&buf, "// %s\n", strings.Join(os.Args, " "))
+ fmt.Fprintf(&buf, "\n")
+
+ override := make(map[string]string)
+
+ // Allow source file to specify override mappings.
+ // For example, the socket data structures refer
+ // to in_addr and in_addr6 structs but we want to be
+ // able to treat them as byte arrays, so the godefs
+ // inputs in package syscall say
+ //
+ // // +godefs map struct_in_addr [4]byte
+ // // +godefs map struct_in_addr6 [16]byte
+ //
+ for _, g := range f.Comments {
+ for _, c := range g.List {
+ i := strings.Index(c.Text, "+godefs map")
+ if i < 0 {
+ continue
+ }
+ s := strings.TrimSpace(c.Text[i+len("+godefs map"):])
+ i = strings.Index(s, " ")
+ if i < 0 {
+ fmt.Fprintf(os.Stderr, "invalid +godefs map comment: %s\n", c.Text)
+ continue
+ }
+ override["_Ctype_"+strings.TrimSpace(s[:i])] = strings.TrimSpace(s[i:])
+ }
+ }
+ for _, n := range f.Name {
+ if s := override[n.Go]; s != "" {
+ override[n.Mangle] = s
+ }
+ }
+
+ // Otherwise, if the source file says type T C.whatever,
+ // use "T" as the mangling of C.whatever,
+ // except in the definition (handled at end of function).
+ refName := make(map[*ast.Expr]*Name)
+ for _, r := range f.Ref {
+ refName[r.Expr] = r.Name
+ }
+ for _, d := range f.AST.Decls {
+ d, ok := d.(*ast.GenDecl)
+ if !ok || d.Tok != token.TYPE {
+ continue
+ }
+ for _, s := range d.Specs {
+ s := s.(*ast.TypeSpec)
+ n := refName[&s.Type]
+ if n != nil && n.Mangle != "" {
+ override[n.Mangle] = s.Name.Name
+ }
+ }
+ }
+
+ // Extend overrides using typedefs:
+ // If we know that C.xxx should format as T
+ // and xxx is a typedef for yyy, make C.yyy format as T.
+ for typ, def := range typedef {
+ if new := override[typ]; new != "" {
+ if id, ok := def.Go.(*ast.Ident); ok {
+ override[id.Name] = new
+ }
+ }
+ }
+
+ // Apply overrides.
+ for old, new := range override {
+ if id := goIdent[old]; id != nil {
+ id.Name = new
+ }
+ }
+
+ // Any names still using the _C syntax are not going to compile,
+ // although in general we don't know whether they all made it
+ // into the file, so we can't warn here.
+ //
+ // The most common case is union types, which begin with
+ // _Ctype_union and for which typedef[name] is a Go byte
+ // array of the appropriate size (such as [4]byte).
+ // Substitute those union types with byte arrays.
+ for name, id := range goIdent {
+ if id.Name == name && strings.Contains(name, "_Ctype_union") {
+ if def := typedef[name]; def != nil {
+ id.Name = gofmt(def)
+ }
+ }
+ }
+
+ conf.Fprint(&buf, fset, f.AST)
+
+ 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.
+func gofmt(n interface{}) string {
+ gofmtBuf.Reset()
+ err := printer.Fprint(&gofmtBuf, fset, n)
+ if err != nil {
+ return "<" + err.Error() + ">"
+ }
+ return gofmtBuf.String()
+}
diff --git a/libgo/go/cmd/cgo/main.go b/libgo/go/cmd/cgo/main.go
new file mode 100644
index 0000000000..48257fc6c4
--- /dev/null
+++ b/libgo/go/cmd/cgo/main.go
@@ -0,0 +1,382 @@
+// 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; see gmp.go for an overview.
+
+// TODO(rsc):
+// Emit correct line number annotations.
+// Make 6g understand the annotations.
+
+package main
+
+import (
+ "crypto/md5"
+ "flag"
+ "fmt"
+ "go/ast"
+ "go/printer"
+ "go/token"
+ "io"
+ "os"
+ "path/filepath"
+ "reflect"
+ "runtime"
+ "sort"
+ "strings"
+)
+
+// A Package collects information about the package we're going to write.
+type Package struct {
+ PackageName string // name of package
+ PackagePath string
+ PtrSize int64
+ IntSize int64
+ GccOptions []string
+ CgoFlags map[string][]string // #cgo flags (CFLAGS, LDFLAGS)
+ Written map[string]bool
+ Name map[string]*Name // accumulated Name from Files
+ ExpFunc []*ExpFunc // accumulated ExpFunc from Files
+ Decl []ast.Decl
+ GoFiles []string // list of Go files
+ GccFiles []string // list of gcc output files
+ Preamble string // collected preamble for _cgo_export.h
+}
+
+// A File collects information about a single Go input file.
+type File struct {
+ AST *ast.File // parsed AST
+ Comments []*ast.CommentGroup // comments from file
+ Package string // Package name
+ Preamble string // C preamble (doc comment on import "C")
+ Ref []*Ref // all references to C.xxx in AST
+ ExpFunc []*ExpFunc // exported functions for this file
+ Name map[string]*Name // map from Go name to Name
+}
+
+func nameKeys(m map[string]*Name) []string {
+ var ks []string
+ for k := range m {
+ ks = append(ks, k)
+ }
+ sort.Strings(ks)
+ return ks
+}
+
+// A Ref refers to an expression of the form C.xxx in the AST.
+type Ref struct {
+ Name *Name
+ Expr *ast.Expr
+ Context string // "type", "expr", "call", or "call2"
+}
+
+func (r *Ref) Pos() token.Pos {
+ return (*r.Expr).Pos()
+}
+
+// A Name collects information about C.xxx.
+type Name struct {
+ Go string // name used in Go referring to package C
+ Mangle string // name used in generated Go
+ C string // name used in C
+ Define string // #define expansion
+ Kind string // "const", "type", "var", "fpvar", "func", "not-type"
+ Type *Type // the type of xxx
+ FuncType *FuncType
+ AddError bool
+ Const string // constant definition
+}
+
+// IsVar returns true if Kind is either "var" or "fpvar"
+func (n *Name) IsVar() bool {
+ return n.Kind == "var" || n.Kind == "fpvar"
+}
+
+// A ExpFunc is an exported function, callable from C.
+// Such functions are identified in the Go input file
+// by doc comments containing the line //export ExpName
+type ExpFunc struct {
+ Func *ast.FuncDecl
+ ExpName string // name to use from C
+}
+
+// A TypeRepr contains the string representation of a type.
+type TypeRepr struct {
+ Repr string
+ FormatArgs []interface{}
+}
+
+// A Type collects information about a type in both the C and Go worlds.
+type Type struct {
+ Size int64
+ Align int64
+ C *TypeRepr
+ Go ast.Expr
+ EnumValues map[string]int64
+ Typedef string
+}
+
+// A FuncType collects information about a function type in both the C and Go worlds.
+type FuncType struct {
+ Params []*Type
+ Result *Type
+ Go *ast.FuncType
+}
+
+func usage() {
+ fmt.Fprint(os.Stderr, "usage: cgo -- [compiler options] file.go ...\n")
+ flag.PrintDefaults()
+ os.Exit(2)
+}
+
+var ptrSizeMap = map[string]int64{
+ "386": 4,
+ "alpha": 8,
+ "amd64": 8,
+ "arm": 4,
+ "arm64": 8,
+ "m68k": 4,
+ "mipso32": 4,
+ "mipsn32": 4,
+ "mipso64": 8,
+ "mipsn64": 8,
+ "ppc": 4,
+ "ppc64": 8,
+ "ppc64le": 8,
+ "s390": 4,
+ "s390x": 8,
+ "sparc": 4,
+ "sparc64": 8,
+}
+
+var intSizeMap = map[string]int64{
+ "386": 4,
+ "alpha": 8,
+ "amd64": 8,
+ "arm": 4,
+ "arm64": 8,
+ "m68k": 4,
+ "mipso32": 4,
+ "mipsn32": 4,
+ "mipso64": 8,
+ "mipsn64": 8,
+ "ppc": 4,
+ "ppc64": 8,
+ "ppc64le": 8,
+ "s390": 4,
+ "s390x": 8,
+ "sparc": 4,
+ "sparc64": 8,
+}
+
+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")
+
+// These flags are for bootstrapping a new Go implementation,
+// to generate Go and C headers 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 gccgo = flag.Bool("gccgo", false, "generate files for use with gccgo")
+var gccgoprefix = flag.String("gccgoprefix", "", "-fgo-prefix option used with gccgo")
+var gccgopkgpath = flag.String("gccgopkgpath", "", "-fgo-pkgpath option used with gccgo")
+var importRuntimeCgo = flag.Bool("import_runtime_cgo", true, "import runtime/cgo in generated code")
+var importSyscall = flag.Bool("import_syscall", true, "import syscall in generated code")
+var goarch, goos string
+
+func main() {
+ flag.Usage = usage
+ flag.Parse()
+
+ if *dynobj != "" {
+ // cgo -dynimport is essentially a separate helper command
+ // built into the cgo binary. It scans a gcc-produced executable
+ // and dumps information about the imported symbols and the
+ // imported libraries. The 'go build' rules for cgo prepare an
+ // appropriate executable and then use its import information
+ // instead of needing to make the linkers duplicate all the
+ // specialized knowledge gcc has about where to look for imported
+ // symbols and which ones to use.
+ dynimport(*dynobj)
+ return
+ }
+
+ if *godefs && *cdefs {
+ fmt.Fprintf(os.Stderr, "cgo: cannot use -cdefs and -godefs together\n")
+ os.Exit(2)
+ }
+
+ if *godefs || *cdefs {
+ // Generating definitions pulled from header files,
+ // to be checked into Go repositories.
+ // Line numbers are just noise.
+ conf.Mode &^= printer.SourcePos
+ }
+
+ args := flag.Args()
+ if len(args) < 1 {
+ usage()
+ }
+
+ // Find first arg that looks like a go file and assume everything before
+ // that are options to pass to gcc.
+ var i int
+ for i = len(args); i > 0; i-- {
+ if !strings.HasSuffix(args[i-1], ".go") {
+ break
+ }
+ }
+ if i == len(args) {
+ usage()
+ }
+
+ goFiles := args[i:]
+
+ p := newPackage(args[:i])
+
+ // Record CGO_LDFLAGS from the environment for external linking.
+ if ldflags := os.Getenv("CGO_LDFLAGS"); ldflags != "" {
+ args, err := splitQuoted(ldflags)
+ if err != nil {
+ fatalf("bad CGO_LDFLAGS: %q (%s)", ldflags, err)
+ }
+ p.addToFlag("LDFLAGS", args)
+ }
+
+ // Need a unique prefix for the global C symbols that
+ // we use to coordinate between gcc and ourselves.
+ // We already put _cgo_ at the beginning, so the main
+ // concern is other cgo wrappers for the same functions.
+ // Use the beginning of the md5 of the input to disambiguate.
+ h := md5.New()
+ for _, input := range goFiles {
+ f, err := os.Open(input)
+ if err != nil {
+ fatalf("%s", err)
+ }
+ io.Copy(h, f)
+ f.Close()
+ }
+ cPrefix = fmt.Sprintf("_%x", h.Sum(nil)[0:6])
+
+ fs := make([]*File, len(goFiles))
+ for i, input := range goFiles {
+ f := new(File)
+ f.ReadGo(input)
+ f.DiscardCgoDirectives()
+ fs[i] = f
+ }
+
+ if *objDir == "" {
+ // make sure that _obj directory exists, so that we can write
+ // all the output files there.
+ os.Mkdir("_obj", 0777)
+ *objDir = "_obj"
+ }
+ *objDir += string(filepath.Separator)
+
+ for i, input := range goFiles {
+ f := fs[i]
+ p.Translate(f)
+ for _, cref := range f.Ref {
+ switch cref.Context {
+ case "call", "call2":
+ if cref.Name.Kind != "type" {
+ break
+ }
+ *cref.Expr = cref.Name.Type.Go
+ }
+ }
+ if nerrors > 0 {
+ os.Exit(2)
+ }
+ pkg := f.Package
+ if dir := os.Getenv("CGOPKGPATH"); dir != "" {
+ pkg = filepath.Join(dir, pkg)
+ }
+ p.PackagePath = pkg
+ 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 {
+ p.writeDefs()
+ }
+ if nerrors > 0 {
+ os.Exit(2)
+ }
+}
+
+// newPackage returns a new Package that will invoke
+// gcc with the additional arguments specified in args.
+func newPackage(args []string) *Package {
+ goarch = runtime.GOARCH
+ if s := os.Getenv("GOARCH"); s != "" {
+ goarch = s
+ }
+ goos = runtime.GOOS
+ if s := os.Getenv("GOOS"); s != "" {
+ goos = s
+ }
+ ptrSize := ptrSizeMap[goarch]
+ if ptrSize == 0 {
+ fatalf("unknown ptrSize for $GOARCH %q", goarch)
+ }
+ intSize := intSizeMap[goarch]
+ if intSize == 0 {
+ fatalf("unknown intSize for $GOARCH %q", goarch)
+ }
+
+ // Reset locale variables so gcc emits English errors [sic].
+ os.Setenv("LANG", "en_US.UTF-8")
+ os.Setenv("LC_ALL", "C")
+
+ p := &Package{
+ PtrSize: ptrSize,
+ IntSize: intSize,
+ CgoFlags: make(map[string][]string),
+ Written: make(map[string]bool),
+ }
+ p.addToFlag("CFLAGS", args)
+ return p
+}
+
+// Record what needs to be recorded about f.
+func (p *Package) Record(f *File) {
+ if p.PackageName == "" {
+ p.PackageName = f.Package
+ } else if p.PackageName != f.Package {
+ error_(token.NoPos, "inconsistent package names: %s, %s", p.PackageName, f.Package)
+ }
+
+ if p.Name == nil {
+ p.Name = f.Name
+ } else {
+ for k, v := range f.Name {
+ if p.Name[k] == nil {
+ p.Name[k] = v
+ } else if !reflect.DeepEqual(p.Name[k], v) {
+ error_(token.NoPos, "inconsistent definitions for C.%s", fixGo(k))
+ }
+ }
+ }
+
+ if f.ExpFunc != nil {
+ p.ExpFunc = append(p.ExpFunc, f.ExpFunc...)
+ p.Preamble += "\n" + f.Preamble
+ }
+ p.Decl = append(p.Decl, f.AST.Decls...)
+}
diff --git a/libgo/go/cmd/cgo/out.go b/libgo/go/cmd/cgo/out.go
new file mode 100644
index 0000000000..d92bed9bf0
--- /dev/null
+++ b/libgo/go/cmd/cgo/out.go
@@ -0,0 +1,1334 @@
+// 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 main
+
+import (
+ "bytes"
+ "debug/elf"
+ "debug/macho"
+ "debug/pe"
+ "fmt"
+ "go/ast"
+ "go/printer"
+ "go/token"
+ "os"
+ "sort"
+ "strings"
+)
+
+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.)
+func (p *Package) writeDefs() {
+ fgo2 := creat(*objDir + "_cgo_gotypes.go")
+ fc := creat(*objDir + "_cgo_defun.c")
+ fm := creat(*objDir + "_cgo_main.c")
+
+ var gccgoInit bytes.Buffer
+
+ fflg := creat(*objDir + "_cgo_flags")
+ for k, v := range p.CgoFlags {
+ 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)
+ }
+ }
+ }
+ fflg.Close()
+
+ // Write C main file for using gcc to resolve imports.
+ fmt.Fprintf(fm, "int main() { return 0; }\n")
+ if *importRuntimeCgo {
+ fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c) { }\n")
+ fmt.Fprintf(fm, "char* _cgo_topofstack(void) { return (char*)0; }\n")
+ } else {
+ // If we're not importing runtime/cgo, we *are* runtime/cgo,
+ // which provides crosscall2. We just need a prototype.
+ fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c);\n")
+ }
+ fmt.Fprintf(fm, "void _cgo_allocate(void *a, int c) { }\n")
+ fmt.Fprintf(fm, "void _cgo_panic(void *a, int c) { }\n")
+
+ // Write second Go output: definitions of _C_xxx.
+ // In a separate file so that the import of "unsafe" does not
+ // pollute the original file.
+ fmt.Fprintf(fgo2, "// Created by cgo - DO NOT EDIT\n\n")
+ fmt.Fprintf(fgo2, "package %s\n\n", p.PackageName)
+ fmt.Fprintf(fgo2, "import \"unsafe\"\n\n")
+ if !*gccgo && *importRuntimeCgo {
+ fmt.Fprintf(fgo2, "import _ \"runtime/cgo\"\n\n")
+ }
+ if *importSyscall {
+ fmt.Fprintf(fgo2, "import \"syscall\"\n\n")
+ fmt.Fprintf(fgo2, "var _ syscall.Errno\n")
+ }
+ fmt.Fprintf(fgo2, "func _Cgo_ptr(ptr unsafe.Pointer) unsafe.Pointer { return ptr }\n\n")
+
+ typedefNames := make([]string, 0, len(typedef))
+ for name := range typedef {
+ typedefNames = append(typedefNames, name)
+ }
+ sort.Strings(typedefNames)
+ for _, name := range typedefNames {
+ def := typedef[name]
+ fmt.Fprintf(fgo2, "type %s ", name)
+ conf.Fprint(fgo2, fset, def.Go)
+ fmt.Fprintf(fgo2, "\n\n")
+ }
+ if *gccgo {
+ fmt.Fprintf(fgo2, "type _Ctype_void byte\n")
+ } else {
+ fmt.Fprintf(fgo2, "type _Ctype_void [0]byte\n")
+ }
+
+ if *gccgo {
+ fmt.Fprint(fc, p.cPrologGccgo())
+ } else {
+ fmt.Fprint(fc, cProlog)
+ fmt.Fprint(fgo2, goProlog)
+ }
+
+ gccgoSymbolPrefix := p.gccgoSymbolPrefix()
+
+ cVars := make(map[string]bool)
+ for _, key := range nameKeys(p.Name) {
+ n := p.Name[key]
+ if !n.IsVar() {
+ continue
+ }
+
+ 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)
+ }
+
+ 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(fc, "\n")
+
+ fmt.Fprintf(fgo2, "var %s ", n.Mangle)
+ conf.Fprint(fgo2, fset, node)
+ fmt.Fprintf(fgo2, "\n")
+ }
+ fmt.Fprintf(fc, "\n")
+
+ for _, key := range nameKeys(p.Name) {
+ n := p.Name[key]
+ if n.Const != "" {
+ fmt.Fprintf(fgo2, "const _Cconst_%s = %s\n", n.Go, n.Const)
+ }
+ }
+ fmt.Fprintf(fgo2, "\n")
+
+ for _, key := range nameKeys(p.Name) {
+ n := p.Name[key]
+ if n.FuncType != nil {
+ p.writeDefsFunc(fc, fgo2, n)
+ }
+ }
+
+ if *gccgo {
+ p.writeGccgoExports(fgo2, fc, fm)
+ } else {
+ p.writeExports(fgo2, fc, fm)
+ }
+
+ init := gccgoInit.String()
+ if init != "" {
+ fmt.Fprintln(fc, "static void init(void) __attribute__ ((constructor));")
+ fmt.Fprintln(fc, "static void init(void) {")
+ fmt.Fprint(fc, init)
+ fmt.Fprintln(fc, "}")
+ }
+
+ fgo2.Close()
+ fc.Close()
+}
+
+func dynimport(obj string) {
+ stdout := os.Stdout
+ if *dynout != "" {
+ f, err := os.Create(*dynout)
+ if err != nil {
+ fatalf("%s", err)
+ }
+ stdout = f
+ }
+
+ 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]))
+ }
+ }
+ }
+ sym, err := f.ImportedSymbols()
+ if err != nil {
+ fatalf("cannot load imported symbols from ELF file %s: %v", obj, err)
+ }
+ for _, s := range sym {
+ targ := s.Name
+ if s.Version != "" {
+ targ += "#" + s.Version
+ }
+ fmt.Fprintf(stdout, "#pragma 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)
+ }
+ return
+ }
+
+ if f, err := macho.Open(obj); err == nil {
+ sym, err := f.ImportedSymbols()
+ if err != nil {
+ fatalf("cannot load imported symbols from Mach-O file %s: %v", obj, err)
+ }
+ for _, s := range sym {
+ if len(s) > 0 && s[0] == '_' {
+ s = s[1:]
+ }
+ fmt.Fprintf(stdout, "#pragma 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)
+ }
+ return
+ }
+
+ if f, err := pe.Open(obj); err == nil {
+ sym, err := f.ImportedSymbols()
+ if err != nil {
+ fatalf("cannot load imported symbols from PE file %s: %v", obj, err)
+ }
+ 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]))
+ }
+ return
+ }
+
+ fatalf("cannot parse %s as ELF, Mach-O or PE", obj)
+}
+
+// Construct a gcc struct matching the 6c 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
+// input and output parameters.
+func (p *Package) structType(n *Name) (string, int64) {
+ var buf bytes.Buffer
+ fmt.Fprint(&buf, "struct {\n")
+ off := int64(0)
+ for i, t := range n.FuncType.Params {
+ if off%t.Align != 0 {
+ pad := t.Align - off%t.Align
+ fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
+ off += pad
+ }
+ c := t.Typedef
+ if c == "" {
+ c = t.C.String()
+ }
+ fmt.Fprintf(&buf, "\t\t%s p%d;\n", c, i)
+ off += t.Size
+ }
+ if off%p.PtrSize != 0 {
+ pad := p.PtrSize - off%p.PtrSize
+ fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
+ off += pad
+ }
+ if t := n.FuncType.Result; t != nil {
+ if off%t.Align != 0 {
+ pad := t.Align - off%t.Align
+ fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
+ off += pad
+ }
+ qual := ""
+ if c := t.C.String(); c[len(c)-1] == '*' {
+ qual = "const "
+ }
+ fmt.Fprintf(&buf, "\t\t%s%s r;\n", qual, t.C)
+ off += t.Size
+ }
+ if off%p.PtrSize != 0 {
+ pad := p.PtrSize - off%p.PtrSize
+ fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
+ off += pad
+ }
+ if off == 0 {
+ fmt.Fprintf(&buf, "\t\tchar unused;\n") // avoid empty struct
+ }
+ fmt.Fprintf(&buf, "\t}")
+ return buf.String(), off
+}
+
+func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
+ name := n.Go
+ gtype := n.FuncType.Go
+ void := gtype.Results == nil || len(gtype.Results.List) == 0
+ if n.AddError {
+ // Add "error" to return type list.
+ // Type list is known to be 0 or 1 element - it's a C function.
+ err := &ast.Field{Type: ast.NewIdent("error")}
+ l := gtype.Results.List
+ if len(l) == 0 {
+ l = []*ast.Field{err}
+ } else {
+ l = []*ast.Field{l[0], err}
+ }
+ t := new(ast.FuncType)
+ *t = *gtype
+ t.Results = &ast.FieldList{List: l}
+ gtype = t
+ }
+
+ // Go func declaration.
+ d := &ast.FuncDecl{
+ Name: ast.NewIdent(n.Mangle),
+ Type: gtype,
+ }
+
+ // Builtins defined in the C prolog.
+ inProlog := builtinDefs[name] != ""
+ cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle)
+ paramnames := []string(nil)
+ for i, param := range d.Type.Params.List {
+ paramName := fmt.Sprintf("p%d", i)
+ param.Names = []*ast.Ident{ast.NewIdent(paramName)}
+ paramnames = append(paramnames, paramName)
+ }
+
+ if *gccgo {
+ // Gccgo style hooks.
+ fmt.Fprint(fgo2, "\n")
+ conf.Fprint(fgo2, fset, d)
+ fmt.Fprint(fgo2, " {\n")
+ if !inProlog {
+ fmt.Fprint(fgo2, "\tdefer syscall.CgocallDone()\n")
+ fmt.Fprint(fgo2, "\tsyscall.Cgocall()\n")
+ }
+ if n.AddError {
+ fmt.Fprint(fgo2, "\tsyscall.SetErrno(0)\n")
+ }
+ fmt.Fprint(fgo2, "\t")
+ if !void {
+ fmt.Fprint(fgo2, "r := ")
+ }
+ fmt.Fprintf(fgo2, "%s(%s)\n", cname, strings.Join(paramnames, ", "))
+
+ if n.AddError {
+ fmt.Fprint(fgo2, "\te := syscall.GetErrno()\n")
+ fmt.Fprint(fgo2, "\tif e != 0 {\n")
+ fmt.Fprint(fgo2, "\t\treturn ")
+ if !void {
+ fmt.Fprint(fgo2, "r, ")
+ }
+ fmt.Fprint(fgo2, "e\n")
+ fmt.Fprint(fgo2, "\t}\n")
+ fmt.Fprint(fgo2, "\treturn ")
+ if !void {
+ fmt.Fprint(fgo2, "r, ")
+ }
+ fmt.Fprint(fgo2, "nil\n")
+ } else if !void {
+ fmt.Fprint(fgo2, "\treturn r\n")
+ }
+
+ fmt.Fprint(fgo2, "}\n")
+
+ // declare the C function.
+ fmt.Fprintf(fgo2, "//extern %s\n", cname)
+ d.Name = ast.NewIdent(cname)
+ if n.AddError {
+ l := d.Type.Results.List
+ d.Type.Results.List = l[:len(l)-1]
+ }
+ conf.Fprint(fgo2, fset, d)
+ fmt.Fprint(fgo2, "\n")
+
+ return
+ }
+
+ if inProlog {
+ fmt.Fprint(fgo2, builtinDefs[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)
+
+ nret := 0
+ if !void {
+ d.Type.Results.List[0].Names = []*ast.Ident{ast.NewIdent("r1")}
+ nret = 1
+ }
+ if n.AddError {
+ d.Type.Results.List[nret].Names = []*ast.Ident{ast.NewIdent("r2")}
+ }
+
+ fmt.Fprint(fgo2, "\n")
+ fmt.Fprintf(fgo2, "var %s unsafe.Pointer\n", cname)
+ conf.Fprint(fgo2, fset, d)
+ fmt.Fprint(fgo2, " {\n")
+
+ // NOTE: Using uintptr to hide from escape analysis.
+ arg := "0"
+ if len(paramnames) > 0 {
+ arg = "uintptr(unsafe.Pointer(&p0))"
+ } else if !void {
+ arg = "uintptr(unsafe.Pointer(&r1))"
+ }
+
+ prefix := ""
+ if n.AddError {
+ prefix = "errno := "
+ }
+ fmt.Fprintf(fgo2, "\t%s_cgo_runtime_cgocall_errno(%s, %s)\n", prefix, cname, arg)
+ if n.AddError {
+ fmt.Fprintf(fgo2, "\tif errno != 0 { r2 = syscall.Errno(errno) }\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.)
+func (p *Package) writeOutput(f *File, srcfile string) {
+ base := srcfile
+ if strings.HasSuffix(base, ".go") {
+ base = base[0 : len(base)-3]
+ }
+ base = strings.Map(slashToUnderscore, base)
+ fgo1 := creat(*objDir + base + ".cgo1.go")
+ fgcc := creat(*objDir + base + ".cgo2.c")
+
+ p.GoFiles = append(p.GoFiles, base+".cgo1.go")
+ p.GccFiles = append(p.GccFiles, base+".cgo2.c")
+
+ // Write Go output: Go input with rewrites of C.xxx to _C_xxx.
+ 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.
+ // Gcc output starts with the preamble.
+ fmt.Fprintf(fgcc, "%s\n", f.Preamble)
+ fmt.Fprintf(fgcc, "%s\n", gccProlog)
+
+ for _, key := range nameKeys(f.Name) {
+ n := f.Name[key]
+ if n.FuncType != nil {
+ p.writeOutputFunc(fgcc, n)
+ }
+ }
+
+ fgo1.Close()
+ fgcc.Close()
+}
+
+// fixGo converts the internal Name.Go field into the name we should show
+// to users in error messages. There's only one for now: on input we rewrite
+// C.malloc into C._CMalloc, so change it back here.
+func fixGo(name string) string {
+ if name == "_CMalloc" {
+ return "malloc"
+ }
+ return name
+}
+
+var isBuiltin = map[string]bool{
+ "_Cfunc_CString": true,
+ "_Cfunc_GoString": true,
+ "_Cfunc_GoStringN": true,
+ "_Cfunc_GoBytes": true,
+ "_Cfunc__CMalloc": true,
+}
+
+func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
+ name := n.Mangle
+ if isBuiltin[name] || p.Written[name] {
+ // The builtins are already defined in the C prolog, and we don't
+ // want to duplicate function definitions we've already done.
+ return
+ }
+ p.Written[name] = true
+
+ if *gccgo {
+ p.writeGccgoOutputFunc(fgcc, n)
+ return
+ }
+
+ ctype, _ := p.structType(n)
+
+ // Gcc wrapper unpacks the C argument struct
+ // and calls the actual C function.
+ if n.AddError {
+ fmt.Fprintf(fgcc, "int\n")
+ } else {
+ fmt.Fprintf(fgcc, "void\n")
+ }
+ fmt.Fprintf(fgcc, "_cgo%s%s(void *v)\n", cPrefix, n.Mangle)
+ fmt.Fprintf(fgcc, "{\n")
+ if n.AddError {
+ fmt.Fprintf(fgcc, "\terrno = 0;\n")
+ }
+ // We're trying to write a gcc struct that matches 6c/8c/5c'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())
+ if n.FuncType.Result != nil {
+ // Save the stack top for use below.
+ fmt.Fprintf(fgcc, "\tchar *stktop = _cgo_topofstack();\n")
+ }
+ fmt.Fprintf(fgcc, "\t")
+ if t := n.FuncType.Result; t != nil {
+ fmt.Fprintf(fgcc, "__typeof__(a->r) r = ")
+ if c := t.C.String(); c[len(c)-1] == '*' {
+ fmt.Fprint(fgcc, "(__typeof__(a->r)) ")
+ }
+ }
+ fmt.Fprintf(fgcc, "%s(", n.C)
+ for i, t := range n.FuncType.Params {
+ if i > 0 {
+ fmt.Fprintf(fgcc, ", ")
+ }
+ // We know the type params are correct, because
+ // the Go equivalents had good type params.
+ // However, our version of the type omits the magic
+ // words const and volatile, which can provoke
+ // C compiler warnings. Silence them by casting
+ // all pointers to void*. (Eventually that will produce
+ // other warnings.)
+ if c := t.C.String(); c[len(c)-1] == '*' {
+ fmt.Fprintf(fgcc, "(void*)")
+ }
+ fmt.Fprintf(fgcc, "a->p%d", i)
+ }
+ fmt.Fprintf(fgcc, ");\n")
+ if n.FuncType.Result != nil {
+ // The cgo call may have caused a stack copy (via a callback).
+ // Adjust the return value pointer appropriately.
+ fmt.Fprintf(fgcc, "\ta = (void*)((char*)a + (_cgo_topofstack() - stktop));\n")
+ // Save the return value.
+ fmt.Fprintf(fgcc, "\ta->r = r;\n")
+ }
+ if n.AddError {
+ fmt.Fprintf(fgcc, "\treturn errno;\n")
+ }
+ fmt.Fprintf(fgcc, "}\n")
+ fmt.Fprintf(fgcc, "\n")
+}
+
+// Write out a wrapper for a function when using gccgo. This is a
+// simple wrapper that just calls the real function. We only need a
+// wrapper to support static functions in the prologue--without a
+// wrapper, we can't refer to the function, since the reference is in
+// a different file.
+func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) {
+ if t := n.FuncType.Result; t != nil {
+ fmt.Fprintf(fgcc, "%s\n", t.C.String())
+ } else {
+ fmt.Fprintf(fgcc, "void\n")
+ }
+ fmt.Fprintf(fgcc, "_cgo%s%s(", cPrefix, n.Mangle)
+ for i, t := range n.FuncType.Params {
+ if i > 0 {
+ fmt.Fprintf(fgcc, ", ")
+ }
+ c := t.Typedef
+ if c == "" {
+ c = t.C.String()
+ }
+ fmt.Fprintf(fgcc, "%s p%d", c, i)
+ }
+ fmt.Fprintf(fgcc, ")\n")
+ fmt.Fprintf(fgcc, "{\n")
+ fmt.Fprintf(fgcc, "\t")
+ if t := n.FuncType.Result; t != nil {
+ fmt.Fprintf(fgcc, "return ")
+ // Cast to void* to avoid warnings due to omitted qualifiers.
+ if c := t.C.String(); c[len(c)-1] == '*' {
+ fmt.Fprintf(fgcc, "(void*)")
+ }
+ }
+ fmt.Fprintf(fgcc, "%s(", n.C)
+ for i, t := range n.FuncType.Params {
+ if i > 0 {
+ fmt.Fprintf(fgcc, ", ")
+ }
+ // Cast to void* to avoid warnings due to omitted qualifiers.
+ if c := t.C.String(); c[len(c)-1] == '*' {
+ fmt.Fprintf(fgcc, "(void*)")
+ }
+ fmt.Fprintf(fgcc, "p%d", i)
+ }
+ fmt.Fprintf(fgcc, ");\n")
+ fmt.Fprintf(fgcc, "}\n")
+ fmt.Fprintf(fgcc, "\n")
+}
+
+// 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.
+// Use __gcc_struct__ to work around http://gcc.gnu.org/PR52991 on x86,
+// and http://golang.org/issue/5603.
+func (p *Package) packedAttribute() string {
+ s := "__attribute__((__packed__"
+ if !strings.Contains(p.gccBaseCmd()[0], "clang") && (goarch == "amd64" || goarch == "386") {
+ s += ", __gcc_struct__"
+ }
+ return s + "))"
+}
+
+// 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())
+
+ fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n")
+ fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n")
+
+ fmt.Fprintf(fgcc, "\nextern void crosscall2(void (*fn)(void *, int), void *, int);\n\n")
+
+ for _, exp := range p.ExpFunc {
+ fn := exp.Func
+
+ // Construct a gcc struct matching the 6c argument and
+ // result frame. The gcc struct will be compiled with
+ // __attribute__((packed)) so all padding must be accounted
+ // for explicitly.
+ ctype := "struct {\n"
+ off := int64(0)
+ npad := 0
+ if fn.Recv != nil {
+ t := p.cgoType(fn.Recv.List[0].Type)
+ ctype += fmt.Sprintf("\t\t%s recv;\n", t.C)
+ off += t.Size
+ }
+ fntype := fn.Type
+ forFieldList(fntype.Params,
+ func(i int, atype ast.Expr) {
+ t := p.cgoType(atype)
+ if off%t.Align != 0 {
+ pad := t.Align - off%t.Align
+ ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
+ off += pad
+ npad++
+ }
+ ctype += fmt.Sprintf("\t\t%s p%d;\n", t.C, i)
+ off += t.Size
+ })
+ if off%p.PtrSize != 0 {
+ pad := p.PtrSize - off%p.PtrSize
+ ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
+ off += pad
+ npad++
+ }
+ forFieldList(fntype.Results,
+ func(i int, atype ast.Expr) {
+ t := p.cgoType(atype)
+ if off%t.Align != 0 {
+ pad := t.Align - off%t.Align
+ ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
+ off += pad
+ npad++
+ }
+ ctype += fmt.Sprintf("\t\t%s r%d;\n", t.C, i)
+ off += t.Size
+ })
+ if off%p.PtrSize != 0 {
+ pad := p.PtrSize - off%p.PtrSize
+ ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
+ off += pad
+ npad++
+ }
+ if ctype == "struct {\n" {
+ ctype += "\t\tchar unused;\n" // avoid empty struct
+ }
+ ctype += "\t}"
+
+ // Get the return type of the wrapper function
+ // compiled by gcc.
+ gccResult := ""
+ if fntype.Results == nil || len(fntype.Results.List) == 0 {
+ gccResult = "void"
+ } else if len(fntype.Results.List) == 1 && len(fntype.Results.List[0].Names) <= 1 {
+ gccResult = p.cgoType(fntype.Results.List[0].Type).C.String()
+ } else {
+ fmt.Fprintf(fgcch, "\n/* Return type for %s */\n", exp.ExpName)
+ fmt.Fprintf(fgcch, "struct %s_return {\n", exp.ExpName)
+ forFieldList(fntype.Results,
+ func(i int, atype ast.Expr) {
+ fmt.Fprintf(fgcch, "\t%s r%d;\n", p.cgoType(atype).C, i)
+ })
+ fmt.Fprintf(fgcch, "};\n")
+ gccResult = "struct " + exp.ExpName + "_return"
+ }
+
+ // Build the wrapper function compiled by gcc.
+ s := fmt.Sprintf("%s %s(", gccResult, exp.ExpName)
+ if fn.Recv != nil {
+ s += p.cgoType(fn.Recv.List[0].Type).C.String()
+ s += " recv"
+ }
+ forFieldList(fntype.Params,
+ func(i int, atype ast.Expr) {
+ if i > 0 || fn.Recv != nil {
+ s += ", "
+ }
+ s += fmt.Sprintf("%s p%d", p.cgoType(atype).C, i)
+ })
+ s += ")"
+ 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%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)
+ }
+ if fn.Recv != nil {
+ fmt.Fprintf(fgcc, "\ta.recv = recv;\n")
+ }
+ forFieldList(fntype.Params,
+ func(i int, atype ast.Expr) {
+ fmt.Fprintf(fgcc, "\ta.p%d = p%d;\n", i, i)
+ })
+ fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp%s_%s, &a, %d);\n", cPrefix, exp.ExpName, off)
+ if gccResult != "void" {
+ if len(fntype.Results.List) == 1 && len(fntype.Results.List[0].Names) <= 1 {
+ fmt.Fprintf(fgcc, "\treturn a.r0;\n")
+ } else {
+ forFieldList(fntype.Results,
+ func(i int, atype ast.Expr) {
+ fmt.Fprintf(fgcc, "\tr.r%d = a.r%d;\n", i, i)
+ })
+ fmt.Fprintf(fgcc, "\treturn r;\n")
+ }
+ }
+ fmt.Fprintf(fgcc, "}\n")
+
+ // Build the wrapper function compiled by 6c/8c
+ 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(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName)
+
+ // Calling a function with a receiver from C requires
+ // a Go wrapper function.
+ if fn.Recv != nil {
+ fmt.Fprintf(fgo2, "func %s(recv ", goname)
+ conf.Fprint(fgo2, fset, fn.Recv.List[0].Type)
+ forFieldList(fntype.Params,
+ func(i int, atype ast.Expr) {
+ fmt.Fprintf(fgo2, ", p%d ", i)
+ conf.Fprint(fgo2, fset, atype)
+ })
+ fmt.Fprintf(fgo2, ")")
+ if gccResult != "void" {
+ fmt.Fprint(fgo2, " (")
+ forFieldList(fntype.Results,
+ func(i int, atype ast.Expr) {
+ if i > 0 {
+ fmt.Fprint(fgo2, ", ")
+ }
+ conf.Fprint(fgo2, fset, atype)
+ })
+ fmt.Fprint(fgo2, ")")
+ }
+ fmt.Fprint(fgo2, " {\n")
+ fmt.Fprint(fgo2, "\t")
+ if gccResult != "void" {
+ fmt.Fprint(fgo2, "return ")
+ }
+ fmt.Fprintf(fgo2, "recv.%s(", exp.Func.Name)
+ forFieldList(fntype.Params,
+ func(i int, atype ast.Expr) {
+ if i > 0 {
+ fmt.Fprint(fgo2, ", ")
+ }
+ fmt.Fprintf(fgo2, "p%d", i)
+ })
+ fmt.Fprint(fgo2, ")\n")
+ fmt.Fprint(fgo2, "}\n")
+ }
+ }
+}
+
+// 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")
+
+ 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())
+
+ 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")
+
+ for _, exp := range p.ExpFunc {
+ fn := exp.Func
+ fntype := fn.Type
+
+ cdeclBuf := new(bytes.Buffer)
+ resultCount := 0
+ forFieldList(fntype.Results,
+ func(i int, atype ast.Expr) { resultCount++ })
+ switch resultCount {
+ case 0:
+ fmt.Fprintf(cdeclBuf, "void")
+ case 1:
+ forFieldList(fntype.Results,
+ func(i int, atype ast.Expr) {
+ t := p.cgoType(atype)
+ fmt.Fprintf(cdeclBuf, "%s", t.C)
+ })
+ default:
+ // Declare a result struct.
+ fmt.Fprintf(fgcch, "struct %s_result {\n", exp.ExpName)
+ forFieldList(fntype.Results,
+ func(i int, atype ast.Expr) {
+ t := p.cgoType(atype)
+ fmt.Fprintf(fgcch, "\t%s r%d;\n", t.C, i)
+ })
+ fmt.Fprintf(fgcch, "};\n")
+ fmt.Fprintf(cdeclBuf, "struct %s_result", exp.ExpName)
+ }
+
+ cRet := cdeclBuf.String()
+
+ cdeclBuf = new(bytes.Buffer)
+ fmt.Fprintf(cdeclBuf, "(")
+ if fn.Recv != nil {
+ fmt.Fprintf(cdeclBuf, "%s recv", p.cgoType(fn.Recv.List[0].Type).C.String())
+ }
+ // Function parameters.
+ forFieldList(fntype.Params,
+ func(i int, atype ast.Expr) {
+ if i > 0 || fn.Recv != nil {
+ fmt.Fprintf(cdeclBuf, ", ")
+ }
+ t := p.cgoType(atype)
+ fmt.Fprintf(cdeclBuf, "%s p%d", t.C, i)
+ })
+ fmt.Fprintf(cdeclBuf, ")")
+ cParams := cdeclBuf.String()
+
+ // 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
+ // code.
+ goName := "Cgoexp_" + exp.ExpName
+ fmt.Fprintf(fgcch, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, goName)
+ fmt.Fprint(fgcch, "\n")
+
+ // Use a #define so that the C code that includes
+ // cgo_export.h will be able to refer to the Go
+ // function using the expected name.
+ fmt.Fprintf(fgcch, "#define %s %s\n", exp.ExpName, goName)
+
+ // Use a #undef in _cgo_export.c so that we ignore the
+ // #define from cgo_export.h, since here we are
+ // defining the real function.
+ fmt.Fprintf(fgcc, "#undef %s\n", exp.ExpName)
+
+ fmt.Fprint(fgcc, "\n")
+ fmt.Fprintf(fgcc, "%s %s %s {\n", cRet, exp.ExpName, cParams)
+ fmt.Fprint(fgcc, "\t")
+ if resultCount > 0 {
+ fmt.Fprint(fgcc, "return ")
+ }
+ fmt.Fprintf(fgcc, "%s(", goName)
+ if fn.Recv != nil {
+ fmt.Fprint(fgcc, "recv")
+ }
+ forFieldList(fntype.Params,
+ func(i int, atype ast.Expr) {
+ if i > 0 || fn.Recv != nil {
+ fmt.Fprintf(fgcc, ", ")
+ }
+ fmt.Fprintf(fgcc, "p%d", i)
+ })
+ fmt.Fprint(fgcc, ");\n")
+ fmt.Fprint(fgcc, "}\n")
+
+ // Dummy declaration for _cgo_main.c
+ fmt.Fprintf(fm, "%s %s %s {}\n", cRet, goName, cParams)
+
+ // For gccgo we use a wrapper function in Go, in order
+ // to call CgocallBack and CgocallBackDone.
+
+ // This code uses printer.Fprint, not conf.Fprint,
+ // because we don't want //line comments in the middle
+ // of the function types.
+ fmt.Fprint(fgo2, "\n")
+ fmt.Fprintf(fgo2, "func %s(", goName)
+ if fn.Recv != nil {
+ fmt.Fprint(fgo2, "recv ")
+ printer.Fprint(fgo2, fset, fn.Recv.List[0].Type)
+ }
+ forFieldList(fntype.Params,
+ func(i int, atype ast.Expr) {
+ if i > 0 || fn.Recv != nil {
+ fmt.Fprintf(fgo2, ", ")
+ }
+ fmt.Fprintf(fgo2, "p%d ", i)
+ printer.Fprint(fgo2, fset, atype)
+ })
+ fmt.Fprintf(fgo2, ")")
+ if resultCount > 0 {
+ fmt.Fprintf(fgo2, " (")
+ forFieldList(fntype.Results,
+ func(i int, atype ast.Expr) {
+ if i > 0 {
+ fmt.Fprint(fgo2, ", ")
+ }
+ printer.Fprint(fgo2, fset, atype)
+ })
+ fmt.Fprint(fgo2, ")")
+ }
+ fmt.Fprint(fgo2, " {\n")
+ fmt.Fprint(fgo2, "\tsyscall.CgocallBack()\n")
+ fmt.Fprint(fgo2, "\tdefer syscall.CgocallBackDone()\n")
+ fmt.Fprint(fgo2, "\t")
+ if resultCount > 0 {
+ fmt.Fprint(fgo2, "return ")
+ }
+ if fn.Recv != nil {
+ fmt.Fprint(fgo2, "recv.")
+ }
+ fmt.Fprintf(fgo2, "%s(", exp.Func.Name)
+ forFieldList(fntype.Params,
+ func(i int, atype ast.Expr) {
+ if i > 0 {
+ fmt.Fprint(fgo2, ", ")
+ }
+ fmt.Fprintf(fgo2, "p%d", i)
+ })
+ fmt.Fprint(fgo2, ")\n")
+ fmt.Fprint(fgo2, "}\n")
+ }
+}
+
+// Return the package prefix when using gccgo.
+func (p *Package) gccgoSymbolPrefix() string {
+ if !*gccgo {
+ return ""
+ }
+
+ clean := func(r rune) rune {
+ switch {
+ case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z',
+ '0' <= r && r <= '9':
+ return r
+ }
+ return '_'
+ }
+
+ if *gccgopkgpath != "" {
+ return strings.Map(clean, *gccgopkgpath)
+ }
+ if *gccgoprefix == "" && p.PackageName == "main" {
+ return "main"
+ }
+ prefix := strings.Map(clean, *gccgoprefix)
+ if prefix == "" {
+ prefix = "go"
+ }
+ return prefix + "." + p.PackageName
+}
+
+// Call a function for each entry in an ast.FieldList, passing the
+// index into the list and the type.
+func forFieldList(fl *ast.FieldList, fn func(int, ast.Expr)) {
+ if fl == nil {
+ return
+ }
+ i := 0
+ for _, r := range fl.List {
+ if r.Names == nil {
+ fn(i, r.Type)
+ i++
+ } else {
+ for range r.Names {
+ fn(i, r.Type)
+ i++
+ }
+ }
+ }
+}
+
+func c(repr string, args ...interface{}) *TypeRepr {
+ return &TypeRepr{repr, args}
+}
+
+// Map predeclared Go types to Type.
+var goTypes = map[string]*Type{
+ "bool": {Size: 1, Align: 1, C: c("GoUint8")},
+ "byte": {Size: 1, Align: 1, C: c("GoUint8")},
+ "int": {Size: 0, Align: 0, C: c("GoInt")},
+ "uint": {Size: 0, Align: 0, C: c("GoUint")},
+ "rune": {Size: 4, Align: 4, C: c("GoInt32")},
+ "int8": {Size: 1, Align: 1, C: c("GoInt8")},
+ "uint8": {Size: 1, Align: 1, C: c("GoUint8")},
+ "int16": {Size: 2, Align: 2, C: c("GoInt16")},
+ "uint16": {Size: 2, Align: 2, C: c("GoUint16")},
+ "int32": {Size: 4, Align: 4, C: c("GoInt32")},
+ "uint32": {Size: 4, Align: 4, C: c("GoUint32")},
+ "int64": {Size: 8, Align: 8, C: c("GoInt64")},
+ "uint64": {Size: 8, Align: 8, C: c("GoUint64")},
+ "float32": {Size: 4, Align: 4, C: c("GoFloat32")},
+ "float64": {Size: 8, Align: 8, C: c("GoFloat64")},
+ "complex64": {Size: 8, Align: 8, C: c("GoComplex64")},
+ "complex128": {Size: 16, Align: 16, C: c("GoComplex128")},
+}
+
+// Map an ast type to a Type.
+func (p *Package) cgoType(e ast.Expr) *Type {
+ switch t := e.(type) {
+ case *ast.StarExpr:
+ x := p.cgoType(t.X)
+ return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("%s*", x.C)}
+ case *ast.ArrayType:
+ if t.Len == nil {
+ // Slice: pointer, len, cap.
+ return &Type{Size: p.PtrSize * 3, Align: p.PtrSize, C: c("GoSlice")}
+ }
+ case *ast.StructType:
+ // TODO
+ case *ast.FuncType:
+ return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*")}
+ case *ast.InterfaceType:
+ return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoInterface")}
+ case *ast.MapType:
+ return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoMap")}
+ case *ast.ChanType:
+ return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoChan")}
+ case *ast.Ident:
+ // Look up the type in the top level declarations.
+ // TODO: Handle types defined within a function.
+ for _, d := range p.Decl {
+ gd, ok := d.(*ast.GenDecl)
+ if !ok || gd.Tok != token.TYPE {
+ continue
+ }
+ for _, spec := range gd.Specs {
+ ts, ok := spec.(*ast.TypeSpec)
+ if !ok {
+ continue
+ }
+ if ts.Name.Name == t.Name {
+ return p.cgoType(ts.Type)
+ }
+ }
+ }
+ if def := typedef[t.Name]; def != nil {
+ return def
+ }
+ if t.Name == "uintptr" {
+ return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoUintptr")}
+ }
+ if t.Name == "string" {
+ // The string data is 1 pointer + 1 (pointer-sized) int.
+ return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoString")}
+ }
+ if t.Name == "error" {
+ return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoInterface")}
+ }
+ if r, ok := goTypes[t.Name]; ok {
+ if r.Size == 0 { // int or uint
+ rr := new(Type)
+ *rr = *r
+ rr.Size = p.IntSize
+ rr.Align = p.IntSize
+ r = rr
+ }
+ if r.Align > p.PtrSize {
+ r.Align = p.PtrSize
+ }
+ return r
+ }
+ error_(e.Pos(), "unrecognized Go type %s", t.Name)
+ return &Type{Size: 4, Align: 4, C: c("int")}
+ case *ast.SelectorExpr:
+ id, ok := t.X.(*ast.Ident)
+ if ok && id.Name == "unsafe" && t.Sel.Name == "Pointer" {
+ return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*")}
+ }
+ }
+ error_(e.Pos(), "Go type not supported in export: %s", gofmt(e))
+ return &Type{Size: 4, Align: 4, C: c("int")}
+}
+
+const gccProlog = `
+// Usual nonsense: if x and y are not equal, the type will be invalid
+// (have a negative array count) and an inscrutable error will come
+// out of the compiler and hopefully mention "name".
+#define __cgo_compile_assert_eq(x, y, name) typedef char name[(x-y)*(x-y)*-2+1];
+
+// Check at compile time that the sizes we use match our expectations.
+#define __cgo_size_assert(t, n) __cgo_compile_assert_eq(sizeof(t), n, _cgo_sizeof_##t##_is_not_##n)
+
+__cgo_size_assert(char, 1)
+__cgo_size_assert(short, 2)
+__cgo_size_assert(int, 4)
+typedef long long __cgo_long_long;
+__cgo_size_assert(__cgo_long_long, 8)
+__cgo_size_assert(float, 4)
+__cgo_size_assert(double, 8)
+
+extern char* _cgo_topofstack(void);
+
+#include <errno.h>
+#include <string.h>
+`
+
+const builtinProlog = `
+#include <stddef.h> /* for ptrdiff_t and size_t below */
+
+/* Define intgo when compiling with GCC. */
+typedef ptrdiff_t intgo;
+
+typedef struct { char *p; intgo n; } _GoString_;
+typedef struct { char *p; intgo n; intgo c; } _GoBytes_;
+_GoString_ GoString(char *p);
+_GoString_ GoStringN(char *p, int l);
+_GoBytes_ GoBytes(void *p, int n);
+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
+`
+
+const goStringDef = `
+var _cgo_runtime_gostring func(*_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
+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
+func _Cfunc_GoBytes(p unsafe.Pointer, l _Ctype_int) []byte {
+ return _cgo_runtime_gobytes(p, int(l))
+}
+`
+
+const cStringDef = `
+func _Cfunc_CString(s string) *_Ctype_char {
+ p := _cgo_runtime_cmalloc(uintptr(len(s)+1))
+ pp := (*[1<<30]byte)(p)
+ copy(pp[:], s)
+ pp[len(s)] = 0
+ return (*_Ctype_char)(p)
+}
+`
+
+const cMallocDef = `
+func _Cfunc__CMalloc(n _Ctype_size_t) unsafe.Pointer {
+ return _cgo_runtime_cmalloc(uintptr(n))
+}
+`
+
+var builtinDefs = map[string]string{
+ "GoString": goStringDef,
+ "GoStringN": goStringNDef,
+ "GoBytes": goBytesDef,
+ "CString": cStringDef,
+ "_CMalloc": cMallocDef,
+}
+
+func (p *Package) cPrologGccgo() string {
+ return strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1)
+}
+
+const cPrologGccgo = `
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef unsigned char byte;
+typedef intptr_t intgo;
+
+struct __go_string {
+ const unsigned char *__data;
+ intgo __length;
+};
+
+typedef struct __go_open_array {
+ void* __values;
+ intgo __count;
+ intgo __capacity;
+} Slice;
+
+struct __go_string __go_byte_array_to_string(const void* p, intgo len);
+struct __go_open_array __go_string_to_byte_array (struct __go_string str);
+
+const char *_cgoPREFIX_Cfunc_CString(struct __go_string s) {
+ char *p = malloc(s.__length+1);
+ memmove(p, s.__data, s.__length);
+ p[s.__length] = 0;
+ return p;
+}
+
+struct __go_string _cgoPREFIX_Cfunc_GoString(char *p) {
+ intgo len = (p != NULL) ? strlen(p) : 0;
+ return __go_byte_array_to_string(p, len);
+}
+
+struct __go_string _cgoPREFIX_Cfunc_GoStringN(char *p, int32_t n) {
+ return __go_byte_array_to_string(p, n);
+}
+
+Slice _cgoPREFIX_Cfunc_GoBytes(char *p, int32_t n) {
+ struct __go_string s = { (const unsigned char *)p, n };
+ return __go_string_to_byte_array(s);
+}
+
+extern void runtime_throw(const char *);
+void *_cgoPREFIX_Cfunc__CMalloc(size_t n) {
+ void *p = malloc(n);
+ if(p == NULL && n == 0)
+ p = malloc(1);
+ if(p == NULL)
+ runtime_throw("runtime: C malloc failed");
+ return p;
+}
+`
+
+func (p *Package) gccExportHeaderProlog() string {
+ return strings.Replace(gccExportHeaderProlog, "GOINTBITS", fmt.Sprint(8*p.IntSize), -1)
+}
+
+const gccExportHeaderProlog = `
+typedef signed char GoInt8;
+typedef unsigned char GoUint8;
+typedef short GoInt16;
+typedef unsigned short GoUint16;
+typedef int GoInt32;
+typedef unsigned int GoUint32;
+typedef long long GoInt64;
+typedef unsigned long long GoUint64;
+typedef GoIntGOINTBITS GoInt;
+typedef GoUintGOINTBITS GoUint;
+typedef __SIZE_TYPE__ GoUintptr;
+typedef float GoFloat32;
+typedef double GoFloat64;
+typedef __complex float GoComplex64;
+typedef __complex double GoComplex128;
+
+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;
+`
diff --git a/libgo/go/cmd/cgo/util.go b/libgo/go/cmd/cgo/util.go
new file mode 100644
index 0000000000..4e7800d127
--- /dev/null
+++ b/libgo/go/cmd/cgo/util.go
@@ -0,0 +1,84 @@
+// 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 main
+
+import (
+ "bytes"
+ "fmt"
+ "go/token"
+ "os"
+ "os/exec"
+)
+
+// run runs the command argv, feeding in stdin on standard input.
+// It returns the output to standard output and standard error.
+// ok indicates whether the command exited successfully.
+func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
+ p := exec.Command(argv[0], argv[1:]...)
+ p.Stdin = bytes.NewReader(stdin)
+ var bout, berr bytes.Buffer
+ p.Stdout = &bout
+ p.Stderr = &berr
+ err := p.Run()
+ if _, ok := err.(*exec.ExitError); err != nil && !ok {
+ fatalf("%s", err)
+ }
+ ok = p.ProcessState.Success()
+ stdout, stderr = bout.Bytes(), berr.Bytes()
+ return
+}
+
+func lineno(pos token.Pos) string {
+ return fset.Position(pos).String()
+}
+
+// Die with an error message.
+func fatalf(msg string, args ...interface{}) {
+ // If we've already printed other errors, they might have
+ // caused the fatal condition. Assume they're enough.
+ if nerrors == 0 {
+ fmt.Fprintf(os.Stderr, msg+"\n", args...)
+ }
+ os.Exit(2)
+}
+
+var nerrors int
+
+func error_(pos token.Pos, msg string, args ...interface{}) {
+ nerrors++
+ if pos.IsValid() {
+ fmt.Fprintf(os.Stderr, "%s: ", fset.Position(pos).String())
+ }
+ fmt.Fprintf(os.Stderr, msg, args...)
+ fmt.Fprintf(os.Stderr, "\n")
+}
+
+// isName returns true if 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') {
+ return false
+ }
+ if i == 0 && '0' <= v && v <= '9' {
+ return false
+ }
+ }
+ return s != ""
+}
+
+func creat(name string) *os.File {
+ f, err := os.Create(name)
+ if err != nil {
+ fatalf("%s", err)
+ }
+ return f
+}
+
+func slashToUnderscore(c rune) rune {
+ if c == '/' || c == '\\' || c == ':' {
+ c = '_'
+ }
+ return c
+}
diff --git a/libgo/go/cmd/go/bootstrap.go b/libgo/go/cmd/go/bootstrap.go
new file mode 100644
index 0000000000..dc7ed5f4c0
--- /dev/null
+++ b/libgo/go/cmd/go/bootstrap.go
@@ -0,0 +1,30 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build cmd_go_bootstrap
+
+// This code is compiled only into the bootstrap 'go' binary.
+// These stubs avoid importing packages with large dependency
+// trees, like the use of "net/http" in vcs.go.
+
+package main
+
+import (
+ "errors"
+ "io"
+)
+
+var errHTTP = errors.New("no http in bootstrap go command")
+
+func httpGET(url string) ([]byte, error) {
+ return nil, errHTTP
+}
+
+func httpsOrHTTP(importPath string) (string, io.ReadCloser, error) {
+ return "", nil, errHTTP
+}
+
+func parseMetaGoImports(r io.Reader) ([]metaImport, error) {
+ panic("unreachable")
+}
diff --git a/libgo/go/cmd/go/build.go b/libgo/go/cmd/go/build.go
new file mode 100644
index 0000000000..781a43b5d9
--- /dev/null
+++ b/libgo/go/cmd/go/build.go
@@ -0,0 +1,2691 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "container/heap"
+ "errors"
+ "flag"
+ "fmt"
+ "go/build"
+ "io"
+ "io/ioutil"
+ "log"
+ "os"
+ "os/exec"
+ "path"
+ "path/filepath"
+ "regexp"
+ "runtime"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+var cmdBuild = &Command{
+ UsageLine: "build [-o output] [-i] [build flags] [packages]",
+ Short: "compile packages and dependencies",
+ Long: `
+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.
+ `,
+}
+
+func init() {
+ // break init cycle
+ cmdBuild.Run = runBuild
+ cmdInstall.Run = runInstall
+
+ cmdBuild.Flag.BoolVar(&buildI, "i", false, "")
+
+ addBuildFlags(cmdBuild)
+ addBuildFlags(cmdInstall)
+}
+
+// Flags set by multiple commands.
+var buildA bool // -a flag
+var buildN bool // -n flag
+var buildP = runtime.NumCPU() // -p flag
+var buildV bool // -v flag
+var buildX bool // -x flag
+var buildI bool // -i flag
+var buildO = cmdBuild.Flag.String("o", "", "output file")
+var buildWork bool // -work 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
+
+// Require the source for go std packages
+var reqStdPkgSrc bool
+var buildContext = build.Default
+var buildToolchain toolchain = noToolchain{}
+
+// buildCompiler implements flag.Var.
+// It implements Set by updating both
+// buildToolchain and buildContext.Compiler.
+type buildCompiler struct{}
+
+func (c buildCompiler) Set(value string) error {
+ switch value {
+ case "gc":
+ buildToolchain = gcToolchain{}
+ case "gccgo":
+ buildToolchain = gccgoToolchain{}
+ default:
+ return fmt.Errorf("unknown compiler %q", value)
+ }
+ buildContext.Compiler = value
+ return nil
+}
+
+func (c buildCompiler) String() string {
+ return buildContext.Compiler
+}
+
+func init() {
+ switch build.Default.Compiler {
+ case "gc":
+ buildToolchain = gcToolchain{}
+ case "gccgo":
+ buildToolchain = gccgoToolchain{}
+ }
+}
+
+// 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)(&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.BoolVar(&buildRace, "race", false, "")
+ switch build.Default.Compiler {
+ case "gc":
+ reqStdPkgSrc = true
+ case "gccgo":
+ reqStdPkgSrc = false
+ }
+}
+
+func addBuildFlagsNX(cmd *Command) {
+ cmd.Flag.BoolVar(&buildN, "n", false, "")
+ cmd.Flag.BoolVar(&buildX, "x", false, "")
+}
+
+func isSpaceByte(c byte) bool {
+ return c == ' ' || c == '\t' || c == '\n' || c == '\r'
+}
+
+// fileExtSplit expects a filename and returns the name
+// and ext (without the dot). If the file has no
+// extension, ext will be empty.
+func fileExtSplit(file string) (name, ext string) {
+ dotExt := filepath.Ext(file)
+ name = file[:len(file)-len(dotExt)]
+ if dotExt != "" {
+ ext = dotExt[1:]
+ }
+ return
+}
+
+type stringsFlag []string
+
+func (v *stringsFlag) Set(s string) error {
+ var err error
+ *v, err = splitQuotedFields(s)
+ if *v == nil {
+ *v = []string{}
+ }
+ return err
+}
+
+func splitQuotedFields(s string) ([]string, error) {
+ // Split fields allowing '' or "" around elements.
+ // Quotes further inside the string do not count.
+ var f []string
+ for len(s) > 0 {
+ for len(s) > 0 && isSpaceByte(s[0]) {
+ s = s[1:]
+ }
+ if len(s) == 0 {
+ break
+ }
+ // Accepted quoted string. No unescaping inside.
+ if s[0] == '"' || s[0] == '\'' {
+ quote := s[0]
+ s = s[1:]
+ i := 0
+ for i < len(s) && s[i] != quote {
+ i++
+ }
+ if i >= len(s) {
+ return nil, fmt.Errorf("unterminated %c string", quote)
+ }
+ f = append(f, s[:i])
+ s = s[i+1:]
+ continue
+ }
+ i := 0
+ for i < len(s) && !isSpaceByte(s[i]) {
+ i++
+ }
+ f = append(f, s[:i])
+ s = s[i:]
+ }
+ return f, nil
+}
+
+func (v *stringsFlag) String() string {
+ return "<stringsFlag>"
+}
+
+func runBuild(cmd *Command, args []string) {
+ raceInit()
+ var b builder
+ b.init()
+
+ pkgs := packagesForBuild(args)
+
+ if len(pkgs) == 1 && pkgs[0].Name == "main" && *buildO == "" {
+ _, *buildO = path.Split(pkgs[0].ImportPath)
+ *buildO += exeSuffix
+ }
+
+ // sanity check some often mis-used options
+ switch buildContext.Compiler {
+ case "gccgo":
+ if len(buildGcflags) != 0 {
+ fmt.Println("go build: when using gccgo toolchain, please pass compiler flags using -gccgoflags, not -gcflags")
+ }
+ if len(buildLdflags) != 0 {
+ fmt.Println("go build: when using gccgo toolchain, please pass linker flags using -gccgoflags, not -ldflags")
+ }
+ case "gc":
+ if len(buildGccgoflags) != 0 {
+ fmt.Println("go build: when using gc toolchain, please pass compile flags using -gcflags, and linker flags using -ldflags")
+ }
+ }
+
+ depMode := modeBuild
+ if buildI {
+ depMode = modeInstall
+ }
+
+ if *buildO != "" {
+ if len(pkgs) > 1 {
+ fatalf("go build: cannot use -o with multiple packages")
+ } else if len(pkgs) == 0 {
+ fatalf("no packages to build")
+ }
+ p := pkgs[0]
+ p.target = "" // 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))
+ }
+ b.do(a)
+}
+
+var cmdInstall = &Command{
+ UsageLine: "install [build flags] [packages]",
+ Short: "compile and install packages and dependencies",
+ Long: `
+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.
+ `,
+}
+
+func runInstall(cmd *Command, args []string) {
+ raceInit()
+ pkgs := packagesForBuild(args)
+
+ for _, p := range pkgs {
+ if p.Target == "" && (!p.Standard || p.ImportPath != "unsafe") {
+ if p.cmdline {
+ errorf("go install: no install location for .go files listed on command line (GOBIN not set)")
+ } else if 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)
+ }
+ }
+ }
+ exitIfErrors()
+
+ var b builder
+ b.init()
+ a := &action{}
+ for _, p := range pkgs {
+ a.deps = append(a.deps, b.action(modeInstall, modeInstall, p))
+ }
+ b.do(a)
+}
+
+// Global build parameters (used during package load)
+var (
+ goarch string
+ goos string
+ archChar string
+ exeSuffix string
+)
+
+func init() {
+ goarch = buildContext.GOARCH
+ goos = buildContext.GOOS
+ 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.
+// It does not hold per-package state, because we
+// build packages in parallel, and the builder is shared.
+type builder struct {
+ work string // the temporary work directory (ends in filepath.Separator)
+ actionCache map[cacheKey]*action // a cache of already-constructed actions
+ mkdirCache map[string]bool // a cache of created directories
+ print func(args ...interface{}) (int, error)
+
+ output sync.Mutex
+ scriptDir string // current directory in printed script
+
+ exec sync.Mutex
+ readySema chan bool
+ ready actionQueue
+}
+
+// An action represents a single action in the action graph.
+type action struct {
+ p *Package // the package this action works on
+ deps []*action // actions that must happen before this one
+ triggers []*action // inverse of deps
+ cgo *action // action for cgo binary if needed
+ args []string // additional args for runProgram
+ testOutput *bytes.Buffer // test output buffer
+
+ f func(*builder, *action) error // the action itself (nil = no-op)
+ ignoreFail bool // whether to run f even if dependencies fail
+
+ // Generated files, directories.
+ link bool // target is executable, not just package
+ pkgdir string // the -I or -L argument to use when importing this package
+ objdir string // directory for intermediate objects
+ objpkg string // the intermediate package .a file created during the action
+ target string // goal of the action: the created package or executable
+
+ // Execution state.
+ pending int // number of deps yet to complete
+ priority int // relative execution priority
+ failed bool // whether the action failed
+}
+
+// cacheKey is the key for the action cache.
+type cacheKey struct {
+ mode buildMode
+ p *Package
+}
+
+// buildMode specifies the build mode:
+// are we just building things or also installing the results?
+type buildMode int
+
+const (
+ modeBuild buildMode = iota
+ modeInstall
+)
+
+var (
+ goroot = filepath.Clean(runtime.GOROOT())
+ gobin = os.Getenv("GOBIN")
+ gorootBin = filepath.Join(goroot, "bin")
+ gorootPkg = filepath.Join(goroot, "pkg")
+ gorootSrc = filepath.Join(goroot, "src")
+)
+
+func (b *builder) init() {
+ var err error
+ b.print = func(a ...interface{}) (int, error) {
+ return fmt.Fprint(os.Stderr, a...)
+ }
+ b.actionCache = make(map[cacheKey]*action)
+ b.mkdirCache = make(map[string]bool)
+
+ if buildN {
+ b.work = "$WORK"
+ } else {
+ b.work, err = ioutil.TempDir("", "go-build")
+ if err != nil {
+ fatalf("%s", err)
+ }
+ if buildX || buildWork {
+ fmt.Fprintf(os.Stderr, "WORK=%s\n", b.work)
+ }
+ if !buildWork {
+ workdir := b.work
+ atexit(func() { os.RemoveAll(workdir) })
+ }
+ }
+}
+
+// goFilesPackage creates a package for building a collection of Go files
+// (typically named on the command line). The target is named p.a for
+// package p or named after the first Go file for package main.
+func goFilesPackage(gofiles []string) *Package {
+ // TODO: Remove this restriction.
+ for _, f := range gofiles {
+ if !strings.HasSuffix(f, ".go") {
+ fatalf("named files must be .go files")
+ }
+ }
+
+ var stk importStack
+ ctxt := buildContext
+ ctxt.UseAllFiles = true
+
+ // Synthesize fake "directory" that only shows the named files,
+ // to make it look like this is a standard package or
+ // command directory. So that local imports resolve
+ // consistently, the files must all be in the same directory.
+ var dirent []os.FileInfo
+ var dir string
+ for _, file := range gofiles {
+ fi, err := os.Stat(file)
+ if err != nil {
+ fatalf("%s", err)
+ }
+ if fi.IsDir() {
+ fatalf("%s is a directory, should be a Go file", file)
+ }
+ dir1, _ := filepath.Split(file)
+ if dir == "" {
+ dir = dir1
+ } else if dir != dir1 {
+ fatalf("named files must all be in one directory; have %s and %s", dir, dir1)
+ }
+ dirent = append(dirent, fi)
+ }
+ ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dirent, nil }
+
+ var err error
+ if dir == "" {
+ dir = cwd
+ }
+ dir, err = filepath.Abs(dir)
+ if err != nil {
+ fatalf("%s", err)
+ }
+
+ bp, err := ctxt.ImportDir(dir, 0)
+ pkg := new(Package)
+ pkg.local = true
+ pkg.cmdline = true
+ pkg.load(&stk, bp, err)
+ pkg.localPrefix = dirToImportPath(dir)
+ pkg.ImportPath = "command-line-arguments"
+ pkg.target = ""
+
+ if pkg.Name == "main" {
+ _, elem := filepath.Split(gofiles[0])
+ exe := elem[:len(elem)-len(".go")] + exeSuffix
+ if *buildO == "" {
+ *buildO = exe
+ }
+ if gobin != "" {
+ pkg.target = filepath.Join(gobin, exe)
+ }
+ } else {
+ if *buildO == "" {
+ *buildO = pkg.Name + ".a"
+ }
+ }
+ pkg.Target = pkg.target
+ pkg.Stale = true
+
+ computeStale(pkg)
+ return pkg
+}
+
+// action returns the action for applying the given operation (mode) to the package.
+// depMode is the action to use when building dependencies.
+func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action {
+ key := cacheKey{mode, p}
+ a := b.actionCache[key]
+ if a != nil {
+ 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))
+ }
+
+ // If we are not doing a cross-build, then record the binary we'll
+ // generate for cgo as a dependency of the build of any package
+ // 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 p.Standard {
+ switch p.ImportPath {
+ case "builtin", "unsafe":
+ // Fake packages - nothing to build.
+ return a
+ }
+ // gccgo standard library is "fake" too.
+ if _, ok := buildToolchain.(gccgoToolchain); ok {
+ // the target name is needed for cgo.
+ a.target = p.target
+ return a
+ }
+ }
+
+ if !p.Stale && p.target != "" {
+ // p.Stale==false implies that p.target is up-to-date.
+ // Record target name for use by actions depending on this one.
+ a.target = p.target
+ return a
+ }
+
+ if p.local && p.target == "" {
+ // Imported via local path. No permanent target.
+ mode = modeBuild
+ }
+ work := p.pkgdir
+ if work == "" {
+ work = b.work
+ }
+ a.objdir = filepath.Join(work, a.p.ImportPath, "_obj") + string(filepath.Separator)
+ a.objpkg = buildToolchain.pkgpath(work, a.p)
+ a.link = p.Name == "main"
+
+ switch mode {
+ case modeInstall:
+ a.f = (*builder).install
+ a.deps = []*action{b.action(modeBuild, depMode, p)}
+ a.target = a.p.target
+ case modeBuild:
+ a.f = (*builder).build
+ a.target = a.objpkg
+ if a.link {
+ // An executable file. (This is the name of a temporary file.)
+ // Because we run the temporary file in 'go run' and 'go test',
+ // the name will show up in ps listings. If the caller has specified
+ // a name, use that instead of a.out. The binary is generated
+ // in an otherwise empty subdirectory named exe to avoid
+ // naming conflicts. The only possible conflict is if we were
+ // to create a top-level package named exe.
+ name := "a.out"
+ if p.exeName != "" {
+ name = p.exeName
+ }
+ a.target = a.objdir + filepath.Join("exe", name) + exeSuffix
+ }
+ }
+
+ 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 {
+ seen := map[*action]bool{}
+ all := []*action{}
+ var walk func(*action)
+ walk = func(a *action) {
+ if seen[a] {
+ return
+ }
+ seen[a] = true
+ for _, a1 := range a.deps {
+ walk(a1)
+ }
+ all = append(all, a)
+ }
+ walk(root)
+ return all
+}
+
+// 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.
+ // The original implementation here was a true queue
+ // (using a channel) but it had the effect of getting
+ // distracted by low-level leaf actions to the detriment
+ // of completing higher-level actions. The order of
+ // work does not matter much to overall execution time,
+ // but when running "go test std" it is nice to see each test
+ // results as soon as possible. The priorities assigned
+ // ensure that, all else being equal, the execution prefers
+ // to do what it would have done first in a simple depth-first
+ // dependency order traversal.
+ all := actionList(root)
+ for i, a := range all {
+ a.priority = i
+ }
+
+ b.readySema = make(chan bool, len(all))
+
+ // Initialize per-action execution state.
+ for _, a := range all {
+ for _, a1 := range a.deps {
+ a1.triggers = append(a1.triggers, a)
+ }
+ a.pending = len(a.deps)
+ if a.pending == 0 {
+ b.ready.push(a)
+ b.readySema <- true
+ }
+ }
+
+ // Handle runs a single action and takes care of triggering
+ // any actions that are runnable as a result.
+ handle := func(a *action) {
+ var err error
+ if a.f != nil && (!a.failed || a.ignoreFail) {
+ err = a.f(b, a)
+ }
+
+ // The actions run in parallel but all the updates to the
+ // shared work state are serialized through b.exec.
+ b.exec.Lock()
+ defer b.exec.Unlock()
+
+ if err != nil {
+ if err == errPrintedOutput {
+ setExitStatus(2)
+ } else {
+ errorf("%s", err)
+ }
+ a.failed = true
+ }
+
+ for _, a0 := range a.triggers {
+ if a.failed {
+ a0.failed = true
+ }
+ if a0.pending--; a0.pending == 0 {
+ b.ready.push(a0)
+ b.readySema <- true
+ }
+ }
+
+ if a == root {
+ close(b.readySema)
+ }
+ }
+
+ var wg sync.WaitGroup
+
+ // Kick off goroutines according to parallelism.
+ // If we are using the -n flag (just printing commands)
+ // drop the parallelism to 1, both to make the output
+ // deterministic and because there is no real work anyway.
+ par := buildP
+ if buildN {
+ par = 1
+ }
+ for i := 0; i < par; i++ {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ for {
+ select {
+ case _, ok := <-b.readySema:
+ if !ok {
+ return
+ }
+ // Receiving a value from b.readySema entitles
+ // us to take from the ready queue.
+ b.exec.Lock()
+ a := b.ready.pop()
+ b.exec.Unlock()
+ handle(a)
+ case <-interrupted:
+ setExitStatus(1)
+ return
+ }
+ }
+ }()
+ }
+
+ wg.Wait()
+}
+
+// hasString reports whether s appears in the list of strings.
+func hasString(strings []string, s string) bool {
+ for _, t := range strings {
+ if s == t {
+ return true
+ }
+ }
+ return false
+}
+
+// build is the action for building a single package or command.
+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).
+ 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, ","))
+ }
+ // Same as above for Objective-C files
+ if len(a.p.MFiles) > 0 && !a.p.usesCgo() && !a.p.usesSwig() {
+ return fmt.Errorf("can't build package %s because it contains Objective-C files (%s) but it's not using cgo nor SWIG",
+ a.p.ImportPath, strings.Join(a.p.MFiles, ","))
+ }
+ defer func() {
+ if err != nil && err != errPrintedOutput {
+ err = fmt.Errorf("go build %s: %v", a.p.ImportPath, err)
+ }
+ }()
+ if buildN {
+ // In -n mode, print a banner between packages.
+ // The banner is five lines so that when changes to
+ // different sections of the bootstrap script have to
+ // be merged, the banners give patch something
+ // to use to find its context.
+ fmt.Printf("\n#\n# %s\n#\n\n", a.p.ImportPath)
+ }
+
+ if buildV {
+ fmt.Fprintf(os.Stderr, "%s\n", a.p.ImportPath)
+ }
+
+ if a.p.Standard && a.p.ImportPath == "runtime" && buildContext.Compiler == "gc" &&
+ !hasString(a.p.HFiles, "zasm_"+buildContext.GOOS+"_"+buildContext.GOARCH+".h") {
+ return fmt.Errorf("%s/%s must be bootstrapped using make%v", buildContext.GOOS, buildContext.GOARCH, defaultSuffix())
+ }
+
+ // Make build directory.
+ obj := a.objdir
+ if err := b.mkdir(obj); err != nil {
+ return err
+ }
+
+ // make target directory
+ dir, _ := filepath.Split(a.target)
+ if dir != "" {
+ if err := b.mkdir(dir); err != nil {
+ return err
+ }
+ }
+
+ var gofiles, cfiles, sfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string
+
+ gofiles = append(gofiles, a.p.GoFiles...)
+ cfiles = append(cfiles, a.p.CFiles...)
+ sfiles = append(sfiles, a.p.SFiles...)
+
+ if a.p.usesCgo() || a.p.usesSwig() {
+ if pcCFLAGS, pcLDFLAGS, err = b.getPkgConfigFlags(a.p); err != nil {
+ return
+ }
+ }
+ // Run cgo.
+ if a.p.usesCgo() {
+ // In a package using cgo, cgo compiles the C, C++ and assembly files with gcc.
+ // There is one exception: runtime/cgo's job is to bridge the
+ // cgo and non-cgo worlds, so it necessarily has files in both.
+ // In that case gcc only gets the gcc_* files.
+ var gccfiles []string
+ if a.p.Standard && a.p.ImportPath == "runtime/cgo" {
+ filter := func(files, nongcc, gcc []string) ([]string, []string) {
+ for _, f := range files {
+ if strings.HasPrefix(f, "gcc_") {
+ gcc = append(gcc, f)
+ } else {
+ nongcc = append(nongcc, f)
+ }
+ }
+ return nongcc, gcc
+ }
+ cfiles, gccfiles = filter(cfiles, cfiles[:0], gccfiles)
+ sfiles, gccfiles = filter(sfiles, sfiles[:0], gccfiles)
+ } else {
+ gccfiles = append(cfiles, sfiles...)
+ cfiles = nil
+ sfiles = nil
+ }
+
+ cgoExe := tool("cgo")
+ 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)
+ if err != nil {
+ return err
+ }
+ cgoObjects = append(cgoObjects, outObj...)
+ gofiles = append(gofiles, outGo...)
+ }
+
+ if len(gofiles) == 0 {
+ return &build.NoGoError{Dir: a.p.Dir}
+ }
+
+ // If we're doing coverage, preprocess the .go files and put them in the work directory
+ if a.p.coverMode != "" {
+ for i, file := range gofiles {
+ var sourceFile string
+ var coverFile string
+ var key string
+ if strings.HasSuffix(file, ".cgo1.go") {
+ // cgo files have absolute paths
+ base := filepath.Base(file)
+ sourceFile = file
+ coverFile = filepath.Join(obj, base)
+ key = strings.TrimSuffix(base, ".cgo1.go") + ".go"
+ } else {
+ sourceFile = filepath.Join(a.p.Dir, file)
+ coverFile = filepath.Join(obj, file)
+ key = file
+ }
+ cover := a.p.coverVars[key]
+ if cover == nil || isTestFile(file) {
+ // Not covering this file.
+ continue
+ }
+ if err := b.cover(a, coverFile, sourceFile, 0666, cover.Var); err != nil {
+ return err
+ }
+ gofiles[i] = coverFile
+ }
+ }
+
+ // Prepare Go import path list.
+ inc := b.includeArgs("-I", a.deps)
+
+ // Compile Go.
+ ofile, out, err := buildToolchain.gc(b, a.p, a.objpkg, obj, inc, gofiles)
+ if len(out) > 0 {
+ b.showOutput(a.p.Dir, a.p.ImportPath, b.processOutput(out))
+ if err != nil {
+ return errPrintedOutput
+ }
+ }
+ if err != nil {
+ return err
+ }
+ if ofile != a.objpkg {
+ objects = append(objects, ofile)
+ }
+
+ // Copy .h files named for goos or goarch or goos_goarch
+ // to names using GOOS and GOARCH.
+ // For example, defs_linux_amd64.h becomes defs_GOOS_GOARCH.h.
+ _goos_goarch := "_" + goos + "_" + goarch
+ _goos := "_" + goos
+ _goarch := "_" + goarch
+ for _, file := range a.p.HFiles {
+ name, ext := fileExtSplit(file)
+ 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 {
+ 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 {
+ 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 {
+ return err
+ }
+ }
+ }
+
+ objExt := archChar
+ if _, ok := buildToolchain.(gccgoToolchain); ok {
+ objExt = "o"
+ }
+
+ for _, file := range cfiles {
+ out := file[:len(file)-len(".c")] + "." + objExt
+ if err := buildToolchain.cc(b, a.p, obj, obj+out, file); err != nil {
+ return err
+ }
+ objects = append(objects, out)
+ }
+
+ // Assemble .s files.
+ for _, file := range sfiles {
+ out := file[:len(file)-len(".s")] + "." + objExt
+ if err := buildToolchain.asm(b, a.p, obj, obj+out, file); err != nil {
+ return err
+ }
+ objects = append(objects, out)
+ }
+
+ // 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
+ objects = append(objects, cgoObjects...)
+
+ // Add system object files.
+ for _, syso := range a.p.SysoFiles {
+ objects = append(objects, filepath.Join(a.p.Dir, syso))
+ }
+
+ // Pack into archive in obj directory.
+ // If the Go compiler wrote an archive, we only need to add the
+ // object files for non-Go sources to the archive.
+ // If the Go compiler wrote an archive and the package is entirely
+ // Go sources, there is no pack to execute at all.
+ if len(objects) > 0 {
+ if err := buildToolchain.pack(b, a.p, obj, a.objpkg, objects); err != nil {
+ return err
+ }
+ }
+
+ // Link if needed.
+ if a.link {
+ // The compiler only cares about direct imports, but the
+ // 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 {
+ return err
+ }
+ }
+
+ return nil
+}
+
+// Calls pkg-config if needed and returns the cflags/ldflags needed to build the package.
+func (b *builder) getPkgConfigFlags(p *Package) (cflags, ldflags []string, err error) {
+ if pkgs := p.CgoPkgConfig; len(pkgs) > 0 {
+ var out []byte
+ out, err = b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--cflags", pkgs)
+ if err != nil {
+ b.showOutput(p.Dir, "pkg-config --cflags "+strings.Join(pkgs, " "), string(out))
+ b.print(err.Error() + "\n")
+ err = errPrintedOutput
+ return
+ }
+ if len(out) > 0 {
+ cflags = strings.Fields(string(out))
+ }
+ out, err = b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--libs", pkgs)
+ if err != nil {
+ b.showOutput(p.Dir, "pkg-config --libs "+strings.Join(pkgs, " "), string(out))
+ b.print(err.Error() + "\n")
+ err = errPrintedOutput
+ return
+ }
+ if len(out) > 0 {
+ ldflags = strings.Fields(string(out))
+ }
+ }
+ return
+}
+
+// install is the action for installing a single package or executable.
+func (b *builder) install(a *action) (err error) {
+ defer func() {
+ if err != nil && err != errPrintedOutput {
+ err = fmt.Errorf("go install %s: %v", a.p.ImportPath, err)
+ }
+ }()
+ a1 := a.deps[0]
+ perm := os.FileMode(0644)
+ if a1.link {
+ perm = 0755
+ }
+
+ // make target directory
+ dir, _ := filepath.Split(a.target)
+ if dir != "" {
+ if err := b.mkdir(dir); err != nil {
+ return err
+ }
+ }
+
+ // remove object dir to keep the amount of
+ // garbage down in a large build. On an operating system
+ // with aggressive buffering, cleaning incrementally like
+ // this keeps the intermediate objects from hitting the disk.
+ if !buildWork {
+ defer os.RemoveAll(a1.objdir)
+ defer os.Remove(a1.target)
+ }
+
+ return b.moveOrCopyFile(a, a.target, a1.target, perm)
+}
+
+// includeArgs returns the -I or -L directory list for access
+// to the results of the list of actions.
+func (b *builder) includeArgs(flag string, all []*action) []string {
+ inc := []string{}
+ incMap := map[string]bool{
+ b.work: true, // handled later
+ gorootPkg: true,
+ "": true, // ignore empty strings
+ }
+
+ // Look in the temporary space for results of test-specific actions.
+ // This is the $WORK/my/package/_test directory for the
+ // package being built, so there are few of these.
+ for _, a1 := range all {
+ if dir := a1.pkgdir; dir != a1.p.build.PkgRoot && !incMap[dir] {
+ incMap[dir] = true
+ inc = append(inc, flag, dir)
+ }
+ }
+
+ // Also look in $WORK for any non-test packages that have
+ // been built but not installed.
+ inc = append(inc, flag, b.work)
+
+ // Finally, look in the installed package directories for each action.
+ for _, a1 := range all {
+ 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)
+ }
+ }
+
+ return inc
+}
+
+// moveOrCopyFile is like 'mv src dst' or 'cp src dst'.
+func (b *builder) moveOrCopyFile(a *action, dst, src string, perm os.FileMode) error {
+ if buildN {
+ b.showcmd("", "mv %s %s", src, dst)
+ return nil
+ }
+
+ // If we can update the mode and rename to the dst, do it.
+ // Otherwise fall back to standard copy.
+ if err := os.Chmod(src, perm); err == nil {
+ if err := os.Rename(src, dst); err == nil {
+ if buildX {
+ b.showcmd("", "mv %s %s", src, dst)
+ }
+ return nil
+ }
+ }
+
+ return b.copyFile(a, dst, src, perm)
+}
+
+// copyFile is like 'cp src dst'.
+func (b *builder) copyFile(a *action, dst, src string, perm os.FileMode) error {
+ if buildN || buildX {
+ b.showcmd("", "cp %s %s", src, dst)
+ if buildN {
+ return nil
+ }
+ }
+
+ sf, err := os.Open(src)
+ if err != nil {
+ return err
+ }
+ defer sf.Close()
+
+ // Be careful about removing/overwriting dst.
+ // Do not remove/overwrite if dst exists and is a directory
+ // or a non-object file.
+ if fi, err := os.Stat(dst); err == nil {
+ if fi.IsDir() {
+ return fmt.Errorf("build output %q already exists and is a directory", dst)
+ }
+ if !isObject(dst) {
+ return fmt.Errorf("build output %q already exists and is not an object file", dst)
+ }
+ }
+
+ // On Windows, remove lingering ~ file from last attempt.
+ if toolIsWindows {
+ if _, err := os.Stat(dst + "~"); err == nil {
+ os.Remove(dst + "~")
+ }
+ }
+
+ os.Remove(dst)
+ df, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
+ if err != nil && toolIsWindows {
+ // Windows does not allow deletion of a binary file
+ // while it is executing. Try to move it out of the way.
+ // If the move fails, which is likely, we'll try again the
+ // next time we do an install of this binary.
+ if err := os.Rename(dst, dst+"~"); err == nil {
+ os.Remove(dst + "~")
+ }
+ df, err = os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
+ }
+ if err != nil {
+ return err
+ }
+
+ _, err = io.Copy(df, sf)
+ df.Close()
+ if err != nil {
+ os.Remove(dst)
+ return fmt.Errorf("copying %s to %s: %v", src, dst, err)
+ }
+ return nil
+}
+
+// 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,
+ tool("cover"),
+ "-mode", a.p.coverMode,
+ "-var", varName,
+ "-o", dst,
+ src)
+}
+
+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
+}
+
+func isObject(s string) bool {
+ f, err := os.Open(s)
+ if err != nil {
+ return false
+ }
+ defer f.Close()
+ buf := make([]byte, 64)
+ io.ReadFull(f, buf)
+ for _, magic := range objectMagic {
+ if bytes.HasPrefix(buf, magic) {
+ return true
+ }
+ }
+ return false
+}
+
+// fmtcmd formats a command in the manner of fmt.Sprintf but also:
+//
+// If dir is non-empty and the script is not in dir right now,
+// fmtcmd inserts "cd dir\n" before the command.
+//
+// fmtcmd replaces the value of b.work with $WORK.
+// fmtcmd replaces the value of goroot with $GOROOT.
+// fmtcmd replaces the value of b.gobin with $GOBIN.
+//
+// fmtcmd replaces the name of the current directory with dot (.)
+// but only when it is at the beginning of a space-separated token.
+//
+func (b *builder) fmtcmd(dir string, format string, args ...interface{}) string {
+ cmd := fmt.Sprintf(format, args...)
+ if dir != "" && dir != "/" {
+ cmd = strings.Replace(" "+cmd, " "+dir, " .", -1)[1:]
+ if b.scriptDir != dir {
+ b.scriptDir = dir
+ cmd = "cd " + dir + "\n" + cmd
+ }
+ }
+ if b.work != "" {
+ cmd = strings.Replace(cmd, b.work, "$WORK", -1)
+ }
+ return cmd
+}
+
+// showcmd prints the given command to standard output
+// for the implementation of -n or -x.
+func (b *builder) showcmd(dir string, format string, args ...interface{}) {
+ b.output.Lock()
+ defer b.output.Unlock()
+ b.print(b.fmtcmd(dir, format, args...) + "\n")
+}
+
+// showOutput prints "# desc" followed by the given output.
+// The output is expected to contain references to 'dir', usually
+// the source directory for the package that has failed to build.
+// showOutput rewrites mentions of dir with a relative path to dir
+// when the relative path is shorter. This is usually more pleasant.
+// For example, if fmt doesn't compile and we are in src/html,
+// the output is
+//
+// $ go build
+// # fmt
+// ../fmt/print.go:1090: undefined: asdf
+// $
+//
+// instead of
+//
+// $ go build
+// # fmt
+// /usr/gopher/go/src/fmt/print.go:1090: undefined: asdf
+// $
+//
+// showOutput also replaces references to the work directory with $WORK.
+//
+func (b *builder) showOutput(dir, desc, out string) {
+ prefix := "# " + desc
+ suffix := "\n" + out
+ if reldir := shortPath(dir); reldir != dir {
+ suffix = strings.Replace(suffix, " "+dir, " "+reldir, -1)
+ suffix = strings.Replace(suffix, "\n"+dir, "\n"+reldir, -1)
+ }
+ suffix = strings.Replace(suffix, " "+b.work, " $WORK", -1)
+
+ b.output.Lock()
+ defer b.output.Unlock()
+ b.print(prefix, suffix)
+}
+
+// shortPath returns an absolute or relative name for path, whatever is shorter.
+func shortPath(path string) string {
+ if rel, err := filepath.Rel(cwd, path); err == nil && len(rel) < len(path) {
+ return rel
+ }
+ return path
+}
+
+// relPaths returns a copy of paths with absolute paths
+// made relative to the current directory if they would be shorter.
+func relPaths(paths []string) []string {
+ var out []string
+ pwd, _ := os.Getwd()
+ for _, p := range paths {
+ rel, err := filepath.Rel(pwd, p)
+ if err == nil && len(rel) < len(p) {
+ p = rel
+ }
+ out = append(out, p)
+ }
+ return out
+}
+
+// errPrintedOutput is a special error indicating that a command failed
+// but that it generated output as well, and that output has already
+// been printed, so there's no point showing 'exit status 1' or whatever
+// the wait status was. The main executor, builder.do, knows not to
+// print this error.
+var errPrintedOutput = errors.New("already printed output - no need to show error")
+
+var cgoLine = regexp.MustCompile(`\[[^\[\]]+\.cgo1\.go:[0-9]+\]`)
+var cgoTypeSigRe = regexp.MustCompile(`\b_Ctype_\B`)
+
+// run runs the command given by cmdline in the directory dir.
+// If the command fails, run prints information about the failure
+// and returns a non-nil error.
+func (b *builder) run(dir string, desc string, env []string, cmdargs ...interface{}) error {
+ out, err := b.runOut(dir, desc, env, cmdargs...)
+ if len(out) > 0 {
+ if desc == "" {
+ desc = b.fmtcmd(dir, "%s", strings.Join(stringList(cmdargs...), " "))
+ }
+ b.showOutput(dir, desc, b.processOutput(out))
+ if err != nil {
+ err = errPrintedOutput
+ }
+ }
+ return err
+}
+
+// processOutput prepares the output of runOut to be output to the console.
+func (b *builder) processOutput(out []byte) string {
+ if out[len(out)-1] != '\n' {
+ out = append(out, '\n')
+ }
+ messages := string(out)
+ // Fix up output referring to cgo-generated code to be more readable.
+ // Replace x.go:19[/tmp/.../x.cgo1.go:18] with x.go:19.
+ // Replace *[100]_Ctype_foo with *[100]C.foo.
+ // If we're using -x, assume we're debugging and want the full dump, so disable the rewrite.
+ if !buildX && cgoLine.MatchString(messages) {
+ messages = cgoLine.ReplaceAllString(messages, "")
+ messages = cgoTypeSigRe.ReplaceAllString(messages, "C.")
+ }
+ return messages
+}
+
+// runOut runs the command given by cmdline in the directory dir.
+// It returns the command output and any errors that occurred.
+func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...interface{}) ([]byte, error) {
+ cmdline := stringList(cmdargs...)
+ if buildN || buildX {
+ var envcmdline string
+ for i := range env {
+ envcmdline += env[i]
+ envcmdline += " "
+ }
+ envcmdline += joinUnambiguously(cmdline)
+ b.showcmd(dir, "%s", envcmdline)
+ if buildN {
+ return nil, nil
+ }
+ }
+
+ nbusy := 0
+ for {
+ var buf bytes.Buffer
+ cmd := exec.Command(cmdline[0], cmdline[1:]...)
+ cmd.Stdout = &buf
+ cmd.Stderr = &buf
+ cmd.Dir = dir
+ cmd.Env = mergeEnvLists(env, envForDir(cmd.Dir))
+ err := cmd.Run()
+
+ // cmd.Run will fail on Unix if some other process has the binary
+ // we want to run open for writing. This can happen here because
+ // we build and install the cgo command and then run it.
+ // If another command was kicked off while we were writing the
+ // cgo binary, the child process for that command may be holding
+ // a reference to the fd, keeping us from running exec.
+ //
+ // But, you might reasonably wonder, how can this happen?
+ // The cgo fd, like all our fds, is close-on-exec, so that we need
+ // not worry about other processes inheriting the fd accidentally.
+ // The answer is that running a command is fork and exec.
+ // A child forked while the cgo fd is open inherits that fd.
+ // Until the child has called exec, it holds the fd open and the
+ // kernel will not let us run cgo. Even if the child were to close
+ // the fd explicitly, it would still be open from the time of the fork
+ // until the time of the explicit close, and the race would remain.
+ //
+ // On Unix systems, this results in ETXTBSY, which formats
+ // as "text file busy". Rather than hard-code specific error cases,
+ // we just look for that string. If this happens, sleep a little
+ // and try again. We let this happen three times, with increasing
+ // sleep lengths: 100+200+400 ms = 0.7 seconds.
+ //
+ // An alternate solution might be to split the cmd.Run into
+ // separate cmd.Start and cmd.Wait, and then use an RWLock
+ // to make sure that copyFile only executes when no cmd.Start
+ // call is in progress. However, cmd.Start (really syscall.forkExec)
+ // only guarantees that when it returns, the exec is committed to
+ // happen and succeed. It uses a close-on-exec file descriptor
+ // itself to determine this, so we know that when cmd.Start returns,
+ // at least one close-on-exec file descriptor has been closed.
+ // However, we cannot be sure that all of them have been closed,
+ // so the program might still encounter ETXTBSY even with such
+ // an RWLock. The race window would be smaller, perhaps, but not
+ // guaranteed to be gone.
+ //
+ // Sleeping when we observe the race seems to be the most reliable
+ // option we have.
+ //
+ // http://golang.org/issue/3001
+ //
+ if err != nil && nbusy < 3 && strings.Contains(err.Error(), "text file busy") {
+ time.Sleep(100 * time.Millisecond << uint(nbusy))
+ nbusy++
+ continue
+ }
+
+ // err can be something like 'exit status 1'.
+ // Add information about what program was running.
+ // Note that if buf.Bytes() is non-empty, the caller usually
+ // shows buf.Bytes() and does not print err at all, so the
+ // prefix here does not make most output any more verbose.
+ if err != nil {
+ err = errors.New(cmdline[0] + ": " + err.Error())
+ }
+ return buf.Bytes(), err
+ }
+}
+
+// joinUnambiguously prints the slice, quoting where necessary to make the
+// output unambiguous.
+// TODO: See issue 5279. The printing of commands needs a complete redo.
+func joinUnambiguously(a []string) string {
+ var buf bytes.Buffer
+ for i, s := range a {
+ if i > 0 {
+ buf.WriteByte(' ')
+ }
+ q := strconv.Quote(s)
+ if s == "" || strings.Contains(s, " ") || len(q) > len(s)+2 {
+ buf.WriteString(q)
+ } else {
+ buf.WriteString(s)
+ }
+ }
+ return buf.String()
+}
+
+// mkdir makes the named directory.
+func (b *builder) mkdir(dir string) error {
+ b.exec.Lock()
+ defer b.exec.Unlock()
+ // We can be a little aggressive about being
+ // sure directories exist. Skip repeated calls.
+ if b.mkdirCache[dir] {
+ return nil
+ }
+ b.mkdirCache[dir] = true
+
+ if buildN || buildX {
+ b.showcmd("", "mkdir -p %s", dir)
+ if buildN {
+ return nil
+ }
+ }
+
+ if err := os.MkdirAll(dir, 0777); err != nil {
+ return err
+ }
+ return nil
+}
+
+// mkAbs returns an absolute path corresponding to
+// evaluating f in the directory dir.
+// We always pass absolute paths of source files so that
+// the error messages will include the full path to a file
+// in need of attention.
+func mkAbs(dir, f string) string {
+ // Leave absolute paths alone.
+ // Also, during -n mode we use the pseudo-directory $WORK
+ // instead of creating an actual work directory that won't be used.
+ // Leave paths beginning with $WORK alone too.
+ if filepath.IsAbs(f) || strings.HasPrefix(f, "$WORK") {
+ return f
+ }
+ return filepath.Join(dir, f)
+}
+
+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)
+ // 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
+ // asm runs the assembler in a specific directory on a specific file
+ // to generate the named output file.
+ asm(b *builder, p *Package, obj, ofile, sfile string) error
+ // pkgpath builds an appropriate path for a temporary package file.
+ pkgpath(basedir string, p *Package) string
+ // pack runs the archive packer in a specific directory to create
+ // 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
+
+ compiler() string
+ linker() string
+}
+
+type noToolchain struct{}
+
+func noCompiler() error {
+ log.Fatalf("unknown compiler %q", buildContext.Compiler)
+ return nil
+}
+
+func (noToolchain) compiler() string {
+ noCompiler()
+ return ""
+}
+
+func (noToolchain) linker() string {
+ noCompiler()
+ return ""
+}
+
+func (noToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, out []byte, err error) {
+ return "", nil, noCompiler()
+}
+
+func (noToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
+ return noCompiler()
+}
+
+func (noToolchain) pkgpath(basedir string, p *Package) string {
+ noCompiler()
+ return ""
+}
+
+func (noToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []string) error {
+ return noCompiler()
+}
+
+func (noToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
+ return noCompiler()
+}
+
+func (noToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
+ return noCompiler()
+}
+
+// The Go toolchain.
+type gcToolchain struct{}
+
+func (gcToolchain) compiler() string {
+ return tool(archChar + "g")
+}
+
+func (gcToolchain) linker() string {
+ return tool(archChar + "l")
+}
+
+func (gcToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
+ if archive != "" {
+ ofile = archive
+ } else {
+ out := "_go_." + archChar
+ ofile = obj + out
+ }
+
+ gcargs := []string{"-p", p.ImportPath}
+ if p.Standard && p.ImportPath == "runtime" {
+ // runtime compiles with a special 6g flag to emit
+ // additional reflect type data.
+ gcargs = append(gcargs, "-+")
+ }
+
+ // If we're giving the compiler the entire package (no C etc files), tell it that,
+ // so that it can give good error messages about forward declarations.
+ // Exceptions: a few standard packages have forward declarations for
+ // pieces supplied behind-the-scenes by package runtime.
+ extFiles := len(p.CgoFiles) + len(p.CFiles) + len(p.CXXFiles) + len(p.MFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles)
+ if p.Standard {
+ switch p.ImportPath {
+ case "bytes", "net", "os", "runtime/pprof", "sync", "time":
+ extFiles++
+ }
+ }
+ if extFiles == 0 {
+ gcargs = append(gcargs, "-complete")
+ }
+ if buildContext.InstallSuffix != "" {
+ gcargs = append(gcargs, "-installsuffix", buildContext.InstallSuffix)
+ }
+
+ args := stringList(tool(archChar+"g"), "-o", ofile, "-trimpath", b.work, buildGcflags, gcargs, "-D", p.localPrefix, importArgs)
+ if ofile == archive {
+ args = append(args, "-pack")
+ }
+ for _, f := range gofiles {
+ args = append(args, mkAbs(p.Dir, f))
+ }
+
+ 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))
+ 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)
+}
+
+func (gcToolchain) pkgpath(basedir string, p *Package) string {
+ end := filepath.FromSlash(p.ImportPath + ".a")
+ return filepath.Join(basedir, end)
+}
+
+func (gcToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []string) error {
+ var absOfiles []string
+ for _, f := range ofiles {
+ absOfiles = append(absOfiles, mkAbs(objDir, f))
+ }
+ cmd := "c"
+ absAfile := mkAbs(objDir, afile)
+ appending := false
+ if _, err := os.Stat(absAfile); err == nil {
+ appending = true
+ cmd = "r"
+ }
+
+ cmdline := stringList("pack", cmd, absAfile, absOfiles)
+
+ if appending {
+ if buildN || buildX {
+ b.showcmd(p.Dir, "%s # internal", joinUnambiguously(cmdline))
+ }
+ if buildN {
+ return nil
+ }
+ if err := packInternal(b, absAfile, absOfiles); err != nil {
+ b.showOutput(p.Dir, p.ImportPath, err.Error()+"\n")
+ return errPrintedOutput
+ }
+ return nil
+ }
+
+ // Need actual pack.
+ cmdline[0] = tool("pack")
+ return b.run(p.Dir, p.ImportPath, nil, cmdline)
+}
+
+func packInternal(b *builder, afile string, ofiles []string) error {
+ dst, err := os.OpenFile(afile, os.O_WRONLY|os.O_APPEND, 0)
+ if err != nil {
+ return err
+ }
+ defer dst.Close() // only for error returns or panics
+ w := bufio.NewWriter(dst)
+
+ for _, ofile := range ofiles {
+ src, err := os.Open(ofile)
+ if err != nil {
+ return err
+ }
+ fi, err := src.Stat()
+ if err != nil {
+ src.Close()
+ return err
+ }
+ // Note: Not using %-16.16s format because we care
+ // about bytes, not runes.
+ name := fi.Name()
+ if len(name) > 16 {
+ name = name[:16]
+ } else {
+ name += strings.Repeat(" ", 16-len(name))
+ }
+ size := fi.Size()
+ fmt.Fprintf(w, "%s%-12d%-6d%-6d%-8o%-10d`\n",
+ name, 0, 0, 0, 0644, size)
+ n, err := io.Copy(w, src)
+ src.Close()
+ if err == nil && n < size {
+ err = io.ErrUnexpectedEOF
+ } else if err == nil && n > size {
+ err = fmt.Errorf("file larger than size reported by stat")
+ }
+ if err != nil {
+ return fmt.Errorf("copying %s to %s: %v", ofile, afile, err)
+ }
+ if size&1 != 0 {
+ w.WriteByte(0)
+ }
+ }
+
+ if err := w.Flush(); err != nil {
+ return err
+ }
+ return dst.Close()
+}
+
+func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
+ importArgs := b.includeArgs("-L", allactions)
+ cxx := len(p.CXXFiles) > 0
+ for _, a := range allactions {
+ if a.p != nil && len(a.p.CXXFiles) > 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)]
+ if buildContext.InstallSuffix != "" {
+ ldflags = append(ldflags, "-installsuffix", buildContext.InstallSuffix)
+ }
+ if p.omitDWARF {
+ ldflags = append(ldflags, "-w")
+ }
+
+ // 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.
+ extld := false
+ for _, f := range ldflags {
+ if f == "-extld" || strings.HasPrefix(f, "-extld=") {
+ extld = true
+ break
+ }
+ }
+ 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)
+ }
+ }
+ }
+ return b.run(".", p.ImportPath, nil, tool(archChar+"l"), "-o", out, importArgs, ldflags, mainpkg)
+}
+
+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)
+}
+
+// The Gccgo toolchain.
+type gccgoToolchain struct{}
+
+var gccgoName, gccgoBin string
+
+func init() {
+ gccgoName = os.Getenv("GCCGO")
+ if gccgoName == "" {
+ gccgoName = defaultGCCGO
+ }
+ gccgoBin, _ = exec.LookPath(gccgoName)
+}
+
+func (gccgoToolchain) compiler() string {
+ return gccgoBin
+}
+
+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) {
+ out := "_go_.o"
+ ofile = obj + out
+ gcargs := []string{"-g"}
+ gcargs = append(gcargs, b.gccArchArgs()...)
+ if pkgpath := gccgoPkgpath(p); pkgpath != "" {
+ gcargs = append(gcargs, "-fgo-pkgpath="+pkgpath)
+ }
+ if p.localPrefix != "" {
+ gcargs = append(gcargs, "-fgo-relative-import-path="+p.localPrefix)
+ }
+ args := stringList(tools.compiler(), importArgs, "-c", gcargs, "-o", ofile, buildGccgoflags)
+ for _, f := range gofiles {
+ args = append(args, mkAbs(p.Dir, f))
+ }
+
+ output, err = b.runOut(p.Dir, p.ImportPath, nil, args)
+ return ofile, output, err
+}
+
+func (tools gccgoToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
+ sfile = mkAbs(p.Dir, sfile)
+ defs := []string{"-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch}
+ if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
+ defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`)
+ }
+ defs = append(defs, b.gccArchArgs()...)
+
+ return b.run(p.Dir, p.ImportPath, nil, tools.compiler(), "-c", "-I", obj, "-o", ofile, defs, sfile)
+}
+
+func (gccgoToolchain) pkgpath(basedir string, p *Package) string {
+ end := filepath.FromSlash(p.ImportPath + ".a")
+ afile := filepath.Join(basedir, end)
+ // add "lib" to the final element
+ return filepath.Join(filepath.Dir(afile), "lib"+filepath.Base(afile))
+}
+
+func (gccgoToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []string) error {
+ var absOfiles []string
+ for _, f := range ofiles {
+ absOfiles = append(absOfiles, mkAbs(objDir, f))
+ }
+ 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 {
+ // gccgo needs explicit linking with all package dependencies,
+ // and all LDFLAGS from cgo dependencies.
+ apackagesSeen := make(map[*Package]bool)
+ afiles := []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] {
+ 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
+ // and place them at the head after this loop.
+ xfiles = append(xfiles, a.target)
+ } else if a.p.fake {
+ // move _test files to the top of the link order
+ afiles = append([]string{a.target}, afiles...)
+ } else {
+ afiles = append(afiles, a.target)
+ }
+ }
+ }
+ }
+ afiles = append(xfiles, afiles...)
+
+ for _, a := range allactions {
+ if a.p != nil {
+ 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
+ }
+ }
+ }
+ ldflags = append(ldflags, afiles...)
+ ldflags = append(ldflags, cgoldflags...)
+ ldflags = append(ldflags, envList("CGO_LDFLAGS", "")...)
+ ldflags = append(ldflags, p.CgoLDFLAGS...)
+ if usesCgo && goos == "linux" {
+ ldflags = append(ldflags, "-Wl,-E")
+ }
+ if cxx {
+ ldflags = append(ldflags, "-lstdc++")
+ }
+ if objc {
+ ldflags = append(ldflags, "-lobjc")
+ }
+ return b.run(".", p.ImportPath, nil, tools.linker(), "-o", out, ofiles, "-Wl,-(", ldflags, "-Wl,-)", buildGccgoflags)
+}
+
+func (gccgoToolchain) 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)
+ defs := []string{"-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch}
+ defs = append(defs, b.gccArchArgs()...)
+ if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
+ defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`)
+ }
+ return b.run(p.Dir, p.ImportPath, nil, envList("CC", defaultCC), "-Wall", "-g",
+ "-I", objdir, "-I", inc, "-o", ofile, defs, "-c", cfile)
+}
+
+func gccgoPkgpath(p *Package) string {
+ if p.build.IsCommand() && !p.forceLibrary {
+ return ""
+ }
+ return p.ImportPath
+}
+
+func gccgoCleanPkgpath(p *Package) string {
+ clean := func(r rune) rune {
+ switch {
+ case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z',
+ '0' <= r && r <= '9':
+ return r
+ }
+ return '_'
+ }
+ return strings.Map(clean, gccgoPkgpath(p))
+}
+
+// libgcc returns the filename for libgcc, as determined by invoking gcc with
+// the -print-libgcc-file-name option.
+func (b *builder) libgcc(p *Package) (string, error) {
+ var buf bytes.Buffer
+
+ gccCmd := b.gccCmd(p.Dir)
+
+ prev := b.print
+ if buildN {
+ // In -n mode we temporarily swap out the builder's
+ // print function to capture the command-line. This
+ // let's us assign it to $LIBGCC and produce a valid
+ // buildscript for cgo packages.
+ b.print = func(a ...interface{}) (int, error) {
+ return fmt.Fprint(&buf, a...)
+ }
+ }
+ f, err := b.runOut(p.Dir, p.ImportPath, nil, gccCmd, "-print-libgcc-file-name")
+ if err != nil {
+ return "", fmt.Errorf("gcc -print-libgcc-file-name: %v (%s)", err, f)
+ }
+ if buildN {
+ s := fmt.Sprintf("LIBGCC=$(%s)\n", buf.Next(buf.Len()-1))
+ b.print = prev
+ b.print(s)
+ return "$LIBGCC", nil
+ }
+
+ // The compiler might not be able to find libgcc, and in that case,
+ // it will simply return "libgcc.a", which is of no use to us.
+ if !filepath.IsAbs(string(f)) {
+ return "", nil
+ }
+
+ return strings.Trim(string(f), "\r\n"), nil
+}
+
+// gcc runs the gcc C compiler to create an object from a single C file.
+func (b *builder) gcc(p *Package, out string, flags []string, cfile string) error {
+ return b.ccompile(p, out, flags, cfile, b.gccCmd(p.Dir))
+}
+
+// gxx runs the g++ C++ compiler to create an object from a single C++ file.
+func (b *builder) gxx(p *Package, out string, flags []string, cxxfile string) error {
+ return b.ccompile(p, out, flags, cxxfile, b.gxxCmd(p.Dir))
+}
+
+// ccompile runs the given C or C++ compiler and creates an object from a single source file.
+func (b *builder) ccompile(p *Package, out string, flags []string, file string, compiler []string) error {
+ file = mkAbs(p.Dir, file)
+ return b.run(p.Dir, p.ImportPath, nil, compiler, flags, "-o", out, "-c", file)
+}
+
+// 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 {
+ cmd = b.gxxCmd(p.Dir)
+ } else {
+ cmd = b.gccCmd(p.Dir)
+ }
+ return b.run(p.Dir, p.ImportPath, nil, cmd, "-o", out, obj, flags)
+}
+
+// gccCmd returns a gcc command line prefix
+// defaultCC is defined in zdefaultcc.go, written by cmd/dist.
+func (b *builder) gccCmd(objdir string) []string {
+ return b.ccompilerCmd("CC", defaultCC, objdir)
+}
+
+// gxxCmd returns a g++ command line prefix
+// defaultCXX is defined in zdefaultcc.go, written by cmd/dist.
+func (b *builder) gxxCmd(objdir string) []string {
+ return b.ccompilerCmd("CXX", defaultCXX, objdir)
+}
+
+// ccompilerCmd returns a command line prefix for the given environment
+// variable and using the default command when the variable is empty.
+func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string {
+ // NOTE: env.go's mkEnv knows that the first three
+ // strings returned are "gcc", "-I", objdir (and cuts them off).
+
+ compiler := envList(envvar, defcmd)
+ a := []string{compiler[0], "-I", objdir}
+ a = append(a, compiler[1:]...)
+
+ // Definitely want -fPIC but on Windows gcc complains
+ // "-fPIC ignored for target (all code is position independent)"
+ if goos != "windows" {
+ a = append(a, "-fPIC")
+ }
+ a = append(a, b.gccArchArgs()...)
+ // gcc-4.5 and beyond require explicit "-pthread" flag
+ // for multithreading with pthread library.
+ if buildContext.CgoEnabled {
+ switch goos {
+ case "windows":
+ a = append(a, "-mthreads")
+ default:
+ a = append(a, "-pthread")
+ }
+ }
+
+ if strings.Contains(a[0], "clang") {
+ // disable ASCII art in clang errors, if possible
+ a = append(a, "-fno-caret-diagnostics")
+ // clang is too smart about command-line arguments
+ a = append(a, "-Qunused-arguments")
+ }
+
+ // disable word wrapping in error messages
+ a = append(a, "-fmessage-length=0")
+
+ // On OS X, some of the compilers behave as if -fno-common
+ // is always set, and the Mach-O linker in 6l/8l assumes this.
+ // See http://golang.org/issue/3253.
+ if goos == "darwin" {
+ a = append(a, "-fno-common")
+ }
+
+ return a
+}
+
+// gccArchArgs returns arguments to pass to gcc based on the architecture.
+func (b *builder) gccArchArgs() []string {
+ switch archChar {
+ case "8":
+ return []string{"-m32"}
+ case "6":
+ return []string{"-m64"}
+ case "5":
+ return []string{"-marm"} // not thumb
+ }
+ return nil
+}
+
+// envList returns the value of the given environment variable broken
+// into fields, using the default value when the variable is empty.
+func envList(key, def string) []string {
+ v := os.Getenv(key)
+ if v == "" {
+ v = def
+ }
+ return strings.Fields(v)
+}
+
+// Return the flags to use when invoking the C or C++ compilers, or cgo.
+func (b *builder) cflags(p *Package, def bool) (cppflags, cflags, cxxflags, ldflags []string) {
+ var defaults string
+ if def {
+ defaults = "-g -O2"
+ }
+
+ cppflags = stringList(envList("CGO_CPPFLAGS", ""), p.CgoCPPFLAGS)
+ cflags = stringList(envList("CGO_CFLAGS", defaults), p.CgoCFLAGS)
+ cxxflags = stringList(envList("CGO_CXXFLAGS", defaults), p.CgoCXXFLAGS)
+ ldflags = stringList(envList("CGO_LDFLAGS", defaults), p.CgoLDFLAGS)
+ return
+}
+
+var cgoRe = regexp.MustCompile(`[/\\:]`)
+
+var (
+ cgoLibGccFile string
+ cgoLibGccErr error
+ cgoLibGccFileOnce sync.Once
+)
+
+func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) {
+ cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoLDFLAGS := b.cflags(p, true)
+ _, cgoexeCFLAGS, _, _ := b.cflags(p, false)
+ cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...)
+ cgoLDFLAGS = append(cgoLDFLAGS, pcLDFLAGS...)
+ // If we are compiling Objective-C code, then we need to link against libobjc
+ if len(mfiles) > 0 {
+ cgoLDFLAGS = append(cgoLDFLAGS, "-lobjc")
+ }
+
+ // Allows including _cgo_export.h from .[ch] files in the package.
+ cgoCPPFLAGS = append(cgoCPPFLAGS, "-I", obj)
+
+ // cgo
+ // TODO: CGOPKGPATH, CGO_FLAGS?
+ gofiles := []string{obj + "_cgo_gotypes.go"}
+ cfiles := []string{"_cgo_main.c", "_cgo_export.c"}
+ for _, fn := range p.CgoFiles {
+ f := cgoRe.ReplaceAllString(fn[:len(fn)-2], "_")
+ gofiles = append(gofiles, obj+f+"cgo1.go")
+ cfiles = append(cfiles, f+"cgo2.c")
+ }
+ defunC := obj + "_cgo_defun.c"
+
+ cgoflags := []string{}
+ // TODO: make cgo not depend on $GOARCH?
+
+ objExt := archChar
+
+ if p.Standard && p.ImportPath == "runtime/cgo" {
+ cgoflags = append(cgoflags, "-import_runtime_cgo=false")
+ }
+ if p.Standard && (p.ImportPath == "runtime/race" || p.ImportPath == "runtime/cgo") {
+ cgoflags = append(cgoflags, "-import_syscall=false")
+ }
+
+ // Update $CGO_LDFLAGS with p.CgoLDFLAGS.
+ var cgoenv []string
+ if len(cgoLDFLAGS) > 0 {
+ flags := make([]string, len(cgoLDFLAGS))
+ for i, f := range cgoLDFLAGS {
+ flags[i] = strconv.Quote(f)
+ }
+ cgoenv = []string{"CGO_LDFLAGS=" + strings.Join(flags, " ")}
+ }
+
+ if _, ok := buildToolchain.(gccgoToolchain); ok {
+ 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 {
+ 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
+ }
+ outObj = append(outObj, defunObj)
+
+ // gcc
+ var linkobj []string
+
+ var bareLDFLAGS []string
+ // filter out -lsomelib, -l somelib, *.{so,dll,dylib}, and (on Darwin) -framework X
+ for i := 0; i < len(cgoLDFLAGS); i++ {
+ f := cgoLDFLAGS[i]
+ switch {
+ // skip "-lc" or "-l somelib"
+ case strings.HasPrefix(f, "-l"):
+ if f == "-l" {
+ i++
+ }
+ // skip "-framework X" on Darwin
+ case goos == "darwin" && f == "-framework":
+ i++
+ // skip "*.{dylib,so,dll}"
+ case strings.HasSuffix(f, ".dylib"),
+ strings.HasSuffix(f, ".so"),
+ strings.HasSuffix(f, ".dll"):
+ continue
+ // Remove any -fsanitize=foo flags.
+ // Otherwise the compiler driver thinks that we are doing final link
+ // and links sanitizer runtime into the object file. But we are not doing
+ // the final link, we will link the resulting object file again. And
+ // so the program ends up with two copies of sanitizer runtime.
+ // See issue 8788 for details.
+ case strings.HasPrefix(f, "-fsanitize="):
+ continue
+ default:
+ bareLDFLAGS = append(bareLDFLAGS, f)
+ }
+ }
+
+ cgoLibGccFileOnce.Do(func() {
+ cgoLibGccFile, cgoLibGccErr = b.libgcc(p)
+ })
+ if cgoLibGccFile == "" && cgoLibGccErr != nil {
+ return nil, nil, err
+ }
+
+ var staticLibs []string
+ if goos == "windows" {
+ // libmingw32 and libmingwex might also use libgcc, so libgcc must come last,
+ // and they also have some inter-dependencies, so must use linker groups.
+ staticLibs = []string{"-Wl,--start-group", "-lmingwex", "-lmingw32", "-Wl,--end-group"}
+ }
+ if cgoLibGccFile != "" {
+ staticLibs = append(staticLibs, cgoLibGccFile)
+ }
+
+ cflags := stringList(cgoCPPFLAGS, cgoCFLAGS)
+ for _, cfile := range cfiles {
+ ofile := obj + cfile[:len(cfile)-1] + "o"
+ if err := b.gcc(p, ofile, cflags, obj+cfile); err != nil {
+ return nil, nil, err
+ }
+ linkobj = append(linkobj, ofile)
+ if !strings.HasSuffix(ofile, "_cgo_main.o") {
+ outObj = append(outObj, ofile)
+ }
+ }
+
+ 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
+ }
+ linkobj = append(linkobj, ofile)
+ outObj = append(outObj, ofile)
+ }
+
+ cxxflags := stringList(cgoCPPFLAGS, cgoCXXFLAGS)
+ 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
+ }
+ linkobj = append(linkobj, ofile)
+ outObj = append(outObj, ofile)
+ }
+
+ for _, file := range mfiles {
+ // Append .o to the file, just in case the pkg has file.c and file.m
+ ofile := obj + cgoRe.ReplaceAllString(file, "_") + ".o"
+ if err := b.gcc(p, ofile, cflags, file); err != nil {
+ return nil, nil, err
+ }
+ linkobj = append(linkobj, ofile)
+ outObj = append(outObj, ofile)
+ }
+
+ linkobj = append(linkobj, p.SysoFiles...)
+ dynobj := obj + "_cgo_.o"
+ pie := goarch == "arm" && (goos == "linux" || goos == "android")
+ if pie { // we need to use -pie for Linux/ARM to get accurate imported sym
+ cgoLDFLAGS = append(cgoLDFLAGS, "-pie")
+ }
+ if err := b.gccld(p, dynobj, cgoLDFLAGS, linkobj); err != nil {
+ return nil, nil, err
+ }
+ if pie { // but we don't need -pie for normal cgo programs
+ cgoLDFLAGS = cgoLDFLAGS[0 : len(cgoLDFLAGS)-1]
+ }
+
+ if _, ok := buildToolchain.(gccgoToolchain); ok {
+ // we don't use dynimport when using gccgo.
+ return outGo, outObj, nil
+ }
+
+ // cgo -dynimport
+ importC := obj + "_cgo_import.c"
+ 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 {
+ return nil, nil, err
+ }
+
+ ofile := obj + "_all.o"
+ var gccObjs, nonGccObjs []string
+ for _, f := range outObj {
+ if strings.HasSuffix(f, ".o") {
+ gccObjs = append(gccObjs, f)
+ } else {
+ nonGccObjs = append(nonGccObjs, f)
+ }
+ }
+ 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")
+ }
+
+ if err := b.gccld(p, ofile, ldflags, gccObjs); err != nil {
+ return nil, nil, err
+ }
+
+ // 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)
+
+ return outGo, outObj, nil
+}
+
+// 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)
+ }
+
+ if err := b.swigVersionCheck(); err != nil {
+ return nil, nil, err
+ }
+
+ intgosize, err := b.swigIntSize(obj)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ for _, f := range p.SwigFiles {
+ goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, pcCFLAGS, false, intgosize)
+ if err != nil {
+ return nil, nil, err
+ }
+ if goFile != "" {
+ outGo = append(outGo, goFile)
+ }
+ if objFile != "" {
+ outObj = append(outObj, objFile)
+ }
+ if gccObjFile != "" {
+ outObj = append(outObj, gccObjFile)
+ }
+ }
+ for _, f := range p.SwigCXXFiles {
+ goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, pcCFLAGS, true, intgosize)
+ if err != nil {
+ return nil, nil, err
+ }
+ if goFile != "" {
+ outGo = append(outGo, goFile)
+ }
+ if objFile != "" {
+ outObj = append(outObj, objFile)
+ }
+ if gccObjFile != "" {
+ outObj = append(outObj, gccObjFile)
+ }
+ }
+ return outGo, outObj, nil
+}
+
+// Make sure SWIG is new enough.
+var (
+ swigCheckOnce sync.Once
+ swigCheck error
+)
+
+func (b *builder) swigDoVersionCheck() error {
+ out, err := b.runOut("", "", nil, "swig", "-version")
+ if err != nil {
+ return err
+ }
+ re := regexp.MustCompile(`[vV]ersion +([\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
+ }
+ if major < 3 {
+ return errors.New("must have SWIG version >= 3.0")
+ }
+ return nil
+}
+
+func (b *builder) swigVersionCheck() error {
+ swigCheckOnce.Do(func() {
+ swigCheck = b.swigDoVersionCheck()
+ })
+ return swigCheck
+}
+
+// This code fails to build if sizeof(int) <= 32
+const swigIntSizeCode = `
+package main
+const i int = 1 << 32
+`
+
+// Determine the size of int on the target system for the -intgosize option
+// of swig >= 2.0.9
+func (b *builder) swigIntSize(obj string) (intsize string, err error) {
+ if buildN {
+ return "$INTBITS", nil
+ }
+ src := filepath.Join(b.work, "swig_intsize.go")
+ if err = ioutil.WriteFile(src, []byte(swigIntSizeCode), 0644); err != nil {
+ return
+ }
+ srcs := []string{src}
+
+ p := goFilesPackage(srcs)
+
+ if _, _, e := buildToolchain.gc(b, p, "", obj, 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) {
+ cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true)
+ var cflags []string
+ if cxx {
+ cflags = stringList(cgoCPPFLAGS, pcCFLAGS, cgoCXXFLAGS)
+ } else {
+ cflags = stringList(cgoCPPFLAGS, pcCFLAGS, cgoCFLAGS)
+ }
+
+ n := 5 // length of ".swig"
+ if cxx {
+ n = 8 // length of ".swigcxx"
+ }
+ base := file[:len(file)-n]
+ goFile := base + ".go"
+ cBase := base + "_gc."
+ gccBase := base + "_wrap."
+ gccExt := "c"
+ if cxx {
+ gccExt = "cxx"
+ }
+
+ _, gccgo := buildToolchain.(gccgoToolchain)
+
+ // swig
+ args := []string{
+ "-go",
+ "-intgosize", intgosize,
+ "-module", base,
+ "-o", obj + gccBase + gccExt,
+ "-outdir", obj,
+ }
+
+ for _, f := range cflags {
+ if len(f) > 3 && f[:2] == "-I" {
+ args = append(args, f)
+ }
+ }
+
+ if gccgo {
+ args = append(args, "-gccgo")
+ if pkgpath := gccgoPkgpath(p); pkgpath != "" {
+ args = append(args, "-go-pkgpath", pkgpath)
+ }
+ }
+ if cxx {
+ args = append(args, "-c++")
+ }
+
+ if out, err := b.runOut(p.Dir, p.ImportPath, nil, "swig", args, file); err != nil {
+ if len(out) > 0 {
+ if bytes.Contains(out, []byte("Unrecognized option -intgosize")) {
+ return "", "", "", errors.New("must have SWIG version >= 3.0")
+ }
+ b.showOutput(p.Dir, p.ImportPath, b.processOutput(out))
+ return "", "", "", errPrintedOutput
+ }
+ 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
+ }
+ }
+
+ // 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, cObj, gccObj, nil
+}
+
+// An actionQueue is a priority queue of actions.
+type actionQueue []*action
+
+// Implement heap.Interface
+func (q *actionQueue) Len() int { return len(*q) }
+func (q *actionQueue) Swap(i, j int) { (*q)[i], (*q)[j] = (*q)[j], (*q)[i] }
+func (q *actionQueue) Less(i, j int) bool { return (*q)[i].priority < (*q)[j].priority }
+func (q *actionQueue) Push(x interface{}) { *q = append(*q, x.(*action)) }
+func (q *actionQueue) Pop() interface{} {
+ n := len(*q) - 1
+ x := (*q)[n]
+ *q = (*q)[:n]
+ return x
+}
+
+func (q *actionQueue) push(a *action) {
+ heap.Push(q, a)
+}
+
+func (q *actionQueue) pop() *action {
+ return heap.Pop(q).(*action)
+}
+
+func raceInit() {
+ if !buildRace {
+ return
+ }
+ if goarch != "amd64" || goos != "linux" && goos != "freebsd" && goos != "darwin" && goos != "windows" {
+ fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0])
+ os.Exit(2)
+ }
+ buildGcflags = append(buildGcflags, "-race")
+ buildLdflags = append(buildLdflags, "-race")
+ buildCcflags = append(buildCcflags, "-D", "RACE")
+ if buildContext.InstallSuffix != "" {
+ buildContext.InstallSuffix += "_"
+ }
+ buildContext.InstallSuffix += "race"
+ buildContext.BuildTags = append(buildContext.BuildTags, "race")
+}
+
+// defaultSuffix returns file extension used for command files in
+// current os environment.
+func defaultSuffix() string {
+ switch runtime.GOOS {
+ case "windows":
+ return ".bat"
+ case "plan9":
+ return ".rc"
+ default:
+ return ".bash"
+ }
+}
diff --git a/libgo/go/cmd/go/clean.go b/libgo/go/cmd/go/clean.go
new file mode 100644
index 0000000000..16054a5b5b
--- /dev/null
+++ b/libgo/go/cmd/go/clean.go
@@ -0,0 +1,248 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+var cmdClean = &Command{
+ UsageLine: "clean [-i] [-r] [-n] [-x] [build flags] [packages]",
+ Short: "remove object files",
+ Long: `
+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'.
+ `,
+}
+
+var cleanI bool // clean -i flag
+var cleanR bool // clean -r flag
+
+func init() {
+ // break init cycle
+ cmdClean.Run = runClean
+
+ cmdClean.Flag.BoolVar(&cleanI, "i", false, "")
+ cmdClean.Flag.BoolVar(&cleanR, "r", false, "")
+ // -n and -x are important enough to be
+ // mentioned explicitly in the docs but they
+ // are part of the build flags.
+
+ addBuildFlags(cmdClean)
+}
+
+func runClean(cmd *Command, args []string) {
+ for _, pkg := range packagesAndErrors(args) {
+ clean(pkg)
+ }
+}
+
+var cleaned = map[*Package]bool{}
+
+// TODO: These are dregs left by Makefile-based builds.
+// Eventually, can stop deleting these.
+var cleanDir = map[string]bool{
+ "_test": true,
+ "_obj": true,
+}
+
+var cleanFile = map[string]bool{
+ "_testmain.go": true,
+ "test.out": true,
+ "build.out": true,
+ "a.out": true,
+}
+
+var cleanExt = map[string]bool{
+ ".5": true,
+ ".6": true,
+ ".8": true,
+ ".a": true,
+ ".o": true,
+ ".so": true,
+}
+
+func clean(p *Package) {
+ if cleaned[p] {
+ return
+ }
+ cleaned[p] = true
+
+ if p.Dir == "" {
+ errorf("can't load package: %v", p.Error)
+ return
+ }
+ dirs, err := ioutil.ReadDir(p.Dir)
+ if err != nil {
+ errorf("go clean %s: %v", p.Dir, err)
+ return
+ }
+
+ var b builder
+ b.print = fmt.Print
+
+ packageFile := map[string]bool{}
+ if p.Name != "main" {
+ // Record which files are not in package main.
+ // The others are.
+ keep := func(list []string) {
+ for _, f := range list {
+ packageFile[f] = true
+ }
+ }
+ keep(p.GoFiles)
+ keep(p.CgoFiles)
+ keep(p.TestGoFiles)
+ keep(p.XTestGoFiles)
+ }
+
+ _, elem := filepath.Split(p.Dir)
+ var allRemove []string
+
+ // Remove dir-named executable only if this is package main.
+ if p.Name == "main" {
+ allRemove = append(allRemove,
+ elem,
+ elem+".exe",
+ )
+ }
+
+ // Remove package test executables.
+ allRemove = append(allRemove,
+ elem+".test",
+ elem+".test.exe",
+ )
+
+ // Remove a potential executable for each .go file in the directory that
+ // is not part of the directory's package.
+ for _, dir := range dirs {
+ name := dir.Name()
+ if packageFile[name] {
+ continue
+ }
+ if !dir.IsDir() && strings.HasSuffix(name, ".go") {
+ // TODO(adg,rsc): check that this .go file is actually
+ // in "package main", and therefore capable of building
+ // to an executable file.
+ base := name[:len(name)-len(".go")]
+ allRemove = append(allRemove, base, base+".exe")
+ }
+ }
+
+ if buildN || buildX {
+ b.showcmd(p.Dir, "rm -f %s", strings.Join(allRemove, " "))
+ }
+
+ toRemove := map[string]bool{}
+ for _, name := range allRemove {
+ toRemove[name] = true
+ }
+ for _, dir := range dirs {
+ name := dir.Name()
+ if dir.IsDir() {
+ // TODO: Remove once Makefiles are forgotten.
+ if cleanDir[name] {
+ if buildN || buildX {
+ b.showcmd(p.Dir, "rm -r %s", name)
+ if buildN {
+ continue
+ }
+ }
+ if err := os.RemoveAll(filepath.Join(p.Dir, name)); err != nil {
+ errorf("go clean: %v", err)
+ }
+ }
+ continue
+ }
+
+ if buildN {
+ continue
+ }
+
+ if cleanFile[name] || cleanExt[filepath.Ext(name)] || toRemove[name] {
+ removeFile(filepath.Join(p.Dir, name))
+ }
+ }
+
+ if cleanI && p.target != "" {
+ if buildN || buildX {
+ b.showcmd("", "rm -f %s", p.target)
+ }
+ if !buildN {
+ removeFile(p.target)
+ }
+ }
+
+ if cleanR {
+ for _, p1 := range p.imports {
+ clean(p1)
+ }
+ }
+}
+
+// removeFile tries to remove file f, if error other than file doesn't exist
+// occurs, it will report the error.
+func removeFile(f string) {
+ err := os.Remove(f)
+ if err == nil || os.IsNotExist(err) {
+ return
+ }
+ // Windows does not allow deletion of a binary file while it is executing.
+ if toolIsWindows {
+ // Remove lingering ~ file from last attempt.
+ if _, err2 := os.Stat(f + "~"); err2 == nil {
+ os.Remove(f + "~")
+ }
+ // Try to move it out of the way. If the move fails,
+ // which is likely, we'll try again the
+ // next time we do an install of this binary.
+ if err2 := os.Rename(f, f+"~"); err2 == nil {
+ os.Remove(f + "~")
+ return
+ }
+ }
+ errorf("go clean: %v", err)
+}
diff --git a/libgo/go/cmd/go/context.go b/libgo/go/cmd/go/context.go
new file mode 100644
index 0000000000..68e518259f
--- /dev/null
+++ b/libgo/go/cmd/go/context.go
@@ -0,0 +1,36 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "go/build"
+)
+
+type Context struct {
+ GOARCH string `json:",omitempty"` // target architecture
+ GOOS string `json:",omitempty"` // target operating system
+ GOROOT string `json:",omitempty"` // Go root
+ GOPATH string `json:",omitempty"` // Go path
+ CgoEnabled bool `json:",omitempty"` // whether cgo can be used
+ UseAllFiles bool `json:",omitempty"` // use files regardless of +build lines, file names
+ Compiler string `json:",omitempty"` // compiler to assume when computing target paths
+ BuildTags []string `json:",omitempty"` // build constraints to match in +build lines
+ ReleaseTags []string `json:",omitempty"` // releases the current release is compatible with
+ InstallSuffix string `json:",omitempty"` // suffix to use in the name of the install dir
+}
+
+func newContext(c *build.Context) *Context {
+ return &Context{
+ GOARCH: c.GOARCH,
+ GOOS: c.GOOS,
+ GOROOT: c.GOROOT,
+ CgoEnabled: c.CgoEnabled,
+ UseAllFiles: c.UseAllFiles,
+ Compiler: c.Compiler,
+ BuildTags: c.BuildTags,
+ ReleaseTags: c.ReleaseTags,
+ InstallSuffix: c.InstallSuffix,
+ }
+}
diff --git a/libgo/go/cmd/go/discovery.go b/libgo/go/cmd/go/discovery.go
new file mode 100644
index 0000000000..b9f4279954
--- /dev/null
+++ b/libgo/go/cmd/go/discovery.go
@@ -0,0 +1,83 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !cmd_go_bootstrap
+
+// This code is compiled into the real 'go' binary, but it is not
+// compiled into the binary that is built during all.bash, so as
+// to avoid needing to build net (and thus use cgo) during the
+// bootstrap process.
+
+package main
+
+import (
+ "encoding/xml"
+ "fmt"
+ "io"
+ "strings"
+)
+
+// charsetReader returns a reader for the given charset. Currently
+// it only supports UTF-8 and ASCII. Otherwise, it returns a meaningful
+// error which is printed by go get, so the user can find why the package
+// wasn't downloaded if the encoding is not supported. Note that, in
+// order to reduce potential errors, ASCII is treated as UTF-8 (i.e. characters
+// greater than 0x7f are not rejected).
+func charsetReader(charset string, input io.Reader) (io.Reader, error) {
+ switch strings.ToLower(charset) {
+ case "ascii":
+ return input, nil
+ default:
+ return nil, fmt.Errorf("can't decode XML document using charset %q", charset)
+ }
+}
+
+// parseMetaGoImports returns meta imports from the HTML in r.
+// Parsing ends at the end of the <head> section or the beginning of the <body>.
+func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) {
+ d := xml.NewDecoder(r)
+ d.CharsetReader = charsetReader
+ d.Strict = false
+ var t xml.Token
+ for {
+ t, err = d.Token()
+ if err != nil {
+ if err == io.EOF {
+ err = nil
+ }
+ return
+ }
+ if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") {
+ return
+ }
+ if e, ok := t.(xml.EndElement); ok && strings.EqualFold(e.Name.Local, "head") {
+ return
+ }
+ e, ok := t.(xml.StartElement)
+ if !ok || !strings.EqualFold(e.Name.Local, "meta") {
+ continue
+ }
+ if attrValue(e.Attr, "name") != "go-import" {
+ continue
+ }
+ if f := strings.Fields(attrValue(e.Attr, "content")); len(f) == 3 {
+ imports = append(imports, metaImport{
+ Prefix: f[0],
+ VCS: f[1],
+ RepoRoot: f[2],
+ })
+ }
+ }
+}
+
+// attrValue returns the attribute value for the case-insensitive key
+// `name', or the empty string if nothing is found.
+func attrValue(attrs []xml.Attr, name string) string {
+ for _, a := range attrs {
+ if strings.EqualFold(a.Name.Local, name) {
+ return a.Value
+ }
+ }
+ return ""
+}
diff --git a/libgo/go/cmd/go/doc.go b/libgo/go/cmd/go/doc.go
new file mode 100644
index 0000000000..7191ee0f3a
--- /dev/null
+++ b/libgo/go/cmd/go/doc.go
@@ -0,0 +1,1131 @@
+// 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 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:
+
+ -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 <meta> 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 <meta> tag in the document's HTML
+<head>.
+
+The meta tag has the form:
+
+ <meta name="go-import" content="import-prefix vcs repo-root">
+
+The import-prefix is the import path 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 <meta> tags match.
+
+The vcs is one of "git", "hg", "svn", etc,
+
+The repo-root is the root of the version control system
+containing a scheme and not containing a .vcs qualifier.
+
+For example,
+
+ import "example.org/pkg/foo"
+
+will result in the following request(s):
+
+ https://example.org/pkg/foo?go-get=1 (preferred)
+ http://example.org/pkg/foo?go-get=1 (fallback)
+
+If that page contains the meta tag
+
+ <meta name="go-import" content="example.org git https://code.org/r/p/exproj">
+
+the go tool will verify that https://example.org/?go-get=1 contains the
+same meta tag and then git clone https://code.org/r/p/exproj into
+GOPATH/src/example.org.
+
+New downloaded packages are written to the first directory
+listed in the GOPATH environment variable (see 'go help gopath').
+
+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
diff --git a/libgo/go/cmd/go/env.go b/libgo/go/cmd/go/env.go
new file mode 100644
index 0000000000..26d37df4f9
--- /dev/null
+++ b/libgo/go/cmd/go/env.go
@@ -0,0 +1,112 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "os"
+ "runtime"
+ "strings"
+)
+
+var cmdEnv = &Command{
+ Run: runEnv,
+ UsageLine: "env [var ...]",
+ Short: "print Go environment information",
+ Long: `
+Env prints Go environment information.
+
+By default env prints information as a shell script
+(on Windows, a batch file). If one or more variable
+names is given as arguments, env prints the value of
+each named variable on its own line.
+ `,
+}
+
+type envVar struct {
+ name, value string
+}
+
+func mkEnv() []envVar {
+ var b builder
+ b.init()
+
+ env := []envVar{
+ {"GOARCH", goarch},
+ {"GOBIN", gobin},
+ {"GOCHAR", archChar},
+ {"GOEXE", exeSuffix},
+ {"GOHOSTARCH", runtime.GOARCH},
+ {"GOHOSTOS", runtime.GOOS},
+ {"GOOS", goos},
+ {"GOPATH", os.Getenv("GOPATH")},
+ {"GORACE", os.Getenv("GORACE")},
+ {"GOROOT", goroot},
+ {"GOTOOLDIR", toolDir},
+
+ // disable escape codes in clang errors
+ {"TERM", "dumb"},
+ }
+
+ if goos != "plan9" {
+ cmd := b.gccCmd(".")
+ env = append(env, envVar{"CC", cmd[0]})
+ env = append(env, envVar{"GOGCCFLAGS", strings.Join(cmd[3:], " ")})
+ cmd = b.gxxCmd(".")
+ env = append(env, envVar{"CXX", cmd[0]})
+ }
+
+ if buildContext.CgoEnabled {
+ env = append(env, envVar{"CGO_ENABLED", "1"})
+ } else {
+ env = append(env, envVar{"CGO_ENABLED", "0"})
+ }
+
+ return env
+}
+
+func findEnv(env []envVar, name string) string {
+ for _, e := range env {
+ if e.name == name {
+ return e.value
+ }
+ }
+ return ""
+}
+
+func runEnv(cmd *Command, args []string) {
+ env := mkEnv()
+ if len(args) > 0 {
+ for _, name := range args {
+ fmt.Printf("%s\n", findEnv(env, name))
+ }
+ return
+ }
+
+ for _, e := range env {
+ if e.name != "TERM" {
+ switch runtime.GOOS {
+ default:
+ fmt.Printf("%s=\"%s\"\n", e.name, e.value)
+ case "plan9":
+ if strings.IndexByte(e.value, '\x00') < 0 {
+ fmt.Printf("%s='%s'\n", e.name, strings.Replace(e.value, "'", "''", -1))
+ } else {
+ v := strings.Split(e.value, "\x00")
+ fmt.Printf("%s=(", e.name)
+ for x, s := range v {
+ if x > 0 {
+ fmt.Printf(" ")
+ }
+ fmt.Printf("%s", s)
+ }
+ fmt.Printf(")\n")
+ }
+ case "windows":
+ fmt.Printf("set %s=%s\n", e.name, e.value)
+ }
+ }
+ }
+}
diff --git a/libgo/go/cmd/go/fix.go b/libgo/go/cmd/go/fix.go
new file mode 100644
index 0000000000..8736cce3e2
--- /dev/null
+++ b/libgo/go/cmd/go/fix.go
@@ -0,0 +1,30 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var cmdFix = &Command{
+ Run: runFix,
+ UsageLine: "fix [packages]",
+ Short: "run go tool fix on packages",
+ 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 specifying packages, see 'go help packages'.
+
+To run fix with specific options, run 'go tool fix'.
+
+See also: go fmt, go vet.
+ `,
+}
+
+func runFix(cmd *Command, args []string) {
+ for _, pkg := range packages(args) {
+ // Use pkg.gofiles instead of pkg.Dir so that
+ // the command only applies to this package,
+ // not to packages in subdirectories.
+ run(stringList(tool("fix"), relPaths(pkg.allgofiles)))
+ }
+}
diff --git a/libgo/go/cmd/go/fmt.go b/libgo/go/cmd/go/fmt.go
new file mode 100644
index 0000000000..65dc3ca599
--- /dev/null
+++ b/libgo/go/cmd/go/fmt.go
@@ -0,0 +1,38 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addBuildFlagsNX(cmdFmt)
+}
+
+var cmdFmt = &Command{
+ Run: runFmt,
+ UsageLine: "fmt [-n] [-x] [packages]",
+ Short: "run gofmt on package sources",
+ Long: `
+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.
+ `,
+}
+
+func runFmt(cmd *Command, args []string) {
+ for _, pkg := range packages(args) {
+ // Use pkg.gofiles instead of pkg.Dir so that
+ // the command only applies to this package,
+ // not to packages in subdirectories.
+ run(stringList("gofmt", "-l", "-w", relPaths(pkg.allgofiles)))
+ }
+}
diff --git a/libgo/go/cmd/go/generate.go b/libgo/go/cmd/go/generate.go
new file mode 100644
index 0000000000..3c0af8760b
--- /dev/null
+++ b/libgo/go/cmd/go/generate.go
@@ -0,0 +1,403 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "log"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+ "strconv"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+)
+
+var cmdGenerate = &Command{
+ Run: runGenerate,
+ UsageLine: "generate [-run regexp] [file.go... | packages]",
+ Short: "generate Go files by processing source",
+ Long: `
+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'.
+ `,
+}
+
+var generateRunFlag string // generate -run flag
+
+func init() {
+ addBuildFlags(cmdGenerate)
+ cmdGenerate.Flag.StringVar(&generateRunFlag, "run", "", "")
+}
+
+func runGenerate(cmd *Command, args []string) {
+ // Even if the arguments are .go files, this loop suffices.
+ for _, pkg := range packages(args) {
+ for _, file := range pkg.gofiles {
+ if !generate(pkg.Name, file) {
+ break
+ }
+ }
+ }
+}
+
+// generate runs the generation directives for a single file.
+func generate(pkg, absFile string) bool {
+ fd, err := os.Open(absFile)
+ if err != nil {
+ log.Fatalf("generate: %s", err)
+ }
+ defer fd.Close()
+ g := &Generator{
+ r: fd,
+ path: absFile,
+ pkg: pkg,
+ commands: make(map[string][]string),
+ }
+ return g.run()
+}
+
+// A Generator represents the state of a single Go source file
+// being scanned for generator commands.
+type Generator struct {
+ r io.Reader
+ path string // full rooted path name.
+ dir string // full rooted directory of file.
+ file string // base name of file.
+ pkg string
+ commands map[string][]string
+ lineNum int
+}
+
+// run runs the generators in the current file.
+func (g *Generator) run() (ok bool) {
+ // Processing below here calls g.errorf on failure, which does panic(stop).
+ // If we encounter an error, we abort the package.
+ defer func() {
+ e := recover()
+ if e != nil {
+ ok = false
+ if e != stop {
+ panic(e)
+ }
+ setExitStatus(1)
+ }
+ }()
+ g.dir, g.file = filepath.Split(g.path)
+ g.dir = filepath.Clean(g.dir) // No final separator please.
+ if buildV {
+ fmt.Fprintf(os.Stderr, "%s\n", shortPath(g.path))
+ }
+
+ // Scan for lines that start "//go:generate".
+ // Can't use bufio.Scanner because it can't handle long lines,
+ // which are likely to appear when using generate.
+ input := bufio.NewReader(g.r)
+ var err error
+ // One line per loop.
+ for {
+ g.lineNum++ // 1-indexed.
+ var buf []byte
+ buf, err = input.ReadSlice('\n')
+ if err == bufio.ErrBufferFull {
+ // Line too long - consume and ignore.
+ if isGoGenerate(buf) {
+ g.errorf("directive too long")
+ }
+ for err == bufio.ErrBufferFull {
+ _, err = input.ReadSlice('\n')
+ }
+ if err != nil {
+ break
+ }
+ continue
+ }
+
+ if err != nil {
+ // Check for marker at EOF without final \n.
+ if err == io.EOF && isGoGenerate(buf) {
+ err = io.ErrUnexpectedEOF
+ }
+ break
+ }
+
+ if !isGoGenerate(buf) {
+ continue
+ }
+
+ words := g.split(string(buf))
+ if len(words) == 0 {
+ g.errorf("no arguments to directive")
+ }
+ if words[0] == "-command" {
+ g.setShorthand(words)
+ continue
+ }
+ // Run the command line.
+ if buildN || buildX {
+ fmt.Fprintf(os.Stderr, "%s\n", strings.Join(words, " "))
+ }
+ if buildN {
+ continue
+ }
+ g.exec(words)
+ }
+ if err != nil && err != io.EOF {
+ g.errorf("error reading %s: %s", shortPath(g.path), err)
+ }
+ return true
+}
+
+func isGoGenerate(buf []byte) bool {
+ return bytes.HasPrefix(buf, []byte("//go:generate ")) || bytes.HasPrefix(buf, []byte("//go:generate\t"))
+}
+
+// split breaks the line into words, evaluating quoted
+// strings and evaluating environment variables.
+// The initial //go:generate element is present in line.
+func (g *Generator) split(line string) []string {
+ // Parse line, obeying quoted strings.
+ var words []string
+ line = line[len("//go:generate ") : len(line)-1] // Drop preamble and final newline.
+ // There may still be a carriage return.
+ if len(line) > 0 && line[len(line)-1] == '\r' {
+ line = line[:len(line)-1]
+ }
+ // One (possibly quoted) word per iteration.
+Words:
+ for {
+ line = strings.TrimLeft(line, " \t")
+ if len(line) == 0 {
+ break
+ }
+ if line[0] == '"' {
+ for i := 1; i < len(line); i++ {
+ c := line[i] // Only looking for ASCII so this is OK.
+ switch c {
+ case '\\':
+ if i+1 == len(line) {
+ g.errorf("bad backslash")
+ }
+ i++ // Absorb next byte (If it's a multibyte we'll get an error in Unquote).
+ case '"':
+ word, err := strconv.Unquote(line[0 : i+1])
+ if err != nil {
+ g.errorf("bad quoted string")
+ }
+ words = append(words, word)
+ line = line[i+1:]
+ // Check the next character is space or end of line.
+ if len(line) > 0 && line[0] != ' ' && line[0] != '\t' {
+ g.errorf("expect space after quoted argument")
+ }
+ continue Words
+ }
+ }
+ g.errorf("mismatched quoted string")
+ }
+ i := strings.IndexAny(line, " \t")
+ if i < 0 {
+ i = len(line)
+ }
+ words = append(words, line[0:i])
+ line = line[i:]
+ }
+ // Substitute command if required.
+ if len(words) > 0 && g.commands[words[0]] != nil {
+ // Replace 0th word by command substitution.
+ words = append(g.commands[words[0]], words[1:]...)
+ }
+ // Substitute environment variables.
+ for i, word := range words {
+ words[i] = g.expandEnv(word)
+ }
+ return words
+}
+
+var stop = fmt.Errorf("error in generation")
+
+// errorf logs an error message prefixed with the file and line number.
+// It then exits the program (with exit status 1) because generation stops
+// at the first error.
+func (g *Generator) errorf(format string, args ...interface{}) {
+ fmt.Fprintf(os.Stderr, "%s:%d: %s\n", shortPath(g.path), g.lineNum,
+ fmt.Sprintf(format, args...))
+ 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)
+ }
+ return buf.String()
+}
+
+// identLength returns the length of the identifier beginning the string.
+func (g *Generator) identLength(word string) int {
+ for i, r := range word {
+ if r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r) {
+ continue
+ }
+ return i
+ }
+ return len(word)
+}
+
+// setShorthand installs a new shorthand as defined by a -command directive.
+func (g *Generator) setShorthand(words []string) {
+ // Create command shorthand.
+ if len(words) == 1 {
+ g.errorf("no command specified for -command")
+ }
+ command := words[1]
+ if g.commands[command] != nil {
+ g.errorf("command %q defined multiply defined", command)
+ }
+ g.commands[command] = words[2:len(words):len(words)] // force later append to make copy
+}
+
+// exec runs the command specified by the argument. The first word is
+// the command name itself.
+func (g *Generator) exec(words []string) {
+ cmd := exec.Command(words[0], words[1:]...)
+ // Standard in and out of generator should be the usual.
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ // Run the command in the package directory.
+ cmd.Dir = g.dir
+ env := []string{
+ "GOARCH=" + runtime.GOARCH,
+ "GOOS=" + runtime.GOOS,
+ "GOFILE=" + g.file,
+ "GOPACKAGE=" + g.pkg,
+ }
+ cmd.Env = mergeEnvLists(env, os.Environ())
+ 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
new file mode 100644
index 0000000000..2ec548630a
--- /dev/null
+++ b/libgo/go/cmd/go/generate_test.go
@@ -0,0 +1,54 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "reflect"
+ "runtime"
+ "testing"
+)
+
+type splitTest struct {
+ in string
+ out []string
+}
+
+var splitTests = []splitTest{
+ {"", nil},
+ {"x", []string{"x"}},
+ {" a b\tc ", []string{"a", "b", "c"}},
+ {` " a " `, []string{" a "}},
+ {"$GOARCH", []string{runtime.GOARCH}},
+ {"$GOOS", []string{runtime.GOOS}},
+ {"$GOFILE", []string{"proc.go"}},
+ {"$GOPACKAGE", []string{"sys"}},
+ {"a $XXNOTDEFINEDXX b", []string{"a", "", "b"}},
+ {"/$XXNOTDEFINED/", []string{"//"}},
+ {"yacc -o $GOARCH/yacc_$GOFILE", []string{"go", "tool", "yacc", "-o", runtime.GOARCH + "/yacc_proc.go"}},
+}
+
+func TestGenerateCommandParse(t *testing.T) {
+ g := &Generator{
+ r: nil, // Unused here.
+ path: "/usr/ken/sys/proc.go",
+ dir: "/usr/ken/sys",
+ file: "proc.go",
+ pkg: "sys",
+ commands: make(map[string][]string),
+ }
+ g.setShorthand([]string{"-command", "yacc", "go", "tool", "yacc"})
+ for _, test := range splitTests {
+ // First with newlines.
+ got := g.split("//go:generate " + test.in + "\n")
+ if !reflect.DeepEqual(got, test.out) {
+ t.Errorf("split(%q): got %q expected %q", test.in, got, test.out)
+ }
+ // Then with CRLFs, thank you Windows.
+ got = g.split("//go:generate " + test.in + "\r\n")
+ if !reflect.DeepEqual(got, test.out) {
+ t.Errorf("split(%q): got %q expected %q", test.in, got, test.out)
+ }
+ }
+}
diff --git a/libgo/go/cmd/go/get.go b/libgo/go/cmd/go/get.go
new file mode 100644
index 0000000000..50e0ca93bf
--- /dev/null
+++ b/libgo/go/cmd/go/get.go
@@ -0,0 +1,460 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "go/build"
+ "os"
+ "path/filepath"
+ "regexp"
+ "runtime"
+ "strconv"
+ "strings"
+)
+
+var cmdGet = &Command{
+ UsageLine: "get [-d] [-f] [-fix] [-t] [-u] [build flags] [packages]",
+ Short: "download and install packages and dependencies",
+ Long: `
+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.
+ `,
+}
+
+var getD = cmdGet.Flag.Bool("d", false, "")
+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, "")
+
+func init() {
+ addBuildFlags(cmdGet)
+ cmdGet.Run = runGet // break init loop
+}
+
+func runGet(cmd *Command, args []string) {
+ if *getF && !*getU {
+ fatalf("go get: cannot use -f flag without -u")
+ }
+
+ // Phase 1. Download/update.
+ var stk importStack
+ for _, arg := range downloadPaths(args) {
+ download(arg, &stk, *getT)
+ }
+ exitIfErrors()
+
+ // Phase 2. Rescan packages and re-evaluate args list.
+
+ // Code we downloaded and all code that depends on it
+ // needs to be evicted from the package cache so that
+ // the information will be recomputed. Instead of keeping
+ // track of the reverse dependency information, evict
+ // everything.
+ for name := range packageCache {
+ delete(packageCache, name)
+ }
+
+ args = importPaths(args)
+
+ // Phase 3. Install.
+ if *getD {
+ // Download only.
+ // Check delayed until now so that importPaths
+ // has a chance to print errors.
+ return
+ }
+
+ runInstall(cmd, args)
+}
+
+// downloadPaths prepares the list of paths to pass to download.
+// It expands ... patterns that can be expanded. If there is no match
+// for a particular pattern, downloadPaths leaves it in the result list,
+// in the hope that we can figure out the repository from the
+// initial ...-free prefix.
+func downloadPaths(args []string) []string {
+ args = importPathsNoDotExpansion(args)
+ var out []string
+ for _, a := range args {
+ if strings.Contains(a, "...") {
+ var expand []string
+ // Use matchPackagesInFS to avoid printing
+ // warnings. They will be printed by the
+ // eventual call to importPaths instead.
+ if build.IsLocalImport(a) {
+ expand = matchPackagesInFS(a)
+ } else {
+ expand = matchPackages(a)
+ }
+ if len(expand) > 0 {
+ out = append(out, expand...)
+ continue
+ }
+ }
+ out = append(out, a)
+ }
+ return out
+}
+
+// downloadCache records the import paths we have already
+// considered during the download, to avoid duplicate work when
+// there is more than one dependency sequence leading to
+// a particular package.
+var downloadCache = map[string]bool{}
+
+// downloadRootCache records the version control repository
+// root directories we have already considered during the download.
+// For example, all the packages in the code.google.com/p/codesearch repo
+// share the same root (the directory for that path), and we only need
+// to run the hg commands to consider each repository once.
+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)
+ if p.Error != nil && p.Error.hard {
+ errorf("%s", p.Error)
+ return
+ }
+
+ // There's nothing to do if this is a package in the standard library.
+ if p.Standard {
+ return
+ }
+
+ // 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 {
+ return
+ }
+ downloadCache[arg] = true
+
+ pkgs := []*Package{p}
+ wildcardOkay := len(*stk) == 0
+ isWildcard := false
+
+ // Download if the package is missing, or update if we're using -u.
+ if p.Dir == "" || *getU {
+ // The actual download.
+ stk.push(p.ImportPath)
+ err := downloadPackage(p)
+ if err != nil {
+ errorf("%s", &PackageError{ImportStack: stk.copy(), Err: err.Error()})
+ stk.pop()
+ return
+ }
+
+ args := []string{arg}
+ // If the argument has a wildcard in it, re-evaluate the wildcard.
+ // We delay this until after reloadPackage so that the old entry
+ // for p has been replaced in the package cache.
+ if wildcardOkay && strings.Contains(arg, "...") {
+ if build.IsLocalImport(arg) {
+ args = matchPackagesInFS(arg)
+ } else {
+ args = matchPackages(arg)
+ }
+ isWildcard = true
+ }
+
+ // Clear all relevant package cache entries before
+ // doing any new loads.
+ for _, arg := range args {
+ p := packageCache[arg]
+ if p != nil {
+ delete(packageCache, p.Dir)
+ delete(packageCache, p.ImportPath)
+ }
+ }
+
+ pkgs = pkgs[:0]
+ for _, arg := range args {
+ stk.push(arg)
+ p := loadPackage(arg, stk)
+ stk.pop()
+ if p.Error != nil {
+ errorf("%s", p.Error)
+ continue
+ }
+ pkgs = append(pkgs, p)
+ }
+ }
+
+ // Process package, which might now be multiple packages
+ // due to wildcard expansion.
+ for _, p := range pkgs {
+ if *getFix {
+ run(stringList(tool("fix"), relPaths(p.allgofiles)))
+
+ // The imports might have changed, so reload again.
+ p = reloadPackage(arg, stk)
+ if p.Error != nil {
+ errorf("%s", p.Error)
+ return
+ }
+ }
+
+ if isWildcard {
+ // Report both the real package and the
+ // wildcard in any error message.
+ stk.push(p.ImportPath)
+ }
+
+ // Process dependencies, now that we know what they are.
+ for _, dep := range p.deps {
+ // Don't get test dependencies recursively.
+ download(dep.ImportPath, stk, false)
+ }
+ if getTestDeps {
+ // Process test dependencies when -t is specified.
+ // (Don't get test dependencies for test dependencies.)
+ for _, path := range p.TestImports {
+ download(path, stk, false)
+ }
+ for _, path := range p.XTestImports {
+ download(path, stk, false)
+ }
+ }
+
+ if isWildcard {
+ stk.pop()
+ }
+ }
+}
+
+// downloadPackage runs the create or download command
+// to make the first copy of or update a copy of the given package.
+func downloadPackage(p *Package) error {
+ var (
+ vcs *vcsCmd
+ repo, rootPath string
+ err error
+ )
+ if p.build.SrcRoot != "" {
+ // Directory exists. Look for checkout along path to src.
+ vcs, rootPath, err = vcsForDir(p)
+ if err != nil {
+ return err
+ }
+ repo = "<local>" // should be unused; make distinctive
+
+ // Double-check where it came from.
+ if *getU && vcs.remoteRepo != nil && !*getF {
+ dir := filepath.Join(p.build.SrcRoot, rootPath)
+ if remote, err := vcs.remoteRepo(vcs, dir); err == nil {
+ if rr, err := repoRootForImportPath(p.ImportPath); err == nil {
+ repo := rr.repo
+ if rr.vcs.resolveRepo != nil {
+ resolved, err := rr.vcs.resolveRepo(rr.vcs, dir, repo)
+ if err == nil {
+ repo = resolved
+ }
+ }
+ if remote != repo {
+ return fmt.Errorf("%s is a custom import path for %s, but %s is checked out from %s", rr.root, repo, dir, remote)
+ }
+ }
+ }
+ }
+ } 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)
+ if err != nil {
+ return err
+ }
+ vcs, repo, rootPath = rr.vcs, rr.repo, rr.root
+ }
+
+ if p.build.SrcRoot == "" {
+ // Package not found. Put in first directory of $GOPATH.
+ list := filepath.SplitList(buildContext.GOPATH)
+ if len(list) == 0 {
+ return fmt.Errorf("cannot download, $GOPATH not set. For more details see: go help gopath")
+ }
+ // Guard against people setting GOPATH=$GOROOT.
+ if list[0] == goroot {
+ return fmt.Errorf("cannot download, $GOPATH must not be set to $GOROOT. For more details see: go help gopath")
+ }
+ p.build.SrcRoot = filepath.Join(list[0], "src")
+ p.build.PkgRoot = filepath.Join(list[0], "pkg")
+ }
+ root := filepath.Join(p.build.SrcRoot, rootPath)
+ // If we've considered this repository already, don't do it again.
+ if downloadRootCache[root] {
+ return nil
+ }
+ downloadRootCache[root] = true
+
+ if buildV {
+ fmt.Fprintf(os.Stderr, "%s (download)\n", rootPath)
+ }
+
+ // Check that this is an appropriate place for the repo to be checked out.
+ // The target directory must either not exist or have a repo checked out already.
+ meta := filepath.Join(root, "."+vcs.cmd)
+ st, err := os.Stat(meta)
+ if err == nil && !st.IsDir() {
+ return fmt.Errorf("%s exists but is not a directory", meta)
+ }
+ if err != nil {
+ // Metadata directory does not exist. Prepare to checkout new copy.
+ // Some version control tools require the target directory not to exist.
+ // We require that too, just to avoid stepping on existing work.
+ if _, err := os.Stat(root); err == nil {
+ return fmt.Errorf("%s exists but %s does not - stale checkout?", root, meta)
+ }
+ // Some version control tools require the parent of the target to exist.
+ parent, _ := filepath.Split(root)
+ if err = os.MkdirAll(parent, 0777); err != nil {
+ return err
+ }
+ if err = vcs.create(root, repo); err != nil {
+ return err
+ }
+ } else {
+ // Metadata directory does exist; download incremental updates.
+ if err = vcs.download(root); err != nil {
+ return err
+ }
+ }
+
+ if buildN {
+ // Do not show tag sync in -n; it's noise more than anything,
+ // and since we're not running commands, no tag will be found.
+ // But avoid printing nothing.
+ fmt.Fprintf(os.Stderr, "# cd %s; %s sync/update\n", root, vcs.cmd)
+ return nil
+ }
+
+ // Select and sync to appropriate version of the repository.
+ tags, err := vcs.tags(root)
+ if err != nil {
+ return err
+ }
+ vers := runtime.Version()
+ if i := strings.Index(vers, " "); i >= 0 {
+ vers = vers[:i]
+ }
+ if err := vcs.tagSync(root, selectTag(vers, tags)); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// goTag matches go release tags such as go1 and go1.2.3.
+// The numbers involved must be small (at most 4 digits),
+// have no unnecessary leading zeros, and the version cannot
+// end in .0 - it is go1, not go1.0 or go1.0.0.
+var goTag = regexp.MustCompile(
+ `^go((0|[1-9][0-9]{0,3})\.)*([1-9][0-9]{0,3})$`,
+)
+
+// selectTag returns the closest matching tag for a given version.
+// Closest means the latest one that is not after the current release.
+// Version "goX" (or "goX.Y" or "goX.Y.Z") matches tags of the same form.
+// Version "release.rN" matches tags of the form "go.rN" (N being a floating-point number).
+// Version "weekly.YYYY-MM-DD" matches tags like "go.weekly.YYYY-MM-DD".
+//
+// NOTE(rsc): Eventually we will need to decide on some logic here.
+// For now, there is only "go1". This matches the docs in go help get.
+func selectTag(goVersion string, tags []string) (match string) {
+ for _, t := range tags {
+ if t == "go1" {
+ return "go1"
+ }
+ }
+ return ""
+
+ /*
+ if goTag.MatchString(goVersion) {
+ v := goVersion
+ for _, t := range tags {
+ if !goTag.MatchString(t) {
+ continue
+ }
+ if cmpGoVersion(match, t) < 0 && cmpGoVersion(t, v) <= 0 {
+ match = t
+ }
+ }
+ }
+
+ return match
+ */
+}
+
+// cmpGoVersion returns -1, 0, +1 reporting whether
+// x < y, x == y, or x > y.
+func cmpGoVersion(x, y string) int {
+ // Malformed strings compare less than well-formed strings.
+ if !goTag.MatchString(x) {
+ return -1
+ }
+ if !goTag.MatchString(y) {
+ return +1
+ }
+
+ // Compare numbers in sequence.
+ xx := strings.Split(x[len("go"):], ".")
+ yy := strings.Split(y[len("go"):], ".")
+
+ for i := 0; i < len(xx) && i < len(yy); i++ {
+ // The Atoi are guaranteed to succeed
+ // because the versions match goTag.
+ xi, _ := strconv.Atoi(xx[i])
+ yi, _ := strconv.Atoi(yy[i])
+ if xi < yi {
+ return -1
+ } else if xi > yi {
+ return +1
+ }
+ }
+
+ if len(xx) < len(yy) {
+ return -1
+ }
+ if len(xx) > len(yy) {
+ return +1
+ }
+ return 0
+}
diff --git a/libgo/go/reflect/makefunc_dummy.c b/libgo/go/cmd/go/go11.go
index aba48df3eb..8a434dfed1 100644
--- a/libgo/go/reflect/makefunc_dummy.c
+++ b/libgo/go/cmd/go/go11.go
@@ -2,11 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !amd64
+// +build go1.1
-// Dummy function for processors without makefunc support.
+package main
-void makeFuncStub () __asm__ ("reflect.makeFuncStub");
-void makeFuncStub ()
-{
-}
+// Test that go1.1 tag above is included in builds. main.go refers to this definition.
+const go11tag = true
diff --git a/libgo/go/cmd/go/go_windows_test.go b/libgo/go/cmd/go/go_windows_test.go
new file mode 100644
index 0000000000..53d695cccc
--- /dev/null
+++ b/libgo/go/cmd/go/go_windows_test.go
@@ -0,0 +1,55 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "testing"
+)
+
+func TestAbsolutePath(t *testing.T) {
+ tmp, err := ioutil.TempDir("", "TestAbsolutePath")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmp)
+
+ file := filepath.Join(tmp, "a.go")
+ err = ioutil.WriteFile(file, []byte{}, 0644)
+ if err != nil {
+ t.Fatal(err)
+ }
+ dir := filepath.Join(tmp, "dir")
+ err = os.Mkdir(dir, 0777)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ wd, err := os.Getwd()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.Chdir(wd)
+
+ // Chdir so current directory and a.go reside on the same drive.
+ err = os.Chdir(dir)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ noVolume := file[len(filepath.VolumeName(file)):]
+ wrongPath := filepath.Join(dir, noVolume)
+ output, err := exec.Command("go", "build", noVolume).CombinedOutput()
+ if err == nil {
+ t.Fatal("build should fail")
+ }
+ if strings.Contains(string(output), wrongPath) {
+ t.Fatalf("wrong output found: %v %v", err, string(output))
+ }
+}
diff --git a/libgo/go/cmd/go/help.go b/libgo/go/cmd/go/help.go
new file mode 100644
index 0000000000..c590fdb37f
--- /dev/null
+++ b/libgo/go/cmd/go/help.go
@@ -0,0 +1,362 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var helpC = &Command{
+ UsageLine: "c",
+ Short: "calling between Go and C",
+ Long: `
+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.
+ `,
+}
+
+var helpPackages = &Command{
+ UsageLine: "packages",
+ Short: "description of package lists",
+ Long: `
+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".
+ `,
+}
+
+var helpImportPath = &Command{
+ UsageLine: "importpath",
+ Short: "import path syntax",
+ Long: `
+
+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 <meta> 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 <meta> tag in the document's HTML
+<head>.
+
+The meta tag has the form:
+
+ <meta name="go-import" content="import-prefix vcs repo-root">
+
+The import-prefix is the import path 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 <meta> tags match.
+
+The vcs is one of "git", "hg", "svn", etc,
+
+The repo-root is the root of the version control system
+containing a scheme and not containing a .vcs qualifier.
+
+For example,
+
+ import "example.org/pkg/foo"
+
+will result in the following request(s):
+
+ https://example.org/pkg/foo?go-get=1 (preferred)
+ http://example.org/pkg/foo?go-get=1 (fallback)
+
+If that page contains the meta tag
+
+ <meta name="go-import" content="example.org git https://code.org/r/p/exproj">
+
+the go tool will verify that https://example.org/?go-get=1 contains the
+same meta tag and then git clone https://code.org/r/p/exproj into
+GOPATH/src/example.org.
+
+New downloaded packages are written to the first directory
+listed in the GOPATH environment variable (see 'go help gopath').
+
+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.
+ `,
+}
+
+var helpGopath = &Command{
+ UsageLine: "gopath",
+ Short: "GOPATH environment variable",
+ Long: `
+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.
+ `,
+}
+
+var helpFileType = &Command{
+ UsageLine: "filetype",
+ Short: "file types",
+ Long: `
+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.
+ `,
+}
diff --git a/libgo/go/cmd/go/http.go b/libgo/go/cmd/go/http.go
new file mode 100644
index 0000000000..107b820f28
--- /dev/null
+++ b/libgo/go/cmd/go/http.go
@@ -0,0 +1,87 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !cmd_go_bootstrap
+
+// This code is compiled into the real 'go' binary, but it is not
+// compiled into the binary that is built during all.bash, so as
+// to avoid needing to build net (and thus use cgo) during the
+// bootstrap process.
+
+package main
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "net/url"
+)
+
+// httpClient is the default HTTP client, but a variable so it can be
+// changed by tests, without modifying http.DefaultClient.
+var httpClient = http.DefaultClient
+
+// httpGET returns the data from an HTTP GET request for the given URL.
+func httpGET(url string) ([]byte, error) {
+ resp, err := httpClient.Get(url)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+ if resp.StatusCode != 200 {
+ return nil, fmt.Errorf("%s: %s", url, resp.Status)
+ }
+ b, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return nil, fmt.Errorf("%s: %v", url, err)
+ }
+ return b, nil
+}
+
+// httpsOrHTTP returns the body of either the importPath's
+// https resource or, if unavailable, the http resource.
+func httpsOrHTTP(importPath string) (urlStr string, body io.ReadCloser, err error) {
+ fetch := func(scheme string) (urlStr string, res *http.Response, err error) {
+ u, err := url.Parse(scheme + "://" + importPath)
+ if err != nil {
+ return "", nil, err
+ }
+ u.RawQuery = "go-get=1"
+ urlStr = u.String()
+ if buildV {
+ log.Printf("Fetching %s", urlStr)
+ }
+ res, err = httpClient.Get(urlStr)
+ return
+ }
+ closeBody := func(res *http.Response) {
+ if res != nil {
+ res.Body.Close()
+ }
+ }
+ urlStr, res, err := fetch("https")
+ if err != nil || res.StatusCode != 200 {
+ if buildV {
+ if err != nil {
+ log.Printf("https fetch failed.")
+ } else {
+ log.Printf("ignoring https fetch with status code %d", res.StatusCode)
+ }
+ }
+ closeBody(res)
+ urlStr, res, err = fetch("http")
+ }
+ if err != nil {
+ closeBody(res)
+ return "", nil, err
+ }
+ // Note: accepting a non-200 OK here, so people can serve a
+ // meta import in their http 404 page.
+ if buildV {
+ log.Printf("Parsing meta tags from %s (status code %d)", urlStr, res.StatusCode)
+ }
+ return urlStr, res.Body, nil
+}
diff --git a/libgo/go/cmd/go/list.go b/libgo/go/cmd/go/list.go
new file mode 100644
index 0000000000..fbf96167fe
--- /dev/null
+++ b/libgo/go/cmd/go/list.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 main
+
+import (
+ "bufio"
+ "encoding/json"
+ "io"
+ "os"
+ "strings"
+ "text/template"
+)
+
+var cmdList = &Command{
+ UsageLine: "list [-e] [-f format] [-json] [build flags] [packages]",
+ Short: "list packages",
+ Long: `
+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'.
+ `,
+}
+
+func init() {
+ cmdList.Run = runList // break init cycle
+ addBuildFlags(cmdList)
+}
+
+var listE = cmdList.Flag.Bool("e", false, "")
+var listFmt = cmdList.Flag.String("f", "{{.ImportPath}}", "")
+var listJson = cmdList.Flag.Bool("json", false, "")
+var nl = []byte{'\n'}
+
+func runList(cmd *Command, args []string) {
+ out := newTrackingWriter(os.Stdout)
+ defer out.w.Flush()
+
+ var do func(*Package)
+ if *listJson {
+ do = func(p *Package) {
+ b, err := json.MarshalIndent(p, "", "\t")
+ if err != nil {
+ out.Flush()
+ fatalf("%s", err)
+ }
+ out.Write(b)
+ out.Write(nl)
+ }
+ } else {
+ var cachedCtxt *Context
+ context := func() *Context {
+ if cachedCtxt == nil {
+ cachedCtxt = newContext(&buildContext)
+ }
+ return cachedCtxt
+ }
+ fm := template.FuncMap{
+ "join": strings.Join,
+ "context": context,
+ }
+ tmpl, err := template.New("main").Funcs(fm).Parse(*listFmt)
+ if err != nil {
+ fatalf("%s", err)
+ }
+ do = func(p *Package) {
+ if err := tmpl.Execute(out, p); err != nil {
+ out.Flush()
+ fatalf("%s", err)
+ }
+ if out.NeedNL() {
+ out.Write(nl)
+ }
+ }
+ }
+
+ load := packages
+ if *listE {
+ load = packagesAndErrors
+ }
+
+ for _, pkg := range load(args) {
+ do(pkg)
+ }
+}
+
+// TrackingWriter tracks the last byte written on every write so
+// we can avoid printing a newline if one was already written or
+// if there is no output at all.
+type TrackingWriter struct {
+ w *bufio.Writer
+ last byte
+}
+
+func newTrackingWriter(w io.Writer) *TrackingWriter {
+ return &TrackingWriter{
+ w: bufio.NewWriter(w),
+ last: '\n',
+ }
+}
+
+func (t *TrackingWriter) Write(p []byte) (n int, err error) {
+ n, err = t.w.Write(p)
+ if n > 0 {
+ t.last = p[n-1]
+ }
+ return
+}
+
+func (t *TrackingWriter) Flush() {
+ t.w.Flush()
+}
+
+func (t *TrackingWriter) NeedNL() bool {
+ return t.last != '\n'
+}
diff --git a/libgo/go/cmd/go/main.go b/libgo/go/cmd/go/main.go
new file mode 100644
index 0000000000..9691f39c76
--- /dev/null
+++ b/libgo/go/cmd/go/main.go
@@ -0,0 +1,723 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "go/build"
+ "io"
+ "log"
+ "os"
+ "os/exec"
+ "path"
+ "path/filepath"
+ "regexp"
+ "runtime"
+ "strings"
+ "sync"
+ "text/template"
+ "unicode"
+ "unicode/utf8"
+)
+
+// A Command is an implementation of a go command
+// like go build or go fix.
+type Command struct {
+ // Run runs the command.
+ // The args are the arguments after the command name.
+ Run func(cmd *Command, args []string)
+
+ // UsageLine is the one-line usage message.
+ // The first word in the line is taken to be the command name.
+ UsageLine string
+
+ // Short is the short description shown in the 'go help' output.
+ Short string
+
+ // Long is the long message shown in the 'go help <this-command>' output.
+ Long string
+
+ // Flag is a set of flags specific to this command.
+ Flag flag.FlagSet
+
+ // CustomFlags indicates that the command will do its own
+ // flag parsing.
+ CustomFlags bool
+}
+
+// Name returns the command's name: the first word in the usage line.
+func (c *Command) Name() string {
+ name := c.UsageLine
+ i := strings.Index(name, " ")
+ if i >= 0 {
+ name = name[:i]
+ }
+ return name
+}
+
+func (c *Command) Usage() {
+ fmt.Fprintf(os.Stderr, "usage: %s\n\n", c.UsageLine)
+ fmt.Fprintf(os.Stderr, "%s\n", strings.TrimSpace(c.Long))
+ os.Exit(2)
+}
+
+// Runnable reports whether the command can be run; otherwise
+// it is a documentation pseudo-command such as importpath.
+func (c *Command) Runnable() bool {
+ return c.Run != nil
+}
+
+// Commands lists the available commands and help topics.
+// The order here is the order in which they are printed by 'go help'.
+var commands = []*Command{
+ cmdBuild,
+ cmdClean,
+ cmdEnv,
+ cmdFix,
+ cmdFmt,
+ cmdGenerate,
+ cmdGet,
+ cmdInstall,
+ cmdList,
+ cmdRun,
+ cmdTest,
+ cmdTool,
+ cmdVersion,
+ cmdVet,
+
+ helpC,
+ helpFileType,
+ helpGopath,
+ helpImportPath,
+ helpPackages,
+ helpTestflag,
+ helpTestfunc,
+}
+
+var exitStatus = 0
+var exitMu sync.Mutex
+
+func setExitStatus(n int) {
+ exitMu.Lock()
+ if exitStatus < n {
+ exitStatus = n
+ }
+ exitMu.Unlock()
+}
+
+func main() {
+ _ = go11tag
+ flag.Usage = usage
+ flag.Parse()
+ log.SetFlags(0)
+
+ args := flag.Args()
+ if len(args) < 1 {
+ usage()
+ }
+
+ if args[0] == "help" {
+ help(args[1:])
+ return
+ }
+
+ // Diagnose common mistake: GOPATH==GOROOT.
+ // This setting is equivalent to not setting GOPATH at all,
+ // which is not what most people want when they do it.
+ if gopath := os.Getenv("GOPATH"); gopath == runtime.GOROOT() {
+ fmt.Fprintf(os.Stderr, "warning: GOPATH set to GOROOT (%s) has no effect\n", gopath)
+ } else {
+ for _, p := range filepath.SplitList(gopath) {
+ // Note: using HasPrefix instead of Contains because a ~ can appear
+ // in the middle of directory elements, such as /tmp/git-1.8.2~rc3
+ // or C:\PROGRA~1. Only ~ as a path prefix has meaning to the shell.
+ if strings.HasPrefix(p, "~") {
+ fmt.Fprintf(os.Stderr, "go: GOPATH entry cannot start with shell metacharacter '~': %q\n", p)
+ os.Exit(2)
+ }
+ if build.IsLocalImport(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)
+ }
+ }
+ }
+
+ if fi, err := os.Stat(goroot); err != nil || !fi.IsDir() {
+ fmt.Fprintf(os.Stderr, "go: cannot find GOROOT directory: %v\n", goroot)
+ os.Exit(2)
+ }
+
+ for _, cmd := range commands {
+ if cmd.Name() == args[0] && cmd.Run != nil {
+ cmd.Flag.Usage = func() { cmd.Usage() }
+ if cmd.CustomFlags {
+ args = args[1:]
+ } else {
+ cmd.Flag.Parse(args[1:])
+ args = cmd.Flag.Args()
+ }
+ cmd.Run(cmd, args)
+ exit()
+ return
+ }
+ }
+
+ fmt.Fprintf(os.Stderr, "go: unknown subcommand %q\nRun 'go help' for usage.\n", args[0])
+ setExitStatus(2)
+ exit()
+}
+
+var usageTemplate = `Go is a tool for managing Go source code.
+
+Usage:
+
+ go command [arguments]
+
+The commands are:
+{{range .}}{{if .Runnable}}
+ {{.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}}
+
+Use "go help [topic]" for more information about that topic.
+
+`
+
+var helpTemplate = `{{if .Runnable}}usage: go {{.UsageLine}}
+
+{{end}}{{.Long | trim}}
+`
+
+var documentationTemplate = `// 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 mkdoc.sh.
+// Edit the documentation in other files and rerun mkdoc.sh to generate this one.
+
+/*
+{{range .}}{{if .Short}}{{.Short | capitalize}}
+
+{{end}}{{if .Runnable}}Usage:
+
+ go {{.UsageLine}}
+
+{{end}}{{.Long | trim}}
+
+
+{{end}}*/
+package main
+`
+
+// 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 {
+ panic(err)
+ }
+}
+
+func capitalize(s string) string {
+ if s == "" {
+ return s
+ }
+ r, n := utf8.DecodeRuneInString(s)
+ return string(unicode.ToTitle(r)) + s[n:]
+}
+
+func printUsage(w io.Writer) {
+ tmpl(w, usageTemplate, commands)
+}
+
+func usage() {
+ // special case "go test -h"
+ if len(os.Args) > 1 && os.Args[1] == "test" {
+ help([]string{"testflag"})
+ os.Exit(2)
+ }
+ printUsage(os.Stderr)
+ os.Exit(2)
+}
+
+// help implements the 'help' command.
+func help(args []string) {
+ if len(args) == 0 {
+ printUsage(os.Stdout)
+ // not exit 2: succeeded at 'go help'.
+ return
+ }
+ if len(args) != 1 {
+ fmt.Fprintf(os.Stderr, "usage: go help command\n\nToo many arguments given.\n")
+ os.Exit(2) // failed at 'go help'
+ }
+
+ arg := args[0]
+
+ // 'go help documentation' generates doc.go.
+ if arg == "documentation" {
+ buf := new(bytes.Buffer)
+ printUsage(buf)
+ usage := &Command{Long: buf.String()}
+ tmpl(os.Stdout, documentationTemplate, append([]*Command{usage}, commands...))
+ return
+ }
+
+ for _, cmd := range commands {
+ if cmd.Name() == arg {
+ tmpl(os.Stdout, helpTemplate, cmd)
+ // not exit 2: succeeded at 'go help cmd'.
+ return
+ }
+ }
+
+ fmt.Fprintf(os.Stderr, "Unknown help topic %#q. Run 'go help'.\n", arg)
+ os.Exit(2) // failed at 'go help cmd'
+}
+
+// importPathsNoDotExpansion returns the import paths to use for the given
+// command line, but it does no ... expansion.
+func importPathsNoDotExpansion(args []string) []string {
+ if len(args) == 0 {
+ return []string{"."}
+ }
+ var out []string
+ for _, a := range args {
+ // Arguments are supposed to be import paths, but
+ // as a courtesy to Windows developers, rewrite \ to /
+ // in command-line arguments. Handles .\... and so on.
+ if filepath.Separator == '\\' {
+ a = strings.Replace(a, `\`, `/`, -1)
+ }
+
+ // Put argument in canonical form, but preserve leading ./.
+ if strings.HasPrefix(a, "./") {
+ a = "./" + path.Clean(a)
+ if a == "./." {
+ a = "."
+ }
+ } else {
+ a = path.Clean(a)
+ }
+ if a == "all" || a == "std" {
+ out = append(out, allPackages(a)...)
+ continue
+ }
+ out = append(out, a)
+ }
+ return out
+}
+
+// importPaths returns the import paths to use for the given command line.
+func importPaths(args []string) []string {
+ args = importPathsNoDotExpansion(args)
+ var out []string
+ for _, a := range args {
+ if strings.Contains(a, "...") {
+ if build.IsLocalImport(a) {
+ out = append(out, allPackagesInFS(a)...)
+ } else {
+ out = append(out, allPackages(a)...)
+ }
+ continue
+ }
+ out = append(out, a)
+ }
+ return out
+}
+
+var atexitFuncs []func()
+
+func atexit(f func()) {
+ atexitFuncs = append(atexitFuncs, f)
+}
+
+func exit() {
+ for _, f := range atexitFuncs {
+ f()
+ }
+ os.Exit(exitStatus)
+}
+
+func fatalf(format string, args ...interface{}) {
+ errorf(format, args...)
+ exit()
+}
+
+func errorf(format string, args ...interface{}) {
+ log.Printf(format, args...)
+ setExitStatus(1)
+}
+
+var logf = log.Printf
+
+func exitIfErrors() {
+ if exitStatus != 0 {
+ exit()
+ }
+}
+
+func run(cmdargs ...interface{}) {
+ cmdline := stringList(cmdargs...)
+ if buildN || buildX {
+ fmt.Printf("%s\n", strings.Join(cmdline, " "))
+ if buildN {
+ return
+ }
+ }
+
+ cmd := exec.Command(cmdline[0], cmdline[1:]...)
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ if err := cmd.Run(); err != nil {
+ errorf("%v", err)
+ }
+}
+
+func runOut(dir string, cmdargs ...interface{}) []byte {
+ cmdline := stringList(cmdargs...)
+ cmd := exec.Command(cmdline[0], cmdline[1:]...)
+ cmd.Dir = dir
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ os.Stderr.Write(out)
+ errorf("%v", err)
+ out = nil
+ }
+ return out
+}
+
+// envForDir returns a copy of the environment
+// suitable for running in the given directory.
+// 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()
+ // 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)
+}
+
+// mergeEnvLists merges the two environment lists such that
+// variables with the same name in "in" replace those in "out".
+func mergeEnvLists(in, out []string) []string {
+NextVar:
+ for _, inkv := range in {
+ k := strings.SplitAfterN(inkv, "=", 2)[0]
+ for i, outkv := range out {
+ if strings.HasPrefix(outkv, k) {
+ out[i] = inkv
+ continue NextVar
+ }
+ }
+ out = append(out, inkv)
+ }
+ return out
+}
+
+// matchPattern(pattern)(name) reports whether
+// name matches pattern. Pattern is a limited glob
+// pattern in which '...' means 'any string' and there
+// is no other special syntax.
+func matchPattern(pattern string) func(name string) bool {
+ re := regexp.QuoteMeta(pattern)
+ re = strings.Replace(re, `\.\.\.`, `.*`, -1)
+ // Special case: foo/... matches foo too.
+ if strings.HasSuffix(re, `/.*`) {
+ re = re[:len(re)-len(`/.*`)] + `(/.*)?`
+ }
+ reg := regexp.MustCompile(`^` + re + `$`)
+ return func(name string) bool {
+ return reg.MatchString(name)
+ }
+}
+
+// hasPathPrefix reports whether the path s begins with the
+// elements in prefix.
+func hasPathPrefix(s, prefix string) bool {
+ switch {
+ default:
+ return false
+ case len(s) == len(prefix):
+ return s == prefix
+ case len(s) > len(prefix):
+ if prefix != "" && prefix[len(prefix)-1] == '/' {
+ return strings.HasPrefix(s, prefix)
+ }
+ return s[len(prefix)] == '/' && 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.
+func treeCanMatchPattern(pattern string) func(name string) bool {
+ wildCard := false
+ if i := strings.Index(pattern, "..."); i >= 0 {
+ wildCard = true
+ pattern = pattern[:i]
+ }
+ return func(name string) bool {
+ return len(name) <= len(pattern) && hasPathPrefix(pattern, name) ||
+ wildCard && strings.HasPrefix(name, pattern)
+ }
+}
+
+// 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 "...".
+func allPackages(pattern string) []string {
+ pkgs := matchPackages(pattern)
+ if len(pkgs) == 0 {
+ fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
+ }
+ return pkgs
+}
+
+func matchPackages(pattern string) []string {
+ match := func(string) bool { return true }
+ treeCanMatch := func(string) bool { return true }
+ if pattern != "all" && pattern != "std" {
+ match = matchPattern(pattern)
+ treeCanMatch = treeCanMatchPattern(pattern)
+ }
+
+ have := map[string]bool{
+ "builtin": true, // ignore pseudo-package that exists only for documentation
+ }
+ if !buildContext.CgoEnabled {
+ have["runtime/cgo"] = true // ignore during walk
+ }
+ 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 {
+ continue
+ }
+ src = filepath.Clean(src) + string(filepath.Separator)
+ filepath.Walk(src, func(path string, fi os.FileInfo, err error) error {
+ if err != nil || !fi.IsDir() || path == src {
+ return nil
+ }
+
+ // Avoid .foo, _foo, and testdata directory trees.
+ _, elem := filepath.Split(path)
+ if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
+ return filepath.SkipDir
+ }
+
+ name := filepath.ToSlash(path[len(src):])
+ if pattern == "std" && strings.Contains(name, ".") {
+ return filepath.SkipDir
+ }
+ if !treeCanMatch(name) {
+ return filepath.SkipDir
+ }
+ 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 {
+ return nil
+ }
+ }
+ pkgs = append(pkgs, name)
+ return nil
+ })
+ }
+ return pkgs
+}
+
+// allPackagesInFS is like allPackages but is passed a pattern
+// beginning ./ or ../, meaning it should scan the tree rooted
+// at the given directory. There are ... in the pattern too.
+func allPackagesInFS(pattern string) []string {
+ pkgs := matchPackagesInFS(pattern)
+ if len(pkgs) == 0 {
+ fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
+ }
+ return pkgs
+}
+
+func matchPackagesInFS(pattern string) []string {
+ // Find directory to begin the scan.
+ // Could be smarter but this one optimization
+ // is enough for now, since ... is usually at the
+ // end of a path.
+ i := strings.Index(pattern, "...")
+ dir, _ := path.Split(pattern[:i])
+
+ // pattern begins with ./ or ../.
+ // path.Clean will discard the ./ but not the ../.
+ // We need to preserve the ./ for pattern matching
+ // and in the returned import paths.
+ prefix := ""
+ if strings.HasPrefix(pattern, "./") {
+ prefix = "./"
+ }
+ match := matchPattern(pattern)
+
+ var pkgs []string
+ filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
+ if err != nil || !fi.IsDir() {
+ return nil
+ }
+ if path == dir {
+ // filepath.Walk starts at dir and recurses. For the recursive case,
+ // the path is the result of filepath.Join, which calls filepath.Clean.
+ // The initial case is not Cleaned, though, so we do this explicitly.
+ //
+ // This converts a path like "./io/" to "io". Without this step, running
+ // "cd $GOROOT/src; go list ./io/..." would incorrectly skip the io
+ // package, because prepending the prefix "./" to the unclean path would
+ // result in "././io", and match("././io") returns false.
+ path = filepath.Clean(path)
+ }
+
+ // Avoid .foo, _foo, and testdata directory trees, but do not avoid "." or "..".
+ _, elem := filepath.Split(path)
+ dot := strings.HasPrefix(elem, ".") && elem != "." && elem != ".."
+ if dot || strings.HasPrefix(elem, "_") || elem == "testdata" {
+ return filepath.SkipDir
+ }
+
+ name := prefix + filepath.ToSlash(path)
+ if !match(name) {
+ return nil
+ }
+ if _, err = build.ImportDir(path, 0); err != nil {
+ if _, noGo := err.(*build.NoGoError); !noGo {
+ log.Print(err)
+ }
+ return nil
+ }
+ pkgs = append(pkgs, name)
+ return nil
+ })
+ return pkgs
+}
+
+// stringList's arguments should be a sequence of string or []string values.
+// stringList flattens them into a single []string.
+func stringList(args ...interface{}) []string {
+ var x []string
+ for _, arg := range args {
+ switch arg := arg.(type) {
+ case []string:
+ x = append(x, arg...)
+ case string:
+ x = append(x, arg)
+ default:
+ panic("stringList: invalid argument")
+ }
+ }
+ return x
+}
+
+// toFold returns a string with the property that
+// strings.EqualFold(s, t) iff toFold(s) == toFold(t)
+// This lets us test a large set of strings for fold-equivalent
+// duplicates without making a quadratic number of calls
+// to EqualFold. Note that strings.ToUpper and strings.ToLower
+// have the desired property in some corner cases.
+func toFold(s string) string {
+ // Fast path: all ASCII, no upper case.
+ // Most paths look like this already.
+ for i := 0; i < len(s); i++ {
+ c := s[i]
+ if c >= utf8.RuneSelf || 'A' <= c && c <= 'Z' {
+ goto Slow
+ }
+ }
+ return s
+
+Slow:
+ var buf bytes.Buffer
+ for _, r := range s {
+ // SimpleFold(x) cycles to the next equivalent rune > x
+ // or wraps around to smaller values. Iterate until it wraps,
+ // and we've found the minimum value.
+ for {
+ r0 := r
+ r = unicode.SimpleFold(r0)
+ if r <= r0 {
+ break
+ }
+ }
+ // Exception to allow fast path above: A-Z => a-z
+ if 'A' <= r && r <= 'Z' {
+ r += 'a' - 'A'
+ }
+ buf.WriteRune(r)
+ }
+ return buf.String()
+}
+
+// foldDup reports a pair of strings from the list that are
+// equal according to strings.EqualFold.
+// It returns "", "" if there are no such strings.
+func foldDup(list []string) (string, string) {
+ clash := map[string]string{}
+ for _, s := range list {
+ fold := toFold(s)
+ if t := clash[fold]; t != "" {
+ if s > t {
+ s, t = t, s
+ }
+ return s, t
+ }
+ clash[fold] = s
+ }
+ return "", ""
+}
diff --git a/libgo/go/cmd/go/match_test.go b/libgo/go/cmd/go/match_test.go
new file mode 100644
index 0000000000..38b9b115e7
--- /dev/null
+++ b/libgo/go/cmd/go/match_test.go
@@ -0,0 +1,88 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "testing"
+
+var matchPatternTests = []stringPairTest{
+ {"...", "foo", true},
+ {"net", "net", true},
+ {"net", "net/http", false},
+ {"net/http", "net", false},
+ {"net/http", "net/http", true},
+ {"net...", "netchan", true},
+ {"net...", "net", true},
+ {"net...", "net/http", true},
+ {"net...", "not/http", false},
+ {"net/...", "netchan", false},
+ {"net/...", "net", true},
+ {"net/...", "net/http", true},
+ {"net/...", "not/http", false},
+}
+
+func TestMatchPattern(t *testing.T) {
+ testStringPairs(t, "matchPattern", matchPatternTests, func(pattern, name string) bool {
+ return matchPattern(pattern)(name)
+ })
+}
+
+var treeCanMatchPatternTests = []stringPairTest{
+ {"...", "foo", true},
+ {"net", "net", true},
+ {"net", "net/http", false},
+ {"net/http", "net", true},
+ {"net/http", "net/http", true},
+ {"net...", "netchan", true},
+ {"net...", "net", true},
+ {"net...", "net/http", true},
+ {"net...", "not/http", false},
+ {"net/...", "netchan", false},
+ {"net/...", "net", true},
+ {"net/...", "net/http", true},
+ {"net/...", "not/http", false},
+ {"abc.../def", "abcxyz", true},
+ {"abc.../def", "xyxabc", false},
+ {"x/y/z/...", "x", true},
+ {"x/y/z/...", "x/y", true},
+ {"x/y/z/...", "x/y/z", true},
+ {"x/y/z/...", "x/y/z/w", true},
+ {"x/y/z", "x", true},
+ {"x/y/z", "x/y", true},
+ {"x/y/z", "x/y/z", true},
+ {"x/y/z", "x/y/z/w", false},
+ {"x/.../y/z", "x/a/b/c", true},
+ {"x/.../y/z", "y/x/a/b/c", false},
+}
+
+func TestChildrenCanMatchPattern(t *testing.T) {
+ testStringPairs(t, "treeCanMatchPattern", treeCanMatchPatternTests, func(pattern, name string) bool {
+ return treeCanMatchPattern(pattern)(name)
+ })
+}
+
+var hasPathPrefixTests = []stringPairTest{
+ {"abc", "a", false},
+ {"a/bc", "a", true},
+ {"a", "a", true},
+ {"a/bc", "a/", true},
+}
+
+func TestHasPathPrefix(t *testing.T) {
+ testStringPairs(t, "hasPathPrefix", hasPathPrefixTests, hasPathPrefix)
+}
+
+type stringPairTest struct {
+ in1 string
+ in2 string
+ out bool
+}
+
+func testStringPairs(t *testing.T, name string, tests []stringPairTest, f func(string, string) bool) {
+ for _, tt := range tests {
+ if out := f(tt.in1, tt.in2); out != tt.out {
+ t.Errorf("%s(%q, %q) = %v, want %v", name, tt.in1, tt.in2, out, tt.out)
+ }
+ }
+}
diff --git a/libgo/go/cmd/go/mkdoc.sh b/libgo/go/cmd/go/mkdoc.sh
new file mode 100644
index 0000000000..12fd7ba3e7
--- /dev/null
+++ b/libgo/go/cmd/go/mkdoc.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+# 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.
+
+go install # So the next line will produce updated documentation.
+go help documentation > doc.go
+gofmt -w doc.go
+
diff --git a/libgo/go/cmd/go/pkg.go b/libgo/go/cmd/go/pkg.go
new file mode 100644
index 0000000000..ef440dd3b7
--- /dev/null
+++ b/libgo/go/cmd/go/pkg.go
@@ -0,0 +1,969 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "go/build"
+ "go/scanner"
+ "go/token"
+ "os"
+ pathpkg "path"
+ "path/filepath"
+ "runtime"
+ "sort"
+ "strings"
+ "time"
+ "unicode"
+)
+
+// A Package describes a single package found in a directory.
+type Package struct {
+ // Note: These fields are part of the go command's public API.
+ // See list.go. It is okay to add fields, but not to change or
+ // remove existing ones. Keep in sync with list.go
+ Dir string `json:",omitempty"` // directory containing package sources
+ ImportPath string `json:",omitempty"` // import path of package in dir
+ ImportComment string `json:",omitempty"` // path in import comment on package statement
+ Name string `json:",omitempty"` // package name
+ Doc string `json:",omitempty"` // package documentation string
+ Target string `json:",omitempty"` // install path
+ Goroot bool `json:",omitempty"` // is this package found in the Go root?
+ Standard bool `json:",omitempty"` // is this package part of the standard Go library?
+ Stale bool `json:",omitempty"` // would 'go install' do anything for this package?
+ Root string `json:",omitempty"` // Go root or Go path dir containing this package
+ ConflictDir string `json:",omitempty"` // Dir is hidden by this other directory
+
+ // Source files
+ GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
+ CgoFiles []string `json:",omitempty"` // .go sources files that import "C"
+ IgnoredGoFiles []string `json:",omitempty"` // .go sources ignored due to build constraints
+ CFiles []string `json:",omitempty"` // .c source files
+ CXXFiles []string `json:",omitempty"` // .cc, .cpp and .cxx source files
+ MFiles []string `json:",omitempty"` // .m source files
+ HFiles []string `json:",omitempty"` // .h, .hh, .hpp and .hxx source files
+ SFiles []string `json:",omitempty"` // .s source files
+ SwigFiles []string `json:",omitempty"` // .swig files
+ SwigCXXFiles []string `json:",omitempty"` // .swigcxx files
+ SysoFiles []string `json:",omitempty"` // .syso system object files added to package
+
+ // Cgo directives
+ CgoCFLAGS []string `json:",omitempty"` // cgo: flags for C compiler
+ CgoCPPFLAGS []string `json:",omitempty"` // cgo: flags for C preprocessor
+ CgoCXXFLAGS []string `json:",omitempty"` // cgo: flags for C++ compiler
+ CgoLDFLAGS []string `json:",omitempty"` // cgo: flags for linker
+ CgoPkgConfig []string `json:",omitempty"` // cgo: pkg-config names
+
+ // Dependency information
+ Imports []string `json:",omitempty"` // import paths used by this package
+ Deps []string `json:",omitempty"` // all (recursively) imported dependencies
+
+ // Error information
+ Incomplete bool `json:",omitempty"` // was there an error loading this package or dependencies?
+ Error *PackageError `json:",omitempty"` // error loading this package (not dependencies)
+ DepsErrors []*PackageError `json:",omitempty"` // errors loading dependencies
+
+ // Test information
+ TestGoFiles []string `json:",omitempty"` // _test.go files in package
+ TestImports []string `json:",omitempty"` // imports from TestGoFiles
+ XTestGoFiles []string `json:",omitempty"` // _test.go files outside package
+ XTestImports []string `json:",omitempty"` // imports from XTestGoFiles
+
+ // Unexported fields are not part of the public API.
+ build *build.Package
+ pkgdir string // overrides build.PkgDir
+ imports []*Package
+ deps []*Package
+ gofiles []string // GoFiles+CgoFiles+TestGoFiles+XTestGoFiles files, absolute paths
+ sfiles []string
+ allgofiles []string // gofiles + IgnoredGoFiles, absolute paths
+ target string // installed file for this package (may be executable)
+ fake bool // synthesized package
+ external bool // synthesized external test package
+ forceBuild bool // this package must be rebuilt
+ forceLibrary bool // this package is a library (even if named "main")
+ cmdline bool // defined by files listed on command line
+ local bool // imported via local path (./ or ../)
+ localPrefix string // interpret ./ and ../ imports relative to this prefix
+ exeName string // desired name for temporary executable
+ 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
+}
+
+// CoverVar holds the name of the generated coverage variables targeting the named file.
+type CoverVar struct {
+ File string // local file name
+ Var string // name of count struct
+}
+
+func (p *Package) copyBuild(pp *build.Package) {
+ p.build = pp
+
+ p.Dir = pp.Dir
+ p.ImportPath = pp.ImportPath
+ p.ImportComment = pp.ImportComment
+ p.Name = pp.Name
+ p.Doc = pp.Doc
+ p.Root = pp.Root
+ p.ConflictDir = pp.ConflictDir
+ // TODO? Target
+ p.Goroot = pp.Goroot
+ if buildContext.Compiler == "gccgo" {
+ p.Standard = stdpkg[p.ImportPath]
+ } else {
+ p.Standard = p.Goroot && p.ImportPath != "" && !strings.Contains(p.ImportPath, ".")
+ }
+ p.GoFiles = pp.GoFiles
+ p.CgoFiles = pp.CgoFiles
+ p.IgnoredGoFiles = pp.IgnoredGoFiles
+ p.CFiles = pp.CFiles
+ p.CXXFiles = pp.CXXFiles
+ p.MFiles = pp.MFiles
+ p.HFiles = pp.HFiles
+ p.SFiles = pp.SFiles
+ p.SwigFiles = pp.SwigFiles
+ p.SwigCXXFiles = pp.SwigCXXFiles
+ p.SysoFiles = pp.SysoFiles
+ p.CgoCFLAGS = pp.CgoCFLAGS
+ p.CgoCPPFLAGS = pp.CgoCPPFLAGS
+ p.CgoCXXFLAGS = pp.CgoCXXFLAGS
+ p.CgoLDFLAGS = pp.CgoLDFLAGS
+ p.CgoPkgConfig = pp.CgoPkgConfig
+ p.Imports = pp.Imports
+ p.TestGoFiles = pp.TestGoFiles
+ p.TestImports = pp.TestImports
+ p.XTestGoFiles = pp.XTestGoFiles
+ p.XTestImports = pp.XTestImports
+}
+
+// A PackageError describes an error loading information about a package.
+type PackageError struct {
+ ImportStack []string // shortest path from package named on command line to this one
+ Pos string // position of error
+ Err string // the error itself
+ isImportCycle bool // the error is an import cycle
+ hard bool // whether the error is soft or hard; soft errors are ignored in some places
+}
+
+func (p *PackageError) Error() string {
+ // Import cycles deserve special treatment.
+ if p.isImportCycle {
+ return fmt.Sprintf("%s\npackage %s\n", p.Err, strings.Join(p.ImportStack, "\n\timports "))
+ }
+ if p.Pos != "" {
+ // Omit import stack. The full path to the file where the error
+ // is the most important thing.
+ return p.Pos + ": " + p.Err
+ }
+ if len(p.ImportStack) == 0 {
+ return p.Err
+ }
+ return "package " + strings.Join(p.ImportStack, "\n\timports ") + ": " + p.Err
+}
+
+// An importStack is a stack of import paths.
+type importStack []string
+
+func (s *importStack) push(p string) {
+ *s = append(*s, p)
+}
+
+func (s *importStack) pop() {
+ *s = (*s)[0 : len(*s)-1]
+}
+
+func (s *importStack) copy() []string {
+ return append([]string{}, *s...)
+}
+
+// shorterThan returns true if 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 {
+ s := *sp
+ if len(s) != len(t) {
+ return len(s) < len(t)
+ }
+ // If they are the same length, settle ties using string ordering.
+ for i := range s {
+ if s[i] != t[i] {
+ return s[i] < t[i]
+ }
+ }
+ return false // they are equal
+}
+
+// packageCache is a lookup cache for loadPackage,
+// so that if we look up a package multiple times
+// we return the same pointer each time.
+var packageCache = map[string]*Package{}
+
+// reloadPackage is like loadPackage but makes sure
+// not to use the package cache.
+func reloadPackage(arg string, stk *importStack) *Package {
+ p := packageCache[arg]
+ if p != nil {
+ delete(packageCache, p.Dir)
+ delete(packageCache, p.ImportPath)
+ }
+ return loadPackage(arg, stk)
+}
+
+// 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
+// the pseudo-import path is _/c_/home/gopher/my/pkg.
+// Using a pseudo-import path like this makes the ./ imports no longer
+// a special case, so that all the code to deal with ordinary imports works
+// automatically.
+func dirToImportPath(dir string) string {
+ return pathpkg.Join("_", strings.Map(makeImportValid, filepath.ToSlash(dir)))
+}
+
+func makeImportValid(r rune) rune {
+ // Should match Go spec, compilers, and ../../go/parser/parser.go:/isValidImport.
+ const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
+ if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
+ return '_'
+ }
+ return r
+}
+
+// loadImport scans the directory named by path, which must be an import path,
+// 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 {
+ stk.push(path)
+ defer stk.pop()
+
+ // Determine canonical identifier for this package.
+ // 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.
+ importPath := path
+ isLocal := build.IsLocalImport(path)
+ if isLocal {
+ importPath = dirToImportPath(filepath.Join(srcDir, path))
+ }
+ if p := packageCache[importPath]; p != nil {
+ if perr := disallowInternal(srcDir, p, stk); perr != p {
+ return perr
+ }
+ return reusePackage(p, stk)
+ }
+
+ p := new(Package)
+ p.local = isLocal
+ p.ImportPath = importPath
+ packageCache[importPath] = p
+
+ // Load package.
+ // Import always returns bp != nil, even if an error occurs,
+ // in order to return partial information.
+ //
+ // 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)
+ bp.ImportPath = importPath
+ if gobin != "" {
+ bp.BinDir = gobin
+ }
+ if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path {
+ err = fmt.Errorf("code in directory %s expects import %q", bp.Dir, bp.ImportComment)
+ }
+ p.load(stk, bp, err)
+ if p.Error != nil && len(importPos) > 0 {
+ pos := importPos[0]
+ pos.Filename = shortPath(pos.Filename)
+ p.Error.Pos = pos.String()
+ }
+
+ if perr := disallowInternal(srcDir, p, stk); perr != p {
+ return perr
+ }
+
+ return p
+}
+
+// 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.
+func reusePackage(p *Package, stk *importStack) *Package {
+ // We use p.imports==nil to detect a package that
+ // is in the midst of its own loadPackage call
+ // (all the recursion below happens before p.imports gets set).
+ if p.imports == nil {
+ if p.Error == nil {
+ p.Error = &PackageError{
+ ImportStack: stk.copy(),
+ Err: "import cycle not allowed",
+ isImportCycle: true,
+ }
+ }
+ p.Incomplete = true
+ }
+ // Don't rewrite the import stack in the error if we have an import cycle.
+ // If we do, we'll lose the path that describes the cycle.
+ if p.Error != nil && !p.Error.isImportCycle && stk.shorterThan(p.Error.ImportStack) {
+ p.Error.ImportStack = stk.copy()
+ }
+ return p
+}
+
+// disallowInternal checks that srcDir is allowed to import p.
+// If the import is allowed, disallowInternal returns the original package p.
+// If not, it returns a new package containing just an appropriate error.
+func disallowInternal(srcDir string, p *Package, stk *importStack) *Package {
+ // golang.org/s/go14internal:
+ // 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 {
+ 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
+ }
+
+ // Check for "internal" element: four cases depending on begin of string and/or end of string.
+ i, ok := findInternal(p.ImportPath)
+ if !ok {
+ return p
+ }
+
+ // Internal is present.
+ // Map import path back to directory corresponding to parent of internal.
+ if i > 0 {
+ i-- // rewind over slash in ".../internal"
+ }
+ parent := p.Dir[:i+len(p.Dir)-len(p.ImportPath)]
+ if hasPathPrefix(filepath.ToSlash(srcDir), filepath.ToSlash(parent)) {
+ return p
+ }
+
+ // Internal is present, and srcDir is outside parent's tree. Not allowed.
+ perr := *p
+ perr.Error = &PackageError{
+ ImportStack: stk.copy(),
+ Err: "use of internal package not allowed",
+ }
+ perr.Incomplete = true
+ return &perr
+}
+
+// findInternal looks for the final "internal" path element in the given import path.
+// If there isn't one, findInternal returns ok=false.
+// Otherwise, findInternal returns ok=true and the index of the "internal".
+func findInternal(path string) (index int, ok bool) {
+ // Four cases, depending on internal at start/end of string or not.
+ // The order matters: we must return the index of the final element,
+ // because the final one produces the most restrictive requirement
+ // on the importer.
+ switch {
+ case strings.HasSuffix(path, "/internal"):
+ return len(path) - len("internal"), true
+ case strings.Contains(path, "/internal/"):
+ return strings.LastIndex(path, "/internal/") + 1, true
+ case path == "internal", strings.HasPrefix(path, "internal/"):
+ return 0, true
+ }
+ return 0, false
+}
+
+type targetDir int
+
+const (
+ toRoot targetDir = iota // to bin dir inside package root (default)
+ toTool // GOROOT/pkg/tool
+ toBin // GOROOT/bin
+ stalePath // the old import path; fail to build
+)
+
+// goTools is a map of Go program import path to install target directory.
+var goTools = map[string]targetDir{
+ "cmd/addr2line": toTool,
+ "cmd/api": toTool,
+ "cmd/cgo": toTool,
+ "cmd/fix": toTool,
+ "cmd/link": toTool,
+ "cmd/nm": toTool,
+ "cmd/objdump": toTool,
+ "cmd/pack": toTool,
+ "cmd/pprof": 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,
+}
+
+// expandScanner expands a scanner.List error into all the errors in the list.
+// The default Error method only shows the first error.
+func expandScanner(err error) error {
+ // Look for parser errors.
+ if err, ok := err.(scanner.ErrorList); ok {
+ // Prepare error with \n before each message.
+ // When printed in something like context: %v
+ // this will put the leading file positions each on
+ // its own line. It will also show all the errors
+ // instead of just the first, as err.Error does.
+ var buf bytes.Buffer
+ for _, e := range err {
+ e.Pos.Filename = shortPath(e.Pos.Filename)
+ buf.WriteString("\n")
+ buf.WriteString(e.Error())
+ }
+ return errors.New(buf.String())
+ }
+ return err
+}
+
+var raceExclude = map[string]bool{
+ "runtime/race": true,
+ "runtime/cgo": true,
+ "cmd/cgo": true,
+ "syscall": true,
+ "errors": true,
+}
+
+var cgoExclude = map[string]bool{
+ "runtime/cgo": true,
+}
+
+var cgoSyscallExclude = map[string]bool{
+ "runtime/cgo": true,
+ "runtime/race": true,
+}
+
+// load populates p using information from bp, err, which should
+// be the result of calling build.Context.Import.
+func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package {
+ p.copyBuild(bp)
+
+ // The localPrefix is the path we interpret ./ imports relative to.
+ // Synthesized main packages sometimes override this.
+ p.localPrefix = dirToImportPath(p.Dir)
+
+ if err != nil {
+ p.Incomplete = true
+ err = expandScanner(err)
+ p.Error = &PackageError{
+ ImportStack: stk.copy(),
+ Err: err.Error(),
+ }
+ return p
+ }
+
+ if p.Name == "main" {
+ // 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)
+ e := fmt.Sprintf("the %v command has moved; use %v instead.", p.ImportPath, newPath)
+ p.Error = &PackageError{Err: e}
+ return p
+ }
+ _, elem := filepath.Split(p.Dir)
+ full := buildContext.GOOS + "_" + buildContext.GOARCH + "/" + elem
+ if buildContext.GOOS != toolGOOS || buildContext.GOARCH != toolGOARCH {
+ // Install cross-compiled binaries to subdirectories of bin.
+ elem = full
+ }
+ if p.build.BinDir != gobin && goTools[p.ImportPath] == toBin {
+ // Override BinDir.
+ // This is from a subrepo but installs to $GOROOT/bin
+ // by default anyway (like godoc).
+ p.target = filepath.Join(gorootBin, elem)
+ } else if p.build.BinDir != "" {
+ // Install to GOBIN or bin of GOPATH entry.
+ p.target = filepath.Join(p.build.BinDir, elem)
+ }
+ if goTools[p.ImportPath] == toTool {
+ // This is for 'go tool'.
+ // Override all the usual logic and force it into the tool directory.
+ p.target = filepath.Join(gorootPkg, "tool", full)
+ }
+ if p.target != "" && buildContext.GOOS == "windows" {
+ p.target += ".exe"
+ }
+ } else if p.local {
+ // Local import turned into absolute path.
+ // No permanent install target.
+ p.target = ""
+ } else {
+ p.target = p.build.PkgObj
+ }
+
+ importPaths := p.Imports
+ // Packages that use cgo import runtime/cgo implicitly.
+ // Packages that use cgo also import syscall implicitly,
+ // to wrap errno.
+ // Exclude certain packages to avoid circular dependencies.
+ if len(p.CgoFiles) > 0 && (!p.Standard || !cgoExclude[p.ImportPath]) {
+ importPaths = append(importPaths, "runtime/cgo")
+ }
+ if len(p.CgoFiles) > 0 && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) {
+ importPaths = append(importPaths, "syscall")
+ }
+ // Everything depends on runtime, except runtime and unsafe.
+ if !p.Standard || (p.ImportPath != "runtime" && p.ImportPath != "unsafe") {
+ importPaths = append(importPaths, "runtime")
+ // When race detection enabled everything depends on runtime/race.
+ // Exclude certain packages to avoid circular dependencies.
+ if buildRace && (!p.Standard || !raceExclude[p.ImportPath]) {
+ importPaths = append(importPaths, "runtime/race")
+ }
+ }
+
+ // Build list of full paths to all Go files in the package,
+ // for use by commands like go fmt.
+ p.gofiles = stringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles)
+ for i := range p.gofiles {
+ p.gofiles[i] = filepath.Join(p.Dir, p.gofiles[i])
+ }
+ sort.Strings(p.gofiles)
+
+ p.sfiles = stringList(p.SFiles)
+ for i := range p.sfiles {
+ p.sfiles[i] = filepath.Join(p.Dir, p.sfiles[i])
+ }
+ sort.Strings(p.sfiles)
+
+ p.allgofiles = stringList(p.IgnoredGoFiles)
+ for i := range p.allgofiles {
+ p.allgofiles[i] = filepath.Join(p.Dir, p.allgofiles[i])
+ }
+ p.allgofiles = append(p.allgofiles, p.gofiles...)
+ sort.Strings(p.allgofiles)
+
+ // Check for case-insensitive collision of input files.
+ // To avoid problems on case-insensitive files, we reject any package
+ // where two different input files have equal names under a case-insensitive
+ // comparison.
+ f1, f2 := foldDup(stringList(
+ p.GoFiles,
+ p.CgoFiles,
+ p.IgnoredGoFiles,
+ p.CFiles,
+ p.CXXFiles,
+ p.MFiles,
+ p.HFiles,
+ p.SFiles,
+ p.SysoFiles,
+ p.SwigFiles,
+ p.SwigCXXFiles,
+ p.TestGoFiles,
+ p.XTestGoFiles,
+ ))
+ if f1 != "" {
+ p.Error = &PackageError{
+ ImportStack: stk.copy(),
+ Err: fmt.Sprintf("case-insensitive file name collision: %q and %q", f1, f2),
+ }
+ return p
+ }
+
+ // Build list of imported packages and full dependency list.
+ imports := make([]*Package, 0, len(p.Imports))
+ deps := make(map[string]*Package)
+ for i, path := range importPaths {
+ if path == "C" {
+ continue
+ }
+ p1 := loadImport(path, p.Dir, stk, p.build.ImportPos[path])
+ if !reqStdPkgSrc && p1.Standard {
+ continue
+ }
+ if p1.local {
+ if !p.local && p.Error == nil {
+ p.Error = &PackageError{
+ ImportStack: stk.copy(),
+ Err: fmt.Sprintf("local import %q in non-local package", path),
+ }
+ pos := p.build.ImportPos[path]
+ if len(pos) > 0 {
+ p.Error.Pos = pos[0].String()
+ }
+ }
+ path = p1.ImportPath
+ importPaths[i] = path
+ }
+ deps[path] = p1
+ imports = append(imports, p1)
+ for _, dep := range p1.deps {
+ deps[dep.ImportPath] = dep
+ }
+ if p1.Incomplete {
+ p.Incomplete = true
+ }
+ }
+ p.imports = imports
+
+ p.Deps = make([]string, 0, len(deps))
+ for dep := range deps {
+ p.Deps = append(p.Deps, dep)
+ }
+ sort.Strings(p.Deps)
+ for _, dep := range p.Deps {
+ p1 := deps[dep]
+ if p1 == nil {
+ panic("impossible: missing entry in package cache for " + dep + " imported by " + p.ImportPath)
+ }
+ p.deps = append(p.deps, p1)
+ if p1.Error != nil {
+ p.DepsErrors = append(p.DepsErrors, p1.Error)
+ }
+ }
+
+ // unsafe is a fake package.
+ if p.Standard && (p.ImportPath == "unsafe" || buildContext.Compiler == "gccgo") {
+ p.target = ""
+ }
+ p.Target = p.target
+
+ // Check for C code compiled with Plan 9 C compiler.
+ // No longer allowed except in runtime and runtime/cgo, for now.
+ if len(p.CFiles) > 0 && !p.usesCgo() && (!p.Standard || p.ImportPath != "runtime") {
+ p.Error = &PackageError{
+ ImportStack: stk.copy(),
+ Err: fmt.Sprintf("C source files not allowed when not using cgo: %s", strings.Join(p.CFiles, " ")),
+ }
+ return p
+ }
+
+ // In the absence of errors lower in the dependency tree,
+ // check for case-insensitive collisions of import paths.
+ if len(p.DepsErrors) == 0 {
+ dep1, dep2 := foldDup(p.Deps)
+ if dep1 != "" {
+ p.Error = &PackageError{
+ ImportStack: stk.copy(),
+ Err: fmt.Sprintf("case-insensitive import collision: %q and %q", dep1, dep2),
+ }
+ return p
+ }
+ }
+
+ return p
+}
+
+// usesSwig reports whether the package needs to run SWIG.
+func (p *Package) usesSwig() bool {
+ return len(p.SwigFiles) > 0 || len(p.SwigCXXFiles) > 0
+}
+
+// usesCgo reports whether the package needs to run cgo
+func (p *Package) usesCgo() bool {
+ return len(p.CgoFiles) > 0
+}
+
+// packageList returns the list of packages in the dag rooted at roots
+// as visited in a depth-first post-order traversal.
+func packageList(roots []*Package) []*Package {
+ seen := map[*Package]bool{}
+ all := []*Package{}
+ var walk func(*Package)
+ walk = func(p *Package) {
+ if seen[p] {
+ return
+ }
+ seen[p] = true
+ for _, p1 := range p.imports {
+ walk(p1)
+ }
+ all = append(all, p)
+ }
+ for _, root := range roots {
+ walk(root)
+ }
+ return all
+}
+
+// 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)
+ }
+}
+
+// The runtime version string takes one of two forms:
+// "go1.X[.Y]" for Go releases, and "devel +hash" at tip.
+// Determine whether we are in a released copy by
+// inspecting the version.
+var isGoRelease = strings.HasPrefix(runtime.Version(), "go1")
+
+// isStale reports whether package p needs to be rebuilt.
+func isStale(p *Package, topRoot map[string]bool) bool {
+ if p.Standard && (p.ImportPath == "unsafe" || buildContext.Compiler == "gccgo") {
+ // fake, builtin package
+ return false
+ }
+ if p.Error != nil {
+ return true
+ }
+
+ // A package without Go sources means we only found
+ // the installed .a file. Since we don't know how to rebuild
+ // it, it can't be stale, even if -a is set. This enables binary-only
+ // distributions of Go packages, although such binaries are
+ // only useful with the specific version of the toolchain that
+ // created them.
+ if len(p.gofiles) == 0 && !p.usesSwig() {
+ 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 pkgBuildA || 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()
+ }
+ if built.IsZero() {
+ return true
+ }
+
+ olderThan := func(file string) bool {
+ fi, err := os.Stat(file)
+ return err != nil || fi.ModTime().After(built)
+ }
+
+ // 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) {
+ return true
+ }
+ }
+
+ // As a courtesy to developers installing new versions of the compiler
+ // frequently, define that packages are stale if they are
+ // older than the compiler, and commands if they are older than
+ // the linker. This heuristic will not work if the binaries are
+ // 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.
+ if p.Root != goroot {
+ if olderThan(buildToolchain.compiler()) {
+ return true
+ }
+ if p.build.IsCommand() && olderThan(buildToolchain.linker()) {
+ return true
+ }
+ }
+
+ // 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
+ }
+
+ 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 {
+ if olderThan(filepath.Join(p.Dir, src)) {
+ return true
+ }
+ }
+
+ return false
+}
+
+var cwd, _ = os.Getwd()
+
+var cmdCache = map[string]*Package{}
+
+// loadPackage is like loadImport but is used for command-line arguments,
+// not for paths found in import statements. In addition to ordinary import paths,
+// loadPackage accepts pseudo-paths beginning with cmd/ to denote commands
+// in the Go command directory, as well as paths to those directories.
+func loadPackage(arg string, stk *importStack) *Package {
+ if build.IsLocalImport(arg) {
+ dir := arg
+ if !filepath.IsAbs(dir) {
+ if abs, err := filepath.Abs(dir); err == nil {
+ // interpret relative to current directory
+ dir = abs
+ }
+ }
+ if sub, ok := hasSubdir(gorootSrc, dir); ok && strings.HasPrefix(sub, "cmd/") && !strings.Contains(sub[4:], "/") {
+ arg = sub
+ }
+ }
+ if strings.HasPrefix(arg, "cmd/") && !strings.Contains(arg[4:], "/") {
+ if p := cmdCache[arg]; p != nil {
+ return p
+ }
+ stk.push(arg)
+ defer stk.pop()
+
+ bp, err := buildContext.ImportDir(filepath.Join(gorootSrc, arg), 0)
+ bp.ImportPath = arg
+ bp.Goroot = true
+ bp.BinDir = gorootBin
+ if gobin != "" {
+ bp.BinDir = gobin
+ }
+ bp.Root = goroot
+ bp.SrcRoot = gorootSrc
+ p := new(Package)
+ cmdCache[arg] = p
+ p.load(stk, bp, err)
+ if p.Error == nil && p.Name != "main" {
+ p.Error = &PackageError{
+ ImportStack: stk.copy(),
+ Err: fmt.Sprintf("expected package main but found package %s in %s", p.Name, p.Dir),
+ }
+ }
+ return p
+ }
+
+ // Wasn't a command; must be a package.
+ // If it is a local import path but names a standard package,
+ // we treat it as if the user specified the standard package.
+ // This lets you run go test ./ioutil in package io and be
+ // referring to io/ioutil rather than a hypothetical import of
+ // "./ioutil".
+ if build.IsLocalImport(arg) {
+ bp, _ := buildContext.ImportDir(filepath.Join(cwd, arg), build.FindOnly)
+ if bp.ImportPath != "" && bp.ImportPath != "." {
+ arg = bp.ImportPath
+ }
+ }
+
+ return loadImport(arg, cwd, stk, nil)
+}
+
+// packages returns the packages named by the
+// command line arguments 'args'. If a named package
+// cannot be loaded at all (for example, if the directory does not exist),
+// then packages prints an error and does not include that
+// package in the results. However, if errors occur trying
+// to load dependencies of a named package, the named
+// package is still returned, with p.Incomplete = true
+// and details in p.DepsErrors.
+func packages(args []string) []*Package {
+ var pkgs []*Package
+ for _, pkg := range packagesAndErrors(args) {
+ if pkg.Error != nil {
+ errorf("can't load package: %s", pkg.Error)
+ continue
+ }
+ pkgs = append(pkgs, pkg)
+ }
+ return pkgs
+}
+
+// packagesAndErrors is like 'packages' but returns a
+// *Package for every argument, even the ones that
+// cannot be loaded at all.
+// The packages that fail to load will have p.Error != nil.
+func packagesAndErrors(args []string) []*Package {
+ if len(args) > 0 && strings.HasSuffix(args[0], ".go") {
+ return []*Package{goFilesPackage(args)}
+ }
+
+ args = importPaths(args)
+ var pkgs []*Package
+ var stk importStack
+ var set = make(map[string]bool)
+
+ for _, arg := range args {
+ if !set[arg] {
+ pkgs = append(pkgs, loadPackage(arg, &stk))
+ set[arg] = true
+ }
+ }
+ computeStale(pkgs...)
+
+ return pkgs
+}
+
+// packagesForBuild is like 'packages' but fails if any of
+// the packages or their dependencies have errors
+// (cannot be built).
+func packagesForBuild(args []string) []*Package {
+ pkgs := packagesAndErrors(args)
+ printed := map[*PackageError]bool{}
+ for _, pkg := range pkgs {
+ if pkg.Error != nil {
+ errorf("can't load package: %s", pkg.Error)
+ }
+ for _, err := range pkg.DepsErrors {
+ // Since these are errors in dependencies,
+ // the same error might show up multiple times,
+ // once in each package that depends on it.
+ // Only print each once.
+ if !printed[err] {
+ printed[err] = true
+ errorf("%s", err)
+ }
+ }
+ }
+ exitIfErrors()
+ return pkgs
+}
+
+// hasSubdir reports whether dir is a subdirectory of
+// (possibly multiple levels below) root.
+// If so, it sets rel to the path fragment that must be
+// appended to root to reach dir.
+func hasSubdir(root, dir string) (rel string, ok bool) {
+ if p, err := filepath.EvalSymlinks(root); err == nil {
+ root = p
+ }
+ if p, err := filepath.EvalSymlinks(dir); err == nil {
+ dir = p
+ }
+ const sep = string(filepath.Separator)
+ root = filepath.Clean(root)
+ if !strings.HasSuffix(root, sep) {
+ root += sep
+ }
+ dir = filepath.Clean(dir)
+ if !strings.HasPrefix(dir, root) {
+ return "", false
+ }
+ return filepath.ToSlash(dir[len(root):]), true
+}
diff --git a/libgo/go/cmd/go/pkg_test.go b/libgo/go/cmd/go/pkg_test.go
new file mode 100644
index 0000000000..06b9f0ac6e
--- /dev/null
+++ b/libgo/go/cmd/go/pkg_test.go
@@ -0,0 +1,73 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "reflect"
+ "strings"
+ "testing"
+)
+
+var foldDupTests = []struct {
+ list []string
+ f1, f2 string
+}{
+ {stringList("math/rand", "math/big"), "", ""},
+ {stringList("math", "strings"), "", ""},
+ {stringList("strings"), "", ""},
+ {stringList("strings", "strings"), "strings", "strings"},
+ {stringList("Rand", "rand", "math", "math/rand", "math/Rand"), "Rand", "rand"},
+}
+
+func TestFoldDup(t *testing.T) {
+ for _, tt := range foldDupTests {
+ f1, f2 := foldDup(tt.list)
+ if f1 != tt.f1 || f2 != tt.f2 {
+ t.Errorf("foldDup(%q) = %q, %q, want %q, %q", tt.list, f1, f2, tt.f1, tt.f2)
+ }
+ }
+}
+
+var parseMetaGoImportsTests = []struct {
+ in string
+ out []metaImport
+}{
+ {
+ `<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">`,
+ []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
+ },
+ {
+ `<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
+ <meta name="go-import" content="baz/quux git http://github.com/rsc/baz/quux">`,
+ []metaImport{
+ {"foo/bar", "git", "https://github.com/rsc/foo/bar"},
+ {"baz/quux", "git", "http://github.com/rsc/baz/quux"},
+ },
+ },
+ {
+ `<head>
+ <meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
+ </head>`,
+ []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
+ },
+ {
+ `<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
+ <body>`,
+ []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
+ },
+}
+
+func TestParseMetaGoImports(t *testing.T) {
+ for i, tt := range parseMetaGoImportsTests {
+ out, err := parseMetaGoImports(strings.NewReader(tt.in))
+ if err != nil {
+ t.Errorf("test#%d: %v", i, err)
+ continue
+ }
+ if !reflect.DeepEqual(out, tt.out) {
+ t.Errorf("test#%d:\n\thave %q\n\twant %q", i, out, tt.out)
+ }
+ }
+}
diff --git a/libgo/go/cmd/go/run.go b/libgo/go/cmd/go/run.go
new file mode 100644
index 0000000000..ef8aa95a35
--- /dev/null
+++ b/libgo/go/cmd/go/run.go
@@ -0,0 +1,143 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "os"
+ "os/exec"
+ "runtime"
+ "strings"
+)
+
+var execCmd []string // -exec flag, for run and test
+
+func findExecCmd() []string {
+ if execCmd != nil {
+ return execCmd
+ }
+ execCmd = []string{} // avoid work the second time
+ if goos == runtime.GOOS && goarch == runtime.GOARCH {
+ return execCmd
+ }
+ path, err := exec.LookPath(fmt.Sprintf("go_%s_%s_exec", goos, goarch))
+ if err == nil {
+ execCmd = []string{path}
+ }
+ return execCmd
+}
+
+var cmdRun = &Command{
+ UsageLine: "run [build flags] [-exec xprog] gofiles... [arguments...]",
+ Short: "compile and run Go program",
+ Long: `
+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.
+ `,
+}
+
+func init() {
+ cmdRun.Run = runRun // break init loop
+
+ addBuildFlags(cmdRun)
+ cmdRun.Flag.Var((*stringsFlag)(&execCmd), "exec", "")
+}
+
+func printStderr(args ...interface{}) (int, error) {
+ return fmt.Fprint(os.Stderr, args...)
+}
+
+func runRun(cmd *Command, args []string) {
+ raceInit()
+ var b builder
+ b.init()
+ b.print = printStderr
+ i := 0
+ for i < len(args) && strings.HasSuffix(args[i], ".go") {
+ i++
+ }
+ files, cmdArgs := args[:i], args[i:]
+ if len(files) == 0 {
+ fatalf("go run: no go files listed")
+ }
+ for _, file := range files {
+ if strings.HasSuffix(file, "_test.go") {
+ // goFilesPackage is going to assign this to TestGoFiles.
+ // Reject since it won't be part of the build.
+ fatalf("go run: cannot run *_test.go files (%s)", file)
+ }
+ }
+ p := goFilesPackage(files)
+ if p.Error != nil {
+ fatalf("%s", p.Error)
+ }
+ p.omitDWARF = true
+ for _, err := range p.DepsErrors {
+ errorf("%s", err)
+ }
+ exitIfErrors()
+ if p.Name != "main" {
+ fatalf("go run: cannot run non-main package")
+ }
+ p.target = "" // must build - not up to date
+ var src string
+ if len(p.GoFiles) > 0 {
+ src = p.GoFiles[0]
+ } else if len(p.CgoFiles) > 0 {
+ src = p.CgoFiles[0]
+ } else {
+ // this case could only happen if the provided source uses cgo
+ // while cgo is disabled.
+ hint := ""
+ if !buildContext.CgoEnabled {
+ hint = " (cgo is disabled)"
+ }
+ fatalf("go run: no suitable source files%s", hint)
+ }
+ p.exeName = src[:len(src)-len(".go")] // name temporary executable for first go file
+ a1 := b.action(modeBuild, modeBuild, p)
+ a := &action{f: (*builder).runProgram, args: cmdArgs, deps: []*action{a1}}
+ b.do(a)
+}
+
+// runProgram is the action for running a binary that has already
+// been compiled. We ignore exit status.
+func (b *builder) runProgram(a *action) error {
+ cmdline := stringList(findExecCmd(), a.deps[0].target, a.args)
+ if buildN || buildX {
+ b.showcmd("", "%s", strings.Join(cmdline, " "))
+ if buildN {
+ return nil
+ }
+ }
+
+ runStdin(cmdline)
+ return nil
+}
+
+// runStdin is like run, but connects Stdin.
+func runStdin(cmdline []string) {
+ cmd := exec.Command(cmdline[0], cmdline[1:]...)
+ cmd.Stdin = os.Stdin
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ startSigHandlers()
+ if err := cmd.Run(); err != nil {
+ errorf("%v", err)
+ }
+}
diff --git a/libgo/go/cmd/go/script b/libgo/go/cmd/go/script
new file mode 100644
index 0000000000..340a7e824c
--- /dev/null
+++ b/libgo/go/cmd/go/script
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+x() {
+ echo '--- ' "$@"
+ "$@"
+ echo '---'
+ echo
+}
+
+x go help
+x go help build
+x go help clean
+x go help install
+x go help fix
+x go help fmt
+x go help get
+x go help list
+x go help test
+x go help version
+x go help vet
+x go help gopath
+x go help importpath
+x go help remote
diff --git a/libgo/go/cmd/go/script.txt b/libgo/go/cmd/go/script.txt
new file mode 100644
index 0000000000..a672146584
--- /dev/null
+++ b/libgo/go/cmd/go/script.txt
@@ -0,0 +1,352 @@
+--- go help
+usage: go command [arguments]
+
+go manages Go source code.
+
+The commands are:
+
+ build compile and install packages and dependencies
+ clean remove intermediate objects
+ fix run gofix on packages
+ fmt run gofmt -w on packages
+ get download and install packages and dependencies
+ install install packages and dependencies
+ list list packages
+ test test packages
+ version print Go version
+ vet run govet on packages
+
+Use "go help [command]" for more information about a command.
+
+Additional help topics:
+
+ gopath GOPATH environment variable
+ importpath description of import paths
+ remote remote import path syntax
+
+Use "go help [topic]" for more information about that topic.
+
+---
+
+--- go help build
+usage: go build [-n] [-v] [importpath...]
+
+Build compiles the packages named by the import paths,
+along with their dependencies, but it does not install the results.
+
+The -n flag prints the commands but does not run them.
+The -v flag prints the commands.
+
+For more about import paths, see 'go help importpath'.
+
+See also: go install, go get, go clean.
+---
+
+--- go help clean
+usage: go clean [-nuke] [importpath...]
+
+Clean removes intermediate object files generated during
+the compilation of the packages named by the import paths,
+but by default it does not remove the installed package binaries.
+
+The -nuke flag causes clean to remove the installed package binaries too.
+
+TODO: Clean does not clean dependencies of the packages.
+
+For more about import paths, see 'go help importpath'.
+---
+
+--- go help install
+usage: go install [-n] [-v] [importpath...]
+
+Install compiles and installs the packages named by the import paths,
+along with their dependencies.
+
+The -n flag prints the commands but does not run them.
+The -v flag prints the commands.
+
+For more about import paths, see 'go help importpath'.
+
+See also: go build, go get, go clean.
+---
+
+--- go help fix
+usage: go fix [importpath...]
+
+Fix runs the gofix command on the packages named by the import paths.
+
+For more about gofix, see 'godoc gofix'.
+For more about import paths, see 'go help importpath'.
+
+To run gofix with specific options, run gofix itself.
+
+See also: go fmt, go vet.
+---
+
+--- go help fmt
+usage: go fmt [importpath...]
+
+Fmt runs the command 'gofmt -w' on the packages named by the import paths.
+
+For more about gofmt, see 'godoc gofmt'.
+For more about import paths, see 'go help importpath'.
+
+To run gofmt with specific options, run gofmt itself.
+
+See also: go fix, go vet.
+---
+
+--- go help get
+usage: go get [importpath...]
+
+Get downloads and installs the packages named by the import paths,
+along with their dependencies.
+
+After downloading the code, 'go get' looks for a tag beginning
+with "go." that corresponds to the local Go version.
+For Go "release.r58" it looks for a tag named "go.r58".
+For "weekly.2011-06-03" it looks for "go.weekly.2011-06-03".
+If the specific "go.X" tag is not found, it uses the latest earlier
+version it can find. Otherwise, it uses the default version for
+the version control system: HEAD for git, tip for Mercurial,
+and so on.
+
+TODO: Explain versions better.
+
+For more about import paths, see 'go help importpath'.
+
+For more about how 'go get' finds source code to
+download, see 'go help remote'.
+
+See also: go build, go install, go clean.
+---
+
+--- go help list
+usage: go list [-f format] [-json] [importpath...]
+
+List lists the packages named by the import paths.
+
+The default output shows the package name and file system location:
+
+ books /home/you/src/google-api-go-client.googlecode.com/hg/books/v1
+ oauth /home/you/src/goauth2.googlecode.com/hg/oauth
+ sqlite /home/you/src/gosqlite.googlecode.com/hg/sqlite
+
+The -f flag specifies an alternate format for the list,
+using the syntax of package template. The default output
+is equivalent to -f '{{.Name}} {{.Dir}}' The struct
+being passed to the template is:
+
+ type Package struct {
+ Name string // package name
+ Doc string // package documentation string
+ GoFiles []string // names of Go source files in package
+ ImportPath string // import path denoting package
+ Imports []string // import paths used by this package
+ Deps []string // all (recursively) imported dependencies
+ Dir string // directory containing package sources
+ Version string // version of installed package
+ }
+
+The -json flag causes the package data to be printed in JSON format.
+
+For more about import paths, see 'go help importpath'.
+---
+
+--- go help test
+usage: go test [importpath...]
+
+Test runs gotest to test the packages named by the import paths.
+It prints a summary of the test results in the format:
+
+ test archive/tar
+ FAIL archive/zip
+ test compress/gzip
+ ...
+
+followed by gotest output for each failed package.
+
+For more about import paths, see 'go help importpath'.
+
+See also: go build, go compile, go vet.
+---
+
+--- go help version
+usage: go version
+
+Version prints the Go version, as reported by runtime.Version.
+---
+
+--- go help vet
+usage: go vet [importpath...]
+
+Vet runs the govet command on the packages named by the import paths.
+
+For more about govet, see 'godoc govet'.
+For more about import paths, see 'go help importpath'.
+
+To run govet with specific options, run govet itself.
+
+See also: go fmt, go fix.
+---
+
+--- go help gopath
+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 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.
+
+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.
+---
+
+--- go help importpath
+Many commands apply to a set of packages named by import paths:
+
+ go action [importpath...]
+
+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.
+
+The special import path "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.
+
+An import path can also name a package to be downloaded from
+a remote repository. Run 'go help remote' 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 'project.googlecode.com/'.
+---
+
+--- go help remote
+An import path (see 'go help importpath') denotes a package
+stored in the local file system. 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 (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 "project.googlecode.com/git"
+ import "project.googlecode.com/git/sub/directory"
+
+ import "project.googlecode.com/hg"
+ import "project.googlecode.com/hg/sub/directory"
+
+ import "project.googlecode.com/svn/trunk"
+ import "project.googlecode.com/svn/trunk/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"
+
+For code hosted on other servers, 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.com/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://.
+
+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 install' for more.
+---
+
diff --git a/libgo/go/cmd/go/signal.go b/libgo/go/cmd/go/signal.go
new file mode 100644
index 0000000000..e8ba0d3655
--- /dev/null
+++ b/libgo/go/cmd/go/signal.go
@@ -0,0 +1,31 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "os"
+ "os/signal"
+ "sync"
+)
+
+// interrupted is closed, if go process is interrupted.
+var interrupted = make(chan struct{})
+
+// processSignals setups signal handler.
+func processSignals() {
+ sig := make(chan os.Signal)
+ signal.Notify(sig, signalsToIgnore...)
+ go func() {
+ <-sig
+ close(interrupted)
+ }()
+}
+
+var onceProcessSignals sync.Once
+
+// startSigHandlers start signal handlers.
+func startSigHandlers() {
+ onceProcessSignals.Do(processSignals)
+}
diff --git a/libgo/go/cmd/go/signal_notunix.go b/libgo/go/cmd/go/signal_notunix.go
new file mode 100644
index 0000000000..29aa9d8c20
--- /dev/null
+++ b/libgo/go/cmd/go/signal_notunix.go
@@ -0,0 +1,17 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build plan9 windows
+
+package main
+
+import (
+ "os"
+)
+
+var signalsToIgnore = []os.Signal{os.Interrupt}
+
+// signalTrace is the signal to send to make a Go program
+// crash with a stack trace.
+var signalTrace os.Signal = nil
diff --git a/libgo/go/cmd/go/signal_unix.go b/libgo/go/cmd/go/signal_unix.go
new file mode 100644
index 0000000000..e86cd46523
--- /dev/null
+++ b/libgo/go/cmd/go/signal_unix.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.
+
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+
+package main
+
+import (
+ "os"
+ "syscall"
+)
+
+var signalsToIgnore = []os.Signal{os.Interrupt, syscall.SIGQUIT}
+
+// signalTrace is the signal to send to make a Go program
+// crash with a stack trace.
+var signalTrace os.Signal = syscall.SIGQUIT
diff --git a/libgo/go/cmd/go/tag_test.go b/libgo/go/cmd/go/tag_test.go
new file mode 100644
index 0000000000..ffe218c7b6
--- /dev/null
+++ b/libgo/go/cmd/go/tag_test.go
@@ -0,0 +1,100 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "testing"
+
+var selectTagTestTags = []string{
+ "go.r58",
+ "go.r58.1",
+ "go.r59",
+ "go.r59.1",
+ "go.r61",
+ "go.r61.1",
+ "go.weekly.2010-01-02",
+ "go.weekly.2011-10-12",
+ "go.weekly.2011-10-12.1",
+ "go.weekly.2011-10-14",
+ "go.weekly.2011-11-01",
+ "go1",
+ "go1.0.1",
+ "go1.999",
+ "go1.9.2",
+ "go5",
+
+ // these should be ignored:
+ "release.r59",
+ "release.r59.1",
+ "release",
+ "weekly.2011-10-12",
+ "weekly.2011-10-12.1",
+ "weekly",
+ "foo",
+ "bar",
+ "go.f00",
+ "go!r60",
+ "go.1999-01-01",
+ "go.2x",
+ "go.20000000000000",
+ "go.2.",
+ "go.2.0",
+ "go2x",
+ "go20000000000000",
+ "go2.",
+ "go2.0",
+}
+
+var selectTagTests = []struct {
+ version string
+ selected string
+}{
+ /*
+ {"release.r57", ""},
+ {"release.r58.2", "go.r58.1"},
+ {"release.r59", "go.r59"},
+ {"release.r59.1", "go.r59.1"},
+ {"release.r60", "go.r59.1"},
+ {"release.r60.1", "go.r59.1"},
+ {"release.r61", "go.r61"},
+ {"release.r66", "go.r61.1"},
+ {"weekly.2010-01-01", ""},
+ {"weekly.2010-01-02", "go.weekly.2010-01-02"},
+ {"weekly.2010-01-02.1", "go.weekly.2010-01-02"},
+ {"weekly.2010-01-03", "go.weekly.2010-01-02"},
+ {"weekly.2011-10-12", "go.weekly.2011-10-12"},
+ {"weekly.2011-10-12.1", "go.weekly.2011-10-12.1"},
+ {"weekly.2011-10-13", "go.weekly.2011-10-12.1"},
+ {"weekly.2011-10-14", "go.weekly.2011-10-14"},
+ {"weekly.2011-10-14.1", "go.weekly.2011-10-14"},
+ {"weekly.2011-11-01", "go.weekly.2011-11-01"},
+ {"weekly.2014-01-01", "go.weekly.2011-11-01"},
+ {"weekly.3000-01-01", "go.weekly.2011-11-01"},
+ {"go1", "go1"},
+ {"go1.1", "go1.0.1"},
+ {"go1.998", "go1.9.2"},
+ {"go1.1000", "go1.999"},
+ {"go6", "go5"},
+
+ // faulty versions:
+ {"release.f00", ""},
+ {"weekly.1999-01-01", ""},
+ {"junk", ""},
+ {"", ""},
+ {"go2x", ""},
+ {"go200000000000", ""},
+ {"go2.", ""},
+ {"go2.0", ""},
+ */
+ {"anything", "go1"},
+}
+
+func TestSelectTag(t *testing.T) {
+ for _, c := range selectTagTests {
+ selected := selectTag(c.version, selectTagTestTags)
+ if selected != c.selected {
+ t.Errorf("selectTag(%q) = %q, want %q", c.version, selected, c.selected)
+ }
+ }
+}
diff --git a/libgo/go/cmd/go/test.bash b/libgo/go/cmd/go/test.bash
new file mode 100644
index 0000000000..0060ce2185
--- /dev/null
+++ b/libgo/go/cmd/go/test.bash
@@ -0,0 +1,820 @@
+#!/bin/bash
+# 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.
+
+set -e
+go build -o testgo
+go() {
+ echo TEST ERROR: ran go, not testgo: go "$@" >&2
+ exit 2
+}
+
+started=false
+TEST() {
+ if $started; then
+ stop
+ fi
+ echo TEST: "$@"
+ started=true
+ ok=true
+}
+stop() {
+ if ! $started; then
+ echo TEST ERROR: stop missing start >&2
+ exit 2
+ fi
+ started=false
+ if $ok; then
+ echo PASS
+ else
+ echo FAIL
+ allok=false
+ fi
+}
+
+ok=true
+allok=true
+
+unset GOBIN
+unset GOPATH
+unset GOROOT
+
+TEST 'file:line in error messages'
+# Test that error messages have file:line information at beginning of
+# the line. Also test issue 4917: that the error is on stderr.
+d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
+fn=$d/err.go
+echo "package main" > $fn
+echo 'import "bar"' >> $fn
+./testgo run $fn 2>$d/err.out || true
+if ! grep -q "^$fn:" $d/err.out; then
+ echo "missing file:line in error message"
+ cat $d/err.out
+ ok=false
+fi
+rm -r $d
+
+# Test local (./) imports.
+testlocal() {
+ local="$1"
+ TEST local imports $2 '(easy)'
+ ./testgo build -o hello "testdata/$local/easy.go"
+ ./hello >hello.out
+ if ! grep -q '^easysub\.Hello' hello.out; then
+ echo "testdata/$local/easy.go did not generate expected output"
+ cat hello.out
+ ok=false
+ fi
+
+ TEST local imports $2 '(easysub)'
+ ./testgo build -o hello "testdata/$local/easysub/main.go"
+ ./hello >hello.out
+ if ! grep -q '^easysub\.Hello' hello.out; then
+ echo "testdata/$local/easysub/main.go did not generate expected output"
+ cat hello.out
+ ok=false
+ fi
+
+ TEST local imports $2 '(hard)'
+ ./testgo build -o hello "testdata/$local/hard.go"
+ ./hello >hello.out
+ if ! grep -q '^sub\.Hello' hello.out || ! grep -q '^subsub\.Hello' hello.out ; then
+ echo "testdata/$local/hard.go did not generate expected output"
+ cat hello.out
+ ok=false
+ fi
+
+ rm -f hello.out hello
+
+ # Test that go install x.go fails.
+ TEST local imports $2 '(go install should fail)'
+ if ./testgo install "testdata/$local/easy.go" >/dev/null 2>&1; then
+ echo "go install testdata/$local/easy.go succeeded"
+ ok=false
+ fi
+}
+
+# Test local imports
+testlocal local ''
+
+# Test local imports again, with bad characters in the directory name.
+bad='#$%:, &()*;<=>?\^{}'
+rm -rf "testdata/$bad"
+cp -R testdata/local "testdata/$bad"
+testlocal "$bad" 'with bad characters in path'
+rm -rf "testdata/$bad"
+
+TEST error message for syntax error in test go file says FAIL
+export GOPATH=$(pwd)/testdata
+if ./testgo test syntaxerror 2>testdata/err; then
+ echo 'go test syntaxerror succeeded'
+ ok=false
+elif ! grep FAIL testdata/err >/dev/null; then
+ echo 'go test did not say FAIL:'
+ cat testdata/err
+ ok=false
+fi
+rm -f ./testdata/err
+unset GOPATH
+
+TEST wildcards do not look in useless directories
+export GOPATH=$(pwd)/testdata
+if ./testgo list ... >testdata/err 2>&1; then
+ echo "go list ... succeeded"
+ ok=false
+elif ! grep badpkg testdata/err >/dev/null; then
+ echo "go list ... failure does not mention badpkg"
+ cat testdata/err
+ ok=false
+elif ! ./testgo list m... >testdata/err 2>&1; then
+ echo "go list m... failed"
+ ok=false
+fi
+rm -rf ./testdata/err
+unset GOPATH
+
+# Test tests with relative imports.
+TEST relative imports '(go test)'
+if ! ./testgo test ./testdata/testimport; then
+ echo "go test ./testdata/testimport failed"
+ ok=false
+fi
+
+# Test installation with relative imports.
+TEST relative imports '(go test -i)'
+if ! ./testgo test -i ./testdata/testimport; then
+ echo "go test -i ./testdata/testimport failed"
+ ok=false
+fi
+
+# Test tests with relative imports in packages synthesized
+# from Go files named on the command line.
+TEST relative imports in command-line package
+if ! ./testgo test ./testdata/testimport/*.go; then
+ echo "go test ./testdata/testimport/*.go failed"
+ ok=false
+fi
+
+TEST version control error message includes correct directory
+export GOPATH=$(pwd)/testdata/shadow/root1
+if ./testgo get -u foo 2>testdata/err; then
+ echo "go get -u foo succeeded unexpectedly"
+ ok=false
+elif ! grep testdata/shadow/root1/src/foo testdata/err >/dev/null; then
+ echo "go get -u error does not mention shadow/root1/src/foo:"
+ cat testdata/err
+ ok=false
+fi
+unset GOPATH
+
+TEST go install fails with no buildable files
+export GOPATH=$(pwd)/testdata
+export CGO_ENABLED=0
+if ./testgo install cgotest 2>testdata/err; then
+ echo "go install cgotest succeeded unexpectedly"
+elif ! grep 'no buildable Go source files' testdata/err >/dev/null; then
+ echo "go install cgotest did not report 'no buildable Go source files'"
+ cat testdata/err
+ ok=false
+fi
+unset CGO_ENABLED
+unset GOPATH
+
+# Test that without $GOBIN set, binaries get installed
+# into the GOPATH bin directory.
+TEST install into GOPATH
+rm -rf testdata/bin
+if ! GOPATH=$(pwd)/testdata ./testgo install go-cmd-test; then
+ echo "go install go-cmd-test failed"
+ ok=false
+elif ! test -x testdata/bin/go-cmd-test; then
+ echo "go install go-cmd-test did not write to testdata/bin/go-cmd-test"
+ ok=false
+fi
+
+TEST package main_test imports archive not binary
+export GOBIN=$(pwd)/testdata/bin
+mkdir -p $GOBIN
+export GOPATH=$(pwd)/testdata
+touch ./testdata/src/main_test/m.go
+if ! ./testgo test main_test; then
+ echo "go test main_test failed without install"
+ ok=false
+elif ! ./testgo install main_test; then
+ echo "go test main_test failed"
+ ok=false
+elif [ "$(./testgo list -f '{{.Stale}}' main_test)" != false ]; then
+ echo "after go install, main listed as stale"
+ ok=false
+elif ! ./testgo test main_test; then
+ echo "go test main_test failed after install"
+ ok=false
+fi
+rm -rf $GOBIN
+unset GOBIN
+
+# And with $GOBIN set, binaries get installed to $GOBIN.
+TEST install into GOBIN
+if ! GOBIN=$(pwd)/testdata/bin1 GOPATH=$(pwd)/testdata ./testgo install go-cmd-test; then
+ echo "go install go-cmd-test failed"
+ ok=false
+elif ! test -x testdata/bin1/go-cmd-test; then
+ echo "go install go-cmd-test did not write to testdata/bin1/go-cmd-test"
+ ok=false
+fi
+
+# Without $GOBIN set, installing a program outside $GOPATH should fail
+# (there is nowhere to install it).
+TEST install without destination fails
+if ./testgo install testdata/src/go-cmd-test/helloworld.go 2>testdata/err; then
+ echo "go install testdata/src/go-cmd-test/helloworld.go should have failed, did not"
+ ok=false
+elif ! grep 'no install location for .go files listed on command line' testdata/err; then
+ echo "wrong error:"
+ cat testdata/err
+ ok=false
+fi
+rm -f testdata/err
+
+# With $GOBIN set, should install there.
+TEST install to GOBIN '(command-line package)'
+if ! GOBIN=$(pwd)/testdata/bin1 ./testgo install testdata/src/go-cmd-test/helloworld.go; then
+ echo "go install testdata/src/go-cmd-test/helloworld.go failed"
+ ok=false
+elif ! test -x testdata/bin1/helloworld; then
+ echo "go install testdata/src/go-cmd-test/helloworld.go did not write testdata/bin1/helloworld"
+ ok=false
+fi
+
+TEST godoc installs into GOBIN
+d=$(mktemp -d -t testgoXXX)
+export GOPATH=$d
+mkdir $d/gobin
+GOBIN=$d/gobin ./testgo get code.google.com/p/go.tools/cmd/godoc
+if [ ! -x $d/gobin/godoc ]; then
+ echo did not install godoc to '$GOBIN'
+ GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' code.google.com/p/go.tools/cmd/godoc
+ ok=false
+fi
+
+TEST godoc installs into GOROOT
+GOROOT=$(./testgo env GOROOT)
+rm -f $GOROOT/bin/godoc
+./testgo install code.google.com/p/go.tools/cmd/godoc
+if [ ! -x $GOROOT/bin/godoc ]; then
+ echo did not install godoc to '$GOROOT/bin'
+ ./testgo list -f 'Target: {{.Target}}' code.google.com/p/go.tools/cmd/godoc
+ ok=false
+fi
+
+TEST cmd/fix installs into tool
+GOOS=$(./testgo env GOOS)
+GOARCH=$(./testgo env GOARCH)
+rm -f $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix
+./testgo install cmd/fix
+if [ ! -x $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix ]; then
+ echo 'did not install cmd/fix to $GOROOT/pkg/tool'
+ GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' cmd/fix
+ ok=false
+fi
+rm -f $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix
+GOBIN=$d/gobin ./testgo install cmd/fix
+if [ ! -x $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix ]; then
+ echo 'did not install cmd/fix to $GOROOT/pkg/tool with $GOBIN set'
+ GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' cmd/fix
+ ok=false
+fi
+
+TEST gopath program installs into GOBIN
+mkdir $d/src/progname
+echo 'package main; func main() {}' >$d/src/progname/p.go
+GOBIN=$d/gobin ./testgo install progname
+if [ ! -x $d/gobin/progname ]; then
+ echo 'did not install progname to $GOBIN/progname'
+ ./testgo list -f 'Target: {{.Target}}' cmd/api
+ ok=false
+fi
+rm -f $d/gobin/progname $d/bin/progname
+
+TEST gopath program installs into GOPATH/bin
+./testgo install progname
+if [ ! -x $d/bin/progname ]; then
+ echo 'did not install progname to $GOPATH/bin/progname'
+ ./testgo list -f 'Target: {{.Target}}' progname
+ ok=false
+fi
+
+unset GOPATH
+rm -rf $d
+
+# Reject relative paths in GOPATH.
+TEST reject relative paths in GOPATH '(command-line package)'
+if GOPATH=. ./testgo build testdata/src/go-cmd-test/helloworld.go; then
+ echo 'GOPATH="." go build should have failed, did not'
+ ok=false
+fi
+
+TEST reject relative paths in GOPATH
+if GOPATH=:$(pwd)/testdata:. ./testgo build go-cmd-test; then
+ echo 'GOPATH=":$(pwd)/testdata:." go build should have failed, did not'
+ ok=false
+fi
+
+# issue 4104
+TEST go test with package listed multiple times
+if [ $(./testgo test fmt fmt fmt fmt fmt | wc -l) -ne 1 ] ; then
+ echo 'go test fmt fmt fmt fmt fmt tested the same package multiple times'
+ ok=false
+fi
+
+# ensure that output of 'go list' is consistent between runs
+TEST go list is consistent
+./testgo list std > test_std.list
+if ! ./testgo list std | cmp -s test_std.list - ; then
+ echo "go list std ordering is inconsistent"
+ ok=false
+fi
+rm -f test_std.list
+
+# issue 4096. Validate the output of unsuccessful go install foo/quxx
+TEST unsuccessful go install should mention missing package
+if [ $(./testgo install 'foo/quxx' 2>&1 | grep -c 'cannot find package "foo/quxx" in any of') -ne 1 ] ; then
+ echo 'go install foo/quxx expected error: .*cannot find package "foo/quxx" in any of'
+ ok=false
+fi
+# test GOROOT search failure is reported
+TEST GOROOT search failure reporting
+if [ $(./testgo install 'foo/quxx' 2>&1 | egrep -c 'foo/quxx \(from \$GOROOT\)$') -ne 1 ] ; then
+ echo 'go install foo/quxx expected error: .*foo/quxx (from $GOROOT)'
+ ok=false
+fi
+# test multiple GOPATH entries are reported separately
+TEST multiple GOPATH entries reported separately
+if [ $(GOPATH=$(pwd)/testdata/a:$(pwd)/testdata/b ./testgo install 'foo/quxx' 2>&1 | egrep -c 'testdata/./src/foo/quxx') -ne 2 ] ; then
+ echo 'go install foo/quxx expected error: .*testdata/a/src/foo/quxx (from $GOPATH)\n.*testdata/b/src/foo/quxx'
+ ok=false
+fi
+# test (from $GOPATH) annotation is reported for the first GOPATH entry
+TEST mention GOPATH in first GOPATH entry
+if [ $(GOPATH=$(pwd)/testdata/a:$(pwd)/testdata/b ./testgo install 'foo/quxx' 2>&1 | egrep -c 'testdata/a/src/foo/quxx \(from \$GOPATH\)$') -ne 1 ] ; then
+ echo 'go install foo/quxx expected error: .*testdata/a/src/foo/quxx (from $GOPATH)'
+ ok=false
+fi
+# but not on the second
+TEST but not the second entry
+if [ $(GOPATH=$(pwd)/testdata/a:$(pwd)/testdata/b ./testgo install 'foo/quxx' 2>&1 | egrep -c 'testdata/b/src/foo/quxx$') -ne 1 ] ; then
+ echo 'go install foo/quxx expected error: .*testdata/b/src/foo/quxx'
+ ok=false
+fi
+# test missing GOPATH is reported
+TEST missing GOPATH is reported
+if [ $(GOPATH= ./testgo install 'foo/quxx' 2>&1 | egrep -c '\(\$GOPATH not set\)$') -ne 1 ] ; then
+ echo 'go install foo/quxx expected error: ($GOPATH not set)'
+ ok=false
+fi
+
+# issue 4186. go get cannot be used to download packages to $GOROOT
+# Test that without GOPATH set, go get should fail
+TEST without GOPATH, go get fails
+d=$(mktemp -d -t testgoXXX)
+mkdir -p $d/src/pkg
+if GOPATH= GOROOT=$d ./testgo get -d code.google.com/p/go.codereview/cmd/hgpatch ; then
+ echo 'go get code.google.com/p/go.codereview/cmd/hgpatch should not succeed with $GOPATH unset'
+ ok=false
+fi
+rm -rf $d
+
+# Test that with GOPATH=$GOROOT, go get should fail
+TEST with GOPATH=GOROOT, go get fails
+d=$(mktemp -d -t testgoXXX)
+mkdir -p $d/src/pkg
+if GOPATH=$d GOROOT=$d ./testgo get -d code.google.com/p/go.codereview/cmd/hgpatch ; then
+ echo 'go get code.google.com/p/go.codereview/cmd/hgpatch should not succeed with GOPATH=$GOROOT'
+ ok=false
+fi
+rm -rf $d
+
+TEST ldflags arguments with spaces '(issue 3941)'
+d=$(mktemp -d -t testgoXXX)
+cat >$d/main.go<<EOF
+package main
+var extern string
+func main() {
+ println(extern)
+}
+EOF
+./testgo run -ldflags '-X main.extern "hello world"' $d/main.go 2>hello.out
+if ! grep -q '^hello world' hello.out; then
+ echo "ldflags -X main.extern 'hello world' failed. Output:"
+ cat hello.out
+ ok=false
+fi
+rm -rf $d hello.out
+
+TEST go test -cpuprofile leaves binary behind
+./testgo test -cpuprofile strings.prof strings || ok=false
+if [ ! -x strings.test ]; then
+ echo "go test -cpuprofile did not create strings.test"
+ ok=false
+fi
+rm -f strings.prof strings.test
+
+TEST symlinks do not confuse go list '(issue 4568)'
+old=$(pwd)
+tmp=$(cd /tmp && pwd -P)
+d=$(TMPDIR=$tmp mktemp -d -t testgoXXX)
+mkdir -p $d/src
+(
+ ln -s $d $d/src/dir1
+ cd $d/src
+ echo package p >dir1/p.go
+ export GOPATH=$d
+ if [ "$($old/testgo list -f '{{.Root}}' dir1)" != "$d" ]; then
+ echo Confused by symlinks.
+ echo "Package in current directory $(pwd) should have Root $d"
+ env|grep WD
+ $old/testgo list -json . dir1
+ touch $d/failed
+ fi
+)
+if [ -f $d/failed ]; then
+ ok=false
+fi
+rm -rf $d
+
+TEST 'install with tags (issue 4515)'
+d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
+mkdir -p $d/src/example/a $d/src/example/b $d/bin
+cat >$d/src/example/a/main.go <<EOF
+package main
+func main() {}
+EOF
+cat >$d/src/example/b/main.go <<EOF
+// +build mytag
+
+package main
+func main() {}
+EOF
+GOPATH=$d ./testgo install -tags mytag example/a example/b || ok=false
+if [ ! -x $d/bin/a -o ! -x $d/bin/b ]; then
+ echo go install example/a example/b did not install binaries
+ ok=false
+fi
+rm -f $d/bin/*
+GOPATH=$d ./testgo install -tags mytag example/... || ok=false
+if [ ! -x $d/bin/a -o ! -x $d/bin/b ]; then
+ echo go install example/... did not install binaries
+ ok=false
+fi
+rm -f $d/bin/*go
+export GOPATH=$d
+if [ "$(./testgo list -tags mytag example/b...)" != "example/b" ]; then
+ echo go list example/b did not find example/b
+ ok=false
+fi
+unset GOPATH
+rm -rf $d
+
+TEST case collisions '(issue 4773)'
+d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
+export GOPATH=$d
+mkdir -p $d/src/example/{a/pkg,a/Pkg,b}
+cat >$d/src/example/a/a.go <<EOF
+package p
+import (
+ _ "example/a/pkg"
+ _ "example/a/Pkg"
+)
+EOF
+cat >$d/src/example/a/pkg/pkg.go <<EOF
+package pkg
+EOF
+cat >$d/src/example/a/Pkg/pkg.go <<EOF
+package pkg
+EOF
+if ./testgo list example/a 2>$d/out; then
+ echo go list example/a should have failed, did not.
+ ok=false
+elif ! grep "case-insensitive import collision" $d/out >/dev/null; then
+ echo go list example/a did not report import collision.
+ ok=false
+fi
+cat >$d/src/example/b/file.go <<EOF
+package b
+EOF
+cat >$d/src/example/b/FILE.go <<EOF
+package b
+EOF
+if [ $(ls $d/src/example/b | wc -l) = 2 ]; then
+ # case-sensitive file system, let directory read find both files
+ args="example/b"
+else
+ # case-insensitive file system, list files explicitly on command line.
+ args="$d/src/example/b/file.go $d/src/example/b/FILE.go"
+fi
+if ./testgo list $args 2>$d/out; then
+ echo go list example/b should have failed, did not.
+ ok=false
+elif ! grep "case-insensitive file name collision" $d/out >/dev/null; then
+ echo go list example/b did not report file name collision.
+ ok=false
+fi
+
+TEST go get cover
+./testgo get code.google.com/p/go.tools/cmd/cover || ok=false
+
+unset GOPATH
+rm -rf $d
+
+TEST shadowing logic
+export GOPATH=$(pwd)/testdata/shadow/root1:$(pwd)/testdata/shadow/root2
+
+# The math in root1 is not "math" because the standard math is.
+cdir=$(./testgo list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./testdata/shadow/root1/src/math)
+if [ "$cdir" != "(_$(pwd)/testdata/shadow/root1/src/math) ($GOROOT/src/pkg/math)" ]; then
+ echo shadowed math is not shadowed: "$cdir"
+ ok=false
+fi
+
+# The foo in root1 is "foo".
+cdir=$(./testgo list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./testdata/shadow/root1/src/foo)
+if [ "$cdir" != "(foo) ()" ]; then
+ echo unshadowed foo is shadowed: "$cdir"
+ ok=false
+fi
+
+# The foo in root2 is not "foo" because the foo in root1 got there first.
+cdir=$(./testgo list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./testdata/shadow/root2/src/foo)
+if [ "$cdir" != "(_$(pwd)/testdata/shadow/root2/src/foo) ($(pwd)/testdata/shadow/root1/src/foo)" ]; then
+ echo shadowed foo is not shadowed: "$cdir"
+ ok=false
+fi
+
+# The error for go install should mention the conflicting directory.
+err=$(! ./testgo install ./testdata/shadow/root2/src/foo 2>&1)
+if [ "$err" != "go install: no install location for $(pwd)/testdata/shadow/root2/src/foo: hidden by $(pwd)/testdata/shadow/root1/src/foo" ]; then
+ echo wrong shadowed install error: "$err"
+ ok=false
+fi
+
+# Only succeeds if source order is preserved.
+TEST source file name order preserved
+./testgo test testdata/example[12]_test.go || ok=false
+
+# Check that coverage analysis works at all.
+# Don't worry about the exact numbers but require not 0.0%.
+checkcoverage() {
+ if grep '[^0-9]0\.0%' testdata/cover.txt >/dev/null; then
+ echo 'some coverage results are 0.0%'
+ ok=false
+ fi
+ cat testdata/cover.txt
+ rm -f testdata/cover.txt
+}
+
+TEST coverage runs
+./testgo test -short -coverpkg=strings strings regexp >testdata/cover.txt 2>&1 || ok=false
+./testgo test -short -cover strings math regexp >>testdata/cover.txt 2>&1 || ok=false
+checkcoverage
+
+# Check that coverage analysis uses set mode.
+TEST coverage uses set mode
+if ./testgo test -short -cover encoding/binary -coverprofile=testdata/cover.out >testdata/cover.txt 2>&1; then
+ if ! grep -q 'mode: set' testdata/cover.out; then
+ ok=false
+ fi
+ checkcoverage
+else
+ ok=false
+fi
+rm -f testdata/cover.out testdata/cover.txt
+
+TEST coverage uses atomic mode for -race.
+if ./testgo test -short -race -cover encoding/binary -coverprofile=testdata/cover.out >testdata/cover.txt 2>&1; then
+ if ! grep -q 'mode: atomic' testdata/cover.out; then
+ ok=false
+ fi
+ checkcoverage
+else
+ ok=false
+fi
+rm -f testdata/cover.out
+
+TEST coverage uses actual setting to override even for -race.
+if ./testgo test -short -race -cover encoding/binary -covermode=count -coverprofile=testdata/cover.out >testdata/cover.txt 2>&1; then
+ if ! grep -q 'mode: count' testdata/cover.out; then
+ ok=false
+ fi
+ checkcoverage
+else
+ ok=false
+fi
+rm -f testdata/cover.out
+
+TEST coverage with cgo
+d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
+./testgo test -short -cover ./testdata/cgocover >testdata/cover.txt 2>&1 || ok=false
+checkcoverage
+
+TEST cgo depends on syscall
+rm -rf $GOROOT/pkg/*_race
+d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
+export GOPATH=$d
+mkdir -p $d/src/foo
+echo '
+package foo
+//#include <stdio.h>
+import "C"
+' >$d/src/foo/foo.go
+./testgo build -race foo || ok=false
+rm -rf $d
+unset GOPATH
+
+TEST cgo shows full path names
+d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
+export GOPATH=$d
+mkdir -p $d/src/x/y/dirname
+echo '
+package foo
+import "C"
+func f() {
+' >$d/src/x/y/dirname/foo.go
+if ./testgo build x/y/dirname >$d/err 2>&1; then
+ echo build succeeded unexpectedly.
+ ok=false
+elif ! grep x/y/dirname $d/err >/dev/null; then
+ echo error did not use full path.
+ cat $d/err
+ ok=false
+fi
+rm -rf $d
+unset GOPATH
+
+TEST 'cgo handles -Wl,$ORIGIN'
+d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
+export GOPATH=$d
+mkdir -p $d/src/origin
+echo '
+package origin
+// #cgo !darwin LDFLAGS: -Wl,-rpath -Wl,$ORIGIN
+// void f(void) {}
+import "C"
+
+func f() { C.f() }
+' >$d/src/origin/origin.go
+if ! ./testgo build origin; then
+ echo build failed
+ ok=false
+fi
+rm -rf $d
+unset GOPATH
+
+TEST 'Issue 6480: "go test -c -test.bench=XXX fmt" should not hang'
+if ! ./testgo test -c -test.bench=XXX fmt; then
+ echo build test failed
+ ok=false
+fi
+rm -f fmt.test
+
+TEST 'Issue 7573: cmd/cgo: undefined reference when linking a C-library using gccgo'
+d=$(mktemp -d -t testgoXXX)
+export GOPATH=$d
+mkdir -p $d/src/cgoref
+ldflags="-L alibpath -lalib"
+echo "
+package main
+// #cgo LDFLAGS: $ldflags
+// void f(void) {}
+import \"C\"
+
+func main() { C.f() }
+" >$d/src/cgoref/cgoref.go
+go_cmds="$(./testgo build -n -compiler gccgo cgoref 2>&1 1>/dev/null)"
+ldflags_count="$(echo "$go_cmds" | egrep -c "^gccgo.*$(echo $ldflags | sed -e 's/-/\\-/g')" || true)"
+if [ "$ldflags_count" -lt 1 ]; then
+ echo "No Go-inline "#cgo LDFLAGS:" (\"$ldflags\") passed to gccgo linking stage."
+ ok=false
+fi
+rm -rf $d
+unset ldflags_count
+unset go_cmds
+unset ldflags
+unset GOPATH
+
+TEST list template can use context function
+if ! ./testgo list -f "GOARCH: {{context.GOARCH}}"; then
+ echo unable to use context in list template
+ ok=false
+fi
+
+TEST 'Issue 7108: cmd/go: "go test" should fail if package does not build'
+export GOPATH=$(pwd)/testdata
+if ./testgo test notest >/dev/null 2>&1; then
+ echo 'go test notest succeeded, but should fail'
+ ok=false
+fi
+unset GOPATH
+
+TEST 'Issue 6844: cmd/go: go test -a foo does not rebuild regexp'
+if ! ./testgo test -x -a -c testdata/dep_test.go 2>deplist; then
+ echo "go test -x -a -c testdata/dep_test.go failed"
+ ok=false
+elif ! grep -q regexp deplist; then
+ echo "go test -x -a -c testdata/dep_test.go did not rebuild regexp"
+ ok=false
+fi
+rm -f deplist
+rm -f deps.test
+
+TEST list template can use context function
+if ! ./testgo list -f "GOARCH: {{context.GOARCH}}"; then
+ echo unable to use context in list template
+ ok=false
+fi
+
+TEST build -i installs dependencies
+d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
+export GOPATH=$d
+mkdir -p $d/src/x/y/foo $d/src/x/y/bar
+echo '
+package foo
+func F() {}
+' >$d/src/x/y/foo/foo.go
+echo '
+package bar
+import "x/y/foo"
+func F() { foo.F() }
+' >$d/src/x/y/bar/bar.go
+if ! ./testgo build -v -i x/y/bar &> $d/err; then
+ echo build -i failed
+ cat $d/err
+ ok=false
+elif ! grep x/y/foo $d/err >/dev/null; then
+ echo first build -i did not build x/y/foo
+ cat $d/err
+ ok=false
+fi
+if ! ./testgo build -v -i x/y/bar &> $d/err; then
+ echo second build -i failed
+ cat $d/err
+ ok=false
+elif grep x/y/foo $d/err >/dev/null; then
+ echo second build -i built x/y/foo
+ cat $d/err
+ ok=false
+fi
+rm -rf $d
+unset GOPATH
+
+TEST 'go build in test-only directory fails with a good error'
+if ./testgo build ./testdata/testonly 2>testdata/err.out; then
+ echo "go build ./testdata/testonly succeeded, should have failed"
+ ok=false
+elif ! grep 'no buildable Go' testdata/err.out >/dev/null; then
+ echo "go build ./testdata/testonly produced unexpected error:"
+ cat testdata/err.out
+ ok=false
+fi
+rm -f testdata/err.out
+
+TEST 'go test detects test-only import cycles'
+export GOPATH=$(pwd)/testdata
+if ./testgo test -c testcycle/p3 2>testdata/err.out; then
+ echo "go test testcycle/p3 succeeded, should have failed"
+ ok=false
+elif ! grep 'import cycle not allowed in test' testdata/err.out >/dev/null; then
+ echo "go test testcycle/p3 produced unexpected error:"
+ cat testdata/err.out
+ ok=false
+fi
+rm -f testdata/err.out
+unset GOPATH
+
+TEST 'go test foo_test.go works'
+if ! ./testgo test testdata/standalone_test.go; then
+ echo "go test testdata/standalone_test.go failed"
+ ok=false
+fi
+
+TEST 'go test xtestonly works'
+export GOPATH=$(pwd)/testdata
+./testgo clean -i xtestonly
+if ! ./testgo test xtestonly >/dev/null; then
+ echo "go test xtestonly failed"
+ ok=false
+fi
+unset GOPATH
+
+
+# clean up
+if $started; then stop; fi
+rm -rf testdata/bin testdata/bin1
+rm -f testgo
+
+if $allok; then
+ echo PASS
+else
+ echo FAIL
+ exit 1
+fi
diff --git a/libgo/go/cmd/go/test.go b/libgo/go/cmd/go/test.go
new file mode 100644
index 0000000000..5cf7aaf071
--- /dev/null
+++ b/libgo/go/cmd/go/test.go
@@ -0,0 +1,1412 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "go/ast"
+ "go/build"
+ "go/doc"
+ "go/parser"
+ "go/token"
+ "log"
+ "os"
+ "os/exec"
+ "path"
+ "path/filepath"
+ "regexp"
+ "runtime"
+ "sort"
+ "strings"
+ "text/template"
+ "time"
+ "unicode"
+ "unicode/utf8"
+)
+
+// Break init loop.
+func init() {
+ cmdTest.Run = runTest
+}
+
+var cmdTest = &Command{
+ CustomFlags: true,
+ UsageLine: "test [-c] [-i] [build and test flags] [packages] [flags for test binary]",
+ Short: "test packages",
+ Long: `
+'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.
+`,
+}
+
+var helpTestflag = &Command{
+ UsageLine: "testflag",
+ Short: "description of testing flags",
+ Long: `
+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.
+`,
+}
+
+var helpTestfunc = &Command{
+ UsageLine: "testfunc",
+ Short: "description of testing functions",
+ Long: `
+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.
+`,
+}
+
+var (
+ testC bool // -c flag
+ testCover bool // -cover flag
+ testCoverMode string // -covermode flag
+ testCoverPaths []string // -coverpkg flag
+ testCoverPkgs []*Package // -coverpkg flag
+ testO string // -o flag
+ testProfile bool // some profiling flag
+ testNeedBinary bool // profile needs to keep binary around
+ testV bool // -v flag
+ testTimeout string // -timeout flag
+ testArgs []string
+ testBench bool
+ testStreamOutput bool // show output as it is generated
+ testShowPass bool // show passing output
+
+ testKillTimeout = 10 * time.Minute
+)
+
+var testMainDeps = map[string]bool{
+ // Dependencies for testmain.
+ "testing": true,
+ "regexp": true,
+ "os": true,
+}
+
+func runTest(cmd *Command, args []string) {
+ var pkgArgs []string
+ pkgArgs, testArgs = testFlags(args)
+
+ findExecCmd() // initialize cached result
+
+ raceInit()
+ pkgs := packagesForBuild(pkgArgs)
+ if len(pkgs) == 0 {
+ fatalf("no packages to test")
+ }
+
+ if testC && len(pkgs) != 1 {
+ fatalf("cannot use -c flag with multiple packages")
+ }
+ if testO != "" && len(pkgs) != 1 {
+ fatalf("cannot use -o flag with multiple packages")
+ }
+ if testProfile && len(pkgs) != 1 {
+ fatalf("cannot use test profile flag with multiple packages")
+ }
+
+ // If a test timeout was given and is parseable, set our kill timeout
+ // to that timeout plus one minute. This is a backup alarm in case
+ // the test wedges with a goroutine spinning and its background
+ // timer does not get a chance to fire.
+ if dt, err := time.ParseDuration(testTimeout); err == nil && dt > 0 {
+ testKillTimeout = dt + 1*time.Minute
+ }
+
+ // show passing test output (after buffering) with -v flag.
+ // must buffer because tests are running in parallel, and
+ // otherwise the output will get mixed.
+ testShowPass = testV
+
+ // stream test output (no buffering) when no package has
+ // 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.
+ testStreamOutput = len(pkgArgs) == 0 || testBench ||
+ (len(pkgs) <= 1 && testShowPass)
+
+ var b builder
+ b.init()
+
+ if buildI {
+ buildV = testV
+
+ deps := make(map[string]bool)
+ for dep := range testMainDeps {
+ deps[dep] = true
+ }
+
+ for _, p := range pkgs {
+ // Dependencies for each test.
+ for _, path := range p.Imports {
+ deps[path] = true
+ }
+ for _, path := range p.TestImports {
+ deps[path] = true
+ }
+ for _, path := range p.XTestImports {
+ deps[path] = true
+ }
+ }
+
+ // translate C to runtime/cgo
+ if deps["C"] {
+ delete(deps, "C")
+ deps["runtime/cgo"] = true
+ if buildContext.GOOS == runtime.GOOS && buildContext.GOARCH == runtime.GOARCH {
+ deps["cmd/cgo"] = true
+ }
+ }
+ // Ignore pseudo-packages.
+ delete(deps, "unsafe")
+
+ all := []string{}
+ for path := range deps {
+ if !build.IsLocalImport(path) {
+ all = append(all, path)
+ }
+ }
+ sort.Strings(all)
+
+ a := &action{}
+ for _, p := range packagesForBuild(all) {
+ if !reqStdPkgSrc && p.Standard {
+ continue
+ }
+ a.deps = append(a.deps, b.action(modeInstall, modeInstall, p))
+ }
+ b.do(a)
+ if !testC || a.failed {
+ return
+ }
+ b.init()
+ }
+
+ var builds, runs, prints []*action
+
+ if testCoverPaths != nil {
+ // Load packages that were asked about for coverage.
+ // packagesForBuild exits if the packages cannot be loaded.
+ testCoverPkgs = packagesForBuild(testCoverPaths)
+
+ // Warn about -coverpkg arguments that are not actually used.
+ used := make(map[string]bool)
+ for _, p := range pkgs {
+ used[p.ImportPath] = true
+ for _, dep := range p.Deps {
+ used[dep] = true
+ }
+ }
+ for _, p := range testCoverPkgs {
+ if !used[p.ImportPath] {
+ log.Printf("warning: no packages being tested depend on %s", p.ImportPath)
+ }
+ }
+
+ // Mark all the coverage packages for rebuilding with coverage.
+ for _, p := range testCoverPkgs {
+ p.Stale = true // rebuild
+ p.fake = true // do not warn about rebuild
+ p.coverMode = testCoverMode
+ var coverFiles []string
+ coverFiles = append(coverFiles, p.GoFiles...)
+ coverFiles = append(coverFiles, p.CgoFiles...)
+ coverFiles = append(coverFiles, p.TestGoFiles...)
+ p.coverVars = declareCoverVars(p.ImportPath, coverFiles...)
+ }
+ }
+
+ // Prepare build + run + print actions for all packages being tested.
+ for _, p := range pkgs {
+ buildTest, runTest, printTest, err := b.test(p)
+ if err != nil {
+ str := err.Error()
+ if strings.HasPrefix(str, "\n") {
+ str = str[1:]
+ }
+ failed := fmt.Sprintf("FAIL\t%s [setup failed]\n", p.ImportPath)
+
+ if p.ImportPath != "" {
+ errorf("# %s\n%s\n%s", p.ImportPath, str, failed)
+ } else {
+ errorf("%s\n%s", str, failed)
+ }
+ continue
+ }
+ builds = append(builds, buildTest)
+ runs = append(runs, runTest)
+ prints = append(prints, printTest)
+ }
+
+ // Ultimately the goal is to print the output.
+ root := &action{deps: prints}
+
+ // Force the printing of results to happen in order,
+ // one at a time.
+ for i, a := range prints {
+ if i > 0 {
+ a.deps = append(a.deps, prints[i-1])
+ }
+ }
+
+ // Force benchmarks to run in serial.
+ if !testC && testBench {
+ // The first run must wait for all builds.
+ // Later runs must wait for the previous run's print.
+ for i, run := range runs {
+ if i == 0 {
+ run.deps = append(run.deps, builds...)
+ } else {
+ run.deps = append(run.deps, prints[i-1])
+ }
+ }
+ }
+
+ // If we are building any out-of-date packages other
+ // than those under test, warn.
+ okBuild := map[*Package]bool{}
+ for _, p := range pkgs {
+ okBuild[p] = true
+ }
+ warned := false
+ for _, a := range actionList(root) {
+ if a.p == nil || okBuild[a.p] {
+ continue
+ }
+ okBuild[a.p] = true // warn at most once
+
+ // Don't warn about packages being rebuilt because of
+ // things like coverage analysis.
+ for _, p1 := range a.p.imports {
+ if p1.fake {
+ a.p.fake = true
+ }
+ }
+
+ if a.f != nil && !okBuild[a.p] && !a.p.fake && !a.p.local {
+ if !warned {
+ fmt.Fprintf(os.Stderr, "warning: building out-of-date packages:\n")
+ warned = true
+ }
+ fmt.Fprintf(os.Stderr, "\t%s\n", a.p.ImportPath)
+ }
+ }
+ if warned {
+ args := strings.Join(pkgArgs, " ")
+ if args != "" {
+ args = " " + args
+ }
+ extraOpts := ""
+ if buildRace {
+ extraOpts = "-race "
+ }
+ fmt.Fprintf(os.Stderr, "installing these packages with 'go test %s-i%s' will speed future tests.\n\n", extraOpts, args)
+ }
+
+ b.do(root)
+}
+
+func contains(x []string, s string) bool {
+ for _, t := range x {
+ if t == s {
+ return true
+ }
+ }
+ return false
+}
+
+var windowsBadWords = []string{
+ "install",
+ "patch",
+ "setup",
+ "update",
+}
+
+func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, err error) {
+ if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
+ build := b.action(modeBuild, modeBuild, p)
+ run := &action{p: p, deps: []*action{build}}
+ print := &action{f: (*builder).notest, p: p, deps: []*action{run}}
+ return build, run, print, nil
+ }
+
+ // Build Package structs describing:
+ // ptest - package + test files
+ // pxtest - package of external test files
+ // pmain - pkg.test binary
+ var ptest, pxtest, pmain *Package
+
+ 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])
+ if !reqStdPkgSrc && p1.Standard {
+ continue
+ }
+ if p1.Error != nil {
+ return nil, nil, nil, p1.Error
+ }
+ if contains(p1.Deps, 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.
+ err := &PackageError{
+ ImportStack: testImportStack(stk[0], p1, p.ImportPath),
+ Err: "import cycle not allowed in test",
+ isImportCycle: true,
+ }
+ return nil, nil, nil, err
+ }
+ 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])
+ if !reqStdPkgSrc && p1.Standard {
+ continue
+ }
+ if p1.Error != nil {
+ return nil, nil, nil, p1.Error
+ }
+ ximports = append(ximports, p1)
+ }
+ stk.pop()
+
+ // Use last element of import path, not package name.
+ // They differ when package name is "main".
+ // But if the import path is "command-line-arguments",
+ // like it is during 'go run', use the package name.
+ var elem string
+ if p.ImportPath == "command-line-arguments" {
+ elem = p.Name
+ } else {
+ _, elem = path.Split(p.ImportPath)
+ }
+ testBinary := elem + ".test"
+
+ // The ptest package needs to be importable under the
+ // same import path that p has, but we cannot put it in
+ // the usual place in the temporary tree, because then
+ // other tests will see it as the real package.
+ // Instead we make a _test directory under the import path
+ // and then repeat the import path there. We tell the
+ // compiler and linker to look in that _test directory first.
+ //
+ // That is, if the package under test is unicode/utf8,
+ // then the normal place to write the package archive is
+ // $WORK/unicode/utf8.a, but we write the test package archive to
+ // $WORK/unicode/utf8/_test/unicode/utf8.a.
+ // We write the external test package archive to
+ // $WORK/unicode/utf8/_test/unicode/utf8_test.a.
+ testDir := filepath.Join(b.work, filepath.FromSlash(p.ImportPath+"/_test"))
+ ptestObj := buildToolchain.pkgpath(testDir, p)
+
+ // Create the directory for the .a files.
+ ptestDir, _ := filepath.Split(ptestObj)
+ if err := b.mkdir(ptestDir); err != nil {
+ return nil, nil, nil, err
+ }
+
+ // Should we apply coverage analysis locally,
+ // only for this package and only for this test?
+ // Yes, if -cover is on but -coverpkg has not specified
+ // a list of packages for global coverage.
+ localCover := testCover && testCoverPaths == nil
+
+ // Test package.
+ if len(p.TestGoFiles) > 0 || localCover || p.Name == "main" {
+ ptest = new(Package)
+ *ptest = *p
+ ptest.GoFiles = nil
+ ptest.GoFiles = append(ptest.GoFiles, p.GoFiles...)
+ ptest.GoFiles = append(ptest.GoFiles, p.TestGoFiles...)
+ ptest.target = ""
+ ptest.Imports = stringList(p.Imports, p.TestImports)
+ ptest.imports = append(append([]*Package{}, p.imports...), imports...)
+ ptest.pkgdir = testDir
+ ptest.fake = true
+ ptest.forceLibrary = true
+ ptest.Stale = true
+ ptest.build = new(build.Package)
+ *ptest.build = *p.build
+ m := map[string][]token.Position{}
+ for k, v := range p.build.ImportPos {
+ m[k] = append(m[k], v...)
+ }
+ for k, v := range p.build.TestImportPos {
+ m[k] = append(m[k], v...)
+ }
+ ptest.build.ImportPos = m
+
+ if localCover {
+ ptest.coverMode = testCoverMode
+ var coverFiles []string
+ coverFiles = append(coverFiles, ptest.GoFiles...)
+ coverFiles = append(coverFiles, ptest.CgoFiles...)
+ ptest.coverVars = declareCoverVars(ptest.ImportPath, coverFiles...)
+ }
+ } else {
+ ptest = p
+ }
+
+ // External test package.
+ if len(p.XTestGoFiles) > 0 {
+ pxtest = &Package{
+ Name: p.Name + "_test",
+ ImportPath: p.ImportPath + "_test",
+ localPrefix: p.localPrefix,
+ Root: p.Root,
+ Dir: p.Dir,
+ GoFiles: p.XTestGoFiles,
+ Imports: p.XTestImports,
+ build: &build.Package{
+ ImportPos: p.build.XTestImportPos,
+ },
+ imports: ximports,
+ pkgdir: testDir,
+ fake: true,
+ external: true,
+ Stale: true,
+ }
+ if pxtestNeedsPtest {
+ pxtest.imports = append(pxtest.imports, ptest)
+ }
+ }
+
+ // Action for building pkg.test.
+ pmain = &Package{
+ Name: "main",
+ Dir: testDir,
+ GoFiles: []string{"_testmain.go"},
+ ImportPath: "testmain",
+ Root: p.Root,
+ build: &build.Package{Name: "main"},
+ pkgdir: testDir,
+ fake: true,
+ Stale: true,
+ omitDWARF: !testC && !testNeedBinary,
+ }
+
+ // The generated main also imports testing, regexp, and os.
+ stk.push("testmain")
+ for dep := range testMainDeps {
+ if dep == ptest.ImportPath {
+ pmain.imports = append(pmain.imports, ptest)
+ } else {
+ p1 := loadImport(dep, "", &stk, nil)
+ if !reqStdPkgSrc && p1.Standard {
+ continue
+ }
+ if p1.Error != nil {
+ return nil, nil, nil, p1.Error
+ }
+ pmain.imports = append(pmain.imports, p1)
+ }
+ }
+
+ if testCoverPkgs != nil {
+ // Add imports, but avoid duplicates.
+ seen := map[*Package]bool{p: true, ptest: true}
+ for _, p1 := range pmain.imports {
+ seen[p1] = true
+ }
+ for _, p1 := range testCoverPkgs {
+ if !seen[p1] {
+ seen[p1] = true
+ pmain.imports = append(pmain.imports, p1)
+ }
+ }
+ }
+
+ // Do initial scan for metadata needed for writing _testmain.go
+ // Use that metadata to update the list of imports for package main.
+ // The list of imports is used by recompileForTest and by the loop
+ // afterward that gathers t.Cover information.
+ t, err := loadTestFuncs(ptest)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ if len(ptest.GoFiles) > 0 {
+ pmain.imports = append(pmain.imports, ptest)
+ t.ImportTest = true
+ }
+ if pxtest != nil {
+ pmain.imports = append(pmain.imports, pxtest)
+ t.ImportXtest = true
+ }
+
+ if ptest != p && localCover {
+ // We have made modifications to the package p being tested
+ // and are rebuilding p (as ptest), writing it to the testDir tree.
+ // Arrange to rebuild, writing to that same tree, all packages q
+ // such that the test depends on q, and q depends on p.
+ // This makes sure that q sees the modifications to p.
+ // Strictly speaking, the rebuild is only necessary if the
+ // modifications to p change its export metadata, but
+ // determining that is a bit tricky, so we rebuild always.
+ //
+ // This will cause extra compilation, so for now we only do it
+ // when testCover is set. The conditions are more general, though,
+ // and we may find that we need to do it always in the future.
+ recompileForTest(pmain, p, ptest, testDir)
+ }
+
+ for _, cp := range pmain.imports {
+ if len(cp.coverVars) > 0 {
+ t.Cover = append(t.Cover, coverInfo{cp, cp.coverVars})
+ }
+ }
+
+ // writeTestmain writes _testmain.go. This must happen after recompileForTest,
+ // because recompileForTest modifies XXX.
+ if err := writeTestmain(filepath.Join(testDir, "_testmain.go"), t); err != nil {
+ return nil, nil, nil, err
+ }
+
+ computeStale(pmain)
+
+ if ptest != p {
+ a := b.action(modeBuild, modeBuild, ptest)
+ a.objdir = testDir + string(filepath.Separator) + "_obj_test" + string(filepath.Separator)
+ a.objpkg = ptestObj
+ a.target = ptestObj
+ a.link = false
+ }
+
+ if pxtest != nil {
+ a := b.action(modeBuild, modeBuild, pxtest)
+ a.objdir = testDir + string(filepath.Separator) + "_obj_xtest" + string(filepath.Separator)
+ a.objpkg = buildToolchain.pkgpath(testDir, pxtest)
+ a.target = a.objpkg
+ }
+
+ a := b.action(modeBuild, modeBuild, pmain)
+ a.objdir = testDir + string(filepath.Separator)
+ a.objpkg = filepath.Join(testDir, "main.a")
+ a.target = filepath.Join(testDir, testBinary) + exeSuffix
+ if goos == "windows" {
+ // There are many reserved words on Windows that,
+ // if used in the name of an executable, cause Windows
+ // to try to ask for extra permissions.
+ // The word list includes setup, install, update, and patch,
+ // but it does not appear to be defined anywhere.
+ // We have run into this trying to run the
+ // go.codereview/patch tests.
+ // For package names containing those words, use test.test.exe
+ // instead of pkgname.test.exe.
+ // Note that this file name is only used in the Go command's
+ // temporary directory. If the -c or other flags are
+ // given, the code below will still use pkgname.test.exe.
+ // There are two user-visible effects of this change.
+ // First, you can actually run 'go test' in directories that
+ // have names that Windows thinks are installer-like,
+ // without getting a dialog box asking for more permissions.
+ // Second, in the Windows process listing during go test,
+ // the test shows up as test.test.exe, not pkgname.test.exe.
+ // That second one is a drawback, but it seems a small
+ // price to pay for the test running at all.
+ // If maintaining the list of bad words is too onerous,
+ // we could just do this always on Windows.
+ for _, bad := range windowsBadWords {
+ if strings.Contains(testBinary, bad) {
+ a.target = filepath.Join(testDir, "test.test") + exeSuffix
+ break
+ }
+ }
+ }
+ buildAction = a
+
+ if testC || testNeedBinary {
+ // -c or profiling flag: create action to copy binary to ./test.out.
+ target := filepath.Join(cwd, testBinary+exeSuffix)
+ if testO != "" {
+ target = testO
+ if !filepath.IsAbs(target) {
+ target = filepath.Join(cwd, target)
+ }
+ }
+ buildAction = &action{
+ f: (*builder).install,
+ deps: []*action{buildAction},
+ p: pmain,
+ target: target,
+ }
+ runAction = buildAction // make sure runAction != nil even if not running test
+ }
+ if testC {
+ printAction = &action{p: p, deps: []*action{runAction}} // nop
+ } else {
+ // run test
+ runAction = &action{
+ f: (*builder).runTest,
+ deps: []*action{buildAction},
+ p: p,
+ ignoreFail: true,
+ }
+ cleanAction := &action{
+ f: (*builder).cleanTest,
+ deps: []*action{runAction},
+ p: p,
+ }
+ printAction = &action{
+ f: (*builder).printTest,
+ deps: []*action{cleanAction},
+ p: p,
+ }
+ }
+
+ return buildAction, runAction, printAction, nil
+}
+
+func testImportStack(top string, p *Package, target string) []string {
+ stk := []string{top, p.ImportPath}
+Search:
+ for p.ImportPath != target {
+ for _, p1 := range p.imports {
+ if p1.ImportPath == target || contains(p1.Deps, target) {
+ stk = append(stk, p1.ImportPath)
+ p = p1
+ continue Search
+ }
+ }
+ // Can't happen, but in case it does...
+ stk = append(stk, "<lost path to cycle>")
+ break
+ }
+ return stk
+}
+
+func recompileForTest(pmain, preal, ptest *Package, testDir string) {
+ // The "test copy" of preal is ptest.
+ // For each package that depends on preal, make a "test copy"
+ // that depends on ptest. And so on, up the dependency tree.
+ testCopy := map[*Package]*Package{preal: ptest}
+ for _, p := range packageList([]*Package{pmain}) {
+ // Copy on write.
+ didSplit := false
+ split := func() {
+ if didSplit {
+ return
+ }
+ didSplit = true
+ if p.pkgdir != testDir {
+ p1 := new(Package)
+ testCopy[p] = p1
+ *p1 = *p
+ p1.imports = make([]*Package, len(p.imports))
+ copy(p1.imports, p.imports)
+ p = p1
+ p.pkgdir = testDir
+ p.target = ""
+ p.fake = true
+ p.Stale = true
+ }
+ }
+
+ // Update p.deps and p.imports to use at test copies.
+ for i, dep := range p.deps {
+ if p1 := testCopy[dep]; p1 != nil && p1 != dep {
+ split()
+ p.deps[i] = p1
+ }
+ }
+ for i, imp := range p.imports {
+ if p1 := testCopy[imp]; p1 != nil && p1 != imp {
+ split()
+ p.imports[i] = p1
+ }
+ }
+ }
+}
+
+var coverIndex = 0
+
+// isTestFile reports whether the source file is a set of tests and should therefore
+// be excluded from coverage analysis.
+func isTestFile(file string) bool {
+ // We don't cover tests, only the code they test.
+ return strings.HasSuffix(file, "_test.go")
+}
+
+// declareCoverVars attaches the required cover variables names
+// to the files, to be used when annotating the files.
+func declareCoverVars(importPath string, files ...string) map[string]*CoverVar {
+ coverVars := make(map[string]*CoverVar)
+ for _, file := range files {
+ if isTestFile(file) {
+ continue
+ }
+ coverVars[file] = &CoverVar{
+ File: filepath.Join(importPath, file),
+ Var: fmt.Sprintf("GoCover_%d", coverIndex),
+ }
+ coverIndex++
+ }
+ return coverVars
+}
+
+// runTest is the action for running a test binary.
+func (b *builder) runTest(a *action) error {
+ args := stringList(findExecCmd(), a.deps[0].target, testArgs)
+ a.testOutput = new(bytes.Buffer)
+
+ if buildN || buildX {
+ b.showcmd("", "%s", strings.Join(args, " "))
+ if buildN {
+ return nil
+ }
+ }
+
+ if a.failed {
+ // We were unable to build the binary.
+ a.failed = false
+ fmt.Fprintf(a.testOutput, "FAIL\t%s [build failed]\n", a.p.ImportPath)
+ setExitStatus(1)
+ return nil
+ }
+
+ cmd := exec.Command(args[0], args[1:]...)
+ cmd.Dir = a.p.Dir
+ cmd.Env = envForDir(cmd.Dir)
+ var buf bytes.Buffer
+ if testStreamOutput {
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ } else {
+ cmd.Stdout = &buf
+ cmd.Stderr = &buf
+ }
+
+ // If there are any local SWIG dependencies, we want to load
+ // the shared library from the build directory.
+ if a.p.usesSwig() {
+ env := cmd.Env
+ found := false
+ prefix := "LD_LIBRARY_PATH="
+ for i, v := range env {
+ if strings.HasPrefix(v, prefix) {
+ env[i] = v + ":."
+ found = true
+ break
+ }
+ }
+ if !found {
+ env = append(env, "LD_LIBRARY_PATH=.")
+ }
+ cmd.Env = env
+ }
+
+ t0 := time.Now()
+ err := cmd.Start()
+
+ // This is a last-ditch deadline to detect and
+ // stop wedged test binaries, to keep the builders
+ // running.
+ if err == nil {
+ tick := time.NewTimer(testKillTimeout)
+ startSigHandlers()
+ done := make(chan error)
+ go func() {
+ done <- cmd.Wait()
+ }()
+ Outer:
+ select {
+ case err = <-done:
+ // ok
+ case <-tick.C:
+ if signalTrace != nil {
+ // Send a quit signal in the hope that the program will print
+ // a stack trace and exit. Give it five seconds before resorting
+ // to Kill.
+ cmd.Process.Signal(signalTrace)
+ select {
+ case err = <-done:
+ fmt.Fprintf(&buf, "*** Test killed with %v: ran too long (%v).\n", signalTrace, testKillTimeout)
+ break Outer
+ case <-time.After(5 * time.Second):
+ }
+ }
+ cmd.Process.Kill()
+ err = <-done
+ fmt.Fprintf(&buf, "*** Test killed: ran too long (%v).\n", testKillTimeout)
+ }
+ tick.Stop()
+ }
+ out := buf.Bytes()
+ t := fmt.Sprintf("%.3fs", time.Since(t0).Seconds())
+ if err == nil {
+ if testShowPass {
+ a.testOutput.Write(out)
+ }
+ fmt.Fprintf(a.testOutput, "ok \t%s\t%s%s\n", a.p.ImportPath, t, coveragePercentage(out))
+ return nil
+ }
+
+ setExitStatus(1)
+ if len(out) > 0 {
+ a.testOutput.Write(out)
+ // assume printing the test binary's exit status is superfluous
+ } else {
+ fmt.Fprintf(a.testOutput, "%s\n", err)
+ }
+ fmt.Fprintf(a.testOutput, "FAIL\t%s\t%s\n", a.p.ImportPath, t)
+
+ return nil
+}
+
+// coveragePercentage returns the coverage results (if enabled) for the
+// test. It uncovers the data by scanning the output from the test run.
+func coveragePercentage(out []byte) string {
+ if !testCover {
+ return ""
+ }
+ // The string looks like
+ // test coverage for encoding/binary: 79.9% of statements
+ // Extract the piece from the percentage to the end of the line.
+ re := regexp.MustCompile(`coverage: (.*)\n`)
+ matches := re.FindSubmatch(out)
+ if matches == nil {
+ // Probably running "go test -cover" not "go test -cover fmt".
+ // The coverage output will appear in the output directly.
+ return ""
+ }
+ return fmt.Sprintf("\tcoverage: %s", matches[1])
+}
+
+// cleanTest is the action for cleaning up after a test.
+func (b *builder) cleanTest(a *action) error {
+ if buildWork {
+ return nil
+ }
+ run := a.deps[0]
+ testDir := filepath.Join(b.work, filepath.FromSlash(run.p.ImportPath+"/_test"))
+ os.RemoveAll(testDir)
+ return nil
+}
+
+// printTest is the action for printing a test result.
+func (b *builder) printTest(a *action) error {
+ clean := a.deps[0]
+ run := clean.deps[0]
+ os.Stdout.Write(run.testOutput.Bytes())
+ run.testOutput = nil
+ return nil
+}
+
+// notest is the action for testing a package with no test files.
+func (b *builder) notest(a *action) error {
+ fmt.Printf("? \t%s\t[no test files]\n", a.p.ImportPath)
+ return nil
+}
+
+// isTestMain tells whether fn is a TestMain(m *testing.M) function.
+func isTestMain(fn *ast.FuncDecl) bool {
+ if fn.Name.String() != "TestMain" ||
+ fn.Type.Results != nil && len(fn.Type.Results.List) > 0 ||
+ fn.Type.Params == nil ||
+ len(fn.Type.Params.List) != 1 ||
+ len(fn.Type.Params.List[0].Names) > 1 {
+ return false
+ }
+ ptr, ok := fn.Type.Params.List[0].Type.(*ast.StarExpr)
+ if !ok {
+ return false
+ }
+ // We can't easily check that the type is *testing.M
+ // because we don't know how testing has been imported,
+ // but at least check that it's *M or *something.M.
+ if name, ok := ptr.X.(*ast.Ident); ok && name.Name == "M" {
+ return true
+ }
+ if sel, ok := ptr.X.(*ast.SelectorExpr); ok && sel.Sel.Name == "M" {
+ return true
+ }
+ return false
+}
+
+// isTest tells whether name looks like a test (or benchmark, according to prefix).
+// It is a Test (say) if there is a character after Test that is not a lower-case letter.
+// We don't want TesticularCancer.
+func isTest(name, prefix string) bool {
+ if !strings.HasPrefix(name, prefix) {
+ return false
+ }
+ if len(name) == len(prefix) { // "Test" is ok
+ return true
+ }
+ rune, _ := utf8.DecodeRuneInString(name[len(prefix):])
+ return !unicode.IsLower(rune)
+}
+
+type coverInfo struct {
+ Package *Package
+ Vars map[string]*CoverVar
+}
+
+// loadTestFuncs returns the testFuncs describing the tests that will be run.
+func loadTestFuncs(ptest *Package) (*testFuncs, error) {
+ t := &testFuncs{
+ Package: ptest,
+ }
+ for _, file := range ptest.TestGoFiles {
+ if err := t.load(filepath.Join(ptest.Dir, file), "_test", &t.ImportTest, &t.NeedTest); err != nil {
+ return nil, err
+ }
+ }
+ for _, file := range ptest.XTestGoFiles {
+ if err := t.load(filepath.Join(ptest.Dir, file), "_xtest", &t.ImportXtest, &t.NeedXtest); err != nil {
+ return nil, err
+ }
+ }
+ return t, nil
+}
+
+// writeTestmain writes the _testmain.go file for t to the file named out.
+func writeTestmain(out string, t *testFuncs) error {
+ f, err := os.Create(out)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+
+ if err := testmainTmpl.Execute(f, t); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+type testFuncs struct {
+ Tests []testFunc
+ Benchmarks []testFunc
+ Examples []testFunc
+ TestMain *testFunc
+ Package *Package
+ ImportTest bool
+ NeedTest bool
+ ImportXtest bool
+ NeedXtest bool
+ Cover []coverInfo
+}
+
+func (t *testFuncs) CoverMode() string {
+ return testCoverMode
+}
+
+func (t *testFuncs) CoverEnabled() bool {
+ return testCover
+}
+
+// Covered returns a string describing which packages are being tested for coverage.
+// If the covered package is the same as the tested package, it returns the empty string.
+// Otherwise it is a comma-separated human-readable list of packages beginning with
+// " in", ready for use in the coverage message.
+func (t *testFuncs) Covered() string {
+ if testCoverPaths == nil {
+ return ""
+ }
+ return " in " + strings.Join(testCoverPaths, ", ")
+}
+
+// Tested returns the name of the package being tested.
+func (t *testFuncs) Tested() string {
+ return t.Package.Name
+}
+
+type testFunc struct {
+ Package string // imported package name (_test or _xtest)
+ Name string // function name
+ Output string // output, for examples
+}
+
+var testFileSet = token.NewFileSet()
+
+func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error {
+ f, err := parser.ParseFile(testFileSet, filename, nil, parser.ParseComments)
+ if err != nil {
+ return expandScanner(err)
+ }
+ for _, d := range f.Decls {
+ n, ok := d.(*ast.FuncDecl)
+ if !ok {
+ continue
+ }
+ if n.Recv != nil {
+ continue
+ }
+ name := n.Name.String()
+ switch {
+ case isTestMain(n):
+ if t.TestMain != nil {
+ return errors.New("multiple definitions of TestMain")
+ }
+ t.TestMain = &testFunc{pkg, name, ""}
+ *doImport, *seen = true, true
+ case isTest(name, "Test"):
+ t.Tests = append(t.Tests, testFunc{pkg, name, ""})
+ *doImport, *seen = true, true
+ case isTest(name, "Benchmark"):
+ t.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, ""})
+ *doImport, *seen = true, true
+ }
+ }
+ ex := doc.Examples(f)
+ sort.Sort(byOrder(ex))
+ for _, e := range ex {
+ *doImport = true // import test file whether executed or not
+ if e.Output == "" && !e.EmptyOutput {
+ // Don't run examples with no output.
+ continue
+ }
+ t.Examples = append(t.Examples, testFunc{pkg, "Example" + e.Name, e.Output})
+ *seen = true
+ }
+ return nil
+}
+
+type byOrder []*doc.Example
+
+func (x byOrder) Len() int { return len(x) }
+func (x byOrder) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x byOrder) Less(i, j int) bool { return x[i].Order < x[j].Order }
+
+var testmainTmpl = template.Must(template.New("main").Parse(`
+package main
+
+import (
+{{if not .TestMain}}
+ "os"
+{{end}}
+ "regexp"
+ "testing"
+
+{{if .ImportTest}}
+ {{if .NeedTest}}_test{{else}}_{{end}} {{.Package.ImportPath | printf "%q"}}
+{{end}}
+{{if .ImportXtest}}
+ {{if .NeedXtest}}_xtest{{else}}_{{end}} {{.Package.ImportPath | printf "%s_test" | printf "%q"}}
+{{end}}
+{{range $i, $p := .Cover}}
+ _cover{{$i}} {{$p.Package.ImportPath | printf "%q"}}
+{{end}}
+)
+
+var tests = []testing.InternalTest{
+{{range .Tests}}
+ {"{{.Name}}", {{.Package}}.{{.Name}}},
+{{end}}
+}
+
+var benchmarks = []testing.InternalBenchmark{
+{{range .Benchmarks}}
+ {"{{.Name}}", {{.Package}}.{{.Name}}},
+{{end}}
+}
+
+var examples = []testing.InternalExample{
+{{range .Examples}}
+ {"{{.Name}}", {{.Package}}.{{.Name}}, {{.Output | printf "%q"}}},
+{{end}}
+}
+
+var matchPat string
+var matchRe *regexp.Regexp
+
+func matchString(pat, str string) (result bool, err error) {
+ if matchRe == nil || matchPat != pat {
+ matchPat = pat
+ matchRe, err = regexp.Compile(matchPat)
+ if err != nil {
+ return
+ }
+ }
+ return matchRe.MatchString(str), nil
+}
+
+{{if .CoverEnabled}}
+
+// Only updated by init functions, so no need for atomicity.
+var (
+ coverCounters = make(map[string][]uint32)
+ coverBlocks = make(map[string][]testing.CoverBlock)
+)
+
+func init() {
+ {{range $i, $p := .Cover}}
+ {{range $file, $cover := $p.Vars}}
+ coverRegisterFile({{printf "%q" $cover.File}}, _cover{{$i}}.{{$cover.Var}}.Count[:], _cover{{$i}}.{{$cover.Var}}.Pos[:], _cover{{$i}}.{{$cover.Var}}.NumStmt[:])
+ {{end}}
+ {{end}}
+}
+
+func coverRegisterFile(fileName string, counter []uint32, pos []uint32, numStmts []uint16) {
+ if 3*len(counter) != len(pos) || len(counter) != len(numStmts) {
+ panic("coverage: mismatched sizes")
+ }
+ if coverCounters[fileName] != nil {
+ // Already registered.
+ return
+ }
+ coverCounters[fileName] = counter
+ block := make([]testing.CoverBlock, len(counter))
+ for i := range counter {
+ block[i] = testing.CoverBlock{
+ Line0: pos[3*i+0],
+ Col0: uint16(pos[3*i+2]),
+ Line1: pos[3*i+1],
+ Col1: uint16(pos[3*i+2]>>16),
+ Stmts: numStmts[i],
+ }
+ }
+ coverBlocks[fileName] = block
+}
+{{end}}
+
+func main() {
+{{if .CoverEnabled}}
+ testing.RegisterCover(testing.Cover{
+ Mode: {{printf "%q" .CoverMode}},
+ Counters: coverCounters,
+ Blocks: coverBlocks,
+ CoveredPackages: {{printf "%q" .Covered}},
+ })
+{{end}}
+ m := testing.MainStart(matchString, tests, benchmarks, examples)
+{{with .TestMain}}
+ {{.Package}}.{{.Name}}(m)
+{{else}}
+ os.Exit(m.Run())
+{{end}}
+}
+
+`))
diff --git a/libgo/go/cmd/go/testdata/cgocover/p.go b/libgo/go/cmd/go/testdata/cgocover/p.go
new file mode 100644
index 0000000000..a6a3891cd4
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/cgocover/p.go
@@ -0,0 +1,19 @@
+package p
+
+/*
+void
+f(void)
+{
+}
+*/
+import "C"
+
+var b bool
+
+func F() {
+ if b {
+ for {
+ }
+ }
+ C.f()
+}
diff --git a/libgo/go/cmd/go/testdata/cgocover/p_test.go b/libgo/go/cmd/go/testdata/cgocover/p_test.go
new file mode 100644
index 0000000000..a8f057e358
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/cgocover/p_test.go
@@ -0,0 +1,7 @@
+package p
+
+import "testing"
+
+func TestF(t *testing.T) {
+ F()
+}
diff --git a/libgo/go/go/types/testdata/expr1.src b/libgo/go/cmd/go/testdata/dep_test.go
index 8ef0aed6d2..0c53ac4f96 100644
--- a/libgo/go/go/types/testdata/expr1.src
+++ b/libgo/go/cmd/go/testdata/dep_test.go
@@ -1,7 +1,7 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// 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.
-// binary expressions
+package deps
-package expr1
+import _ "testing"
diff --git a/libgo/go/cmd/go/testdata/example1_test.go b/libgo/go/cmd/go/testdata/example1_test.go
new file mode 100644
index 0000000000..ec7092e972
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/example1_test.go
@@ -0,0 +1,23 @@
+// 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.
+
+// Make sure that go test runs Example_Z before Example_A, preserving source order.
+
+package p
+
+import "fmt"
+
+var n int
+
+func Example_Z() {
+ n++
+ fmt.Println(n)
+ // Output: 1
+}
+
+func Example_A() {
+ n++
+ fmt.Println(n)
+ // Output: 2
+}
diff --git a/libgo/go/cmd/go/testdata/example2_test.go b/libgo/go/cmd/go/testdata/example2_test.go
new file mode 100644
index 0000000000..1e0e80b80f
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/example2_test.go
@@ -0,0 +1,21 @@
+// 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.
+
+// Make sure that go test runs Example_Y before Example_B, preserving source order.
+
+package p
+
+import "fmt"
+
+func Example_Y() {
+ n++
+ fmt.Println(n)
+ // Output: 3
+}
+
+func Example_B() {
+ n++
+ fmt.Println(n)
+ // Output: 4
+}
diff --git a/libgo/go/cmd/go/testdata/generate/test1.go b/libgo/go/cmd/go/testdata/generate/test1.go
new file mode 100644
index 0000000000..1f05734f04
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/generate/test1.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.
+
+// Simple test for go generate.
+
+// We include a build tag that go generate should ignore.
+
+// +build ignore
+
+//go:generate echo Success
+
+package p
diff --git a/libgo/go/cmd/go/testdata/generate/test2.go b/libgo/go/cmd/go/testdata/generate/test2.go
new file mode 100644
index 0000000000..ef1a3d9515
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/generate/test2.go
@@ -0,0 +1,10 @@
+// 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.
+
+// Test that go generate handles command aliases.
+
+//go:generate -command run echo Now is the time
+//go:generate run for all good men
+
+package p
diff --git a/libgo/go/cmd/go/testdata/generate/test3.go b/libgo/go/cmd/go/testdata/generate/test3.go
new file mode 100644
index 0000000000..41ffb7ea87
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/generate/test3.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.
+
+// Test go generate variable substitution.
+
+//go:generate echo $GOARCH $GOFILE $GOPACKAGE xyz$GOPACKAGE/$GOFILE/123
+
+package p
diff --git a/libgo/go/cmd/go/testdata/importcom/bad.go b/libgo/go/cmd/go/testdata/importcom/bad.go
new file mode 100644
index 0000000000..e104c2e992
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/importcom/bad.go
@@ -0,0 +1,3 @@
+package p
+
+import "bad"
diff --git a/libgo/go/cmd/go/testdata/importcom/conflict.go b/libgo/go/cmd/go/testdata/importcom/conflict.go
new file mode 100644
index 0000000000..995556c511
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/importcom/conflict.go
@@ -0,0 +1,3 @@
+package p
+
+import "conflict"
diff --git a/libgo/go/cmd/go/testdata/importcom/src/bad/bad.go b/libgo/go/cmd/go/testdata/importcom/src/bad/bad.go
new file mode 100644
index 0000000000..bc51fd3fde
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/importcom/src/bad/bad.go
@@ -0,0 +1 @@
+package bad // import
diff --git a/libgo/go/cmd/go/testdata/importcom/src/conflict/a.go b/libgo/go/cmd/go/testdata/importcom/src/conflict/a.go
new file mode 100644
index 0000000000..2d67703511
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/importcom/src/conflict/a.go
@@ -0,0 +1 @@
+package conflict // import "a"
diff --git a/libgo/go/cmd/go/testdata/importcom/src/conflict/b.go b/libgo/go/cmd/go/testdata/importcom/src/conflict/b.go
new file mode 100644
index 0000000000..8fcfb3c8bd
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/importcom/src/conflict/b.go
@@ -0,0 +1 @@
+package conflict /* import "b" */
diff --git a/libgo/go/cmd/go/testdata/importcom/src/works/x/x.go b/libgo/go/cmd/go/testdata/importcom/src/works/x/x.go
new file mode 100644
index 0000000000..044c6eca80
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/importcom/src/works/x/x.go
@@ -0,0 +1 @@
+package x // import "works/x"
diff --git a/libgo/go/cmd/go/testdata/importcom/src/works/x/x1.go b/libgo/go/cmd/go/testdata/importcom/src/works/x/x1.go
new file mode 100644
index 0000000000..2449b29df5
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/importcom/src/works/x/x1.go
@@ -0,0 +1 @@
+package x // important! not an import comment
diff --git a/libgo/go/cmd/go/testdata/importcom/src/wrongplace/x.go b/libgo/go/cmd/go/testdata/importcom/src/wrongplace/x.go
new file mode 100644
index 0000000000..b89849da78
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/importcom/src/wrongplace/x.go
@@ -0,0 +1 @@
+package x // import "my/x"
diff --git a/libgo/go/cmd/go/testdata/importcom/works.go b/libgo/go/cmd/go/testdata/importcom/works.go
new file mode 100644
index 0000000000..31b55d08a3
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/importcom/works.go
@@ -0,0 +1,3 @@
+package p
+
+import _ "works/x"
diff --git a/libgo/go/cmd/go/testdata/importcom/wrongplace.go b/libgo/go/cmd/go/testdata/importcom/wrongplace.go
new file mode 100644
index 0000000000..e2535e01ae
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/importcom/wrongplace.go
@@ -0,0 +1,3 @@
+package p
+
+import "wrongplace"
diff --git a/libgo/go/cmd/go/testdata/local/easy.go b/libgo/go/cmd/go/testdata/local/easy.go
new file mode 100644
index 0000000000..4eeb517da1
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/local/easy.go
@@ -0,0 +1,7 @@
+package main
+
+import "./easysub"
+
+func main() {
+ easysub.Hello()
+}
diff --git a/libgo/go/cmd/go/testdata/local/easysub/easysub.go b/libgo/go/cmd/go/testdata/local/easysub/easysub.go
new file mode 100644
index 0000000000..07040daee5
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/local/easysub/easysub.go
@@ -0,0 +1,7 @@
+package easysub
+
+import "fmt"
+
+func Hello() {
+ fmt.Println("easysub.Hello")
+}
diff --git a/libgo/go/cmd/go/testdata/local/easysub/main.go b/libgo/go/cmd/go/testdata/local/easysub/main.go
new file mode 100644
index 0000000000..6c30b52362
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/local/easysub/main.go
@@ -0,0 +1,9 @@
+// +build ignore
+
+package main
+
+import "."
+
+func main() {
+ easysub.Hello()
+}
diff --git a/libgo/go/cmd/go/testdata/local/hard.go b/libgo/go/cmd/go/testdata/local/hard.go
new file mode 100644
index 0000000000..2ffac3fd73
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/local/hard.go
@@ -0,0 +1,7 @@
+package main
+
+import "./sub"
+
+func main() {
+ sub.Hello()
+}
diff --git a/libgo/go/cmd/go/testdata/local/sub/sub.go b/libgo/go/cmd/go/testdata/local/sub/sub.go
new file mode 100644
index 0000000000..d5dbf6d5fa
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/local/sub/sub.go
@@ -0,0 +1,12 @@
+package sub
+
+import (
+ "fmt"
+
+ subsub "./sub"
+)
+
+func Hello() {
+ fmt.Println("sub.Hello")
+ subsub.Hello()
+}
diff --git a/libgo/go/cmd/go/testdata/local/sub/sub/subsub.go b/libgo/go/cmd/go/testdata/local/sub/sub/subsub.go
new file mode 100644
index 0000000000..4cc72233e1
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/local/sub/sub/subsub.go
@@ -0,0 +1,7 @@
+package subsub
+
+import "fmt"
+
+func Hello() {
+ fmt.Println("subsub.Hello")
+}
diff --git a/libgo/go/cmd/go/testdata/norunexample/example_test.go b/libgo/go/cmd/go/testdata/norunexample/example_test.go
new file mode 100644
index 0000000000..e158305a6c
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/norunexample/example_test.go
@@ -0,0 +1,11 @@
+package pkg_test
+
+import "os"
+
+func init() {
+ os.Stdout.Write([]byte("File with non-runnable example was built.\n"))
+}
+
+func Example_test() {
+ // This test will not be run, it has no "Output:" comment.
+}
diff --git a/libgo/go/cmd/go/testdata/norunexample/test_test.go b/libgo/go/cmd/go/testdata/norunexample/test_test.go
new file mode 100644
index 0000000000..d2e919838f
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/norunexample/test_test.go
@@ -0,0 +1,10 @@
+package pkg
+
+import (
+ "os"
+ "testing"
+)
+
+func TestBuilt(t *testing.T) {
+ os.Stdout.Write([]byte("A normal test was executed.\n"))
+}
diff --git a/libgo/go/cmd/go/testdata/shadow/root1/src/foo/foo.go b/libgo/go/cmd/go/testdata/shadow/root1/src/foo/foo.go
new file mode 100644
index 0000000000..f52652b1ba
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/shadow/root1/src/foo/foo.go
@@ -0,0 +1 @@
+package foo
diff --git a/libgo/go/cmd/go/testdata/shadow/root1/src/math/math.go b/libgo/go/cmd/go/testdata/shadow/root1/src/math/math.go
new file mode 100644
index 0000000000..c91c24e967
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/shadow/root1/src/math/math.go
@@ -0,0 +1 @@
+package math
diff --git a/libgo/go/cmd/go/testdata/shadow/root2/src/foo/foo.go b/libgo/go/cmd/go/testdata/shadow/root2/src/foo/foo.go
new file mode 100644
index 0000000000..f52652b1ba
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/shadow/root2/src/foo/foo.go
@@ -0,0 +1 @@
+package foo
diff --git a/libgo/go/cmd/go/testdata/src/badc/x.go b/libgo/go/cmd/go/testdata/src/badc/x.go
new file mode 100644
index 0000000000..bfa1de28bd
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/badc/x.go
@@ -0,0 +1 @@
+package badc
diff --git a/libgo/go/cmd/go/testdata/src/badpkg/x.go b/libgo/go/cmd/go/testdata/src/badpkg/x.go
new file mode 100644
index 0000000000..dda35e8ed3
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/badpkg/x.go
@@ -0,0 +1 @@
+pkg badpkg
diff --git a/libgo/go/cmd/go/testdata/src/badtest/badexec/x_test.go b/libgo/go/cmd/go/testdata/src/badtest/badexec/x_test.go
new file mode 100644
index 0000000000..12f5051712
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/badtest/badexec/x_test.go
@@ -0,0 +1,5 @@
+package badexec
+
+func init() {
+ panic("badexec")
+}
diff --git a/libgo/go/cmd/go/testdata/src/badtest/badsyntax/x.go b/libgo/go/cmd/go/testdata/src/badtest/badsyntax/x.go
new file mode 100644
index 0000000000..c8a5407a5a
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/badtest/badsyntax/x.go
@@ -0,0 +1 @@
+package badsyntax
diff --git a/libgo/go/cmd/go/testdata/src/badtest/badsyntax/x_test.go b/libgo/go/cmd/go/testdata/src/badtest/badsyntax/x_test.go
new file mode 100644
index 0000000000..5be10745d9
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/badtest/badsyntax/x_test.go
@@ -0,0 +1,3 @@
+package badsyntax
+
+func func func func func!
diff --git a/libgo/go/cmd/go/testdata/src/badtest/badvar/x.go b/libgo/go/cmd/go/testdata/src/badtest/badvar/x.go
new file mode 100644
index 0000000000..fdd46c4c72
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/badtest/badvar/x.go
@@ -0,0 +1 @@
+package badvar
diff --git a/libgo/go/cmd/go/testdata/src/badtest/badvar/x_test.go b/libgo/go/cmd/go/testdata/src/badtest/badvar/x_test.go
new file mode 100644
index 0000000000..c67df01c5c
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/badtest/badvar/x_test.go
@@ -0,0 +1,5 @@
+package badvar_test
+
+func f() {
+ _ = notdefined
+}
diff --git a/libgo/go/cmd/go/testdata/src/cgotest/m.go b/libgo/go/cmd/go/testdata/src/cgotest/m.go
new file mode 100644
index 0000000000..4d68307cf0
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/cgotest/m.go
@@ -0,0 +1,5 @@
+package cgotest
+
+import "C"
+
+var _ C.int
diff --git a/libgo/go/cmd/go/testdata/src/go-cmd-test/helloworld.go b/libgo/go/cmd/go/testdata/src/go-cmd-test/helloworld.go
new file mode 100644
index 0000000000..002a5c740c
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/go-cmd-test/helloworld.go
@@ -0,0 +1,5 @@
+package main
+
+func main() {
+ println("hello world")
+}
diff --git a/libgo/go/cmd/go/testdata/src/main_test/m.go b/libgo/go/cmd/go/testdata/src/main_test/m.go
new file mode 100644
index 0000000000..c682f030b4
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/main_test/m.go
@@ -0,0 +1,4 @@
+package main
+
+func F() {}
+func main() {}
diff --git a/libgo/go/cmd/go/testdata/src/main_test/m_test.go b/libgo/go/cmd/go/testdata/src/main_test/m_test.go
new file mode 100644
index 0000000000..f865b7734f
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/main_test/m_test.go
@@ -0,0 +1,10 @@
+package main_test
+
+import (
+ . "main_test"
+ "testing"
+)
+
+func Test1(t *testing.T) {
+ F()
+}
diff --git a/libgo/go/cmd/go/testdata/src/notest/hello.go b/libgo/go/cmd/go/testdata/src/notest/hello.go
new file mode 100644
index 0000000000..7c42c32fb0
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/notest/hello.go
@@ -0,0 +1,6 @@
+package notest
+
+func hello() {
+ println("hello world")
+}
+Hello world
diff --git a/libgo/go/cmd/go/testdata/src/syntaxerror/x.go b/libgo/go/cmd/go/testdata/src/syntaxerror/x.go
new file mode 100644
index 0000000000..c89cd18d0f
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/syntaxerror/x.go
@@ -0,0 +1 @@
+package p
diff --git a/libgo/go/cmd/go/testdata/src/syntaxerror/x_test.go b/libgo/go/cmd/go/testdata/src/syntaxerror/x_test.go
new file mode 100644
index 0000000000..2460743e50
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/syntaxerror/x_test.go
@@ -0,0 +1,4 @@
+package p
+
+func f() (x.y, z int) {
+}
diff --git a/libgo/go/cmd/go/testdata/src/testcycle/p1/p1.go b/libgo/go/cmd/go/testdata/src/testcycle/p1/p1.go
new file mode 100644
index 0000000000..65ab76d4e1
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/testcycle/p1/p1.go
@@ -0,0 +1,7 @@
+package p1
+
+import _ "testcycle/p2"
+
+func init() {
+ println("p1 init")
+}
diff --git a/libgo/go/cmd/go/testdata/src/testcycle/p1/p1_test.go b/libgo/go/cmd/go/testdata/src/testcycle/p1/p1_test.go
new file mode 100644
index 0000000000..75abb13e6d
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/testcycle/p1/p1_test.go
@@ -0,0 +1,6 @@
+package p1
+
+import "testing"
+
+func Test(t *testing.T) {
+}
diff --git a/libgo/go/cmd/go/testdata/src/testcycle/p2/p2.go b/libgo/go/cmd/go/testdata/src/testcycle/p2/p2.go
new file mode 100644
index 0000000000..7e26cdf19c
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/testcycle/p2/p2.go
@@ -0,0 +1,7 @@
+package p2
+
+import _ "testcycle/p3"
+
+func init() {
+ println("p2 init")
+}
diff --git a/libgo/go/cmd/go/testdata/src/testcycle/p3/p3.go b/libgo/go/cmd/go/testdata/src/testcycle/p3/p3.go
new file mode 100644
index 0000000000..bb0a2f4f65
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/testcycle/p3/p3.go
@@ -0,0 +1,5 @@
+package p3
+
+func init() {
+ println("p3 init")
+}
diff --git a/libgo/go/cmd/go/testdata/src/testcycle/p3/p3_test.go b/libgo/go/cmd/go/testdata/src/testcycle/p3/p3_test.go
new file mode 100644
index 0000000000..9b4b0757f8
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/testcycle/p3/p3_test.go
@@ -0,0 +1,10 @@
+package p3
+
+import (
+ "testing"
+
+ _ "testcycle/p1"
+)
+
+func Test(t *testing.T) {
+}
diff --git a/libgo/go/cmd/go/testdata/src/vetpkg/a_test.go b/libgo/go/cmd/go/testdata/src/vetpkg/a_test.go
new file mode 100644
index 0000000000..9b64e8e1a2
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/vetpkg/a_test.go
@@ -0,0 +1 @@
+package p_test
diff --git a/libgo/go/cmd/go/testdata/src/vetpkg/b.go b/libgo/go/cmd/go/testdata/src/vetpkg/b.go
new file mode 100644
index 0000000000..99e18f63dc
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/vetpkg/b.go
@@ -0,0 +1,7 @@
+package p
+
+import "fmt"
+
+func f() {
+ fmt.Printf("%d")
+}
diff --git a/libgo/go/cmd/go/testdata/src/xtestonly/f.go b/libgo/go/cmd/go/testdata/src/xtestonly/f.go
new file mode 100644
index 0000000000..dac039e1ad
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/xtestonly/f.go
@@ -0,0 +1,3 @@
+package xtestonly
+
+func F() int { return 42 }
diff --git a/libgo/go/cmd/go/testdata/src/xtestonly/f_test.go b/libgo/go/cmd/go/testdata/src/xtestonly/f_test.go
new file mode 100644
index 0000000000..01f6e83730
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/xtestonly/f_test.go
@@ -0,0 +1,12 @@
+package xtestonly_test
+
+import (
+ "testing"
+ "xtestonly"
+)
+
+func TestF(t *testing.T) {
+ if x := xtestonly.F(); x != 42 {
+ t.Errorf("f.F() = %d, want 42", x)
+ }
+}
diff --git a/libgo/go/cmd/go/testdata/standalone_test.go b/libgo/go/cmd/go/testdata/standalone_test.go
new file mode 100644
index 0000000000..59cf918b9b
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/standalone_test.go
@@ -0,0 +1,6 @@
+package standalone_test
+
+import "testing"
+
+func Test(t *testing.T) {
+}
diff --git a/libgo/go/cmd/go/testdata/testimport/p.go b/libgo/go/cmd/go/testdata/testimport/p.go
new file mode 100644
index 0000000000..f94d2cd0e6
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/testimport/p.go
@@ -0,0 +1,3 @@
+package p
+
+func F() int { return 1 }
diff --git a/libgo/go/cmd/go/testdata/testimport/p1/p1.go b/libgo/go/cmd/go/testdata/testimport/p1/p1.go
new file mode 100644
index 0000000000..fd315272ea
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/testimport/p1/p1.go
@@ -0,0 +1,3 @@
+package p1
+
+func F() int { return 1 }
diff --git a/libgo/go/cmd/go/testdata/testimport/p2/p2.go b/libgo/go/cmd/go/testdata/testimport/p2/p2.go
new file mode 100644
index 0000000000..d4888865dd
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/testimport/p2/p2.go
@@ -0,0 +1,3 @@
+package p2
+
+func F() int { return 1 }
diff --git a/libgo/go/cmd/go/testdata/testimport/p_test.go b/libgo/go/cmd/go/testdata/testimport/p_test.go
new file mode 100644
index 0000000000..a3fb4a9e27
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/testimport/p_test.go
@@ -0,0 +1,13 @@
+package p
+
+import (
+ "./p1"
+
+ "testing"
+)
+
+func TestF(t *testing.T) {
+ if F() != p1.F() {
+ t.Fatal(F())
+ }
+}
diff --git a/libgo/go/cmd/go/testdata/testimport/x_test.go b/libgo/go/cmd/go/testdata/testimport/x_test.go
new file mode 100644
index 0000000000..b253e3fd2d
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/testimport/x_test.go
@@ -0,0 +1,15 @@
+package p_test
+
+import (
+ . "../testimport"
+
+ "./p2"
+
+ "testing"
+)
+
+func TestF1(t *testing.T) {
+ if F() != p2.F() {
+ t.Fatal(F())
+ }
+}
diff --git a/libgo/go/cmd/go/testdata/testinternal/p.go b/libgo/go/cmd/go/testdata/testinternal/p.go
new file mode 100644
index 0000000000..e3558a53b2
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/testinternal/p.go
@@ -0,0 +1,3 @@
+package p
+
+import _ "net/http/internal"
diff --git a/libgo/go/cmd/go/testdata/testinternal2/p.go b/libgo/go/cmd/go/testdata/testinternal2/p.go
new file mode 100644
index 0000000000..c594f5c5e9
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/testinternal2/p.go
@@ -0,0 +1,3 @@
+package p
+
+import _ "./x/y/z/internal/w"
diff --git a/libgo/go/cmd/go/testdata/testinternal2/x/y/z/internal/w/w.go b/libgo/go/cmd/go/testdata/testinternal2/x/y/z/internal/w/w.go
new file mode 100644
index 0000000000..a796c0b5f4
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/testinternal2/x/y/z/internal/w/w.go
@@ -0,0 +1 @@
+package w
diff --git a/libgo/go/cmd/go/testdata/testonly/p_test.go b/libgo/go/cmd/go/testdata/testonly/p_test.go
new file mode 100644
index 0000000000..c89cd18d0f
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/testonly/p_test.go
@@ -0,0 +1 @@
+package p
diff --git a/libgo/go/cmd/go/testflag.go b/libgo/go/cmd/go/testflag.go
new file mode 100644
index 0000000000..6da74b9967
--- /dev/null
+++ b/libgo/go/cmd/go/testflag.go
@@ -0,0 +1,319 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+)
+
+// The flag handling part of go test is large and distracting.
+// We can't use the flag package because some of the flags from
+// 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
+ passToTest bool // pass to Test
+ multiOK bool // OK to have multiple instances
+ present bool // flag has been seen
+}
+
+// testFlagDefn is the set of flags we process.
+var testFlagDefn = []*testFlagSpec{
+ // local.
+ {name: "c", boolVar: &testC},
+ {name: "cover", boolVar: &testCover},
+ {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: "coverprofile", passToTest: true},
+ {name: "cpu", passToTest: true},
+ {name: "cpuprofile", passToTest: true},
+ {name: "memprofile", passToTest: true},
+ {name: "memprofilerate", passToTest: true},
+ {name: "blockprofile", passToTest: true},
+ {name: "blockprofilerate", passToTest: true},
+ {name: "outputdir", passToTest: true},
+ {name: "parallel", passToTest: true},
+ {name: "run", passToTest: true},
+ {name: "short", boolVar: new(bool), passToTest: true},
+ {name: "timeout", passToTest: true},
+ {name: "v", boolVar: &testV, passToTest: true},
+}
+
+// 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
+// grabs some flags but otherwise its command line is just a holding place for
+// pkg.test's arguments.
+// We allow known flags both before and after the package name list,
+// to allow both
+// go test fmt -custom-flag-for-fmt-test
+// go test -x math
+func testFlags(args []string) (packageNames, passToTest []string) {
+ inPkg := false
+ outputDir := ""
+ for i := 0; i < len(args); i++ {
+ if !strings.HasPrefix(args[i], "-") {
+ if !inPkg && packageNames == nil {
+ // First package name we've seen.
+ inPkg = true
+ }
+ if inPkg {
+ packageNames = append(packageNames, args[i])
+ continue
+ }
+ }
+
+ if inPkg {
+ // Found an argument beginning with "-"; end of package list.
+ inPkg = false
+ }
+
+ f, value, extraWord := testFlag(args, i)
+ if f == nil {
+ // This is a flag we do not know; we must assume
+ // that any args we see after this might be flag
+ // arguments, not package names.
+ inPkg = false
+ if packageNames == nil {
+ // make non-nil: we have seen the empty package list
+ packageNames = []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 {
+ 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)
+ }
+ testCover = true
+ case "outputdir":
+ outputDir = value
+ }
+ if extraWord {
+ i++
+ }
+ if f.passToTest {
+ passToTest = append(passToTest, "-test."+f.name+"="+value)
+ }
+ }
+
+ if testCoverMode == "" {
+ testCoverMode = "set"
+ if buildRace {
+ // Default coverage mode is atomic when -race is set.
+ testCoverMode = "atomic"
+ }
+ }
+
+ // Tell the test what directory we're running in, so it can write the profiles there.
+ if testProfile && outputDir == "" {
+ dir, err := os.Getwd()
+ if err != nil {
+ fatalf("error from os.Getwd: %s", err)
+ }
+ passToTest = append(passToTest, "-test.outputdir", dir)
+ }
+ return
+}
+
+// testFlag sees if argument i is a known flag and returns its definition, value, and whether it consumed an extra word.
+func testFlag(args []string, i int) (f *testFlagSpec, value string, extra bool) {
+ arg := args[i]
+ if strings.HasPrefix(arg, "--") { // reduce two minuses to one
+ arg = arg[1:]
+ }
+ switch arg {
+ case "-?", "-h", "-help":
+ usage()
+ }
+ if arg == "" || arg[0] != '-' {
+ return
+ }
+ name := arg[1:]
+ // If there's already "test.", drop it for now.
+ name = strings.TrimPrefix(name, "test.")
+ equals := strings.Index(name, "=")
+ if equals >= 0 {
+ value = name[equals+1:]
+ name = name[:equals]
+ }
+ 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 equals < 0 { // otherwise, it's been set and will be verified in setBoolFlag
+ value = "true"
+ } else {
+ // verify it parses
+ setBoolFlag(new(bool), value)
+ }
+ } else { // Non-booleans must have a value.
+ extra = equals < 0
+ if extra {
+ if i+1 >= len(args) {
+ testSyntaxError("missing argument for flag " + f.name)
+ }
+ value = args[i+1]
+ }
+ }
+ if f.present && !f.multiOK {
+ testSyntaxError(f.name + " flag may be set only once")
+ }
+ f.present = true
+ return
+ }
+ }
+ f = nil
+ return
+}
+
+// setBoolFlag sets the addressed boolean to the value.
+func setBoolFlag(flag *bool, value string) {
+ x, err := strconv.ParseBool(value)
+ if err != nil {
+ testSyntaxError("illegal bool flag value " + value)
+ }
+ *flag = x
+}
+
+// setIntFlag sets the addressed integer to the value.
+func setIntFlag(flag *int, value string) {
+ x, err := strconv.Atoi(value)
+ if err != nil {
+ testSyntaxError("illegal int flag value " + value)
+ }
+ *flag = x
+}
+
+func testSyntaxError(msg string) {
+ fmt.Fprintf(os.Stderr, "go test: %s\n", msg)
+ fmt.Fprintf(os.Stderr, `run "go help test" or "go help testflag" for more information`+"\n")
+ os.Exit(2)
+}
diff --git a/libgo/go/cmd/go/testgo.go b/libgo/go/cmd/go/testgo.go
new file mode 100644
index 0000000000..01923f74bd
--- /dev/null
+++ b/libgo/go/cmd/go/testgo.go
@@ -0,0 +1,21 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains extra hooks for testing the go command.
+// It is compiled into the Go binary only when building the
+// test copy; it does not get compiled into the standard go
+// command, so these testing hooks are not present in the
+// go command that everyone uses.
+
+// +build testgo
+
+package main
+
+import "os"
+
+func init() {
+ if v := os.Getenv("TESTGO_IS_GO_RELEASE"); v != "" {
+ isGoRelease = v == "1"
+ }
+}
diff --git a/libgo/go/cmd/go/tool.go b/libgo/go/cmd/go/tool.go
new file mode 100644
index 0000000000..3f11c3e3d4
--- /dev/null
+++ b/libgo/go/cmd/go/tool.go
@@ -0,0 +1,146 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "go/build"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+ "sort"
+ "strings"
+)
+
+var cmdTool = &Command{
+ Run: runTool,
+ UsageLine: "tool [-n] command [args...]",
+ Short: "run specified go tool",
+ Long: `
+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'.
+`,
+}
+
+var (
+ toolGOOS = runtime.GOOS
+ toolGOARCH = runtime.GOARCH
+ toolIsWindows = toolGOOS == "windows"
+ toolDir = build.ToolDir
+
+ toolN bool
+)
+
+func init() {
+ cmdTool.Flag.BoolVar(&toolN, "n", false, "")
+}
+
+const toolWindowsExtension = ".exe"
+
+func tool(toolName string) string {
+ toolPath := filepath.Join(toolDir, toolName)
+ if toolIsWindows {
+ toolPath += toolWindowsExtension
+ }
+ // Give a nice message if there is no tool with that name.
+ if _, err := os.Stat(toolPath); err != nil {
+ if isInGoToolsRepo(toolName) {
+ fmt.Fprintf(os.Stderr, "go tool: no such tool %q; to install:\n\tgo get golang.org/x/tools/cmd/%s\n", toolName, toolName)
+ } else {
+ fmt.Fprintf(os.Stderr, "go tool: no such tool %q\n", toolName)
+ }
+ setExitStatus(3)
+ exit()
+ }
+ return toolPath
+}
+
+func isInGoToolsRepo(toolName string) bool {
+ switch toolName {
+ case "cover", "vet":
+ return true
+ }
+ return false
+}
+
+func runTool(cmd *Command, args []string) {
+ if len(args) == 0 {
+ listTools()
+ return
+ }
+ toolName := args[0]
+ // The tool name must be lower-case letters, numbers or underscores.
+ for _, c := range toolName {
+ switch {
+ case 'a' <= c && c <= 'z', '0' <= c && c <= '9', c == '_':
+ default:
+ fmt.Fprintf(os.Stderr, "go tool: bad tool name %q\n", toolName)
+ setExitStatus(2)
+ return
+ }
+ }
+ toolPath := tool(toolName)
+ if toolPath == "" {
+ return
+ }
+ if toolN {
+ fmt.Printf("%s %s\n", toolPath, strings.Join(args[1:], " "))
+ return
+ }
+ toolCmd := &exec.Cmd{
+ Path: toolPath,
+ Args: args,
+ Stdin: os.Stdin,
+ Stdout: os.Stdout,
+ Stderr: os.Stderr,
+ }
+ err := toolCmd.Run()
+ if err != nil {
+ // Only print about the exit status if the command
+ // didn't even run (not an ExitError) or it didn't exit cleanly
+ // or we're printing command lines too (-x mode).
+ // Assume if command exited cleanly (even with non-zero status)
+ // it printed any messages it wanted to print.
+ if e, ok := err.(*exec.ExitError); !ok || !e.Exited() || buildX {
+ fmt.Fprintf(os.Stderr, "go tool %s: %s\n", toolName, err)
+ }
+ setExitStatus(1)
+ return
+ }
+}
+
+// listTools prints a list of the available tools in the tools directory.
+func listTools() {
+ f, err := os.Open(toolDir)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "go tool: no tool directory: %s\n", err)
+ setExitStatus(2)
+ return
+ }
+ defer f.Close()
+ names, err := f.Readdirnames(-1)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "go tool: can't read directory: %s\n", err)
+ setExitStatus(2)
+ return
+ }
+
+ sort.Strings(names)
+ for _, name := range names {
+ // Unify presentation by going to lower case.
+ name = strings.ToLower(name)
+ // If it's windows, don't show the .exe suffix.
+ if toolIsWindows && strings.HasSuffix(name, toolWindowsExtension) {
+ name = name[:len(name)-len(toolWindowsExtension)]
+ }
+ fmt.Println(name)
+ }
+}
diff --git a/libgo/go/cmd/go/vcs.go b/libgo/go/cmd/go/vcs.go
new file mode 100644
index 0000000000..1cac613388
--- /dev/null
+++ b/libgo/go/cmd/go/vcs.go
@@ -0,0 +1,855 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bytes"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "log"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "regexp"
+ "strings"
+)
+
+// A vcsCmd describes how to use a version control system
+// like Mercurial, Git, or Subversion.
+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
+
+ 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
+
+ scheme []string
+ pingCmd string
+
+ remoteRepo func(v *vcsCmd, rootDir string) (remoteRepo string, err error)
+ resolveRepo func(v *vcsCmd, rootDir, remoteRepo string) (realRepo string, err error)
+}
+
+// A tagCmd describes a command to list available tags
+// that can be passed to tagSyncCmd.
+type tagCmd struct {
+ cmd string // command to list tags
+ pattern string // regexp to extract tags from list
+}
+
+// vcsList lists the known version control systems
+var vcsList = []*vcsCmd{
+ vcsHg,
+ vcsGit,
+ vcsSvn,
+ vcsBzr,
+}
+
+// vcsByCmd returns the version control system for the given
+// command name (hg, git, svn, bzr).
+func vcsByCmd(cmd string) *vcsCmd {
+ for _, vcs := range vcsList {
+ if vcs.cmd == cmd {
+ return vcs
+ }
+ }
+ return nil
+}
+
+// vcsHg describes how to use Mercurial.
+var vcsHg = &vcsCmd{
+ name: "Mercurial",
+ cmd: "hg",
+
+ createCmd: "clone -U {repo} {dir}",
+ downloadCmd: "pull",
+
+ // We allow both tag and branch names as 'tags'
+ // for selecting a version. This lets people have
+ // a go.release.r60 branch and a go1 branch
+ // and make changes in both, without constantly
+ // editing .hgtags.
+ tagCmd: []tagCmd{
+ {"tags", `^(\S+)`},
+ {"branches", `^(\S+)`},
+ },
+ tagSyncCmd: "update -r {tag}",
+ tagSyncDefault: "update default",
+
+ scheme: []string{"https", "http", "ssh"},
+ pingCmd: "identify {scheme}://{repo}",
+ remoteRepo: hgRemoteRepo,
+}
+
+func hgRemoteRepo(vcsHg *vcsCmd, rootDir string) (remoteRepo string, err error) {
+ out, err := vcsHg.runOutput(rootDir, "paths default")
+ if err != nil {
+ return "", err
+ }
+ return strings.TrimSpace(string(out)), nil
+}
+
+// vcsGit describes how to use Git.
+var vcsGit = &vcsCmd{
+ name: "Git",
+ cmd: "git",
+
+ createCmd: "clone {repo} {dir}",
+ downloadCmd: "pull --ff-only",
+
+ tagCmd: []tagCmd{
+ // tags/xxx matches a git tag named xxx
+ // origin/xxx matches a git branch named xxx on the default remote repository
+ {"show-ref", `(?:tags|origin)/(\S+)$`},
+ },
+ tagLookupCmd: []tagCmd{
+ {"show-ref tags/{tag} origin/{tag}", `((?:tags|origin)/\S+)$`},
+ },
+ tagSyncCmd: "checkout {tag}",
+ tagSyncDefault: "checkout master",
+
+ scheme: []string{"git", "https", "http", "git+ssh"},
+ pingCmd: "ls-remote {scheme}://{repo}",
+ remoteRepo: gitRemoteRepo,
+}
+
+func gitRemoteRepo(vcsGit *vcsCmd, rootDir string) (remoteRepo string, err error) {
+ outb, err := vcsGit.runOutput(rootDir, "remote -v")
+ if err != nil {
+ return "", err
+ }
+ out := string(outb)
+
+ // Expect:
+ // origin https://github.com/rsc/pdf (fetch)
+ // origin https://github.com/rsc/pdf (push)
+ // use first line only.
+
+ if !strings.HasPrefix(out, "origin\t") {
+ return "", fmt.Errorf("unable to parse output of git remote -v")
+ }
+ out = strings.TrimPrefix(out, "origin\t")
+ i := strings.Index(out, "\n")
+ if i < 0 {
+ return "", fmt.Errorf("unable to parse output of git remote -v")
+ }
+ out = out[:i]
+ i = strings.LastIndex(out, " ")
+ if i < 0 {
+ return "", fmt.Errorf("unable to parse output of git remote -v")
+ }
+ out = out[:i]
+ return strings.TrimSpace(string(out)), nil
+}
+
+// vcsBzr describes how to use Bazaar.
+var vcsBzr = &vcsCmd{
+ name: "Bazaar",
+ cmd: "bzr",
+
+ createCmd: "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",
+
+ tagCmd: []tagCmd{{"tags", `^(\S+)`}},
+ tagSyncCmd: "update -r {tag}",
+ tagSyncDefault: "update -r revno:-1",
+
+ scheme: []string{"https", "http", "bzr", "bzr+ssh"},
+ pingCmd: "info {scheme}://{repo}",
+ remoteRepo: bzrRemoteRepo,
+ resolveRepo: bzrResolveRepo,
+}
+
+func bzrRemoteRepo(vcsBzr *vcsCmd, rootDir string) (remoteRepo string, err error) {
+ outb, err := vcsBzr.runOutput(rootDir, "config parent_location")
+ if err != nil {
+ return "", err
+ }
+ return strings.TrimSpace(string(outb)), nil
+}
+
+func bzrResolveRepo(vcsBzr *vcsCmd, rootDir, remoteRepo string) (realRepo string, err error) {
+ outb, err := vcsBzr.runOutput(rootDir, "info "+remoteRepo)
+ if err != nil {
+ return "", err
+ }
+ out := string(outb)
+
+ // Expect:
+ // ...
+ // (branch root|repository branch): <URL>
+ // ...
+
+ found := false
+ for _, prefix := range []string{"\n branch root: ", "\n repository branch: "} {
+ i := strings.Index(out, prefix)
+ if i >= 0 {
+ out = out[i+len(prefix):]
+ found = true
+ break
+ }
+ }
+ if !found {
+ return "", fmt.Errorf("unable to parse output of bzr info")
+ }
+
+ i := strings.Index(out, "\n")
+ if i < 0 {
+ return "", fmt.Errorf("unable to parse output of bzr info")
+ }
+ out = out[:i]
+ return strings.TrimSpace(string(out)), nil
+}
+
+// vcsSvn describes how to use Subversion.
+var vcsSvn = &vcsCmd{
+ name: "Subversion",
+ cmd: "svn",
+
+ createCmd: "checkout {repo} {dir}",
+ downloadCmd: "update",
+
+ // There is no tag command in subversion.
+ // The branch information is all in the path names.
+
+ scheme: []string{"https", "http", "svn", "svn+ssh"},
+ pingCmd: "info {scheme}://{repo}",
+ remoteRepo: svnRemoteRepo,
+}
+
+func svnRemoteRepo(vcsSvn *vcsCmd, rootDir string) (remoteRepo string, err error) {
+ outb, err := vcsSvn.runOutput(rootDir, "info")
+ if err != nil {
+ return "", err
+ }
+ out := string(outb)
+
+ // Expect:
+ // ...
+ // Repository Root: <URL>
+ // ...
+
+ i := strings.Index(out, "\nRepository Root: ")
+ if i < 0 {
+ return "", fmt.Errorf("unable to parse output of svn info")
+ }
+ out = out[i+len("\nRepository Root: "):]
+ i = strings.Index(out, "\n")
+ if i < 0 {
+ return "", fmt.Errorf("unable to parse output of svn info")
+ }
+ out = out[:i]
+ return strings.TrimSpace(string(out)), nil
+}
+
+func (v *vcsCmd) String() string {
+ return v.name
+}
+
+// run runs the command line cmd in the given directory.
+// keyval is a list of key, value pairs. run expands
+// instances of {key} in cmd into value, but only after
+// splitting cmd into individual arguments.
+// If an error occurs, run prints the command line and the
+// command's combined stdout+stderr to standard error.
+// Otherwise run discards the command's output.
+func (v *vcsCmd) run(dir string, cmd string, keyval ...string) error {
+ _, err := v.run1(dir, cmd, keyval, true)
+ return err
+}
+
+// runVerboseOnly is like run but only generates error output to standard error in verbose mode.
+func (v *vcsCmd) runVerboseOnly(dir string, cmd string, keyval ...string) error {
+ _, err := v.run1(dir, cmd, keyval, false)
+ return err
+}
+
+// runOutput is like run but returns the output of the command.
+func (v *vcsCmd) runOutput(dir string, cmd string, keyval ...string) ([]byte, error) {
+ return v.run1(dir, cmd, keyval, true)
+}
+
+// run1 is the generalized implementation of run and runOutput.
+func (v *vcsCmd) run1(dir string, cmdline string, keyval []string, verbose bool) ([]byte, error) {
+ m := make(map[string]string)
+ for i := 0; i < len(keyval); i += 2 {
+ m[keyval[i]] = keyval[i+1]
+ }
+ args := strings.Fields(cmdline)
+ for i, arg := range args {
+ args[i] = expand(m, arg)
+ }
+
+ _, err := exec.LookPath(v.cmd)
+ if err != nil {
+ fmt.Fprintf(os.Stderr,
+ "go: missing %s command. See http://golang.org/s/gogetcmd\n",
+ v.name)
+ return nil, err
+ }
+
+ cmd := exec.Command(v.cmd, args...)
+ cmd.Dir = dir
+ cmd.Env = envForDir(cmd.Dir)
+ if buildX {
+ fmt.Printf("cd %s\n", dir)
+ fmt.Printf("%s %s\n", v.cmd, strings.Join(args, " "))
+ }
+ var buf bytes.Buffer
+ cmd.Stdout = &buf
+ cmd.Stderr = &buf
+ err = cmd.Run()
+ out := buf.Bytes()
+ if err != nil {
+ if verbose || buildV {
+ fmt.Fprintf(os.Stderr, "# cd %s; %s %s\n", dir, v.cmd, strings.Join(args, " "))
+ os.Stderr.Write(out)
+ }
+ return nil, err
+ }
+ return out, nil
+}
+
+// ping pings to determine scheme to use.
+func (v *vcsCmd) ping(scheme, repo string) error {
+ return v.runVerboseOnly(".", v.pingCmd, "scheme", scheme, "repo", repo)
+}
+
+// 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)
+}
+
+// download downloads any new changes for the repo in dir.
+func (v *vcsCmd) download(dir string) error {
+ if err := v.fixDetachedHead(dir); err != nil {
+ return err
+ }
+ return v.run(dir, v.downloadCmd)
+}
+
+// fixDetachedHead switches a Git repository in dir from a detached head to the master branch.
+// Go versions before 1.2 downloaded Git repositories in an unfortunate way
+// that resulted in the working tree state being on a detached head.
+// That meant the repository was not usable for normal Git operations.
+// Go 1.2 fixed that, but we can't pull into a detached head, so if this is
+// a Git repository we check for being on a detached head and switch to the
+// real branch, almost always called "master".
+// TODO(dsymonds): Consider removing this for Go 1.3.
+func (v *vcsCmd) fixDetachedHead(dir string) error {
+ if v != vcsGit {
+ return nil
+ }
+
+ // "git symbolic-ref HEAD" succeeds iff we are not on a detached head.
+ if err := v.runVerboseOnly(dir, "symbolic-ref HEAD"); err == nil {
+ // not on a detached head
+ return nil
+ }
+ if buildV {
+ log.Printf("%s on detached head; repairing", dir)
+ }
+ return v.run(dir, "checkout master")
+}
+
+// tags returns the list of available tags for the repo in dir.
+func (v *vcsCmd) tags(dir string) ([]string, error) {
+ var tags []string
+ for _, tc := range v.tagCmd {
+ out, err := v.runOutput(dir, tc.cmd)
+ if err != nil {
+ return nil, err
+ }
+ re := regexp.MustCompile(`(?m-s)` + tc.pattern)
+ for _, m := range re.FindAllStringSubmatch(string(out), -1) {
+ tags = append(tags, m[1])
+ }
+ }
+ return tags, nil
+}
+
+// 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 == "" {
+ return nil
+ }
+ if tag != "" {
+ for _, tc := range v.tagLookupCmd {
+ out, err := v.runOutput(dir, tc.cmd, "tag", tag)
+ if err != nil {
+ return err
+ }
+ re := regexp.MustCompile(`(?m-s)` + tc.pattern)
+ m := re.FindStringSubmatch(string(out))
+ if len(m) > 1 {
+ tag = m[1]
+ break
+ }
+ }
+ }
+ if tag == "" && v.tagSyncDefault != "" {
+ return v.run(dir, v.tagSyncDefault)
+ }
+ return v.run(dir, v.tagSyncCmd, "tag", tag)
+}
+
+// A vcsPath describes how to convert an import path into a
+// version control system and repository name.
+type vcsPath struct {
+ prefix string // prefix this description applies to
+ re string // pattern for import path
+ repo string // repository to use (expand with match of re)
+ vcs string // version control system to use (expand with match of re)
+ check func(match map[string]string) error // additional checks
+ ping bool // ping for scheme to use to download repo
+
+ regexp *regexp.Regexp // cached compiled form of re
+}
+
+// vcsForDir inspects dir and its parents to determine the
+// version control system and code repository to use.
+// On return, root is the import path
+// corresponding to the root of the repository
+// (thus root is a prefix of importPath).
+func vcsForDir(p *Package) (vcs *vcsCmd, root string, err error) {
+ // Clean and double-check that dir is in (a subdirectory of) srcRoot.
+ dir := filepath.Clean(p.Dir)
+ srcRoot := filepath.Clean(p.build.SrcRoot)
+ if len(dir) <= len(srcRoot) || dir[len(srcRoot)] != filepath.Separator {
+ return nil, "", fmt.Errorf("directory %q is outside source root %q", dir, srcRoot)
+ }
+
+ origDir := dir
+ for len(dir) > len(srcRoot) {
+ for _, vcs := range vcsList {
+ if fi, err := os.Stat(filepath.Join(dir, "."+vcs.cmd)); err == nil && fi.IsDir() {
+ return vcs, dir[len(srcRoot)+1:], nil
+ }
+ }
+
+ // Move to parent.
+ ndir := filepath.Dir(dir)
+ if len(ndir) >= len(dir) {
+ // Shouldn't happen, but just in case, stop.
+ break
+ }
+ dir = ndir
+ }
+
+ return nil, "", fmt.Errorf("directory %q is not using a known version control system", origDir)
+}
+
+// repoRoot represents a version control system, a repo, and a root of
+// where to put it on disk.
+type repoRoot struct {
+ vcs *vcsCmd
+
+ // repo is the repository URL, including scheme
+ repo string
+
+ // root is the import path corresponding to the root of the
+ // repository
+ root string
+}
+
+var httpPrefixRE = regexp.MustCompile(`^https?:`)
+
+// repoRootForImportPath analyzes importPath to determine the
+// version control system, and code repository to use.
+func repoRootForImportPath(importPath string) (*repoRoot, error) {
+ rr, err := repoRootForImportPathStatic(importPath, "")
+ if err == errUnknownSite {
+ // If there are wildcards, look up the thing before the wildcard,
+ // hoping it applies to the wildcarded parts too.
+ // This makes 'go get rsc.io/pdf/...' work in a fresh GOPATH.
+ lookup := strings.TrimSuffix(importPath, "/...")
+ if i := strings.Index(lookup, "/.../"); i >= 0 {
+ lookup = lookup[:i]
+ }
+ rr, err = repoRootForImportDynamic(lookup)
+
+ // repoRootForImportDynamic returns error detail
+ // that is irrelevant if the user didn't intend to use a
+ // dynamic import in the first place.
+ // Squelch it.
+ if err != nil {
+ if buildV {
+ log.Printf("import %q: %v", importPath, err)
+ }
+ err = fmt.Errorf("unrecognized import path %q", importPath)
+ }
+ }
+
+ if err == nil && strings.Contains(importPath, "...") && strings.Contains(rr.root, "...") {
+ // Do not allow wildcards in the repo root.
+ rr = nil
+ err = fmt.Errorf("cannot expand ... in %q", importPath)
+ }
+ return rr, err
+}
+
+var errUnknownSite = errors.New("dynamic lookup required to find mapping")
+
+// repoRootForImportPathStatic attempts to map importPath to a
+// repoRoot using the commonly-used VCS hosting sites in vcsPaths
+// (github.com/user/dir), or from a fully-qualified importPath already
+// containing its VCS type (foo.com/repo.git/dir)
+//
+// If scheme is non-empty, that scheme is forced.
+func repoRootForImportPathStatic(importPath, scheme string) (*repoRoot, error) {
+ // 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 {
+ // The importPath has been cleaned, so has only one slash. The pattern
+ // ignores the slashes; the error message puts them back on the RHS at least.
+ return nil, fmt.Errorf("%q not allowed in import path", importPath[loc[0]:loc[1]]+"//")
+ }
+ for _, srv := range vcsPaths {
+ if !strings.HasPrefix(importPath, srv.prefix) {
+ continue
+ }
+ m := srv.regexp.FindStringSubmatch(importPath)
+ if m == nil {
+ if srv.prefix != "" {
+ return nil, fmt.Errorf("invalid %s import path %q", srv.prefix, importPath)
+ }
+ continue
+ }
+
+ // Build map of named subexpression matches for expand.
+ match := map[string]string{
+ "prefix": srv.prefix,
+ "import": importPath,
+ }
+ for i, name := range srv.regexp.SubexpNames() {
+ if name != "" && match[name] == "" {
+ match[name] = m[i]
+ }
+ }
+ if srv.vcs != "" {
+ match["vcs"] = expand(match, srv.vcs)
+ }
+ if srv.repo != "" {
+ match["repo"] = expand(match, srv.repo)
+ }
+ if srv.check != nil {
+ if err := srv.check(match); err != nil {
+ return nil, err
+ }
+ }
+ vcs := vcsByCmd(match["vcs"])
+ if vcs == nil {
+ return nil, fmt.Errorf("unknown version control system %q", match["vcs"])
+ }
+ if srv.ping {
+ if scheme != "" {
+ match["repo"] = scheme + "://" + match["repo"]
+ } else {
+ for _, scheme := range vcs.scheme {
+ if vcs.ping(scheme, match["repo"]) == nil {
+ match["repo"] = scheme + "://" + match["repo"]
+ break
+ }
+ }
+ }
+ }
+ rr := &repoRoot{
+ vcs: vcs,
+ repo: match["repo"],
+ root: match["root"],
+ }
+ return rr, nil
+ }
+ return nil, errUnknownSite
+}
+
+// repoRootForImportDynamic finds a *repoRoot for a custom domain that's not
+// statically known by repoRootForImportPathStatic.
+//
+// This handles "vanity import paths" like "name.tld/pkg/foo".
+func repoRootForImportDynamic(importPath string) (*repoRoot, error) {
+ slash := strings.Index(importPath, "/")
+ if slash < 0 {
+ return nil, errors.New("import path does not contain a slash")
+ }
+ host := importPath[:slash]
+ if !strings.Contains(host, ".") {
+ return nil, errors.New("import path does not begin with hostname")
+ }
+ urlStr, body, err := httpsOrHTTP(importPath)
+ if err != nil {
+ return nil, fmt.Errorf("http/https fetch: %v", 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)
+ if err != nil {
+ if err != errNoMatch {
+ return nil, fmt.Errorf("parse %s: %v", urlStr, err)
+ }
+ return nil, fmt.Errorf("parse %s: no go-import meta tags", urlStr)
+ }
+ if buildV {
+ log.Printf("get %q: found meta tag %#v at %s", importPath, metaImport, urlStr)
+ }
+ // If the import was "uni.edu/bob/project", which said the
+ // prefix was "uni.edu" and the RepoRoot was "evilroot.com",
+ // make sure we don't trust Bob and check out evilroot.com to
+ // "uni.edu" yet (possibly overwriting/preempting another
+ // non-evil student). Instead, first verify the root and see
+ // if it matches Bob's claim.
+ if metaImport.Prefix != importPath {
+ if buildV {
+ log.Printf("get %q: verifying non-authoritative meta tag", importPath)
+ }
+ urlStr0 := urlStr
+ urlStr, body, err = httpsOrHTTP(metaImport.Prefix)
+ if err != nil {
+ return nil, fmt.Errorf("fetch %s: %v", urlStr, err)
+ }
+ imports, 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)
+ }
+ metaImport2, err := matchGoImport(imports, importPath)
+ if err != nil || metaImport != metaImport2 {
+ return nil, fmt.Errorf("%s and %s disagree about go-import for %s", urlStr0, urlStr, metaImport.Prefix)
+ }
+ }
+
+ if !strings.Contains(metaImport.RepoRoot, "://") {
+ return nil, fmt.Errorf("%s: invalid repo root %q; no scheme", urlStr, metaImport.RepoRoot)
+ }
+ rr := &repoRoot{
+ vcs: vcsByCmd(metaImport.VCS),
+ repo: metaImport.RepoRoot,
+ root: metaImport.Prefix,
+ }
+ if rr.vcs == nil {
+ return nil, fmt.Errorf("%s: unknown vcs %q", urlStr, metaImport.VCS)
+ }
+ return rr, nil
+}
+
+// metaImport represents the parsed <meta name="go-import"
+// content="prefix vcs reporoot" /> tags from HTML files.
+type metaImport struct {
+ Prefix, VCS, RepoRoot string
+}
+
+// errNoMatch is returned from matchGoImport when there's no applicable match.
+var errNoMatch = errors.New("no import match")
+
+// matchGoImport returns the metaImport from imports matching importPath.
+// An error is returned if there are multiple matches.
+// errNoMatch is returned if none match.
+func matchGoImport(imports []metaImport, importPath string) (_ metaImport, err error) {
+ match := -1
+ for i, im := range imports {
+ if !strings.HasPrefix(importPath, im.Prefix) {
+ continue
+ }
+ if match != -1 {
+ err = fmt.Errorf("multiple meta tags match import path %q", importPath)
+ return
+ }
+ match = i
+ }
+ if match == -1 {
+ err = errNoMatch
+ return
+ }
+ return imports[match], nil
+}
+
+// expand rewrites s to replace {k} with match[k] for each key k in match.
+func expand(match map[string]string, s string) string {
+ for k, v := range match {
+ s = strings.Replace(s, "{"+k+"}", v, -1)
+ }
+ return s
+}
+
+// vcsPaths lists the known vcs paths.
+var vcsPaths = []*vcsPath{
+ // Google Code - new syntax
+ {
+ prefix: "code.google.com/",
+ re: `^(?P<root>code\.google\.com/p/(?P<project>[a-z0-9\-]+)(\.(?P<subrepo>[a-z0-9\-]+))?)(/[A-Za-z0-9_.\-]+)*$`,
+ repo: "https://{root}",
+ check: googleCodeVCS,
+ },
+
+ // Google Code - old syntax
+ {
+ re: `^(?P<project>[a-z0-9_\-.]+)\.googlecode\.com/(git|hg|svn)(?P<path>/.*)?$`,
+ check: oldGoogleCode,
+ },
+
+ // Github
+ {
+ prefix: "github.com/",
+ re: `^(?P<root>github\.com/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`,
+ vcs: "git",
+ repo: "https://{root}",
+ check: noVCSSuffix,
+ },
+
+ // Bitbucket
+ {
+ prefix: "bitbucket.org/",
+ re: `^(?P<root>bitbucket\.org/(?P<bitname>[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`,
+ repo: "https://{root}",
+ check: bitbucketVCS,
+ },
+
+ // Launchpad
+ {
+ prefix: "launchpad.net/",
+ re: `^(?P<root>launchpad\.net/((?P<project>[A-Za-z0-9_.\-]+)(?P<series>/[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",
+ re: `^(?P<root>hub.jazz.net/git/[a-z0-9]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`,
+ vcs: "git",
+ repo: "https://{root}",
+ check: noVCSSuffix,
+ },
+
+ // General syntax for any server.
+ {
+ re: `^(?P<root>(?P<repo>([a-z0-9.\-]+\.)+[a-z0-9.\-]+(:[0-9]+)?/[A-Za-z0-9_.\-/]*?)\.(?P<vcs>bzr|git|hg|svn))(/[A-Za-z0-9_.\-]+)*$`,
+ ping: true,
+ },
+}
+
+func init() {
+ // fill in cached regexps.
+ // Doing this eagerly discovers invalid regexp syntax
+ // without having to run a command that needs that regexp.
+ for _, srv := range vcsPaths {
+ srv.regexp = regexp.MustCompile(srv.re)
+ }
+}
+
+// noVCSSuffix checks that the repository name does not
+// end in .foo for any version control system foo.
+// The usual culprit is ".git".
+func noVCSSuffix(match map[string]string) error {
+ repo := match["repo"]
+ for _, vcs := range vcsList {
+ if strings.HasSuffix(repo, "."+vcs.cmd) {
+ return fmt.Errorf("invalid version control suffix in %s path", match["prefix"])
+ }
+ }
+ return nil
+}
+
+var googleCheckout = regexp.MustCompile(`id="checkoutcmd">(hg|git|svn)`)
+
+// googleCodeVCS determines the version control system for
+// a code.google.com repository, by scraping the project's
+// /source/checkout page.
+func googleCodeVCS(match map[string]string) error {
+ if err := noVCSSuffix(match); err != nil {
+ return err
+ }
+ data, err := httpGET(expand(match, "https://code.google.com/p/{project}/source/checkout?repo={subrepo}"))
+ if err != nil {
+ return err
+ }
+
+ if m := googleCheckout.FindSubmatch(data); m != nil {
+ if vcs := vcsByCmd(string(m[1])); vcs != nil {
+ // Subversion requires the old URLs.
+ // TODO: Test.
+ if vcs == vcsSvn {
+ if match["subrepo"] != "" {
+ return fmt.Errorf("sub-repositories not supported in Google Code Subversion projects")
+ }
+ match["repo"] = expand(match, "https://{project}.googlecode.com/svn")
+ }
+ match["vcs"] = vcs.cmd
+ return nil
+ }
+ }
+
+ return fmt.Errorf("unable to detect version control system for code.google.com/ path")
+}
+
+// oldGoogleCode is invoked for old-style foo.googlecode.com paths.
+// It prints an error giving the equivalent new path.
+func oldGoogleCode(match map[string]string) error {
+ return fmt.Errorf("invalid Google Code import path: use %s instead",
+ expand(match, "code.google.com/p/{project}{path}"))
+}
+
+// bitbucketVCS determines the version control system for a
+// Bitbucket repository, by using the Bitbucket API.
+func bitbucketVCS(match map[string]string) error {
+ if err := noVCSSuffix(match); err != nil {
+ return err
+ }
+
+ var resp struct {
+ SCM string `json:"scm"`
+ }
+ 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 vcsByCmd(resp.SCM) != nil {
+ match["vcs"] = resp.SCM
+ if resp.SCM == "git" {
+ match["repo"] += ".git"
+ }
+ return nil
+ }
+
+ return fmt.Errorf("unable to detect version control system for bitbucket.org/ path")
+}
+
+// launchpadVCS solves the ambiguity for "lp.net/project/foo". In this case,
+// "foo" could be a series name registered in Launchpad with its own branch,
+// and it could also be the name of a directory within the main project
+// branch one level up.
+func launchpadVCS(match map[string]string) error {
+ if match["project"] == "" || match["series"] == "" {
+ return nil
+ }
+ _, err := httpGET(expand(match, "https://code.launchpad.net/{project}{series}/.bzr/branch-format"))
+ if err != nil {
+ match["root"] = expand(match, "launchpad.net/{project}")
+ match["repo"] = expand(match, "https://{root}")
+ }
+ return nil
+}
diff --git a/libgo/go/cmd/go/vcs_test.go b/libgo/go/cmd/go/vcs_test.go
new file mode 100644
index 0000000000..14d681ba6a
--- /dev/null
+++ b/libgo/go/cmd/go/vcs_test.go
@@ -0,0 +1,124 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "runtime"
+ "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)
+ }
+ tests := []struct {
+ path string
+ want *repoRoot
+ }{
+ {
+ "code.google.com/p/go",
+ &repoRoot{
+ vcs: vcsHg,
+ repo: "https://code.google.com/p/go",
+ },
+ },
+ /*{
+ "code.google.com/r/go",
+ &repoRoot{
+ vcs: vcsHg,
+ repo: "https://code.google.com/r/go",
+ },
+ },*/
+ {
+ "github.com/golang/groupcache",
+ &repoRoot{
+ vcs: vcsGit,
+ repo: "https://github.com/golang/groupcache",
+ },
+ },
+ // IBM DevOps Services tests
+ {
+ "hub.jazz.net/git/user1/pkgname",
+ &repoRoot{
+ vcs: vcsGit,
+ repo: "https://hub.jazz.net/git/user1/pkgname",
+ },
+ },
+ {
+ "hub.jazz.net/git/user1/pkgname/submodule/submodule/submodule",
+ &repoRoot{
+ vcs: vcsGit,
+ repo: "https://hub.jazz.net/git/user1/pkgname",
+ },
+ },
+ {
+ "hub.jazz.net",
+ nil,
+ },
+ {
+ "hub2.jazz.net",
+ nil,
+ },
+ {
+ "hub.jazz.net/someotherprefix",
+ nil,
+ },
+ {
+ "hub.jazz.net/someotherprefix/user1/pkgname",
+ nil,
+ },
+ // Spaces are not valid in user names or package names
+ {
+ "hub.jazz.net/git/User 1/pkgname",
+ nil,
+ },
+ {
+ "hub.jazz.net/git/user1/pkg name",
+ nil,
+ },
+ // Dots are not valid in user names
+ {
+ "hub.jazz.net/git/user.1/pkgname",
+ nil,
+ },
+ {
+ "hub.jazz.net/git/user/pkg.name",
+ &repoRoot{
+ vcs: vcsGit,
+ repo: "https://hub.jazz.net/git/user/pkg.name",
+ },
+ },
+ // User names cannot have uppercase letters
+ {
+ "hub.jazz.net/git/USER/pkgname",
+ nil,
+ },
+ }
+
+ for _, test := range tests {
+ got, err := repoRootForImportPath(test.path)
+ want := test.want
+
+ if want == nil {
+ if err == nil {
+ t.Errorf("RepoRootForImport(%q): Error expected but not received", test.path)
+ }
+ continue
+ }
+ if err != nil {
+ t.Errorf("RepoRootForImport(%q): %v", test.path, err)
+ continue
+ }
+ if got.vcs.name != want.vcs.name || got.repo != want.repo {
+ t.Errorf("RepoRootForImport(%q) = VCS(%s) Repo(%s), want VCS(%s) Repo(%s)", test.path, got.vcs, got.repo, want.vcs, want.repo)
+ }
+ }
+}
diff --git a/libgo/go/cmd/go/version.go b/libgo/go/cmd/go/version.go
new file mode 100644
index 0000000000..a41f4a7361
--- /dev/null
+++ b/libgo/go/cmd/go/version.go
@@ -0,0 +1,25 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "runtime"
+)
+
+var cmdVersion = &Command{
+ Run: runVersion,
+ UsageLine: "version",
+ Short: "print Go version",
+ Long: `Version prints the Go version, as reported by runtime.Version.`,
+}
+
+func runVersion(cmd *Command, args []string) {
+ if len(args) != 0 {
+ cmd.Usage()
+ }
+
+ fmt.Printf("go version %s %s/%s\n", runtime.Version(), runtime.GOOS, runtime.GOARCH)
+}
diff --git a/libgo/go/cmd/go/vet.go b/libgo/go/cmd/go/vet.go
new file mode 100644
index 0000000000..02ff54b2ac
--- /dev/null
+++ b/libgo/go/cmd/go/vet.go
@@ -0,0 +1,50 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "path/filepath"
+
+func init() {
+ addBuildFlagsNX(cmdVet)
+}
+
+var cmdVet = &Command{
+ Run: runVet,
+ UsageLine: "vet [-n] [-x] [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 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.
+ `,
+}
+
+func runVet(cmd *Command, args []string) {
+ for _, p := range packages(args) {
+ // Vet expects to be given a set of files all from the same package.
+ // Run once for package p and once for package p_test.
+ if len(p.GoFiles)+len(p.CgoFiles)+len(p.TestGoFiles) > 0 {
+ runVetFiles(p, stringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.SFiles))
+ }
+ if len(p.XTestGoFiles) > 0 {
+ runVetFiles(p, stringList(p.XTestGoFiles))
+ }
+ }
+}
+
+func runVetFiles(p *Package, files []string) {
+ for i := range files {
+ files[i] = filepath.Join(p.Dir, files[i])
+ }
+ run(tool("vet"), relPaths(files))
+}
diff --git a/libgo/go/cmd/gofmt/doc.go b/libgo/go/cmd/gofmt/doc.go
new file mode 100644
index 0000000000..3fc0439548
--- /dev/null
+++ b/libgo/go/cmd/gofmt/doc.go
@@ -0,0 +1,93 @@
+// 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.
+
+/*
+Gofmt formats Go programs.
+It uses tabs (width = 8) for indentation and blanks for alignment.
+
+Without an explicit path, it processes the standard input. Given a file,
+it operates on that file; given a directory, it operates on all .go files in
+that directory, recursively. (Files starting with a period are ignored.)
+By default, gofmt prints the reformatted sources to standard output.
+
+Usage:
+ gofmt [flags] [path ...]
+
+The flags are:
+ -d
+ Do not print reformatted sources to standard output.
+ If a file's formatting is different than gofmt's, print diffs
+ to standard output.
+ -e
+ Print all (including spurious) errors.
+ -l
+ Do not print reformatted sources to standard output.
+ If a file's formatting is different from gofmt's, print its name
+ to standard output.
+ -r rule
+ Apply the rewrite rule to the source before reformatting.
+ -s
+ Try to simplify code (after applying the rewrite rule, if any).
+ -w
+ Do not print reformatted sources to standard output.
+ If a file's formatting is different from gofmt's, overwrite it
+ with gofmt's version.
+
+Debugging support:
+ -cpuprofile filename
+ Write cpu profile to the specified file.
+
+
+The rewrite rule specified with the -r flag must be a string of the form:
+
+ pattern -> replacement
+
+Both pattern and replacement must be valid Go expressions.
+In the pattern, single-character lowercase identifiers serve as
+wildcards matching arbitrary sub-expressions; those expressions
+will be substituted for the same identifiers in the replacement.
+
+When gofmt reads from standard input, it accepts either a full Go program
+or a program fragment. A program fragment must be a syntactically
+valid declaration list, statement list, or expression. When formatting
+such a fragment, gofmt preserves leading indentation as well as leading
+and trailing spaces, so that individual sections of a Go program can be
+formatted by piping them through gofmt.
+
+Examples
+
+To check files for unnecessary parentheses:
+
+ gofmt -r '(a) -> a' -l *.go
+
+To remove the parentheses:
+
+ gofmt -r '(a) -> a' -w *.go
+
+To convert the package tree from explicit slice upper bounds to implicit ones:
+
+ gofmt -r 'α[β:len(α)] -> α[β:]' -w $GOROOT/src
+
+The simplify command
+
+When invoked with -s gofmt will make the following source transformations where possible.
+
+ An array, slice, or map composite literal of the form:
+ []T{T{}, T{}}
+ will be simplified to:
+ []T{{}, {}}
+
+ A slice expression of the form:
+ s[a:len(s)]
+ will be simplified to:
+ s[a:]
+
+ A range of the form:
+ for x, _ = range v {...}
+ will be simplified to:
+ for x = range v {...}
+*/
+package main
+
+// BUG(rsc): The implementation of -r is a bit slow.
diff --git a/libgo/go/cmd/gofmt/gofmt.go b/libgo/go/cmd/gofmt/gofmt.go
new file mode 100644
index 0000000000..81da21ff10
--- /dev/null
+++ b/libgo/go/cmd/gofmt/gofmt.go
@@ -0,0 +1,387 @@
+// 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 main
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/printer"
+ "go/scanner"
+ "go/token"
+ "io"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime/pprof"
+ "strings"
+)
+
+var (
+ // main operation modes
+ list = flag.Bool("l", false, "list files whose formatting differs from gofmt's")
+ write = flag.Bool("w", false, "write result to (source) file instead of stdout")
+ rewriteRule = flag.String("r", "", "rewrite rule (e.g., 'a[b:len(a)] -> a[b:]')")
+ simplifyAST = flag.Bool("s", false, "simplify code")
+ doDiff = flag.Bool("d", false, "display diffs instead of rewriting files")
+ allErrors = flag.Bool("e", false, "report all errors (not just the first 10 on different lines)")
+
+ // debugging
+ cpuprofile = flag.String("cpuprofile", "", "write cpu profile to this file")
+)
+
+const (
+ tabWidth = 8
+ printerMode = printer.UseSpaces | printer.TabIndent
+)
+
+var (
+ fileSet = token.NewFileSet() // per process FileSet
+ exitCode = 0
+ rewrite func(*ast.File) *ast.File
+ parserMode parser.Mode
+)
+
+func report(err error) {
+ scanner.PrintError(os.Stderr, err)
+ exitCode = 2
+}
+
+func usage() {
+ fmt.Fprintf(os.Stderr, "usage: gofmt [flags] [path ...]\n")
+ flag.PrintDefaults()
+ os.Exit(2)
+}
+
+func initParserMode() {
+ parserMode = parser.ParseComments
+ if *allErrors {
+ parserMode |= parser.AllErrors
+ }
+}
+
+func isGoFile(f os.FileInfo) bool {
+ // ignore non-Go files
+ name := f.Name()
+ return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
+}
+
+// If in == nil, the source is the contents of the file with the given filename.
+func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error {
+ if in == nil {
+ f, err := os.Open(filename)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ in = f
+ }
+
+ src, err := ioutil.ReadAll(in)
+ if err != nil {
+ return err
+ }
+
+ file, sourceAdj, indentAdj, err := parse(fileSet, filename, src, stdin)
+ if err != nil {
+ return err
+ }
+
+ if rewrite != nil {
+ if sourceAdj == nil {
+ file = rewrite(file)
+ } else {
+ fmt.Fprintf(os.Stderr, "warning: rewrite ignored for incomplete programs\n")
+ }
+ }
+
+ ast.SortImports(fileSet, file)
+
+ if *simplifyAST {
+ simplify(file)
+ }
+
+ res, err := format(fileSet, file, sourceAdj, indentAdj, src, printer.Config{Mode: printerMode, Tabwidth: tabWidth})
+ if err != nil {
+ return err
+ }
+
+ if !bytes.Equal(src, res) {
+ // formatting has changed
+ if *list {
+ fmt.Fprintln(out, filename)
+ }
+ if *write {
+ err = ioutil.WriteFile(filename, res, 0644)
+ if err != nil {
+ return err
+ }
+ }
+ if *doDiff {
+ data, err := diff(src, res)
+ if err != nil {
+ return fmt.Errorf("computing diff: %s", err)
+ }
+ fmt.Printf("diff %s gofmt/%s\n", filename, filename)
+ out.Write(data)
+ }
+ }
+
+ if !*list && !*write && !*doDiff {
+ _, err = out.Write(res)
+ }
+
+ return err
+}
+
+func visitFile(path string, f os.FileInfo, err error) error {
+ if err == nil && isGoFile(f) {
+ err = processFile(path, nil, os.Stdout, false)
+ }
+ if err != nil {
+ report(err)
+ }
+ return nil
+}
+
+func walkDir(path string) {
+ filepath.Walk(path, visitFile)
+}
+
+func main() {
+ // call gofmtMain in a separate function
+ // so that it can use defer and have them
+ // run before the exit.
+ gofmtMain()
+ os.Exit(exitCode)
+}
+
+func gofmtMain() {
+ flag.Usage = usage
+ flag.Parse()
+
+ if *cpuprofile != "" {
+ f, err := os.Create(*cpuprofile)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "creating cpu profile: %s\n", err)
+ exitCode = 2
+ return
+ }
+ defer f.Close()
+ pprof.StartCPUProfile(f)
+ defer pprof.StopCPUProfile()
+ }
+
+ initParserMode()
+ initRewrite()
+
+ if flag.NArg() == 0 {
+ if *write {
+ fmt.Fprintln(os.Stderr, "error: cannot use -w with standard input")
+ exitCode = 2
+ return
+ }
+ if err := processFile("<standard input>", os.Stdin, os.Stdout, true); err != nil {
+ report(err)
+ }
+ return
+ }
+
+ for i := 0; i < flag.NArg(); i++ {
+ path := flag.Arg(i)
+ switch dir, err := os.Stat(path); {
+ case err != nil:
+ report(err)
+ case dir.IsDir():
+ walkDir(path)
+ default:
+ if err := processFile(path, nil, os.Stdout, false); err != nil {
+ report(err)
+ }
+ }
+ }
+}
+
+func diff(b1, b2 []byte) (data []byte, err error) {
+ f1, err := ioutil.TempFile("", "gofmt")
+ if err != nil {
+ return
+ }
+ defer os.Remove(f1.Name())
+ defer f1.Close()
+
+ f2, err := ioutil.TempFile("", "gofmt")
+ if err != nil {
+ return
+ }
+ defer os.Remove(f2.Name())
+ defer f2.Close()
+
+ f1.Write(b1)
+ f2.Write(b2)
+
+ data, err = exec.Command("diff", "-u", f1.Name(), f2.Name()).CombinedOutput()
+ if len(data) > 0 {
+ // diff exits with a non-zero status when the files don't match.
+ // Ignore that failure as long as we get output.
+ err = nil
+ }
+ 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/gofmt_test.go b/libgo/go/cmd/gofmt/gofmt_test.go
new file mode 100644
index 0000000000..d1edb7bcc1
--- /dev/null
+++ b/libgo/go/cmd/gofmt/gofmt_test.go
@@ -0,0 +1,173 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bytes"
+ "flag"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+ "text/scanner"
+)
+
+var update = flag.Bool("update", false, "update .golden files")
+
+// gofmtFlags looks for a comment of the form
+//
+// //gofmt flags
+//
+// within the first maxLines lines of the given file,
+// and returns the flags string, if any. Otherwise it
+// returns the empty string.
+func gofmtFlags(filename string, maxLines int) string {
+ f, err := os.Open(filename)
+ if err != nil {
+ return "" // ignore errors - they will be found later
+ }
+ defer f.Close()
+
+ // initialize scanner
+ var s scanner.Scanner
+ s.Init(f)
+ s.Error = func(*scanner.Scanner, string) {} // ignore errors
+ s.Mode = scanner.GoTokens &^ scanner.SkipComments // want comments
+
+ // look for //gofmt comment
+ for s.Line <= maxLines {
+ switch s.Scan() {
+ case scanner.Comment:
+ const prefix = "//gofmt "
+ if t := s.TokenText(); strings.HasPrefix(t, prefix) {
+ return strings.TrimSpace(t[len(prefix):])
+ }
+ case scanner.EOF:
+ return ""
+ }
+
+ }
+
+ return ""
+}
+
+func runTest(t *testing.T, in, out string) {
+ // process flags
+ *simplifyAST = false
+ *rewriteRule = ""
+ stdin := false
+ for _, flag := range strings.Split(gofmtFlags(in, 20), " ") {
+ elts := strings.SplitN(flag, "=", 2)
+ name := elts[0]
+ value := ""
+ if len(elts) == 2 {
+ value = elts[1]
+ }
+ switch name {
+ case "":
+ // no flags
+ case "-r":
+ *rewriteRule = value
+ case "-s":
+ *simplifyAST = true
+ case "-stdin":
+ // fake flag - pretend input is from stdin
+ stdin = true
+ default:
+ t.Errorf("unrecognized flag name: %s", name)
+ }
+ }
+
+ initParserMode()
+ initRewrite()
+
+ var buf bytes.Buffer
+ err := processFile(in, nil, &buf, stdin)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ expected, err := ioutil.ReadFile(out)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ if got := buf.Bytes(); !bytes.Equal(got, expected) {
+ if *update {
+ if in != out {
+ if err := ioutil.WriteFile(out, got, 0666); err != nil {
+ t.Error(err)
+ }
+ return
+ }
+ // in == out: don't accidentally destroy input
+ t.Errorf("WARNING: -update did not rewrite input file %s", in)
+ }
+
+ t.Errorf("(gofmt %s) != %s (see %s.gofmt)", in, out, in)
+ d, err := diff(expected, got)
+ if err == nil {
+ t.Errorf("%s", d)
+ }
+ if err := ioutil.WriteFile(in+".gofmt", got, 0666); err != nil {
+ t.Error(err)
+ }
+ }
+}
+
+// TestRewrite processes testdata/*.input files and compares them to the
+// corresponding testdata/*.golden files. The gofmt flags used to process
+// a file must be provided via a comment of the form
+//
+// //gofmt flags
+//
+// in the processed file within the first 20 lines, if any.
+func TestRewrite(t *testing.T) {
+ // determine input files
+ match, err := filepath.Glob("testdata/*.input")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // add larger examples
+ match = append(match, "gofmt.go", "gofmt_test.go")
+
+ for _, in := range match {
+ out := in // for files where input and output are identical
+ if strings.HasSuffix(in, ".input") {
+ out = in[:len(in)-len(".input")] + ".golden"
+ }
+ runTest(t, in, out)
+ if in != out {
+ // Check idempotence.
+ runTest(t, out, out)
+ }
+ }
+}
+
+// Test case for issue 3961.
+func TestCRLF(t *testing.T) {
+ const input = "testdata/crlf.input" // must contain CR/LF's
+ const golden = "testdata/crlf.golden" // must not contain any CR's
+
+ data, err := ioutil.ReadFile(input)
+ if err != nil {
+ t.Error(err)
+ }
+ if bytes.Index(data, []byte("\r\n")) < 0 {
+ t.Errorf("%s contains no CR/LF's", input)
+ }
+
+ data, err = ioutil.ReadFile(golden)
+ if err != nil {
+ t.Error(err)
+ }
+ if bytes.Index(data, []byte("\r")) >= 0 {
+ t.Errorf("%s contains CR's", golden)
+ }
+}
diff --git a/libgo/go/cmd/gofmt/long_test.go b/libgo/go/cmd/gofmt/long_test.go
new file mode 100644
index 0000000000..237b86021b
--- /dev/null
+++ b/libgo/go/cmd/gofmt/long_test.go
@@ -0,0 +1,159 @@
+// 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 test applies gofmt to all Go files under -root.
+// To test specific files provide a list of comma-separated
+// filenames via the -files flag: go test -files=gofmt.go .
+
+package main
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "go/ast"
+ "go/printer"
+ "go/token"
+ "io"
+ "os"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "testing"
+)
+
+var (
+ root = flag.String("root", runtime.GOROOT(), "test root directory")
+ files = flag.String("files", "", "comma-separated list of files to test")
+ ngo = flag.Int("n", runtime.NumCPU(), "number of goroutines used")
+ verbose = flag.Bool("verbose", false, "verbose mode")
+ nfiles int // number of files processed
+)
+
+func gofmt(fset *token.FileSet, filename string, src *bytes.Buffer) error {
+ f, _, _, err := parse(fset, filename, src.Bytes(), false)
+ if err != nil {
+ return err
+ }
+ ast.SortImports(fset, f)
+ src.Reset()
+ return (&printer.Config{Mode: printerMode, Tabwidth: tabWidth}).Fprint(src, fset, f)
+}
+
+func testFile(t *testing.T, b1, b2 *bytes.Buffer, filename string) {
+ // open file
+ f, err := os.Open(filename)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ // read file
+ b1.Reset()
+ _, err = io.Copy(b1, f)
+ f.Close()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ // exclude files w/ syntax errors (typically test cases)
+ fset := token.NewFileSet()
+ if _, _, _, err = parse(fset, filename, b1.Bytes(), false); err != nil {
+ if *verbose {
+ fmt.Fprintf(os.Stderr, "ignoring %s\n", err)
+ }
+ return
+ }
+
+ // gofmt file
+ if err = gofmt(fset, filename, b1); err != nil {
+ t.Errorf("1st gofmt failed: %v", err)
+ return
+ }
+
+ // make a copy of the result
+ b2.Reset()
+ b2.Write(b1.Bytes())
+
+ // gofmt result again
+ if err = gofmt(fset, filename, b2); err != nil {
+ t.Errorf("2nd gofmt failed: %v", err)
+ return
+ }
+
+ // the first and 2nd result should be identical
+ if !bytes.Equal(b1.Bytes(), b2.Bytes()) {
+ t.Errorf("gofmt %s not idempotent", filename)
+ }
+}
+
+func testFiles(t *testing.T, filenames <-chan string, done chan<- int) {
+ b1 := new(bytes.Buffer)
+ b2 := new(bytes.Buffer)
+ for filename := range filenames {
+ testFile(t, b1, b2, filename)
+ }
+ done <- 0
+}
+
+func genFilenames(t *testing.T, filenames chan<- string) {
+ defer close(filenames)
+
+ handleFile := func(filename string, fi os.FileInfo, err error) error {
+ if err != nil {
+ t.Error(err)
+ return nil
+ }
+ if isGoFile(fi) {
+ filenames <- filename
+ nfiles++
+ }
+ return nil
+ }
+
+ // test Go files provided via -files, if any
+ if *files != "" {
+ for _, filename := range strings.Split(*files, ",") {
+ fi, err := os.Stat(filename)
+ handleFile(filename, fi, err)
+ }
+ return // ignore files under -root
+ }
+
+ // otherwise, test all Go files under *root
+ filepath.Walk(*root, handleFile)
+}
+
+func TestAll(t *testing.T) {
+ if testing.Short() {
+ return
+ }
+
+ if *ngo < 1 {
+ *ngo = 1 // make sure test is run
+ }
+ if *verbose {
+ fmt.Printf("running test using %d goroutines\n", *ngo)
+ }
+
+ // generate filenames
+ filenames := make(chan string, 32)
+ go genFilenames(t, filenames)
+
+ // launch test goroutines
+ done := make(chan int)
+ for i := 0; i < *ngo; i++ {
+ go testFiles(t, filenames, done)
+ }
+
+ // wait for all test goroutines to complete
+ for i := 0; i < *ngo; i++ {
+ <-done
+ }
+
+ if *verbose {
+ fmt.Printf("processed %d files\n", nfiles)
+ }
+}
diff --git a/libgo/go/cmd/gofmt/rewrite.go b/libgo/go/cmd/gofmt/rewrite.go
new file mode 100644
index 0000000000..d267cfcc1d
--- /dev/null
+++ b/libgo/go/cmd/gofmt/rewrite.go
@@ -0,0 +1,303 @@
+// 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 main
+
+import (
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "os"
+ "reflect"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+)
+
+func initRewrite() {
+ if *rewriteRule == "" {
+ rewrite = nil // disable any previous rewrite
+ return
+ }
+ f := strings.Split(*rewriteRule, "->")
+ if len(f) != 2 {
+ fmt.Fprintf(os.Stderr, "rewrite rule must be of the form 'pattern -> replacement'\n")
+ os.Exit(2)
+ }
+ pattern := parseExpr(f[0], "pattern")
+ replace := parseExpr(f[1], "replacement")
+ rewrite = func(p *ast.File) *ast.File { return rewriteFile(pattern, replace, p) }
+}
+
+// parseExpr parses s as an expression.
+// It might make sense to expand this to allow statement patterns,
+// but there are problems with preserving formatting and also
+// with what a wildcard for a statement looks like.
+func parseExpr(s, what string) ast.Expr {
+ x, err := parser.ParseExpr(s)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "parsing %s %s at %s\n", what, s, err)
+ os.Exit(2)
+ }
+ return x
+}
+
+// Keep this function for debugging.
+/*
+func dump(msg string, val reflect.Value) {
+ fmt.Printf("%s:\n", msg)
+ ast.Print(fileSet, val.Interface())
+ fmt.Println()
+}
+*/
+
+// rewriteFile applies the rewrite rule 'pattern -> replace' to an entire file.
+func rewriteFile(pattern, replace ast.Expr, p *ast.File) *ast.File {
+ cmap := ast.NewCommentMap(fileSet, p, p.Comments)
+ m := make(map[string]reflect.Value)
+ pat := reflect.ValueOf(pattern)
+ repl := reflect.ValueOf(replace)
+
+ var rewriteVal func(val reflect.Value) reflect.Value
+ rewriteVal = func(val reflect.Value) reflect.Value {
+ // don't bother if val is invalid to start with
+ if !val.IsValid() {
+ return reflect.Value{}
+ }
+ for k := range m {
+ delete(m, k)
+ }
+ val = apply(rewriteVal, val)
+ if match(m, pat, val) {
+ val = subst(m, repl, reflect.ValueOf(val.Interface().(ast.Node).Pos()))
+ }
+ return val
+ }
+
+ r := apply(rewriteVal, reflect.ValueOf(p)).Interface().(*ast.File)
+ r.Comments = cmap.Filter(r).Comments() // recreate comments list
+ return r
+}
+
+// set is a wrapper for x.Set(y); it protects the caller from panics if x cannot be changed to y.
+func set(x, y reflect.Value) {
+ // don't bother if x cannot be set or y is invalid
+ if !x.CanSet() || !y.IsValid() {
+ return
+ }
+ defer func() {
+ if x := recover(); x != nil {
+ if s, ok := x.(string); ok &&
+ (strings.Contains(s, "type mismatch") || strings.Contains(s, "not assignable")) {
+ // x cannot be set to y - ignore this rewrite
+ return
+ }
+ panic(x)
+ }
+ }()
+ x.Set(y)
+}
+
+// Values/types for special cases.
+var (
+ objectPtrNil = reflect.ValueOf((*ast.Object)(nil))
+ scopePtrNil = reflect.ValueOf((*ast.Scope)(nil))
+
+ identType = reflect.TypeOf((*ast.Ident)(nil))
+ objectPtrType = reflect.TypeOf((*ast.Object)(nil))
+ positionType = reflect.TypeOf(token.NoPos)
+ callExprType = reflect.TypeOf((*ast.CallExpr)(nil))
+ scopePtrType = reflect.TypeOf((*ast.Scope)(nil))
+)
+
+// apply replaces each AST field x in val with f(x), returning val.
+// To avoid extra conversions, f operates on the reflect.Value form.
+func apply(f func(reflect.Value) reflect.Value, val reflect.Value) reflect.Value {
+ if !val.IsValid() {
+ return reflect.Value{}
+ }
+
+ // *ast.Objects introduce cycles and are likely incorrect after
+ // rewrite; don't follow them but replace with nil instead
+ if val.Type() == objectPtrType {
+ return objectPtrNil
+ }
+
+ // similarly for scopes: they are likely incorrect after a rewrite;
+ // replace them with nil
+ if val.Type() == scopePtrType {
+ return scopePtrNil
+ }
+
+ switch v := reflect.Indirect(val); v.Kind() {
+ case reflect.Slice:
+ for i := 0; i < v.Len(); i++ {
+ e := v.Index(i)
+ set(e, f(e))
+ }
+ case reflect.Struct:
+ for i := 0; i < v.NumField(); i++ {
+ e := v.Field(i)
+ set(e, f(e))
+ }
+ case reflect.Interface:
+ e := v.Elem()
+ set(v, f(e))
+ }
+ return val
+}
+
+func isWildcard(s string) bool {
+ rune, size := utf8.DecodeRuneInString(s)
+ return size == len(s) && unicode.IsLower(rune)
+}
+
+// match returns true if 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 {
+ // Wildcard matches any expression. If it appears multiple
+ // times in the pattern, it must match the same expression
+ // each time.
+ if m != nil && pattern.IsValid() && pattern.Type() == identType {
+ name := pattern.Interface().(*ast.Ident).Name
+ if isWildcard(name) && val.IsValid() {
+ // wildcards only match valid (non-nil) expressions.
+ if _, ok := val.Interface().(ast.Expr); ok && !val.IsNil() {
+ if old, ok := m[name]; ok {
+ return match(nil, old, val)
+ }
+ m[name] = val
+ return true
+ }
+ }
+ }
+
+ // Otherwise, pattern and val must match recursively.
+ if !pattern.IsValid() || !val.IsValid() {
+ return !pattern.IsValid() && !val.IsValid()
+ }
+ if pattern.Type() != val.Type() {
+ return false
+ }
+
+ // Special cases.
+ switch pattern.Type() {
+ case identType:
+ // For identifiers, only the names need to match
+ // (and none of the other *ast.Object information).
+ // This is a common case, handle it all here instead
+ // of recursing down any further via reflection.
+ p := pattern.Interface().(*ast.Ident)
+ v := val.Interface().(*ast.Ident)
+ return p == nil && v == nil || p != nil && v != nil && p.Name == v.Name
+ case objectPtrType, positionType:
+ // object pointers and token positions always match
+ return true
+ case callExprType:
+ // For calls, the Ellipsis fields (token.Position) must
+ // match since that is how f(x) and f(x...) are different.
+ // Check them here but fall through for the remaining fields.
+ p := pattern.Interface().(*ast.CallExpr)
+ v := val.Interface().(*ast.CallExpr)
+ if p.Ellipsis.IsValid() != v.Ellipsis.IsValid() {
+ return false
+ }
+ }
+
+ p := reflect.Indirect(pattern)
+ v := reflect.Indirect(val)
+ if !p.IsValid() || !v.IsValid() {
+ return !p.IsValid() && !v.IsValid()
+ }
+
+ switch p.Kind() {
+ case reflect.Slice:
+ if p.Len() != v.Len() {
+ return false
+ }
+ for i := 0; i < p.Len(); i++ {
+ if !match(m, p.Index(i), v.Index(i)) {
+ return false
+ }
+ }
+ return true
+
+ case reflect.Struct:
+ for i := 0; i < p.NumField(); i++ {
+ if !match(m, p.Field(i), v.Field(i)) {
+ return false
+ }
+ }
+ return true
+
+ case reflect.Interface:
+ return match(m, p.Elem(), v.Elem())
+ }
+
+ // Handle token integers, etc.
+ return p.Interface() == v.Interface()
+}
+
+// subst returns a copy of pattern with values from m substituted in place
+// of wildcards and pos used as the position of tokens from the pattern.
+// if m == nil, subst returns a copy of pattern and doesn't change the line
+// number information.
+func subst(m map[string]reflect.Value, pattern reflect.Value, pos reflect.Value) reflect.Value {
+ if !pattern.IsValid() {
+ return reflect.Value{}
+ }
+
+ // Wildcard gets replaced with map value.
+ if m != nil && pattern.Type() == identType {
+ name := pattern.Interface().(*ast.Ident).Name
+ if isWildcard(name) {
+ if old, ok := m[name]; ok {
+ return subst(nil, old, reflect.Value{})
+ }
+ }
+ }
+
+ if pos.IsValid() && pattern.Type() == positionType {
+ // use new position only if old position was valid in the first place
+ if old := pattern.Interface().(token.Pos); !old.IsValid() {
+ return pattern
+ }
+ return pos
+ }
+
+ // Otherwise copy.
+ switch p := pattern; p.Kind() {
+ case reflect.Slice:
+ v := reflect.MakeSlice(p.Type(), p.Len(), p.Len())
+ for i := 0; i < p.Len(); i++ {
+ v.Index(i).Set(subst(m, p.Index(i), pos))
+ }
+ return v
+
+ case reflect.Struct:
+ v := reflect.New(p.Type()).Elem()
+ for i := 0; i < p.NumField(); i++ {
+ v.Field(i).Set(subst(m, p.Field(i), pos))
+ }
+ return v
+
+ case reflect.Ptr:
+ v := reflect.New(p.Type()).Elem()
+ if elem := p.Elem(); elem.IsValid() {
+ v.Set(subst(m, elem, pos).Addr())
+ }
+ return v
+
+ case reflect.Interface:
+ v := reflect.New(p.Type()).Elem()
+ if elem := p.Elem(); elem.IsValid() {
+ v.Set(subst(m, elem, pos))
+ }
+ return v
+ }
+
+ return pattern
+}
diff --git a/libgo/go/cmd/gofmt/simplify.go b/libgo/go/cmd/gofmt/simplify.go
new file mode 100644
index 0000000000..69f7bf23c0
--- /dev/null
+++ b/libgo/go/cmd/gofmt/simplify.go
@@ -0,0 +1,161 @@
+// 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 main
+
+import (
+ "go/ast"
+ "go/token"
+ "reflect"
+)
+
+type simplifier struct {
+ hasDotImport bool // package file contains: import . "some/import/path"
+}
+
+func (s *simplifier) Visit(node ast.Node) ast.Visitor {
+ switch n := node.(type) {
+ case *ast.CompositeLit:
+ // array, slice, and map composite literals may be simplified
+ outer := n
+ var eltType ast.Expr
+ switch typ := outer.Type.(type) {
+ case *ast.ArrayType:
+ eltType = typ.Elt
+ case *ast.MapType:
+ eltType = typ.Value
+ }
+
+ if eltType != nil {
+ typ := reflect.ValueOf(eltType)
+ for i, x := range outer.Elts {
+ px := &outer.Elts[i]
+ // look at value of indexed/named elements
+ if t, ok := x.(*ast.KeyValueExpr); ok {
+ x = t.Value
+ px = &t.Value
+ }
+ ast.Walk(s, x) // simplify x
+ // if the element is a composite literal and its literal type
+ // matches the outer literal's element type exactly, the inner
+ // literal type may be omitted
+ if inner, ok := x.(*ast.CompositeLit); ok {
+ if match(nil, typ, reflect.ValueOf(inner.Type)) {
+ inner.Type = nil
+ }
+ }
+ // if the outer literal's element type is a pointer type *T
+ // and the element is & of a composite literal of type T,
+ // the inner &T may be omitted.
+ if ptr, ok := eltType.(*ast.StarExpr); ok {
+ if addr, ok := x.(*ast.UnaryExpr); ok && addr.Op == token.AND {
+ if inner, ok := addr.X.(*ast.CompositeLit); ok {
+ if match(nil, reflect.ValueOf(ptr.X), reflect.ValueOf(inner.Type)) {
+ inner.Type = nil // drop T
+ *px = inner // drop &
+ }
+ }
+ }
+ }
+ }
+
+ // node was simplified - stop walk (there are no subnodes to simplify)
+ return nil
+ }
+
+ case *ast.SliceExpr:
+ // a slice expression of the form: s[a:len(s)]
+ // can be simplified to: s[a:]
+ // if s is "simple enough" (for now we only accept identifiers)
+ if n.Max != nil || s.hasDotImport {
+ // - 3-index slices always require the 2nd and 3rd index
+ // - if dot imports are present, we cannot be certain that an
+ // unresolved "len" identifier refers to the predefined len()
+ break
+ }
+ if s, _ := n.X.(*ast.Ident); s != nil && s.Obj != nil {
+ // the array/slice object is a single, resolved identifier
+ if call, _ := n.High.(*ast.CallExpr); call != nil && len(call.Args) == 1 && !call.Ellipsis.IsValid() {
+ // the high expression is a function call with a single argument
+ if fun, _ := call.Fun.(*ast.Ident); fun != nil && fun.Name == "len" && fun.Obj == nil {
+ // the function called is "len" and it is not locally defined; and
+ // because we don't have dot imports, it must be the predefined len()
+ if arg, _ := call.Args[0].(*ast.Ident); arg != nil && arg.Obj == s.Obj {
+ // the len argument is the array/slice object
+ n.High = nil
+ }
+ }
+ }
+ }
+ // Note: We could also simplify slice expressions of the form s[0:b] to s[:b]
+ // but we leave them as is since sometimes we want to be very explicit
+ // about the lower bound.
+ // An example where the 0 helps:
+ // x, y, z := b[0:2], b[2:4], b[4:6]
+ // An example where it does not:
+ // x, y := b[:n], b[n:]
+
+ case *ast.RangeStmt:
+ // - a range of the form: for x, _ = range v {...}
+ // can be simplified to: for x = range v {...}
+ // - a range of the form: for _ = range v {...}
+ // can be simplified to: for range v {...}
+ if isBlank(n.Value) {
+ n.Value = nil
+ }
+ if isBlank(n.Key) && n.Value == nil {
+ n.Key = nil
+ }
+ }
+
+ return s
+}
+
+func isBlank(x ast.Expr) bool {
+ ident, ok := x.(*ast.Ident)
+ return ok && ident.Name == "_"
+}
+
+func simplify(f *ast.File) {
+ var s simplifier
+
+ // determine if f contains dot imports
+ for _, imp := range f.Imports {
+ if imp.Name != nil && imp.Name.Name == "." {
+ s.hasDotImport = true
+ break
+ }
+ }
+
+ // remove empty declarations such as "const ()", etc
+ removeEmptyDeclGroups(f)
+
+ ast.Walk(&s, f)
+}
+
+func removeEmptyDeclGroups(f *ast.File) {
+ i := 0
+ for _, d := range f.Decls {
+ if g, ok := d.(*ast.GenDecl); !ok || !isEmpty(f, g) {
+ f.Decls[i] = d
+ i++
+ }
+ }
+ f.Decls = f.Decls[:i]
+}
+
+func isEmpty(f *ast.File, g *ast.GenDecl) bool {
+ if g.Doc != nil || g.Specs != nil {
+ return false
+ }
+
+ for _, c := range f.Comments {
+ // if there is a comment in the declaration, it is not considered empty
+ if g.Pos() <= c.Pos() && c.End() <= g.End() {
+ return false
+ }
+ }
+
+ return true
+}
diff --git a/libgo/go/cmd/gofmt/testdata/comments.golden b/libgo/go/cmd/gofmt/testdata/comments.golden
new file mode 100644
index 0000000000..ad6bcafafa
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/comments.golden
@@ -0,0 +1,9 @@
+package main
+
+func main() {}
+
+// comment here
+
+func f() {}
+
+//line foo.go:1
diff --git a/libgo/go/cmd/gofmt/testdata/comments.input b/libgo/go/cmd/gofmt/testdata/comments.input
new file mode 100644
index 0000000000..ad6bcafafa
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/comments.input
@@ -0,0 +1,9 @@
+package main
+
+func main() {}
+
+// comment here
+
+func f() {}
+
+//line foo.go:1
diff --git a/libgo/go/cmd/gofmt/testdata/composites.golden b/libgo/go/cmd/gofmt/testdata/composites.golden
new file mode 100644
index 0000000000..fc9c98e625
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/composites.golden
@@ -0,0 +1,204 @@
+//gofmt -s
+
+package P
+
+type T struct {
+ x, y int
+}
+
+var _ = [42]T{
+ {},
+ {1, 2},
+ {3, 4},
+}
+
+var _ = [...]T{
+ {},
+ {1, 2},
+ {3, 4},
+}
+
+var _ = []T{
+ {},
+ {1, 2},
+ {3, 4},
+}
+
+var _ = []T{
+ {},
+ 10: {1, 2},
+ 20: {3, 4},
+}
+
+var _ = []struct {
+ x, y int
+}{
+ {},
+ 10: {1, 2},
+ 20: {3, 4},
+}
+
+var _ = []interface{}{
+ T{},
+ 10: T{1, 2},
+ 20: T{3, 4},
+}
+
+var _ = [][]int{
+ {},
+ {1, 2},
+ {3, 4},
+}
+
+var _ = [][]int{
+ ([]int{}),
+ ([]int{1, 2}),
+ {3, 4},
+}
+
+var _ = [][][]int{
+ {},
+ {
+ {},
+ {0, 1, 2, 3},
+ {4, 5},
+ },
+}
+
+var _ = map[string]T{
+ "foo": {},
+ "bar": {1, 2},
+ "bal": {3, 4},
+}
+
+var _ = map[string]struct {
+ x, y int
+}{
+ "foo": {},
+ "bar": {1, 2},
+ "bal": {3, 4},
+}
+
+var _ = map[string]interface{}{
+ "foo": T{},
+ "bar": T{1, 2},
+ "bal": T{3, 4},
+}
+
+var _ = map[string][]int{
+ "foo": {},
+ "bar": {1, 2},
+ "bal": {3, 4},
+}
+
+var _ = map[string][]int{
+ "foo": ([]int{}),
+ "bar": ([]int{1, 2}),
+ "bal": {3, 4},
+}
+
+// from exp/4s/data.go
+var pieces4 = []Piece{
+ {0, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
+ {1, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
+ {2, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
+ {3, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
+}
+
+var _ = [42]*T{
+ {},
+ {1, 2},
+ {3, 4},
+}
+
+var _ = [...]*T{
+ {},
+ {1, 2},
+ {3, 4},
+}
+
+var _ = []*T{
+ {},
+ {1, 2},
+ {3, 4},
+}
+
+var _ = []*T{
+ {},
+ 10: {1, 2},
+ 20: {3, 4},
+}
+
+var _ = []*struct {
+ x, y int
+}{
+ {},
+ 10: {1, 2},
+ 20: {3, 4},
+}
+
+var _ = []interface{}{
+ &T{},
+ 10: &T{1, 2},
+ 20: &T{3, 4},
+}
+
+var _ = []*[]int{
+ {},
+ {1, 2},
+ {3, 4},
+}
+
+var _ = []*[]int{
+ (&[]int{}),
+ (&[]int{1, 2}),
+ {3, 4},
+}
+
+var _ = []*[]*[]int{
+ {},
+ {
+ {},
+ {0, 1, 2, 3},
+ {4, 5},
+ },
+}
+
+var _ = map[string]*T{
+ "foo": {},
+ "bar": {1, 2},
+ "bal": {3, 4},
+}
+
+var _ = map[string]*struct {
+ x, y int
+}{
+ "foo": {},
+ "bar": {1, 2},
+ "bal": {3, 4},
+}
+
+var _ = map[string]interface{}{
+ "foo": &T{},
+ "bar": &T{1, 2},
+ "bal": &T{3, 4},
+}
+
+var _ = map[string]*[]int{
+ "foo": {},
+ "bar": {1, 2},
+ "bal": {3, 4},
+}
+
+var _ = map[string]*[]int{
+ "foo": (&[]int{}),
+ "bar": (&[]int{1, 2}),
+ "bal": {3, 4},
+}
+
+var pieces4 = []*Piece{
+ {0, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
+ {1, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
+ {2, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
+ {3, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
+}
diff --git a/libgo/go/cmd/gofmt/testdata/composites.input b/libgo/go/cmd/gofmt/testdata/composites.input
new file mode 100644
index 0000000000..fc7598af99
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/composites.input
@@ -0,0 +1,204 @@
+//gofmt -s
+
+package P
+
+type T struct {
+ x, y int
+}
+
+var _ = [42]T{
+ T{},
+ T{1, 2},
+ T{3, 4},
+}
+
+var _ = [...]T{
+ T{},
+ T{1, 2},
+ T{3, 4},
+}
+
+var _ = []T{
+ T{},
+ T{1, 2},
+ T{3, 4},
+}
+
+var _ = []T{
+ T{},
+ 10: T{1, 2},
+ 20: T{3, 4},
+}
+
+var _ = []struct {
+ x, y int
+}{
+ struct{ x, y int }{},
+ 10: struct{ x, y int }{1, 2},
+ 20: struct{ x, y int }{3, 4},
+}
+
+var _ = []interface{}{
+ T{},
+ 10: T{1, 2},
+ 20: T{3, 4},
+}
+
+var _ = [][]int{
+ []int{},
+ []int{1, 2},
+ []int{3, 4},
+}
+
+var _ = [][]int{
+ ([]int{}),
+ ([]int{1, 2}),
+ []int{3, 4},
+}
+
+var _ = [][][]int{
+ [][]int{},
+ [][]int{
+ []int{},
+ []int{0, 1, 2, 3},
+ []int{4, 5},
+ },
+}
+
+var _ = map[string]T{
+ "foo": T{},
+ "bar": T{1, 2},
+ "bal": T{3, 4},
+}
+
+var _ = map[string]struct {
+ x, y int
+}{
+ "foo": struct{ x, y int }{},
+ "bar": struct{ x, y int }{1, 2},
+ "bal": struct{ x, y int }{3, 4},
+}
+
+var _ = map[string]interface{}{
+ "foo": T{},
+ "bar": T{1, 2},
+ "bal": T{3, 4},
+}
+
+var _ = map[string][]int{
+ "foo": []int{},
+ "bar": []int{1, 2},
+ "bal": []int{3, 4},
+}
+
+var _ = map[string][]int{
+ "foo": ([]int{}),
+ "bar": ([]int{1, 2}),
+ "bal": []int{3, 4},
+}
+
+// from exp/4s/data.go
+var pieces4 = []Piece{
+ Piece{0, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
+ Piece{1, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
+ Piece{2, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
+ Piece{3, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
+}
+
+var _ = [42]*T{
+ &T{},
+ &T{1, 2},
+ &T{3, 4},
+}
+
+var _ = [...]*T{
+ &T{},
+ &T{1, 2},
+ &T{3, 4},
+}
+
+var _ = []*T{
+ &T{},
+ &T{1, 2},
+ &T{3, 4},
+}
+
+var _ = []*T{
+ &T{},
+ 10: &T{1, 2},
+ 20: &T{3, 4},
+}
+
+var _ = []*struct {
+ x, y int
+}{
+ &struct{ x, y int }{},
+ 10: &struct{ x, y int }{1, 2},
+ 20: &struct{ x, y int }{3, 4},
+}
+
+var _ = []interface{}{
+ &T{},
+ 10: &T{1, 2},
+ 20: &T{3, 4},
+}
+
+var _ = []*[]int{
+ &[]int{},
+ &[]int{1, 2},
+ &[]int{3, 4},
+}
+
+var _ = []*[]int{
+ (&[]int{}),
+ (&[]int{1, 2}),
+ &[]int{3, 4},
+}
+
+var _ = []*[]*[]int{
+ &[]*[]int{},
+ &[]*[]int{
+ &[]int{},
+ &[]int{0, 1, 2, 3},
+ &[]int{4, 5},
+ },
+}
+
+var _ = map[string]*T{
+ "foo": &T{},
+ "bar": &T{1, 2},
+ "bal": &T{3, 4},
+}
+
+var _ = map[string]*struct {
+ x, y int
+}{
+ "foo": &struct{ x, y int }{},
+ "bar": &struct{ x, y int }{1, 2},
+ "bal": &struct{ x, y int }{3, 4},
+}
+
+var _ = map[string]interface{}{
+ "foo": &T{},
+ "bar": &T{1, 2},
+ "bal": &T{3, 4},
+}
+
+var _ = map[string]*[]int{
+ "foo": &[]int{},
+ "bar": &[]int{1, 2},
+ "bal": &[]int{3, 4},
+}
+
+var _ = map[string]*[]int{
+ "foo": (&[]int{}),
+ "bar": (&[]int{1, 2}),
+ "bal": &[]int{3, 4},
+}
+
+var pieces4 = []*Piece{
+ &Piece{0, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
+ &Piece{1, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
+ &Piece{2, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
+ &Piece{3, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
+}
diff --git a/libgo/go/cmd/gofmt/testdata/crlf.golden b/libgo/go/cmd/gofmt/testdata/crlf.golden
new file mode 100644
index 0000000000..193dbacc72
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/crlf.golden
@@ -0,0 +1,13 @@
+/*
+ Source containing CR/LF line endings.
+ The gofmt'ed output must only have LF
+ line endings.
+ Test case for issue 3961.
+*/
+package main
+
+func main() {
+ // line comment
+ println("hello, world!") // another line comment
+ println()
+}
diff --git a/libgo/go/cmd/gofmt/testdata/crlf.input b/libgo/go/cmd/gofmt/testdata/crlf.input
new file mode 100644
index 0000000000..ae7e14dbf1
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/crlf.input
@@ -0,0 +1,13 @@
+/*
+ Source containing CR/LF line endings.
+ The gofmt'ed output must only have LF
+ line endings.
+ Test case for issue 3961.
+*/
+package main
+
+func main() {
+ // line comment
+ println("hello, world!") // another line comment
+ println()
+}
diff --git a/libgo/go/cmd/gofmt/testdata/import.golden b/libgo/go/cmd/gofmt/testdata/import.golden
new file mode 100644
index 0000000000..51d7be79df
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/import.golden
@@ -0,0 +1,126 @@
+package main
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "log"
+ "math"
+)
+
+import (
+ "fmt"
+
+ "math"
+
+ "log"
+
+ "errors"
+
+ "io"
+)
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "log"
+ "math"
+
+ "fmt"
+
+ "math"
+
+ "log"
+
+ "errors"
+
+ "io"
+)
+
+import (
+ // a block with comments
+ "errors"
+ "fmt" // for Printf
+ "io" // for Reader
+ "log" // for Fatal
+ "math"
+)
+
+import (
+ "fmt" // for Printf
+
+ "math"
+
+ "log" // for Fatal
+
+ "errors"
+
+ "io" // for Reader
+)
+
+import (
+ // for Printf
+ "fmt"
+
+ "math"
+
+ // for Fatal
+ "log"
+
+ "errors"
+
+ // for Reader
+ "io"
+)
+
+import (
+ "errors"
+ "fmt" // for Printf
+ "io" // for Reader
+ "log" // for Fatal
+ "math"
+
+ "fmt" // for Printf
+
+ "math"
+
+ "log" // for Fatal
+
+ "errors"
+
+ "io" // for Reader
+)
+
+import (
+ "fmt" // for Printf
+
+ "errors"
+ "io" // for Reader
+ "log" // for Fatal
+ "math"
+
+ "errors"
+ "fmt" // for Printf
+ "io" // for Reader
+ "log" // for Fatal
+ "math"
+)
+
+// Test deduping and extended sorting
+import (
+ a "A" // aA
+ b "A" // bA1
+ b "A" // bA2
+ "B" // B
+ . "B" // .B
+ _ "B" // _b
+ "C"
+ a "D" // aD
+)
+
+import (
+ "dedup_by_group"
+
+ "dedup_by_group"
+)
diff --git a/libgo/go/cmd/gofmt/testdata/import.input b/libgo/go/cmd/gofmt/testdata/import.input
new file mode 100644
index 0000000000..9a4b09dbf9
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/import.input
@@ -0,0 +1,131 @@
+package main
+
+import (
+ "fmt"
+ "math"
+ "log"
+ "errors"
+ "io"
+)
+
+import (
+ "fmt"
+
+ "math"
+
+ "log"
+
+ "errors"
+
+ "io"
+)
+
+import (
+ "fmt"
+ "math"
+ "log"
+ "errors"
+ "io"
+
+ "fmt"
+
+ "math"
+
+ "log"
+
+ "errors"
+
+ "io"
+)
+
+import (
+ // a block with comments
+ "fmt" // for Printf
+ "math"
+ "log" // for Fatal
+ "errors"
+ "io" // for Reader
+)
+
+import (
+ "fmt" // for Printf
+
+ "math"
+
+ "log" // for Fatal
+
+ "errors"
+
+ "io" // for Reader
+)
+
+import (
+ // for Printf
+ "fmt"
+
+ "math"
+
+ // for Fatal
+ "log"
+
+ "errors"
+
+ // for Reader
+ "io"
+)
+
+import (
+ "fmt" // for Printf
+ "math"
+ "log" // for Fatal
+ "errors"
+ "io" // for Reader
+
+ "fmt" // for Printf
+
+ "math"
+
+ "log" // for Fatal
+
+ "errors"
+
+ "io" // for Reader
+)
+
+import (
+ "fmt" // for Printf
+
+ "math"
+ "log" // for Fatal
+ "errors"
+ "io" // for Reader
+
+ "fmt" // for Printf
+ "math"
+ "log" // for Fatal
+ "errors"
+ "io" // for Reader
+)
+
+// Test deduping and extended sorting
+import (
+ "B" // B
+ a "A" // aA
+ b "A" // bA2
+ b "A" // bA1
+ . "B" // .B
+ . "B"
+ "C"
+ "C"
+ "C"
+ a "D" // aD
+ "B"
+ _ "B" // _b
+)
+
+import (
+ "dedup_by_group"
+ "dedup_by_group"
+
+ "dedup_by_group"
+)
diff --git a/libgo/go/cmd/gofmt/testdata/old.golden b/libgo/go/cmd/gofmt/testdata/old.golden
new file mode 100644
index 0000000000..95a0b72a0e
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/old.golden
@@ -0,0 +1,9 @@
+package P
+
+func f() {
+ if x {
+ y
+ } else {
+ z
+ }
+}
diff --git a/libgo/go/cmd/gofmt/testdata/old.input b/libgo/go/cmd/gofmt/testdata/old.input
new file mode 100644
index 0000000000..e24eed215d
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/old.input
@@ -0,0 +1,8 @@
+package P
+
+func f() {
+ if x {
+ y
+ } else
+ z
+}
diff --git a/libgo/go/cmd/gofmt/testdata/rewrite1.golden b/libgo/go/cmd/gofmt/testdata/rewrite1.golden
new file mode 100644
index 0000000000..3ee5373a79
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/rewrite1.golden
@@ -0,0 +1,14 @@
+//gofmt -r=Foo->Bar
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Bar int
+
+func main() {
+ var a Bar
+ println(a)
+}
diff --git a/libgo/go/cmd/gofmt/testdata/rewrite1.input b/libgo/go/cmd/gofmt/testdata/rewrite1.input
new file mode 100644
index 0000000000..a84c8f7816
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/rewrite1.input
@@ -0,0 +1,14 @@
+//gofmt -r=Foo->Bar
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Foo int
+
+func main() {
+ var a Foo
+ println(a)
+}
diff --git a/libgo/go/cmd/gofmt/testdata/rewrite2.golden b/libgo/go/cmd/gofmt/testdata/rewrite2.golden
new file mode 100644
index 0000000000..f980e03530
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/rewrite2.golden
@@ -0,0 +1,12 @@
+//gofmt -r=int->bool
+
+// 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 p
+
+// Slices have nil Len values in the corresponding ast.ArrayType
+// node and reflect.NewValue(slice.Len) is an invalid reflect.Value.
+// The rewriter must not crash in that case. Was issue 1696.
+func f() []bool {}
diff --git a/libgo/go/cmd/gofmt/testdata/rewrite2.input b/libgo/go/cmd/gofmt/testdata/rewrite2.input
new file mode 100644
index 0000000000..489be4e07d
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/rewrite2.input
@@ -0,0 +1,12 @@
+//gofmt -r=int->bool
+
+// 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 p
+
+// Slices have nil Len values in the corresponding ast.ArrayType
+// node and reflect.NewValue(slice.Len) is an invalid reflect.Value.
+// The rewriter must not crash in that case. Was issue 1696.
+func f() []int {}
diff --git a/libgo/go/cmd/gofmt/testdata/rewrite3.golden b/libgo/go/cmd/gofmt/testdata/rewrite3.golden
new file mode 100644
index 0000000000..261a220c65
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/rewrite3.golden
@@ -0,0 +1,14 @@
+//gofmt -r=x->x
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// Field tags are *ast.BasicLit nodes that are nil when the tag is
+// absent. These nil nodes must not be mistaken for expressions,
+// the rewriter should not try to dereference them. Was issue 2410.
+type Foo struct {
+ Field int
+}
diff --git a/libgo/go/cmd/gofmt/testdata/rewrite3.input b/libgo/go/cmd/gofmt/testdata/rewrite3.input
new file mode 100644
index 0000000000..261a220c65
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/rewrite3.input
@@ -0,0 +1,14 @@
+//gofmt -r=x->x
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// Field tags are *ast.BasicLit nodes that are nil when the tag is
+// absent. These nil nodes must not be mistaken for expressions,
+// the rewriter should not try to dereference them. Was issue 2410.
+type Foo struct {
+ Field int
+}
diff --git a/libgo/go/cmd/gofmt/testdata/rewrite4.golden b/libgo/go/cmd/gofmt/testdata/rewrite4.golden
new file mode 100644
index 0000000000..b05547b4bf
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/rewrite4.golden
@@ -0,0 +1,76 @@
+//gofmt -r=(x)->x
+
+// 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.
+
+// Rewriting of parenthesized expressions (x) -> x
+// must not drop parentheses if that would lead to
+// wrong association of the operands.
+// Was issue 1847.
+
+package main
+
+// From example 1 of issue 1847.
+func _() {
+ var t = (&T{1000}).Id()
+}
+
+// From example 2 of issue 1847.
+func _() {
+ fmt.Println((*xpp).a)
+}
+
+// Some more test cases.
+func _() {
+ _ = (-x).f
+ _ = (*x).f
+ _ = (&x).f
+ _ = (!x).f
+ _ = -x.f
+ _ = *x.f
+ _ = &x.f
+ _ = !x.f
+ (-x).f()
+ (*x).f()
+ (&x).f()
+ (!x).f()
+ _ = -x.f()
+ _ = *x.f()
+ _ = &x.f()
+ _ = !x.f()
+
+ _ = (-x).f
+ _ = (*x).f
+ _ = (&x).f
+ _ = (!x).f
+ _ = -x.f
+ _ = *x.f
+ _ = &x.f
+ _ = !x.f
+ (-x).f()
+ (*x).f()
+ (&x).f()
+ (!x).f()
+ _ = -x.f()
+ _ = *x.f()
+ _ = &x.f()
+ _ = !x.f()
+
+ _ = -x.f
+ _ = *x.f
+ _ = &x.f
+ _ = !x.f
+ _ = -x.f
+ _ = *x.f
+ _ = &x.f
+ _ = !x.f
+ _ = -x.f()
+ _ = *x.f()
+ _ = &x.f()
+ _ = !x.f()
+ _ = -x.f()
+ _ = *x.f()
+ _ = &x.f()
+ _ = !x.f()
+}
diff --git a/libgo/go/cmd/gofmt/testdata/rewrite4.input b/libgo/go/cmd/gofmt/testdata/rewrite4.input
new file mode 100644
index 0000000000..0817099209
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/rewrite4.input
@@ -0,0 +1,76 @@
+//gofmt -r=(x)->x
+
+// 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.
+
+// Rewriting of parenthesized expressions (x) -> x
+// must not drop parentheses if that would lead to
+// wrong association of the operands.
+// Was issue 1847.
+
+package main
+
+// From example 1 of issue 1847.
+func _() {
+ var t = (&T{1000}).Id()
+}
+
+// From example 2 of issue 1847.
+func _() {
+ fmt.Println((*xpp).a)
+}
+
+// Some more test cases.
+func _() {
+ _ = (-x).f
+ _ = (*x).f
+ _ = (&x).f
+ _ = (!x).f
+ _ = (-x.f)
+ _ = (*x.f)
+ _ = (&x.f)
+ _ = (!x.f)
+ (-x).f()
+ (*x).f()
+ (&x).f()
+ (!x).f()
+ _ = (-x.f())
+ _ = (*x.f())
+ _ = (&x.f())
+ _ = (!x.f())
+
+ _ = ((-x)).f
+ _ = ((*x)).f
+ _ = ((&x)).f
+ _ = ((!x)).f
+ _ = ((-x.f))
+ _ = ((*x.f))
+ _ = ((&x.f))
+ _ = ((!x.f))
+ ((-x)).f()
+ ((*x)).f()
+ ((&x)).f()
+ ((!x)).f()
+ _ = ((-x.f()))
+ _ = ((*x.f()))
+ _ = ((&x.f()))
+ _ = ((!x.f()))
+
+ _ = -(x).f
+ _ = *(x).f
+ _ = &(x).f
+ _ = !(x).f
+ _ = -x.f
+ _ = *x.f
+ _ = &x.f
+ _ = !x.f
+ _ = -(x).f()
+ _ = *(x).f()
+ _ = &(x).f()
+ _ = !(x).f()
+ _ = -x.f()
+ _ = *x.f()
+ _ = &x.f()
+ _ = !x.f()
+}
diff --git a/libgo/go/cmd/gofmt/testdata/rewrite5.golden b/libgo/go/cmd/gofmt/testdata/rewrite5.golden
new file mode 100644
index 0000000000..9beb34aee7
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/rewrite5.golden
@@ -0,0 +1,17 @@
+//gofmt -r=x+x->2*x
+
+// 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.
+
+// Rewriting of expressions containing nodes with associated comments to
+// expressions without those nodes must also eliminate the associated
+// comments.
+
+package p
+
+func f(x int) int {
+ _ = 2 * x // this comment remains in the rewrite
+ _ = 2 * x
+ return 2 * x
+}
diff --git a/libgo/go/cmd/gofmt/testdata/rewrite5.input b/libgo/go/cmd/gofmt/testdata/rewrite5.input
new file mode 100644
index 0000000000..d7a6122d07
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/rewrite5.input
@@ -0,0 +1,17 @@
+//gofmt -r=x+x->2*x
+
+// 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.
+
+// Rewriting of expressions containing nodes with associated comments to
+// expressions without those nodes must also eliminate the associated
+// comments.
+
+package p
+
+func f(x int) int {
+ _ = x + x // this comment remains in the rewrite
+ _ = x /* this comment must not be in the rewrite */ + x
+ return x /* this comment must not be in the rewrite */ + x
+}
diff --git a/libgo/go/cmd/gofmt/testdata/rewrite6.golden b/libgo/go/cmd/gofmt/testdata/rewrite6.golden
new file mode 100644
index 0000000000..48ec9aa0df
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/rewrite6.golden
@@ -0,0 +1,17 @@
+//gofmt -r=fun(x)->Fun(x)
+
+// 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.
+
+// Rewriting of calls must take the ... (ellipsis)
+// attribute for the last argument into account.
+
+package p
+
+func fun(x []int) {}
+
+func g(x []int) {
+ Fun(x) // -r='fun(x)->Fun(x)' should rewrite this to Fun(x)
+ fun(x...) // -r='fun(x)->Fun(x)' should not rewrite this
+}
diff --git a/libgo/go/cmd/gofmt/testdata/rewrite6.input b/libgo/go/cmd/gofmt/testdata/rewrite6.input
new file mode 100644
index 0000000000..b085a84fef
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/rewrite6.input
@@ -0,0 +1,17 @@
+//gofmt -r=fun(x)->Fun(x)
+
+// 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.
+
+// Rewriting of calls must take the ... (ellipsis)
+// attribute for the last argument into account.
+
+package p
+
+func fun(x []int) {}
+
+func g(x []int) {
+ fun(x) // -r='fun(x)->Fun(x)' should rewrite this to Fun(x)
+ fun(x...) // -r='fun(x)->Fun(x)' should not rewrite this
+}
diff --git a/libgo/go/cmd/gofmt/testdata/rewrite7.golden b/libgo/go/cmd/gofmt/testdata/rewrite7.golden
new file mode 100644
index 0000000000..8386a0b2a3
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/rewrite7.golden
@@ -0,0 +1,17 @@
+//gofmt -r=fun(x...)->Fun(x)
+
+// 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.
+
+// Rewriting of calls must take the ... (ellipsis)
+// attribute for the last argument into account.
+
+package p
+
+func fun(x []int) {}
+
+func g(x []int) {
+ fun(x) // -r='fun(x...)->Fun(x)' should not rewrite this
+ Fun(x) // -r='fun(x...)->Fun(x)' should rewrite this to Fun(x)
+}
diff --git a/libgo/go/cmd/gofmt/testdata/rewrite7.input b/libgo/go/cmd/gofmt/testdata/rewrite7.input
new file mode 100644
index 0000000000..c1984708e7
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/rewrite7.input
@@ -0,0 +1,17 @@
+//gofmt -r=fun(x...)->Fun(x)
+
+// 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.
+
+// Rewriting of calls must take the ... (ellipsis)
+// attribute for the last argument into account.
+
+package p
+
+func fun(x []int) {}
+
+func g(x []int) {
+ fun(x) // -r='fun(x...)->Fun(x)' should not rewrite this
+ fun(x...) // -r='fun(x...)->Fun(x)' should rewrite this to Fun(x)
+}
diff --git a/libgo/go/cmd/gofmt/testdata/rewrite8.golden b/libgo/go/cmd/gofmt/testdata/rewrite8.golden
new file mode 100644
index 0000000000..62f0419dfb
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/rewrite8.golden
@@ -0,0 +1,12 @@
+//gofmt -r=interface{}->int
+
+// 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.
+
+// Check that literal type expression rewrites are accepted.
+// Was issue 4406.
+
+package p
+
+type T int
diff --git a/libgo/go/cmd/gofmt/testdata/rewrite8.input b/libgo/go/cmd/gofmt/testdata/rewrite8.input
new file mode 100644
index 0000000000..7964c5c75c
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/rewrite8.input
@@ -0,0 +1,12 @@
+//gofmt -r=interface{}->int
+
+// 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.
+
+// Check that literal type expression rewrites are accepted.
+// Was issue 4406.
+
+package p
+
+type T interface{}
diff --git a/libgo/go/cmd/gofmt/testdata/slices1.golden b/libgo/go/cmd/gofmt/testdata/slices1.golden
new file mode 100644
index 0000000000..04bc16f216
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/slices1.golden
@@ -0,0 +1,66 @@
+//gofmt -s
+
+// Test cases for slice expression simplification.
+package p
+
+var (
+ a [10]byte
+ b [20]float32
+ s []int
+ t struct {
+ s []byte
+ }
+
+ _ = a[0:]
+ _ = a[1:10]
+ _ = a[2:]
+ _ = a[3:(len(a))]
+ _ = a[len(a) : len(a)-1]
+ _ = a[0:len(b)]
+ _ = a[2:len(a):len(a)]
+
+ _ = a[:]
+ _ = a[:10]
+ _ = a[:]
+ _ = a[:(len(a))]
+ _ = a[:len(a)-1]
+ _ = a[:len(b)]
+ _ = a[:len(a):len(a)]
+
+ _ = s[0:]
+ _ = s[1:10]
+ _ = s[2:]
+ _ = s[3:(len(s))]
+ _ = s[len(a) : len(s)-1]
+ _ = s[0:len(b)]
+ _ = s[2:len(s):len(s)]
+
+ _ = s[:]
+ _ = s[:10]
+ _ = s[:]
+ _ = s[:(len(s))]
+ _ = s[:len(s)-1]
+ _ = s[:len(b)]
+ _ = s[:len(s):len(s)]
+
+ _ = t.s[0:]
+ _ = t.s[1:10]
+ _ = t.s[2:len(t.s)]
+ _ = t.s[3:(len(t.s))]
+ _ = t.s[len(a) : len(t.s)-1]
+ _ = t.s[0:len(b)]
+ _ = t.s[2:len(t.s):len(t.s)]
+
+ _ = t.s[:]
+ _ = t.s[:10]
+ _ = t.s[:len(t.s)]
+ _ = t.s[:(len(t.s))]
+ _ = t.s[:len(t.s)-1]
+ _ = t.s[:len(b)]
+ _ = t.s[:len(t.s):len(t.s)]
+)
+
+func _() {
+ s := s[0:]
+ _ = s
+}
diff --git a/libgo/go/cmd/gofmt/testdata/slices1.input b/libgo/go/cmd/gofmt/testdata/slices1.input
new file mode 100644
index 0000000000..1f25c43ccb
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/slices1.input
@@ -0,0 +1,66 @@
+//gofmt -s
+
+// Test cases for slice expression simplification.
+package p
+
+var (
+ a [10]byte
+ b [20]float32
+ s []int
+ t struct {
+ s []byte
+ }
+
+ _ = a[0:]
+ _ = a[1:10]
+ _ = a[2:len(a)]
+ _ = a[3:(len(a))]
+ _ = a[len(a) : len(a)-1]
+ _ = a[0:len(b)]
+ _ = a[2:len(a):len(a)]
+
+ _ = a[:]
+ _ = a[:10]
+ _ = a[:len(a)]
+ _ = a[:(len(a))]
+ _ = a[:len(a)-1]
+ _ = a[:len(b)]
+ _ = a[:len(a):len(a)]
+
+ _ = s[0:]
+ _ = s[1:10]
+ _ = s[2:len(s)]
+ _ = s[3:(len(s))]
+ _ = s[len(a) : len(s)-1]
+ _ = s[0:len(b)]
+ _ = s[2:len(s):len(s)]
+
+ _ = s[:]
+ _ = s[:10]
+ _ = s[:len(s)]
+ _ = s[:(len(s))]
+ _ = s[:len(s)-1]
+ _ = s[:len(b)]
+ _ = s[:len(s):len(s)]
+
+ _ = t.s[0:]
+ _ = t.s[1:10]
+ _ = t.s[2:len(t.s)]
+ _ = t.s[3:(len(t.s))]
+ _ = t.s[len(a) : len(t.s)-1]
+ _ = t.s[0:len(b)]
+ _ = t.s[2:len(t.s):len(t.s)]
+
+ _ = t.s[:]
+ _ = t.s[:10]
+ _ = t.s[:len(t.s)]
+ _ = t.s[:(len(t.s))]
+ _ = t.s[:len(t.s)-1]
+ _ = t.s[:len(b)]
+ _ = t.s[:len(t.s):len(t.s)]
+)
+
+func _() {
+ s := s[0:len(s)]
+ _ = s
+}
diff --git a/libgo/go/cmd/gofmt/testdata/slices2.golden b/libgo/go/cmd/gofmt/testdata/slices2.golden
new file mode 100644
index 0000000000..ab657004e6
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/slices2.golden
@@ -0,0 +1,63 @@
+//gofmt -s
+
+// Test cases for slice expression simplification.
+// Because of a dot import, these slices must remain untouched.
+package p
+
+import . "math"
+
+var (
+ a [10]byte
+ b [20]float32
+ s []int
+ t struct {
+ s []byte
+ }
+
+ _ = a[0:]
+ _ = a[1:10]
+ _ = a[2:len(a)]
+ _ = a[3:(len(a))]
+ _ = a[len(a) : len(a)-1]
+ _ = a[0:len(b)]
+
+ _ = a[:]
+ _ = a[:10]
+ _ = a[:len(a)]
+ _ = a[:(len(a))]
+ _ = a[:len(a)-1]
+ _ = a[:len(b)]
+
+ _ = s[0:]
+ _ = s[1:10]
+ _ = s[2:len(s)]
+ _ = s[3:(len(s))]
+ _ = s[len(a) : len(s)-1]
+ _ = s[0:len(b)]
+
+ _ = s[:]
+ _ = s[:10]
+ _ = s[:len(s)]
+ _ = s[:(len(s))]
+ _ = s[:len(s)-1]
+ _ = s[:len(b)]
+
+ _ = t.s[0:]
+ _ = t.s[1:10]
+ _ = t.s[2:len(t.s)]
+ _ = t.s[3:(len(t.s))]
+ _ = t.s[len(a) : len(t.s)-1]
+ _ = t.s[0:len(b)]
+
+ _ = t.s[:]
+ _ = t.s[:10]
+ _ = t.s[:len(t.s)]
+ _ = t.s[:(len(t.s))]
+ _ = t.s[:len(t.s)-1]
+ _ = t.s[:len(b)]
+)
+
+func _() {
+ s := s[0:len(s)]
+ _ = s
+}
diff --git a/libgo/go/cmd/gofmt/testdata/slices2.input b/libgo/go/cmd/gofmt/testdata/slices2.input
new file mode 100644
index 0000000000..ab657004e6
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/slices2.input
@@ -0,0 +1,63 @@
+//gofmt -s
+
+// Test cases for slice expression simplification.
+// Because of a dot import, these slices must remain untouched.
+package p
+
+import . "math"
+
+var (
+ a [10]byte
+ b [20]float32
+ s []int
+ t struct {
+ s []byte
+ }
+
+ _ = a[0:]
+ _ = a[1:10]
+ _ = a[2:len(a)]
+ _ = a[3:(len(a))]
+ _ = a[len(a) : len(a)-1]
+ _ = a[0:len(b)]
+
+ _ = a[:]
+ _ = a[:10]
+ _ = a[:len(a)]
+ _ = a[:(len(a))]
+ _ = a[:len(a)-1]
+ _ = a[:len(b)]
+
+ _ = s[0:]
+ _ = s[1:10]
+ _ = s[2:len(s)]
+ _ = s[3:(len(s))]
+ _ = s[len(a) : len(s)-1]
+ _ = s[0:len(b)]
+
+ _ = s[:]
+ _ = s[:10]
+ _ = s[:len(s)]
+ _ = s[:(len(s))]
+ _ = s[:len(s)-1]
+ _ = s[:len(b)]
+
+ _ = t.s[0:]
+ _ = t.s[1:10]
+ _ = t.s[2:len(t.s)]
+ _ = t.s[3:(len(t.s))]
+ _ = t.s[len(a) : len(t.s)-1]
+ _ = t.s[0:len(b)]
+
+ _ = t.s[:]
+ _ = t.s[:10]
+ _ = t.s[:len(t.s)]
+ _ = t.s[:(len(t.s))]
+ _ = t.s[:len(t.s)-1]
+ _ = t.s[:len(b)]
+)
+
+func _() {
+ s := s[0:len(s)]
+ _ = s
+}
diff --git a/libgo/go/cmd/gofmt/testdata/stdin1.golden b/libgo/go/cmd/gofmt/testdata/stdin1.golden
new file mode 100644
index 0000000000..9e4dcd20fe
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/stdin1.golden
@@ -0,0 +1,5 @@
+ //gofmt -stdin
+
+ if x {
+ y
+ }
diff --git a/libgo/go/cmd/gofmt/testdata/stdin1.input b/libgo/go/cmd/gofmt/testdata/stdin1.input
new file mode 100644
index 0000000000..9e4dcd20fe
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/stdin1.input
@@ -0,0 +1,5 @@
+ //gofmt -stdin
+
+ if x {
+ y
+ }
diff --git a/libgo/go/cmd/gofmt/testdata/stdin2.golden b/libgo/go/cmd/gofmt/testdata/stdin2.golden
new file mode 100644
index 0000000000..57df355403
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/stdin2.golden
@@ -0,0 +1,11 @@
+//gofmt -stdin
+
+var x int
+
+func f() {
+ y := z
+ /* this is a comment */
+ // this is a comment too
+}
+
+
diff --git a/libgo/go/cmd/gofmt/testdata/stdin2.input b/libgo/go/cmd/gofmt/testdata/stdin2.input
new file mode 100644
index 0000000000..69d6bdd682
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/stdin2.input
@@ -0,0 +1,11 @@
+//gofmt -stdin
+
+var x int
+
+
+func f() { y := z
+ /* this is a comment */
+ // this is a comment too
+}
+
+
diff --git a/libgo/go/cmd/gofmt/testdata/stdin3.golden b/libgo/go/cmd/gofmt/testdata/stdin3.golden
new file mode 100644
index 0000000000..d6da0e417a
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/stdin3.golden
@@ -0,0 +1,7 @@
+ //gofmt -stdin
+
+ /* note: no newline at end of file */
+ for i := 0; i < 10; i++ {
+ s += i
+ }
+ \ No newline at end of file
diff --git a/libgo/go/cmd/gofmt/testdata/stdin3.input b/libgo/go/cmd/gofmt/testdata/stdin3.input
new file mode 100644
index 0000000000..ab46c1063b
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/stdin3.input
@@ -0,0 +1,5 @@
+ //gofmt -stdin
+
+ /* note: no newline at end of file */
+ for i := 0; i < 10; i++ { s += i }
+ \ No newline at end of file
diff --git a/libgo/go/cmd/gofmt/testdata/stdin4.golden b/libgo/go/cmd/gofmt/testdata/stdin4.golden
new file mode 100644
index 0000000000..0c7acace5d
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/stdin4.golden
@@ -0,0 +1,5 @@
+ //gofmt -stdin
+
+ // comment
+
+ i := 0
diff --git a/libgo/go/cmd/gofmt/testdata/stdin4.input b/libgo/go/cmd/gofmt/testdata/stdin4.input
new file mode 100644
index 0000000000..1fc73f31e5
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/stdin4.input
@@ -0,0 +1,5 @@
+ //gofmt -stdin
+
+ // comment
+
+ i := 0
diff --git a/libgo/go/cmd/gofmt/testdata/typeswitch.golden b/libgo/go/cmd/gofmt/testdata/typeswitch.golden
new file mode 100644
index 0000000000..2b1905edd3
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/typeswitch.golden
@@ -0,0 +1,60 @@
+/*
+ Parenthesized type switch expressions originally
+ accepted by gofmt must continue to be rewritten
+ into the correct unparenthesized form.
+
+ Only type-switches that didn't declare a variable
+ in the type switch type assertion and which
+ contained only "expression-like" (named) types in their
+ cases were permitted to have their type assertion parenthesized
+ by go/parser (due to a weak predicate in the parser). All others
+ were rejected always, either with a syntax error in the
+ type switch header or in the case.
+
+ See also issue 4470.
+*/
+package p
+
+func f() {
+ var x interface{}
+ switch x.(type) { // should remain the same
+ }
+ switch x.(type) { // should become: switch x.(type) {
+ }
+
+ switch x.(type) { // should remain the same
+ case int:
+ }
+ switch x.(type) { // should become: switch x.(type) {
+ case int:
+ }
+
+ switch x.(type) { // should remain the same
+ case []int:
+ }
+
+ // Parenthesized (x.(type)) in type switches containing cases
+ // with unnamed (literal) types were never permitted by gofmt;
+ // thus there won't be any code in the wild using this style if
+ // the code was gofmt-ed.
+ /*
+ switch (x.(type)) {
+ case []int:
+ }
+ */
+
+ switch t := x.(type) { // should remain the same
+ default:
+ _ = t
+ }
+
+ // Parenthesized (x.(type)) in type switches declaring a variable
+ // were never permitted by gofmt; thus there won't be any code in
+ // the wild using this style if the code was gofmt-ed.
+ /*
+ switch t := (x.(type)) {
+ default:
+ _ = t
+ }
+ */
+}
diff --git a/libgo/go/cmd/gofmt/testdata/typeswitch.input b/libgo/go/cmd/gofmt/testdata/typeswitch.input
new file mode 100644
index 0000000000..8f8cba9b85
--- /dev/null
+++ b/libgo/go/cmd/gofmt/testdata/typeswitch.input
@@ -0,0 +1,60 @@
+/*
+ Parenthesized type switch expressions originally
+ accepted by gofmt must continue to be rewritten
+ into the correct unparenthesized form.
+
+ Only type-switches that didn't declare a variable
+ in the type switch type assertion and which
+ contained only "expression-like" (named) types in their
+ cases were permitted to have their type assertion parenthesized
+ by go/parser (due to a weak predicate in the parser). All others
+ were rejected always, either with a syntax error in the
+ type switch header or in the case.
+
+ See also issue 4470.
+*/
+package p
+
+func f() {
+ var x interface{}
+ switch x.(type) { // should remain the same
+ }
+ switch (x.(type)) { // should become: switch x.(type) {
+ }
+
+ switch x.(type) { // should remain the same
+ case int:
+ }
+ switch (x.(type)) { // should become: switch x.(type) {
+ case int:
+ }
+
+ switch x.(type) { // should remain the same
+ case []int:
+ }
+
+ // Parenthesized (x.(type)) in type switches containing cases
+ // with unnamed (literal) types were never permitted by gofmt;
+ // thus there won't be any code in the wild using this style if
+ // the code was gofmt-ed.
+ /*
+ switch (x.(type)) {
+ case []int:
+ }
+ */
+
+ switch t := x.(type) { // should remain the same
+ default:
+ _ = t
+ }
+
+ // Parenthesized (x.(type)) in type switches declaring a variable
+ // were never permitted by gofmt; thus there won't be any code in
+ // the wild using this style if the code was gofmt-ed.
+ /*
+ switch t := (x.(type)) {
+ default:
+ _ = t
+ }
+ */
+}
diff --git a/libgo/go/compress/bzip2/bzip2.go b/libgo/go/compress/bzip2/bzip2.go
index 82e30c7c9d..15575d2202 100644
--- a/libgo/go/compress/bzip2/bzip2.go
+++ b/libgo/go/compress/bzip2/bzip2.go
@@ -42,6 +42,8 @@ type reader struct {
}
// NewReader returns an io.Reader which decompresses bzip2 data from r.
+// If r does not also implement io.ByteReader,
+// the decompressor may read more data than necessary from r.
func NewReader(r io.Reader) io.Reader {
bz2 := new(reader)
bz2.br = newBitReader(r)
@@ -261,6 +263,11 @@ func (bz2 *reader) readBlock() (err error) {
}
}
+ if numSymbols == 0 {
+ // There must be an EOF symbol.
+ return StructuralError("no symbols in input")
+ }
+
// A block uses between two and six different Huffman trees.
numHuffmanTrees := br.ReadBits(3)
if numHuffmanTrees < 2 || numHuffmanTrees > 6 {
@@ -307,10 +314,10 @@ func (bz2 *reader) readBlock() (err error) {
// Now we decode the arrays of code-lengths for each tree.
lengths := make([]uint8, numSymbols)
- for i := 0; i < numHuffmanTrees; i++ {
+ for i := range huffmanTrees {
// The code lengths are delta encoded from a 5-bit base value.
length := br.ReadBits(5)
- for j := 0; j < numSymbols; j++ {
+ for j := range lengths {
for {
if !br.ReadBit() {
break
@@ -333,6 +340,12 @@ func (bz2 *reader) readBlock() (err error) {
}
selectorIndex := 1 // the next tree index to use
+ if len(treeIndexes) == 0 {
+ return StructuralError("no tree selectors given")
+ }
+ if int(treeIndexes[0]) >= len(huffmanTrees) {
+ return StructuralError("tree selector out of range")
+ }
currentHuffmanTree := huffmanTrees[treeIndexes[0]]
bufIndex := 0 // indexes bz2.buf, the output buffer.
// The output of the move-to-front transform is run-length encoded and
@@ -350,6 +363,12 @@ func (bz2 *reader) readBlock() (err error) {
decoded := 0 // counts the number of symbols decoded by the current tree.
for {
if decoded == 50 {
+ if selectorIndex >= numSelectors {
+ return StructuralError("insufficient selector indices for number of symbols")
+ }
+ if int(treeIndexes[selectorIndex]) >= len(huffmanTrees) {
+ return StructuralError("tree selector out of range")
+ }
currentHuffmanTree = huffmanTrees[treeIndexes[selectorIndex]]
selectorIndex++
decoded = 0
diff --git a/libgo/go/compress/bzip2/bzip2_test.go b/libgo/go/compress/bzip2/bzip2_test.go
index ada1f9a001..fb79d089eb 100644
--- a/libgo/go/compress/bzip2/bzip2_test.go
+++ b/libgo/go/compress/bzip2/bzip2_test.go
@@ -14,7 +14,7 @@ import (
)
func TestBitReader(t *testing.T) {
- buf := bytes.NewBuffer([]byte{0xaa})
+ buf := bytes.NewReader([]byte{0xaa})
br := newBitReader(buf)
if n := br.ReadBits(1); n != 1 {
t.Errorf("read 1 wrong")
@@ -31,7 +31,7 @@ func TestBitReader(t *testing.T) {
}
func TestBitReaderLarge(t *testing.T) {
- buf := bytes.NewBuffer([]byte{0x12, 0x34, 0x56, 0x78})
+ buf := bytes.NewReader([]byte{0x12, 0x34, 0x56, 0x78})
br := newBitReader(buf)
if n := br.ReadBits(32); n != 0x12345678 {
t.Errorf("got: %x want: %x", n, 0x12345678)
@@ -43,7 +43,7 @@ func readerFromHex(s string) io.Reader {
if err != nil {
panic("readerFromHex: bad input")
}
- return bytes.NewBuffer(data)
+ return bytes.NewReader(data)
}
func decompressHex(s string) (out []byte, err error) {
@@ -177,7 +177,7 @@ const (
var testfiles = []string{
// Digits is the digits of the irrational number e. Its decimal representation
- // does not repeat, but there are only 10 posible digits, so it should be
+ // does not repeat, but there are only 10 possible digits, so it should be
// reasonably compressible.
digits: "testdata/e.txt.bz2",
// Twain is Project Gutenberg's edition of Mark Twain's classic English novel.
@@ -191,7 +191,7 @@ func benchmarkDecode(b *testing.B, testfile int) {
}
b.SetBytes(int64(len(compressed)))
for i := 0; i < b.N; i++ {
- r := bytes.NewBuffer(compressed)
+ r := bytes.NewReader(compressed)
io.Copy(ioutil.Discard, NewReader(r))
}
}
@@ -201,13 +201,59 @@ func BenchmarkDecodeTwain(b *testing.B) { benchmarkDecode(b, twain) }
func TestBufferOverrun(t *testing.T) {
// Tests https://code.google.com/p/go/issues/detail?id=5747.
- buffer := bytes.NewBuffer([]byte(bufferOverrunBase64))
+ buffer := bytes.NewReader([]byte(bufferOverrunBase64))
decoder := base64.NewDecoder(base64.StdEncoding, buffer)
decompressor := NewReader(decoder)
// This shouldn't panic.
ioutil.ReadAll(decompressor)
}
+func TestOutOfRangeSelector(t *testing.T) {
+ // Tests https://code.google.com/p/go/issues/detail?id=8363.
+ buffer := bytes.NewReader(outOfRangeSelector)
+ decompressor := NewReader(buffer)
+ // This shouldn't panic.
+ ioutil.ReadAll(decompressor)
+}
+
+func TestMTF(t *testing.T) {
+ mtf := newMTFDecoderWithRange(5)
+
+ // 0 1 2 3 4
+ expect := byte(1)
+ x := mtf.Decode(1)
+ if x != expect {
+ t.Errorf("expected %v, got %v", expect, x)
+ }
+
+ // 1 0 2 3 4
+ x = mtf.Decode(0)
+ if x != expect {
+ t.Errorf("expected %v, got %v", expect, x)
+ }
+
+ // 1 0 2 3 4
+ expect = byte(0)
+ x = mtf.Decode(1)
+ if x != expect {
+ t.Errorf("expected %v, got %v", expect, x)
+ }
+
+ // 0 1 2 3 4
+ expect = byte(4)
+ x = mtf.Decode(4)
+ if x != expect {
+ t.Errorf("expected %v, got %v", expect, x)
+ }
+
+ // 4 0 1 2 3
+ expect = byte(0)
+ x = mtf.Decode(1)
+ if x != expect {
+ t.Errorf("expected %v, got %v", expect, x)
+ }
+}
+
var bufferOverrunBase64 string = `
QlpoNTFBWSZTWTzyiGcACMP/////////////////////////////////3/7f3///
////4N/fCZODak2Xo44GIHZgkGzDRbFAuwAAKoFV7T6AO6qwA6APb6s2rOoAkAAD
@@ -361,3 +407,13 @@ O0A8s/iua5oFdNZTWvbVI4FUH9sKcLiB3/fIAF+sB4n8q6L+UCfmbPcAo/crQ6b3
HqhDBMY9J0q/jdz9GNYZ/1fbXdkUqAQKFePhtzJDRBZba27+LPQNMCcrHMq06F1T
4QmLmkHt7LxB2pAczUO+T2O9bHEw/HWw+dYf2MoRDUw=
`
+
+var outOfRangeSelector = []byte{
+ 0x42, 0x5a, 0x68, 0x39, 0x31, 0x41, 0x59, 0x26,
+ 0x53, 0x59, 0x4e, 0xec, 0xe8, 0x36, 0x00, 0x00,
+ 0x02, 0x51, 0x80, 0x00, 0x10, 0x40, 0x00, 0x06,
+ 0x44, 0x90, 0x80, 0x20, 0x00, 0x31, 0x06, 0x4c,
+ 0x41, 0x01, 0xa7, 0xa9, 0xa5, 0x80, 0xbb, 0x94,
+ 0x31, 0x17, 0x72, 0x45, 0x38, 0x50, 0x90, 0x00,
+ 0x00, 0x00, 0x00,
+}
diff --git a/libgo/go/compress/bzip2/huffman.go b/libgo/go/compress/bzip2/huffman.go
index 8f6b0c9cad..75a6223d81 100644
--- a/libgo/go/compress/bzip2/huffman.go
+++ b/libgo/go/compress/bzip2/huffman.go
@@ -190,7 +190,37 @@ func buildHuffmanNode(t *huffmanTree, codes []huffmanCode, level uint32) (nodeIn
right := codes[firstRightIndex:]
if len(left) == 0 || len(right) == 0 {
- return 0, StructuralError("superfluous level in Huffman tree")
+ // There is a superfluous level in the Huffman tree indicating
+ // a bug in the encoder. However, this bug has been observed in
+ // the wild so we handle it.
+
+ // If this function was called recursively then we know that
+ // len(codes) >= 2 because, otherwise, we would have hit the
+ // "leaf node" case, below, and not recursed.
+ //
+ // However, for the initial call it's possible that len(codes)
+ // is zero or one. Both cases are invalid because a zero length
+ // tree cannot encode anything and a length-1 tree can only
+ // encode EOF and so is superfluous. We reject both.
+ if len(codes) < 2 {
+ return 0, StructuralError("empty Huffman tree")
+ }
+
+ // In this case the recursion doesn't always reduce the length
+ // of codes so we need to ensure termination via another
+ // mechanism.
+ if level == 31 {
+ // Since len(codes) >= 2 the only way that the values
+ // can match at all 32 bits is if they are equal, which
+ // is invalid. This ensures that we never enter
+ // infinite recursion.
+ return 0, StructuralError("equal symbols in Huffman tree")
+ }
+
+ if len(left) == 0 {
+ return buildHuffmanNode(t, right, level+1)
+ }
+ return buildHuffmanNode(t, left, level+1)
}
nodeIndex = uint16(t.nextNode)
diff --git a/libgo/go/compress/bzip2/move_to_front.go b/libgo/go/compress/bzip2/move_to_front.go
index b7e75a700a..526dfb34cc 100644
--- a/libgo/go/compress/bzip2/move_to_front.go
+++ b/libgo/go/compress/bzip2/move_to_front.go
@@ -11,88 +11,43 @@ package bzip2
// index into that list. When a symbol is referenced, it's moved to the front
// of the list. Thus, a repeated symbol ends up being encoded with many zeros,
// as the symbol will be at the front of the list after the first access.
-type moveToFrontDecoder struct {
- // Rather than actually keep the list in memory, the symbols are stored
- // as a circular, double linked list with the symbol indexed by head
- // at the front of the list.
- symbols [256]byte
- next [256]uint8
- prev [256]uint8
- head uint8
- len int
-}
+type moveToFrontDecoder []byte
// newMTFDecoder creates a move-to-front decoder with an explicit initial list
// of symbols.
-func newMTFDecoder(symbols []byte) *moveToFrontDecoder {
+func newMTFDecoder(symbols []byte) moveToFrontDecoder {
if len(symbols) > 256 {
panic("too many symbols")
}
-
- m := new(moveToFrontDecoder)
- copy(m.symbols[:], symbols)
- m.len = len(symbols)
- m.threadLinkedList()
- return m
+ return moveToFrontDecoder(symbols)
}
// newMTFDecoderWithRange creates a move-to-front decoder with an initial
// symbol list of 0...n-1.
-func newMTFDecoderWithRange(n int) *moveToFrontDecoder {
+func newMTFDecoderWithRange(n int) moveToFrontDecoder {
if n > 256 {
panic("newMTFDecoderWithRange: cannot have > 256 symbols")
}
- m := new(moveToFrontDecoder)
+ m := make([]byte, n)
for i := 0; i < n; i++ {
- m.symbols[byte(i)] = byte(i)
- }
- m.len = n
- m.threadLinkedList()
- return m
-}
-
-// threadLinkedList creates the initial linked-list pointers.
-func (m *moveToFrontDecoder) threadLinkedList() {
- if m.len == 0 {
- return
- }
-
- m.prev[0] = uint8(m.len - 1)
-
- for i := byte(0); int(i) < m.len-1; i++ {
- m.next[i] = uint8(i + 1)
- m.prev[i+1] = uint8(i)
+ m[i] = byte(i)
}
-
- m.next[m.len-1] = 0
+ return moveToFrontDecoder(m)
}
-func (m *moveToFrontDecoder) Decode(n int) (b byte) {
- // Most of the time, n will be zero so it's worth dealing with this
- // simple case.
- if n == 0 {
- return m.symbols[m.head]
- }
-
- i := m.head
- for j := 0; j < n; j++ {
- i = m.next[i]
- }
- b = m.symbols[i]
-
- m.next[m.prev[i]] = m.next[i]
- m.prev[m.next[i]] = m.prev[i]
- m.next[i] = m.head
- m.prev[i] = m.prev[m.head]
- m.next[m.prev[m.head]] = i
- m.prev[m.head] = i
- m.head = i
-
+func (m moveToFrontDecoder) Decode(n int) (b byte) {
+ // Implement move-to-front with a simple copy. This approach
+ // beats more sophisticated approaches in benchmarking, probably
+ // because it has high locality of reference inside of a
+ // single cache line (most move-to-front operations have n < 64).
+ b = m[n]
+ copy(m[1:], m[:n])
+ m[0] = b
return
}
// First returns the symbol at the front of the list.
-func (m *moveToFrontDecoder) First() byte {
- return m.symbols[m.head]
+func (m moveToFrontDecoder) First() byte {
+ return m[0]
}
diff --git a/libgo/go/compress/bzip2/testdata/Mark.Twain-Tom.Sawyer.txt.bz2 b/libgo/go/compress/bzip2/testdata/Mark.Twain-Tom.Sawyer.txt.bz2
new file mode 100644
index 0000000000..0bd61a6d4e
--- /dev/null
+++ b/libgo/go/compress/bzip2/testdata/Mark.Twain-Tom.Sawyer.txt.bz2
Binary files differ
diff --git a/libgo/go/compress/bzip2/testdata/e.txt.bz2 b/libgo/go/compress/bzip2/testdata/e.txt.bz2
new file mode 100644
index 0000000000..65bf3b4c32
--- /dev/null
+++ b/libgo/go/compress/bzip2/testdata/e.txt.bz2
Binary files differ
diff --git a/libgo/go/compress/flate/fixedhuff.go b/libgo/go/compress/flate/fixedhuff.go
index 41a6b25dfd..7df8b9a293 100644
--- a/libgo/go/compress/flate/fixedhuff.go
+++ b/libgo/go/compress/flate/fixedhuff.go
@@ -1,6 +1,10 @@
+// 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 flate
-// autogenerated by gen.go, DO NOT EDIT
+// autogenerated by go run gen.go -output fixedhuff.go, DO NOT EDIT
var fixedHuffmanDecoder = huffmanDecoder{
7,
diff --git a/libgo/go/compress/flate/flate_test.go b/libgo/go/compress/flate/flate_test.go
index 57fea5ab4d..0687663233 100644
--- a/libgo/go/compress/flate/flate_test.go
+++ b/libgo/go/compress/flate/flate_test.go
@@ -14,7 +14,7 @@ import (
)
func TestUncompressedSource(t *testing.T) {
- decoder := NewReader(bytes.NewBuffer([]byte{0x01, 0x01, 0x00, 0xfe, 0xff, 0x11}))
+ 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 {
diff --git a/libgo/go/compress/flate/gen.go b/libgo/go/compress/flate/gen.go
index 1427557f80..6288ecddd0 100644
--- a/libgo/go/compress/flate/gen.go
+++ b/libgo/go/compress/flate/gen.go
@@ -7,14 +7,21 @@
// This program generates fixedhuff.go
// Invoke as
//
-// go run gen.go |gofmt >fixedhuff.go
+// go run gen.go -output fixedhuff.go
package main
import (
+ "bytes"
+ "flag"
"fmt"
+ "go/format"
+ "io/ioutil"
+ "log"
)
+var filename = flag.String("output", "fixedhuff.go", "output file name")
+
const maxCodeLen = 16
// Note: the definition of the huffmanDecoder struct is copied from
@@ -113,6 +120,8 @@ func (h *huffmanDecoder) init(bits []int) bool {
}
func main() {
+ flag.Parse()
+
var h huffmanDecoder
var bits [288]int
initReverseByte()
@@ -129,27 +138,43 @@ func main() {
bits[i] = 8
}
h.init(bits[:])
- fmt.Println("package flate")
- fmt.Println()
- fmt.Println("// autogenerated by gen.go, DO NOT EDIT")
- fmt.Println()
- fmt.Println("var fixedHuffmanDecoder = huffmanDecoder{")
- fmt.Printf("\t%d,\n", h.min)
- fmt.Println("\t[huffmanNumChunks]uint32{")
+
+ var buf bytes.Buffer
+
+ fmt.Fprintf(&buf, `// 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.`+"\n\n")
+
+ fmt.Fprintln(&buf, "package flate")
+ fmt.Fprintln(&buf)
+ fmt.Fprintln(&buf, "// autogenerated by go run gen.go -output fixedhuff.go, DO NOT EDIT")
+ fmt.Fprintln(&buf)
+ fmt.Fprintln(&buf, "var fixedHuffmanDecoder = huffmanDecoder{")
+ fmt.Fprintf(&buf, "\t%d,\n", h.min)
+ fmt.Fprintln(&buf, "\t[huffmanNumChunks]uint32{")
for i := 0; i < huffmanNumChunks; i++ {
if i&7 == 0 {
- fmt.Printf("\t\t")
+ fmt.Fprintf(&buf, "\t\t")
} else {
- fmt.Printf(" ")
+ fmt.Fprintf(&buf, " ")
}
- fmt.Printf("0x%04x,", h.chunks[i])
+ fmt.Fprintf(&buf, "0x%04x,", h.chunks[i])
if i&7 == 7 {
- fmt.Println()
+ fmt.Fprintln(&buf)
}
}
- fmt.Println("\t},")
- fmt.Println("\tnil, 0,")
- fmt.Println("}")
+ fmt.Fprintln(&buf, "\t},")
+ fmt.Fprintln(&buf, "\tnil, 0,")
+ fmt.Fprintln(&buf, "}")
+
+ data, err := format.Source(buf.Bytes())
+ if err != nil {
+ log.Fatal(err)
+ }
+ err = ioutil.WriteFile(*filename, data, 0644)
+ if err != nil {
+ log.Fatal(err)
+ }
}
var reverseByte [256]byte
diff --git a/libgo/go/compress/flate/inflate.go b/libgo/go/compress/flate/inflate.go
index 3eb3b2b83e..76519bbf42 100644
--- a/libgo/go/compress/flate/inflate.go
+++ b/libgo/go/compress/flate/inflate.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 gen.go -output fixedhuff.go
+
// Package flate implements the DEFLATE compressed data format, described in
// RFC 1951. The gzip and zlib packages implement access to DEFLATE-based file
// formats.
@@ -54,7 +56,16 @@ func (e *WriteError) Error() string {
return "flate: write error at offset " + strconv.FormatInt(e.Offset, 10) + ": " + e.Err.Error()
}
-// Note that much of the implemenation of huffmanDecoder is also copied
+// Resetter resets a ReadCloser returned by NewReader or NewReaderDict to
+// to switch to a new underlying Reader. This permits reusing a ReadCloser
+// instead of allocating a new one.
+type Resetter interface {
+ // Reset discards any buffered data and resets the Resetter as if it was
+ // newly initialized with the given reader.
+ Reset(r io.Reader, dict []byte) error
+}
+
+// Note that much of the implementation of huffmanDecoder is also copied
// into gen.go (in package main) for the purpose of precomputing the
// fixed huffman tables so they can be included statically.
@@ -180,7 +191,7 @@ func (h *huffmanDecoder) init(bits []int) bool {
// the NewReader will introduce its own buffering.
type Reader interface {
io.Reader
- ReadByte() (c byte, err error)
+ io.ByteReader
}
// Decompress state.
@@ -677,10 +688,28 @@ func makeReader(r io.Reader) Reader {
return bufio.NewReader(r)
}
+func (f *decompressor) Reset(r io.Reader, dict []byte) error {
+ *f = decompressor{
+ r: makeReader(r),
+ bits: f.bits,
+ codebits: f.codebits,
+ hist: f.hist,
+ step: (*decompressor).nextBlock,
+ }
+ if dict != nil {
+ f.setDict(dict)
+ }
+ return nil
+}
+
// NewReader returns a new ReadCloser that can be used
-// to read the uncompressed version of r. It is the caller's
-// responsibility to call Close on the ReadCloser when
-// finished reading.
+// to read the uncompressed version of r.
+// If r does not also implement io.ByteReader,
+// the decompressor may read more data than necessary from r.
+// It is the caller's responsibility to call Close on the ReadCloser
+// when finished reading.
+//
+// The ReadCloser returned by NewReader also implements Resetter.
func NewReader(r io.Reader) io.ReadCloser {
var f decompressor
f.bits = new([maxLit + maxDist]int)
@@ -696,6 +725,8 @@ func NewReader(r io.Reader) io.ReadCloser {
// the uncompressed data stream started with the given dictionary,
// which has already been read. NewReaderDict is typically used
// to read data compressed by NewWriterDict.
+//
+// The ReadCloser returned by NewReader also implements Resetter.
func NewReaderDict(r io.Reader, dict []byte) io.ReadCloser {
var f decompressor
f.r = makeReader(r)
diff --git a/libgo/go/compress/flate/inflate_test.go b/libgo/go/compress/flate/inflate_test.go
new file mode 100644
index 0000000000..9f25d30b35
--- /dev/null
+++ b/libgo/go/compress/flate/inflate_test.go
@@ -0,0 +1,39 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package flate
+
+import (
+ "bytes"
+ "io"
+ "testing"
+)
+
+func TestReset(t *testing.T) {
+ ss := []string{
+ "lorem ipsum izzle fo rizzle",
+ "the quick brown fox jumped over",
+ }
+
+ deflated := make([]bytes.Buffer, 2)
+ for i, s := range ss {
+ w, _ := NewWriter(&deflated[i], 1)
+ w.Write([]byte(s))
+ w.Close()
+ }
+
+ inflated := make([]bytes.Buffer, 2)
+
+ f := NewReader(&deflated[0])
+ io.Copy(&inflated[0], f)
+ f.(Resetter).Reset(&deflated[1], nil)
+ io.Copy(&inflated[1], f)
+ f.Close()
+
+ for i, s := range ss {
+ if s != inflated[i].String() {
+ t.Errorf("inflated[%d]:\ngot %q\nwant %q", i, inflated[i], s)
+ }
+ }
+}
diff --git a/libgo/go/compress/flate/reader_test.go b/libgo/go/compress/flate/reader_test.go
index 2a8ebbc943..a62ef741df 100644
--- a/libgo/go/compress/flate/reader_test.go
+++ b/libgo/go/compress/flate/reader_test.go
@@ -29,7 +29,7 @@ const (
var testfiles = []string{
// Digits is the digits of the irrational number e. Its decimal representation
- // does not repeat, but there are only 10 posible digits, so it should be
+ // does not repeat, but there are only 10 possible digits, so it should be
// reasonably compressible.
digits: "../testdata/e.txt",
// Twain is Project Gutenberg's edition of Mark Twain's classic English novel.
diff --git a/libgo/go/compress/gzip/gunzip.go b/libgo/go/compress/gzip/gunzip.go
index 1fb9b0964c..72ee55c4fa 100644
--- a/libgo/go/compress/gzip/gunzip.go
+++ b/libgo/go/compress/gzip/gunzip.go
@@ -74,14 +74,17 @@ type Reader struct {
flg byte
buf [512]byte
err error
+ multistream bool
}
// NewReader creates a new Reader reading the given reader.
-// The implementation buffers input and may read more data than necessary from r.
+// If r does not also implement io.ByteReader,
+// the decompressor may read more data than necessary from r.
// It is the caller's responsibility to call Close on the Reader when done.
func NewReader(r io.Reader) (*Reader, error) {
z := new(Reader)
z.r = makeReader(r)
+ z.multistream = true
z.digest = crc32.NewIEEE()
if err := z.readHeader(true); err != nil {
return nil, err
@@ -89,6 +92,42 @@ func NewReader(r io.Reader) (*Reader, error) {
return z, nil
}
+// Reset discards the Reader z's state and makes it equivalent to the
+// result of its original state from NewReader, but reading from r instead.
+// This permits reusing a Reader rather than allocating a new one.
+func (z *Reader) Reset(r io.Reader) error {
+ z.r = makeReader(r)
+ if z.digest == nil {
+ z.digest = crc32.NewIEEE()
+ } else {
+ z.digest.Reset()
+ }
+ z.size = 0
+ z.err = nil
+ z.multistream = true
+ return z.readHeader(true)
+}
+
+// Multistream controls whether the reader supports multistream files.
+//
+// If enabled (the default), the Reader expects the input to be a sequence
+// of individually gzipped data streams, each with its own header and
+// trailer, ending at EOF. The effect is that the concatenation of a sequence
+// of gzipped files is treated as equivalent to the gzip of the concatenation
+// of the sequence. This is standard behavior for gzip readers.
+//
+// Calling Multistream(false) disables this behavior; disabling the behavior
+// can be useful when reading file formats that distinguish individual gzip
+// data streams or mix gzip data streams with other data streams.
+// In this mode, when the Reader reaches the end of the data stream,
+// Read returns io.EOF. If the underlying reader implements io.ByteReader,
+// it will be left positioned just after the gzip stream.
+// To start the next stream, call z.Reset(r) followed by z.Multistream(false).
+// If there is no next stream, z.Reset(r) will return io.EOF.
+func (z *Reader) Multistream(ok bool) {
+ z.multistream = ok
+}
+
// GZIP (RFC 1952) is little-endian, unlike ZLIB (RFC 1950).
func get4(p []byte) uint32 {
return uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24
@@ -192,7 +231,11 @@ func (z *Reader) readHeader(save bool) error {
}
z.digest.Reset()
- z.decompressor = flate.NewReader(z.r)
+ if z.decompressor == nil {
+ z.decompressor = flate.NewReader(z.r)
+ } else {
+ z.decompressor.(flate.Resetter).Reset(z.r, nil)
+ }
return nil
}
@@ -225,6 +268,10 @@ func (z *Reader) Read(p []byte) (n int, err error) {
}
// File is ok; is there another?
+ if !z.multistream {
+ return 0, io.EOF
+ }
+
if err = z.readHeader(false); err != nil {
z.err = err
return
diff --git a/libgo/go/compress/gzip/gunzip_test.go b/libgo/go/compress/gzip/gunzip_test.go
index 572fb58488..0636dec9ab 100644
--- a/libgo/go/compress/gzip/gunzip_test.go
+++ b/libgo/go/compress/gzip/gunzip_test.go
@@ -9,6 +9,7 @@ import (
"io"
"io/ioutil"
"os"
+ "strings"
"testing"
"time"
)
@@ -284,7 +285,7 @@ var gunzipTests = []gunzipTest{
func TestDecompressor(t *testing.T) {
b := new(bytes.Buffer)
for _, tt := range gunzipTests {
- in := bytes.NewBuffer(tt.gzip)
+ in := bytes.NewReader(tt.gzip)
gzip, err := NewReader(in)
if err != nil {
t.Errorf("%s: NewReader: %s", tt.name, err)
@@ -303,6 +304,26 @@ func TestDecompressor(t *testing.T) {
if s != tt.raw {
t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.name, n, s, len(tt.raw), tt.raw)
}
+
+ // Test Reader Reset.
+ in = bytes.NewReader(tt.gzip)
+ err = gzip.Reset(in)
+ if err != nil {
+ t.Errorf("%s: Reset: %s", tt.name, err)
+ continue
+ }
+ if tt.name != gzip.Name {
+ t.Errorf("%s: got name %s", tt.name, gzip.Name)
+ }
+ b.Reset()
+ n, err = io.Copy(b, gzip)
+ if err != tt.err {
+ t.Errorf("%s: io.Copy: %v want %v", tt.name, err, tt.err)
+ }
+ s = b.String()
+ if s != tt.raw {
+ t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.name, n, s, len(tt.raw), tt.raw)
+ }
}
}
@@ -333,3 +354,57 @@ func TestIssue6550(t *testing.T) {
// ok
}
}
+
+func TestInitialReset(t *testing.T) {
+ var r Reader
+ if err := r.Reset(bytes.NewReader(gunzipTests[1].gzip)); err != nil {
+ t.Error(err)
+ }
+ var buf bytes.Buffer
+ if _, err := io.Copy(&buf, &r); err != nil {
+ t.Error(err)
+ }
+ if s := buf.String(); s != gunzipTests[1].raw {
+ t.Errorf("got %q want %q", s, gunzipTests[1].raw)
+ }
+}
+
+func TestMultistreamFalse(t *testing.T) {
+ // Find concatenation test.
+ var tt gunzipTest
+ for _, tt = range gunzipTests {
+ if strings.HasSuffix(tt.desc, " x2") {
+ goto Found
+ }
+ }
+ t.Fatal("cannot find hello.txt x2 in gunzip tests")
+
+Found:
+ br := bytes.NewReader(tt.gzip)
+ var r Reader
+ if err := r.Reset(br); err != nil {
+ t.Fatalf("first reset: %v", err)
+ }
+
+ // Expect two streams with "hello world\n", then real EOF.
+ const hello = "hello world\n"
+
+ r.Multistream(false)
+ data, err := ioutil.ReadAll(&r)
+ if string(data) != hello || err != nil {
+ t.Fatalf("first stream = %q, %v, want %q, %v", string(data), err, hello, nil)
+ }
+
+ if err := r.Reset(br); err != nil {
+ t.Fatalf("second reset: %v", err)
+ }
+ r.Multistream(false)
+ data, err = ioutil.ReadAll(&r)
+ if string(data) != hello || err != nil {
+ t.Fatalf("second stream = %q, %v, want %q, %v", string(data), err, hello, nil)
+ }
+
+ if err := r.Reset(br); err != io.EOF {
+ t.Fatalf("third reset: err=%v, want io.EOF", err)
+ }
+}
diff --git a/libgo/go/compress/gzip/gzip.go b/libgo/go/compress/gzip/gzip.go
index fe32d6871a..5131d128e4 100644
--- a/libgo/go/compress/gzip/gzip.go
+++ b/libgo/go/compress/gzip/gzip.go
@@ -22,8 +22,8 @@ const (
DefaultCompression = flate.DefaultCompression
)
-// A Writer is an io.WriteCloser that satisfies writes by compressing data written
-// to its wrapped io.Writer.
+// A Writer is an io.WriteCloser.
+// Writes to a Writer are compressed and written to w.
type Writer struct {
Header
w io.Writer
@@ -37,8 +37,8 @@ type Writer struct {
err error
}
-// NewWriter creates a new Writer that satisfies writes by compressing data
-// written to w.
+// NewWriter returns a new Writer.
+// Writes to the returned writer are compressed and written to w.
//
// It is the caller's responsibility to call Close on the WriteCloser when done.
// Writes may be buffered and not flushed until Close.
@@ -245,7 +245,8 @@ func (z *Writer) Flush() error {
return z.err
}
-// Close closes the Writer. It does not close the underlying io.Writer.
+// Close closes the Writer, flushing any unwritten data to the underlying
+// io.Writer, but does not close the underlying io.Writer.
func (z *Writer) Close() error {
if z.err != nil {
return z.err
diff --git a/libgo/go/compress/gzip/gzip_test.go b/libgo/go/compress/gzip/gzip_test.go
index 119be2e135..09271b24e9 100644
--- a/libgo/go/compress/gzip/gzip_test.go
+++ b/libgo/go/compress/gzip/gzip_test.go
@@ -85,7 +85,7 @@ func TestRoundTrip(t *testing.T) {
func TestLatin1(t *testing.T) {
latin1 := []byte{0xc4, 'u', 0xdf, 'e', 'r', 'u', 'n', 'g', 0}
utf8 := "Äußerung"
- z := Reader{r: bufio.NewReader(bytes.NewBuffer(latin1))}
+ z := Reader{r: bufio.NewReader(bytes.NewReader(latin1))}
s, err := z.readString()
if err != nil {
t.Fatalf("readString: %v", err)
diff --git a/libgo/go/compress/lzw/reader.go b/libgo/go/compress/lzw/reader.go
index efbc758f94..526620c827 100644
--- a/libgo/go/compress/lzw/reader.go
+++ b/libgo/go/compress/lzw/reader.go
@@ -6,12 +6,16 @@
// described in T. A. Welch, ``A Technique for High-Performance Data
// Compression'', Computer, 17(6) (June 1984), pp 8-19.
//
-// In particular, it implements LZW as used by the GIF, TIFF and PDF file
+// In particular, it implements LZW as used by the GIF and PDF file
// formats, which means variable-width codes up to 12 bits and the first
// two non-literal codes are a clear code and an EOF code.
+//
+// The TIFF file format uses a similar but incompatible version of the LZW
+// algorithm. See the golang.org/x/image/tiff/lzw package for an
+// implementation.
package lzw
-// TODO(nigeltao): check that TIFF and PDF use LZW in the same way as GIF,
+// TODO(nigeltao): check that PDF uses LZW in the same way as GIF,
// modulo LSB/MSB packing order.
import (
@@ -216,8 +220,10 @@ func (d *decoder) Close() error {
return nil
}
-// NewReader creates a new io.ReadCloser that satisfies reads by decompressing
-// the data read from r.
+// NewReader creates a new io.ReadCloser.
+// Reads from the returned io.ReadCloser read and decompress data from r.
+// If r does not also implement io.ByteReader,
+// the decompressor may read more data than necessary from r.
// It is the caller's responsibility to call Close on the ReadCloser when
// finished reading.
// The number of bits to use for literal codes, litWidth, must be in the
diff --git a/libgo/go/compress/lzw/reader_test.go b/libgo/go/compress/lzw/reader_test.go
index 6f155b1bde..9006c91c23 100644
--- a/libgo/go/compress/lzw/reader_test.go
+++ b/libgo/go/compress/lzw/reader_test.go
@@ -127,7 +127,7 @@ func benchmarkDecoder(b *testing.B, n int) {
if len(buf0) > n-i {
buf0 = buf0[:n-i]
}
- io.Copy(w, bytes.NewBuffer(buf0))
+ w.Write(buf0)
}
w.Close()
buf1 := compressed.Bytes()
@@ -135,7 +135,7 @@ func benchmarkDecoder(b *testing.B, n int) {
runtime.GC()
b.StartTimer()
for i := 0; i < b.N; i++ {
- io.Copy(ioutil.Discard, NewReader(bytes.NewBuffer(buf1), LSB, 8))
+ io.Copy(ioutil.Discard, NewReader(bytes.NewReader(buf1), LSB, 8))
}
}
diff --git a/libgo/go/compress/lzw/writer.go b/libgo/go/compress/lzw/writer.go
index b20691864b..961b25f94f 100644
--- a/libgo/go/compress/lzw/writer.go
+++ b/libgo/go/compress/lzw/writer.go
@@ -225,8 +225,8 @@ func (e *encoder) Close() error {
return e.w.Flush()
}
-// NewWriter creates a new io.WriteCloser that satisfies writes by compressing
-// the data and writing it to w.
+// NewWriter creates a new io.WriteCloser.
+// Writes to the returned io.WriteCloser are compressed and written to w.
// It is the caller's responsibility to call Close on the WriteCloser when
// finished writing.
// The number of bits to use for literal codes, litWidth, must be in the
diff --git a/libgo/go/compress/zlib/reader.go b/libgo/go/compress/zlib/reader.go
index d54746f4c0..816f1bf6bd 100644
--- a/libgo/go/compress/zlib/reader.go
+++ b/libgo/go/compress/zlib/reader.go
@@ -51,44 +51,36 @@ type reader struct {
scratch [4]byte
}
-// NewReader creates a new io.ReadCloser that satisfies reads by decompressing data read from r.
+// Resetter resets a ReadCloser returned by NewReader or NewReaderDict to
+// to switch to a new underlying Reader. This permits reusing a ReadCloser
+// instead of allocating a new one.
+type Resetter interface {
+ // Reset discards any buffered data and resets the Resetter as if it was
+ // newly initialized with the given reader.
+ Reset(r io.Reader, dict []byte) error
+}
+
+// NewReader creates a new ReadCloser.
+// Reads from the returned ReadCloser read and decompress data from r.
// The implementation buffers input and may read more data than necessary from r.
// It is the caller's responsibility to call Close on the ReadCloser when done.
+//
+// The ReadCloser returned by NewReader also implements Resetter.
func NewReader(r io.Reader) (io.ReadCloser, error) {
return NewReaderDict(r, nil)
}
// NewReaderDict is like NewReader but uses a preset dictionary.
// NewReaderDict ignores the dictionary if the compressed data does not refer to it.
+// If the compressed data refers to a different dictionary, NewReaderDict returns ErrDictionary.
+//
+// The ReadCloser returned by NewReaderDict also implements Resetter.
func NewReaderDict(r io.Reader, dict []byte) (io.ReadCloser, error) {
z := new(reader)
- if fr, ok := r.(flate.Reader); ok {
- z.r = fr
- } else {
- z.r = bufio.NewReader(r)
- }
- _, err := io.ReadFull(z.r, z.scratch[0:2])
+ err := z.Reset(r, dict)
if err != nil {
return nil, err
}
- h := uint(z.scratch[0])<<8 | uint(z.scratch[1])
- if (z.scratch[0]&0x0f != zlibDeflate) || (h%31 != 0) {
- return nil, ErrHeader
- }
- if z.scratch[1]&0x20 != 0 {
- _, err = io.ReadFull(z.r, z.scratch[0:4])
- if err != nil {
- return nil, err
- }
- checksum := uint32(z.scratch[0])<<24 | uint32(z.scratch[1])<<16 | uint32(z.scratch[2])<<8 | uint32(z.scratch[3])
- if checksum != adler32.Checksum(dict) {
- return nil, ErrDictionary
- }
- z.decompressor = flate.NewReaderDict(z.r, dict)
- } else {
- z.decompressor = flate.NewReader(z.r)
- }
- z.digest = adler32.New()
return z, nil
}
@@ -129,3 +121,41 @@ func (z *reader) Close() error {
z.err = z.decompressor.Close()
return z.err
}
+
+func (z *reader) Reset(r io.Reader, dict []byte) error {
+ if fr, ok := r.(flate.Reader); ok {
+ z.r = fr
+ } else {
+ z.r = bufio.NewReader(r)
+ }
+ _, err := io.ReadFull(z.r, z.scratch[0:2])
+ if err != nil {
+ return err
+ }
+ h := uint(z.scratch[0])<<8 | uint(z.scratch[1])
+ if (z.scratch[0]&0x0f != zlibDeflate) || (h%31 != 0) {
+ return ErrHeader
+ }
+ haveDict := z.scratch[1]&0x20 != 0
+ if haveDict {
+ _, err = io.ReadFull(z.r, z.scratch[0:4])
+ if err != nil {
+ return err
+ }
+ checksum := uint32(z.scratch[0])<<24 | uint32(z.scratch[1])<<16 | uint32(z.scratch[2])<<8 | uint32(z.scratch[3])
+ if checksum != adler32.Checksum(dict) {
+ return ErrDictionary
+ }
+ }
+ if z.decompressor == nil {
+ if haveDict {
+ z.decompressor = flate.NewReaderDict(z.r, dict)
+ } else {
+ z.decompressor = flate.NewReader(z.r)
+ }
+ } else {
+ z.decompressor.(flate.Resetter).Reset(z.r, dict)
+ }
+ z.digest = adler32.New()
+ return nil
+}
diff --git a/libgo/go/compress/zlib/reader_test.go b/libgo/go/compress/zlib/reader_test.go
index 3b02a08684..218ccba141 100644
--- a/libgo/go/compress/zlib/reader_test.go
+++ b/libgo/go/compress/zlib/reader_test.go
@@ -102,7 +102,7 @@ var zlibTests = []zlibTest{
func TestDecompressor(t *testing.T) {
b := new(bytes.Buffer)
for _, tt := range zlibTests {
- in := bytes.NewBuffer(tt.compressed)
+ in := bytes.NewReader(tt.compressed)
zlib, err := NewReaderDict(in, tt.dict)
if err != nil {
if err != tt.err {
diff --git a/libgo/go/compress/zlib/writer.go b/libgo/go/compress/zlib/writer.go
index 99ff6549ac..3b4313a8be 100644
--- a/libgo/go/compress/zlib/writer.go
+++ b/libgo/go/compress/zlib/writer.go
@@ -34,8 +34,8 @@ type Writer struct {
wroteHeader bool
}
-// NewWriter creates a new Writer that satisfies writes by compressing data
-// written to w.
+// NewWriter creates a new Writer.
+// Writes to the returned Writer are compressed and written to w.
//
// It is the caller's responsibility to call Close on the WriteCloser when done.
// Writes may be buffered and not flushed until Close.
@@ -174,7 +174,8 @@ func (z *Writer) Flush() error {
return z.err
}
-// Calling Close does not close the wrapped io.Writer originally passed to NewWriter.
+// Close closes the Writer, flushing any unwritten data to the underlying
+// io.Writer, but does not close the underlying io.Writer.
func (z *Writer) Close() error {
if !z.wroteHeader {
z.err = z.writeHeader()
diff --git a/libgo/go/compress/zlib/writer_test.go b/libgo/go/compress/zlib/writer_test.go
index cf9c832545..71ba81aaa7 100644
--- a/libgo/go/compress/zlib/writer_test.go
+++ b/libgo/go/compress/zlib/writer_test.go
@@ -120,7 +120,7 @@ func testFileLevelDictReset(t *testing.T, fn string, level int, dict []byte) {
}
out := buf.String()
- // Reset and comprses again.
+ // Reset and compress again.
buf2 := new(bytes.Buffer)
zlibw.Reset(buf2)
_, err = zlibw.Write(b0)
diff --git a/libgo/go/container/heap/heap.go b/libgo/go/container/heap/heap.go
index 52c8507b42..c467a11910 100644
--- a/libgo/go/container/heap/heap.go
+++ b/libgo/go/container/heap/heap.go
@@ -22,7 +22,7 @@ import "sort"
// min-heap with the following invariants (established after
// Init has been called or if the data is empty or sorted):
//
-// !h.Less(j, i) for 0 <= i < h.Len() and j = 2*i+1 or 2*i+2 and j < h.Len()
+// !h.Less(j, i) for 0 <= i < h.Len() and 2*i+1 <= j <= 2*i+2 and j < h.Len()
//
// Note that Push and Pop in this interface are for package heap's
// implementation to call. To add and remove things from the heap,
@@ -78,7 +78,7 @@ func Remove(h Interface, i int) interface{} {
return h.Pop()
}
-// Fix reestablishes the heap ordering after the element at index i has changed its value.
+// Fix re-establishes the heap ordering after the element at index i has changed its value.
// Changing the value of the element at index i and then calling Fix is equivalent to,
// but less expensive than, calling Remove(h, i) followed by a Push of the new value.
// The complexity is O(log(n)) where n = h.Len().
diff --git a/libgo/go/container/list/list.go b/libgo/go/container/list/list.go
index ed2d15a457..0256768efe 100755
--- a/libgo/go/container/list/list.go
+++ b/libgo/go/container/list/list.go
@@ -65,7 +65,7 @@ func New() *List { return new(List).Init() }
// The complexity is O(1).
func (l *List) Len() int { return l.len }
-// Front returns the first element of list l or nil
+// Front returns the first element of list l or nil.
func (l *List) Front() *Element {
if l.len == 0 {
return nil
@@ -180,18 +180,18 @@ func (l *List) MoveToBack(e *Element) {
}
// MoveBefore moves element e to its new position before mark.
-// If e is not an element of l, or e == mark, the list is not modified.
+// If e or mark is not an element of l, or e == mark, the list is not modified.
func (l *List) MoveBefore(e, mark *Element) {
- if e.list != l || e == mark {
+ if e.list != l || e == mark || mark.list != l {
return
}
l.insert(l.remove(e), mark.prev)
}
// MoveAfter moves element e to its new position after mark.
-// If e is not an element of l, or e == mark, the list is not modified.
+// If e or mark is not an element of l, or e == mark, the list is not modified.
func (l *List) MoveAfter(e, mark *Element) {
- if e.list != l || e == mark {
+ if e.list != l || e == mark || mark.list != l {
return
}
l.insert(l.remove(e), mark)
diff --git a/libgo/go/container/list/list_test.go b/libgo/go/container/list/list_test.go
index ee52afe82b..4d8bfc2bf0 100755
--- a/libgo/go/container/list/list_test.go
+++ b/libgo/go/container/list/list_test.go
@@ -285,3 +285,59 @@ func TestMove(t *testing.T) {
checkListPointers(t, l, []*Element{e1, e3, e2, e4})
e1, e2, e3, e4 = e1, e3, e2, e4
}
+
+// Test PushFront, PushBack, PushFrontList, PushBackList with uninitialized List
+func TestZeroList(t *testing.T) {
+ var l1 = new(List)
+ l1.PushFront(1)
+ checkList(t, l1, []interface{}{1})
+
+ var l2 = new(List)
+ l2.PushBack(1)
+ checkList(t, l2, []interface{}{1})
+
+ var l3 = new(List)
+ l3.PushFrontList(l1)
+ checkList(t, l3, []interface{}{1})
+
+ var l4 = new(List)
+ l4.PushBackList(l2)
+ checkList(t, l4, []interface{}{1})
+}
+
+// Test that a list l is not modified when calling InsertBefore with a mark that is not an element of l.
+func TestInsertBeforeUnknownMark(t *testing.T) {
+ var l List
+ l.PushBack(1)
+ l.PushBack(2)
+ l.PushBack(3)
+ l.InsertBefore(1, new(Element))
+ checkList(t, &l, []interface{}{1, 2, 3})
+}
+
+// Test that a list l is not modified when calling InsertAfter with a mark that is not an element of l.
+func TestInsertAfterUnknownMark(t *testing.T) {
+ var l List
+ l.PushBack(1)
+ l.PushBack(2)
+ l.PushBack(3)
+ l.InsertAfter(1, new(Element))
+ checkList(t, &l, []interface{}{1, 2, 3})
+}
+
+// Test that a list l is not modified when calling MoveAfter or MoveBefore with a mark that is not an element of l.
+func TestMoveUnkownMark(t *testing.T) {
+ var l1 List
+ e1 := l1.PushBack(1)
+
+ var l2 List
+ e2 := l2.PushBack(2)
+
+ l1.MoveAfter(e1, e2)
+ checkList(t, &l1, []interface{}{1})
+ checkList(t, &l2, []interface{}{2})
+
+ l1.MoveBefore(e1, e2)
+ checkList(t, &l1, []interface{}{1})
+ checkList(t, &l2, []interface{}{2})
+}
diff --git a/libgo/go/container/ring/ring_test.go b/libgo/go/container/ring/ring_test.go
index 099d92b25b..552f0e24b5 100644
--- a/libgo/go/container/ring/ring_test.go
+++ b/libgo/go/container/ring/ring_test.go
@@ -218,3 +218,11 @@ func TestLinkUnlink(t *testing.T) {
}
}
}
+
+// Test that calling Move() on an empty Ring initializes it.
+func TestMoveEmptyRing(t *testing.T) {
+ var r Ring
+
+ r.Move(1)
+ verify(t, &r, 1, 0)
+}
diff --git a/libgo/go/crypto/aes/aes_test.go b/libgo/go/crypto/aes/aes_test.go
index 6261dd09fb..363180931c 100644
--- a/libgo/go/crypto/aes/aes_test.go
+++ b/libgo/go/crypto/aes/aes_test.go
@@ -354,6 +354,34 @@ func TestCipherDecrypt(t *testing.T) {
}
}
+// Test short input/output.
+// Assembly used to not notice.
+// See issue 7928.
+func TestShortBlocks(t *testing.T) {
+ bytes := func(n int) []byte { return make([]byte, n) }
+
+ c, _ := NewCipher(bytes(16))
+
+ mustPanic(t, "crypto/aes: input not full block", func() { c.Encrypt(bytes(1), bytes(1)) })
+ mustPanic(t, "crypto/aes: input not full block", func() { c.Decrypt(bytes(1), bytes(1)) })
+ mustPanic(t, "crypto/aes: input not full block", func() { c.Encrypt(bytes(100), bytes(1)) })
+ mustPanic(t, "crypto/aes: input not full block", func() { c.Decrypt(bytes(100), bytes(1)) })
+ mustPanic(t, "crypto/aes: output not full block", func() { c.Encrypt(bytes(1), bytes(100)) })
+ mustPanic(t, "crypto/aes: output not full block", func() { c.Decrypt(bytes(1), bytes(100)) })
+}
+
+func mustPanic(t *testing.T, msg string, f func()) {
+ defer func() {
+ err := recover()
+ if err == nil {
+ t.Errorf("function did not panic, wanted %q", msg)
+ } else if err != msg {
+ t.Errorf("got panic %v, wanted %q", err, msg)
+ }
+ }()
+ f()
+}
+
func BenchmarkEncrypt(b *testing.B) {
tt := encryptTests[0]
c, err := NewCipher(tt.key)
diff --git a/libgo/go/crypto/aes/cipher.go b/libgo/go/crypto/aes/cipher.go
index d931134a70..2c6bb0a89c 100644
--- a/libgo/go/crypto/aes/cipher.go
+++ b/libgo/go/crypto/aes/cipher.go
@@ -46,9 +46,21 @@ func NewCipher(key []byte) (cipher.Block, error) {
func (c *aesCipher) BlockSize() int { return BlockSize }
func (c *aesCipher) Encrypt(dst, src []byte) {
+ if len(src) < BlockSize {
+ panic("crypto/aes: input not full block")
+ }
+ if len(dst) < BlockSize {
+ panic("crypto/aes: output not full block")
+ }
encryptBlock(c.enc, dst, src)
}
func (c *aesCipher) Decrypt(dst, src []byte) {
+ if len(src) < BlockSize {
+ panic("crypto/aes: input not full block")
+ }
+ if len(dst) < BlockSize {
+ panic("crypto/aes: output not full block")
+ }
decryptBlock(c.dec, dst, src)
}
diff --git a/libgo/go/crypto/aes/cipher_asm.go b/libgo/go/crypto/aes/cipher_asm.go
index 21369fc382..964eaaa6f8 100644
--- a/libgo/go/crypto/aes/cipher_asm.go
+++ b/libgo/go/crypto/aes/cipher_asm.go
@@ -21,6 +21,7 @@ func encryptBlock(xk []uint32, dst, src []byte) {
encryptBlockGo(xk, dst, src)
}
}
+
func decryptBlock(xk []uint32, dst, src []byte) {
if useAsm {
decryptBlockAsm(len(xk)/4-1, &xk[0], &dst[0], &src[0])
@@ -28,6 +29,7 @@ func decryptBlock(xk []uint32, dst, src []byte) {
decryptBlockGo(xk, dst, src)
}
}
+
func expandKey(key []byte, enc, dec []uint32) {
if useAsm {
rounds := 10
diff --git a/libgo/go/crypto/cipher/benchmark_test.go b/libgo/go/crypto/cipher/benchmark_test.go
new file mode 100644
index 0000000000..027b248510
--- /dev/null
+++ b/libgo/go/crypto/cipher/benchmark_test.go
@@ -0,0 +1,139 @@
+// 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 cipher_test
+
+import (
+ "crypto/aes"
+ "crypto/cipher"
+ "testing"
+)
+
+func BenchmarkAESGCMSeal1K(b *testing.B) {
+ buf := make([]byte, 1024)
+ b.SetBytes(int64(len(buf)))
+
+ var key [16]byte
+ var nonce [12]byte
+ aes, _ := aes.NewCipher(key[:])
+ aesgcm, _ := cipher.NewGCM(aes)
+ var out []byte
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ out = aesgcm.Seal(out[:0], nonce[:], buf, nonce[:])
+ }
+}
+
+func BenchmarkAESGCMOpen1K(b *testing.B) {
+ buf := make([]byte, 1024)
+ b.SetBytes(int64(len(buf)))
+
+ var key [16]byte
+ var nonce [12]byte
+ aes, _ := aes.NewCipher(key[:])
+ aesgcm, _ := cipher.NewGCM(aes)
+ var out []byte
+ out = aesgcm.Seal(out[:0], nonce[:], buf, nonce[:])
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ _, err := aesgcm.Open(buf[:0], nonce[:], out, nonce[:])
+ if err != nil {
+ b.Errorf("Open: %v", err)
+ }
+ }
+}
+
+// If we test exactly 1K blocks, we would generate exact multiples of
+// the cipher's block size, and the cipher stream fragments would
+// always be wordsize aligned, whereas non-aligned is a more typical
+// use-case.
+const almost1K = 1024 - 5
+
+func BenchmarkAESCFBEncrypt1K(b *testing.B) {
+ buf := make([]byte, almost1K)
+ b.SetBytes(int64(len(buf)))
+
+ var key [16]byte
+ var iv [16]byte
+ aes, _ := aes.NewCipher(key[:])
+ ctr := cipher.NewCFBEncrypter(aes, iv[:])
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ ctr.XORKeyStream(buf, buf)
+ }
+}
+
+func BenchmarkAESCFBDecrypt1K(b *testing.B) {
+ buf := make([]byte, almost1K)
+ b.SetBytes(int64(len(buf)))
+
+ var key [16]byte
+ var iv [16]byte
+ aes, _ := aes.NewCipher(key[:])
+ ctr := cipher.NewCFBDecrypter(aes, iv[:])
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ ctr.XORKeyStream(buf, buf)
+ }
+}
+
+func BenchmarkAESOFB1K(b *testing.B) {
+ buf := make([]byte, almost1K)
+ b.SetBytes(int64(len(buf)))
+
+ var key [16]byte
+ var iv [16]byte
+ aes, _ := aes.NewCipher(key[:])
+ ctr := cipher.NewOFB(aes, iv[:])
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ ctr.XORKeyStream(buf, buf)
+ }
+}
+
+func BenchmarkAESCTR1K(b *testing.B) {
+ buf := make([]byte, almost1K)
+ b.SetBytes(int64(len(buf)))
+
+ var key [16]byte
+ var iv [16]byte
+ aes, _ := aes.NewCipher(key[:])
+ ctr := cipher.NewCTR(aes, iv[:])
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ ctr.XORKeyStream(buf, buf)
+ }
+}
+
+func BenchmarkAESCBCEncrypt1K(b *testing.B) {
+ buf := make([]byte, 1024)
+ b.SetBytes(int64(len(buf)))
+
+ var key [16]byte
+ var iv [16]byte
+ aes, _ := aes.NewCipher(key[:])
+ cbc := cipher.NewCBCEncrypter(aes, iv[:])
+ for i := 0; i < b.N; i++ {
+ cbc.CryptBlocks(buf, buf)
+ }
+}
+
+func BenchmarkAESCBCDecrypt1K(b *testing.B) {
+ buf := make([]byte, 1024)
+ b.SetBytes(int64(len(buf)))
+
+ var key [16]byte
+ var iv [16]byte
+ aes, _ := aes.NewCipher(key[:])
+ cbc := cipher.NewCBCDecrypter(aes, iv[:])
+ for i := 0; i < b.N; i++ {
+ cbc.CryptBlocks(buf, buf)
+ }
+}
diff --git a/libgo/go/crypto/cipher/cbc.go b/libgo/go/crypto/cipher/cbc.go
index 4189677e39..241e122ee8 100644
--- a/libgo/go/crypto/cipher/cbc.go
+++ b/libgo/go/crypto/cipher/cbc.go
@@ -48,17 +48,22 @@ func (x *cbcEncrypter) CryptBlocks(dst, src []byte) {
if len(dst) < len(src) {
panic("crypto/cipher: output smaller than input")
}
+
+ iv := x.iv
+
for len(src) > 0 {
- for i := 0; i < x.blockSize; i++ {
- x.iv[i] ^= src[i]
- }
- x.b.Encrypt(x.iv, x.iv)
- for i := 0; i < x.blockSize; i++ {
- dst[i] = x.iv[i]
- }
+ // Write the xor to dst, then encrypt in place.
+ xorBytes(dst[:x.blockSize], src[:x.blockSize], iv)
+ x.b.Encrypt(dst[:x.blockSize], dst[:x.blockSize])
+
+ // Move to the next block with this block as the next iv.
+ iv = dst[:x.blockSize]
src = src[x.blockSize:]
dst = dst[x.blockSize:]
}
+
+ // Save the iv for the next CryptBlocks call.
+ copy(x.iv, iv)
}
func (x *cbcEncrypter) SetIV(iv []byte) {
@@ -89,17 +94,35 @@ func (x *cbcDecrypter) CryptBlocks(dst, src []byte) {
if len(dst) < len(src) {
panic("crypto/cipher: output smaller than input")
}
- for len(src) > 0 {
- x.b.Decrypt(x.tmp, src[:x.blockSize])
- for i := 0; i < x.blockSize; i++ {
- x.tmp[i] ^= x.iv[i]
- x.iv[i] = src[i]
- dst[i] = x.tmp[i]
- }
+ if len(src) == 0 {
+ return
+ }
- src = src[x.blockSize:]
- dst = dst[x.blockSize:]
+ // For each block, we need to xor the decrypted data with the previous block's ciphertext (the iv).
+ // To avoid making a copy each time, we loop over the blocks BACKWARDS.
+ end := len(src)
+ start := end - x.blockSize
+ prev := start - x.blockSize
+
+ // Copy the last block of ciphertext in preparation as the new iv.
+ copy(x.tmp, src[start:end])
+
+ // Loop over all but the first block.
+ for start > 0 {
+ x.b.Decrypt(dst[start:end], src[start:end])
+ xorBytes(dst[start:end], dst[start:end], src[prev:start])
+
+ end = start
+ start = prev
+ prev -= x.blockSize
}
+
+ // The first block is special because it uses the saved iv.
+ x.b.Decrypt(dst[start:end], src[start:end])
+ xorBytes(dst[start:end], dst[start:end], x.iv)
+
+ // Set the new iv to the first block we copied earlier.
+ x.iv, x.tmp = x.tmp, x.iv
}
func (x *cbcDecrypter) SetIV(iv []byte) {
diff --git a/libgo/go/crypto/cipher/cbc_aes_test.go b/libgo/go/crypto/cipher/cbc_aes_test.go
index cee3a784b5..bf9e7ad701 100644
--- a/libgo/go/crypto/cipher/cbc_aes_test.go
+++ b/libgo/go/crypto/cipher/cbc_aes_test.go
@@ -63,28 +63,42 @@ var cbcAESTests = []struct {
},
}
-func TestCBC_AES(t *testing.T) {
- for _, tt := range cbcAESTests {
- test := tt.name
-
- c, err := aes.NewCipher(tt.key)
+func TestCBCEncrypterAES(t *testing.T) {
+ for _, test := range cbcAESTests {
+ c, err := aes.NewCipher(test.key)
if err != nil {
- t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
+ t.Errorf("%s: NewCipher(%d bytes) = %s", test.name, len(test.key), err)
continue
}
- encrypter := cipher.NewCBCEncrypter(c, tt.iv)
- d := make([]byte, len(tt.in))
- encrypter.CryptBlocks(d, tt.in)
- if !bytes.Equal(tt.out, d) {
- t.Errorf("%s: CBCEncrypter\nhave %x\nwant %x", test, d, tt.out)
+ encrypter := cipher.NewCBCEncrypter(c, test.iv)
+
+ data := make([]byte, len(test.in))
+ copy(data, test.in)
+
+ encrypter.CryptBlocks(data, data)
+ if !bytes.Equal(test.out, data) {
+ t.Errorf("%s: CBCEncrypter\nhave %x\nwant %x", test.name, data, test.out)
}
+ }
+}
+
+func TestCBCDecrypterAES(t *testing.T) {
+ for _, test := range cbcAESTests {
+ c, err := aes.NewCipher(test.key)
+ if err != nil {
+ t.Errorf("%s: NewCipher(%d bytes) = %s", test.name, len(test.key), err)
+ continue
+ }
+
+ decrypter := cipher.NewCBCDecrypter(c, test.iv)
+
+ data := make([]byte, len(test.out))
+ copy(data, test.out)
- decrypter := cipher.NewCBCDecrypter(c, tt.iv)
- p := make([]byte, len(d))
- decrypter.CryptBlocks(p, d)
- if !bytes.Equal(tt.in, p) {
- t.Errorf("%s: CBCDecrypter\nhave %x\nwant %x", test, d, tt.in)
+ decrypter.CryptBlocks(data, data)
+ if !bytes.Equal(test.in, data) {
+ t.Errorf("%s: CBCDecrypter\nhave %x\nwant %x", test.name, data, test.in)
}
}
}
diff --git a/libgo/go/crypto/cipher/cfb.go b/libgo/go/crypto/cipher/cfb.go
index 99006b546d..9b4eebf5b4 100644
--- a/libgo/go/crypto/cipher/cfb.go
+++ b/libgo/go/crypto/cipher/cfb.go
@@ -8,18 +8,41 @@ package cipher
type cfb struct {
b Block
+ next []byte
out []byte
outUsed int
+
decrypt bool
}
+func (x *cfb) XORKeyStream(dst, src []byte) {
+ for len(src) > 0 {
+ if x.outUsed == len(x.out) {
+ x.b.Encrypt(x.out, x.next)
+ x.outUsed = 0
+ }
+
+ if x.decrypt {
+ // We can precompute a larger segment of the
+ // keystream on decryption. This will allow
+ // larger batches for xor, and we should be
+ // able to match CTR/OFB performance.
+ copy(x.next[x.outUsed:], src)
+ }
+ n := xorBytes(dst, src, x.out[x.outUsed:])
+ if !x.decrypt {
+ copy(x.next[x.outUsed:], dst)
+ }
+ dst = dst[n:]
+ src = src[n:]
+ x.outUsed += n
+ }
+}
+
// NewCFBEncrypter returns a Stream which encrypts with cipher feedback mode,
// using the given Block. The iv must be the same length as the Block's block
// size.
func NewCFBEncrypter(block Block, iv []byte) Stream {
- if len(iv) != block.BlockSize() {
- panic("cipher.NewCBFEncrypter: IV length must equal block size")
- }
return newCFB(block, iv, false)
}
@@ -27,44 +50,23 @@ func NewCFBEncrypter(block Block, iv []byte) Stream {
// using the given Block. The iv must be the same length as the Block's block
// size.
func NewCFBDecrypter(block Block, iv []byte) Stream {
- if len(iv) != block.BlockSize() {
- panic("cipher.NewCBFEncrypter: IV length must equal block size")
- }
return newCFB(block, iv, true)
}
func newCFB(block Block, iv []byte, decrypt bool) Stream {
blockSize := block.BlockSize()
if len(iv) != blockSize {
- return nil
+ // stack trace will indicate whether it was de or encryption
+ panic("cipher.newCFB: IV length must equal block size")
}
-
x := &cfb{
b: block,
out: make([]byte, blockSize),
- outUsed: 0,
+ next: make([]byte, blockSize),
+ outUsed: blockSize,
decrypt: decrypt,
}
- block.Encrypt(x.out, iv)
+ copy(x.next, iv)
return x
}
-
-func (x *cfb) XORKeyStream(dst, src []byte) {
- for i := 0; i < len(src); i++ {
- if x.outUsed == len(x.out) {
- x.b.Encrypt(x.out, x.out)
- x.outUsed = 0
- }
-
- if x.decrypt {
- t := src[i]
- dst[i] = src[i] ^ x.out[x.outUsed]
- x.out[x.outUsed] = t
- } else {
- x.out[x.outUsed] ^= src[i]
- dst[i] = x.out[x.outUsed]
- }
- x.outUsed++
- }
-}
diff --git a/libgo/go/crypto/cipher/cfb_test.go b/libgo/go/crypto/cipher/cfb_test.go
index f704b337e4..9b544bb211 100644
--- a/libgo/go/crypto/cipher/cfb_test.go
+++ b/libgo/go/crypto/cipher/cfb_test.go
@@ -9,26 +9,103 @@ import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
+ "encoding/hex"
"testing"
)
-func TestCFB(t *testing.T) {
+// cfbTests contains the test vectors from
+// http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf, section
+// F.3.13.
+var cfbTests = []struct {
+ key, iv, plaintext, ciphertext string
+}{
+ {
+ "2b7e151628aed2a6abf7158809cf4f3c",
+ "000102030405060708090a0b0c0d0e0f",
+ "6bc1bee22e409f96e93d7e117393172a",
+ "3b3fd92eb72dad20333449f8e83cfb4a",
+ },
+ {
+ "2b7e151628aed2a6abf7158809cf4f3c",
+ "3B3FD92EB72DAD20333449F8E83CFB4A",
+ "ae2d8a571e03ac9c9eb76fac45af8e51",
+ "c8a64537a0b3a93fcde3cdad9f1ce58b",
+ },
+ {
+ "2b7e151628aed2a6abf7158809cf4f3c",
+ "C8A64537A0B3A93FCDE3CDAD9F1CE58B",
+ "30c81c46a35ce411e5fbc1191a0a52ef",
+ "26751f67a3cbb140b1808cf187a4f4df",
+ },
+ {
+ "2b7e151628aed2a6abf7158809cf4f3c",
+ "26751F67A3CBB140B1808CF187A4F4DF",
+ "f69f2445df4f9b17ad2b417be66c3710",
+ "c04b05357c5d1c0eeac4c66f9ff7f2e6",
+ },
+}
+
+func TestCFBVectors(t *testing.T) {
+ for i, test := range cfbTests {
+ key, err := hex.DecodeString(test.key)
+ if err != nil {
+ t.Fatal(err)
+ }
+ iv, err := hex.DecodeString(test.iv)
+ if err != nil {
+ t.Fatal(err)
+ }
+ plaintext, err := hex.DecodeString(test.plaintext)
+ if err != nil {
+ t.Fatal(err)
+ }
+ expected, err := hex.DecodeString(test.ciphertext)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ block, err := aes.NewCipher(key)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ ciphertext := make([]byte, len(plaintext))
+ cfb := cipher.NewCFBEncrypter(block, iv)
+ cfb.XORKeyStream(ciphertext, plaintext)
+
+ if !bytes.Equal(ciphertext, expected) {
+ t.Errorf("#%d: wrong output: got %x, expected %x", i, ciphertext, expected)
+ }
+
+ cfbdec := cipher.NewCFBDecrypter(block, iv)
+ plaintextCopy := make([]byte, len(ciphertext))
+ cfbdec.XORKeyStream(plaintextCopy, ciphertext)
+
+ if !bytes.Equal(plaintextCopy, plaintextCopy) {
+ t.Errorf("#%d: wrong plaintext: got %x, expected %x", i, plaintextCopy, plaintext)
+ }
+ }
+}
+
+func TestCFBInverse(t *testing.T) {
block, err := aes.NewCipher(commonKey128)
if err != nil {
t.Error(err)
return
}
- plaintext := []byte("this is the plaintext")
+ plaintext := []byte("this is the plaintext. this is the plaintext.")
iv := make([]byte, block.BlockSize())
rand.Reader.Read(iv)
cfb := cipher.NewCFBEncrypter(block, iv)
ciphertext := make([]byte, len(plaintext))
- cfb.XORKeyStream(ciphertext, plaintext)
+ copy(ciphertext, plaintext)
+ cfb.XORKeyStream(ciphertext, ciphertext)
cfbdec := cipher.NewCFBDecrypter(block, iv)
plaintextCopy := make([]byte, len(plaintext))
- cfbdec.XORKeyStream(plaintextCopy, ciphertext)
+ copy(plaintextCopy, ciphertext)
+ cfbdec.XORKeyStream(plaintextCopy, plaintextCopy)
if !bytes.Equal(plaintextCopy, plaintext) {
t.Errorf("got: %x, want: %x", plaintextCopy, plaintext)
diff --git a/libgo/go/crypto/cipher/cipher.go b/libgo/go/crypto/cipher/cipher.go
index 1ffaa8c2c3..67afdb1e05 100644
--- a/libgo/go/crypto/cipher/cipher.go
+++ b/libgo/go/crypto/cipher/cipher.go
@@ -46,16 +46,6 @@ type BlockMode interface {
// Utility routines
-func shift1(dst, src []byte) byte {
- var b byte
- for i := len(src) - 1; i >= 0; i-- {
- bb := src[i] >> 7
- dst[i] = src[i]<<1 | b
- b = bb
- }
- return b
-}
-
func dup(p []byte) []byte {
q := make([]byte, len(p))
copy(q, p)
diff --git a/libgo/go/crypto/cipher/ctr.go b/libgo/go/crypto/cipher/ctr.go
index d9ee9d8272..70ac40f6a7 100644
--- a/libgo/go/crypto/cipher/ctr.go
+++ b/libgo/go/crypto/cipher/ctr.go
@@ -19,37 +19,58 @@ type ctr struct {
outUsed int
}
+const streamBufferSize = 512
+
// NewCTR returns a Stream which encrypts/decrypts using the given Block in
// counter mode. The length of iv must be the same as the Block's block size.
func NewCTR(block Block, iv []byte) Stream {
if len(iv) != block.BlockSize() {
panic("cipher.NewCTR: IV length must equal block size")
}
-
+ bufSize := streamBufferSize
+ if bufSize < block.BlockSize() {
+ bufSize = block.BlockSize()
+ }
return &ctr{
b: block,
ctr: dup(iv),
- out: make([]byte, len(iv)),
- outUsed: len(iv),
+ out: make([]byte, 0, bufSize),
+ outUsed: 0,
}
}
-func (x *ctr) XORKeyStream(dst, src []byte) {
- for i := 0; i < len(src); i++ {
- if x.outUsed == len(x.ctr) {
- x.b.Encrypt(x.out, x.ctr)
- x.outUsed = 0
-
- // Increment counter
- for i := len(x.ctr) - 1; i >= 0; i-- {
- x.ctr[i]++
- if x.ctr[i] != 0 {
- break
- }
+func (x *ctr) refill() {
+ remain := len(x.out) - x.outUsed
+ if remain > x.outUsed {
+ return
+ }
+ copy(x.out, x.out[x.outUsed:])
+ x.out = x.out[:cap(x.out)]
+ bs := x.b.BlockSize()
+ for remain < len(x.out)-bs {
+ x.b.Encrypt(x.out[remain:], x.ctr)
+ remain += bs
+
+ // Increment counter
+ for i := len(x.ctr) - 1; i >= 0; i-- {
+ x.ctr[i]++
+ if x.ctr[i] != 0 {
+ break
}
}
+ }
+ x.out = x.out[:remain]
+ x.outUsed = 0
+}
- dst[i] = src[i] ^ x.out[x.outUsed]
- x.outUsed++
+func (x *ctr) XORKeyStream(dst, src []byte) {
+ for len(src) > 0 {
+ if x.outUsed >= len(x.out)-x.b.BlockSize() {
+ x.refill()
+ }
+ n := xorBytes(dst, src, x.out[x.outUsed:])
+ dst = dst[n:]
+ src = src[n:]
+ x.outUsed += n
}
}
diff --git a/libgo/go/crypto/cipher/example_test.go b/libgo/go/crypto/cipher/example_test.go
index 373f6791be..1cfa982df4 100644
--- a/libgo/go/crypto/cipher/example_test.go
+++ b/libgo/go/crypto/cipher/example_test.go
@@ -240,7 +240,7 @@ func ExampleStreamReader() {
}
// Note that this example is simplistic in that it omits any
- // authentication of the encrypted data. It you were actually to use
+ // authentication of the encrypted data. If you were actually to use
// StreamReader in this manner, an attacker could flip arbitrary bits in
// the output.
}
@@ -277,7 +277,7 @@ func ExampleStreamWriter() {
}
// Note that this example is simplistic in that it omits any
- // authentication of the encrypted data. It you were actually to use
+ // authentication of the encrypted data. If you were actually to use
// StreamReader in this manner, an attacker could flip arbitrary bits in
// the decrypted result.
}
diff --git a/libgo/go/crypto/cipher/gcm.go b/libgo/go/crypto/cipher/gcm.go
index 2bcb469852..bdafd85fc3 100644
--- a/libgo/go/crypto/cipher/gcm.go
+++ b/libgo/go/crypto/cipher/gcm.go
@@ -30,9 +30,9 @@ type AEAD interface {
// Open decrypts and authenticates ciphertext, authenticates the
// additional data and, if successful, appends the resulting plaintext
- // to dst, returning the updated slice and true. On error, nil and
- // false is returned. The nonce must be NonceSize() bytes long and both
- // it and the additional data must match the value passed to Seal.
+ // to dst, returning the updated slice. The nonce must be NonceSize()
+ // bytes long and both it and the additional data must match the
+ // value passed to Seal.
//
// The ciphertext and dst may alias exactly or not at all.
Open(dst, nonce, ciphertext, data []byte) ([]byte, error)
@@ -258,11 +258,11 @@ func (g *gcm) update(y *gcmFieldElement, data []byte) {
// gcmInc32 treats the final four bytes of counterBlock as a big-endian value
// and increments it.
func gcmInc32(counterBlock *[16]byte) {
- c := 1
for i := gcmBlockSize - 1; i >= gcmBlockSize-4; i-- {
- c += int(counterBlock[i])
- counterBlock[i] = byte(c)
- c >>= 8
+ counterBlock[i]++
+ if counterBlock[i] != 0 {
+ break
+ }
}
}
@@ -289,9 +289,7 @@ func (g *gcm) counterCrypt(out, in []byte, counter *[gcmBlockSize]byte) {
g.cipher.Encrypt(mask[:], counter[:])
gcmInc32(counter)
- for i := range mask {
- out[i] = in[i] ^ mask[i]
- }
+ xorWords(out, in, mask[:])
out = out[gcmBlockSize:]
in = in[gcmBlockSize:]
}
@@ -299,10 +297,7 @@ func (g *gcm) counterCrypt(out, in []byte, counter *[gcmBlockSize]byte) {
if len(in) > 0 {
g.cipher.Encrypt(mask[:], counter[:])
gcmInc32(counter)
-
- for i := range in {
- out[i] = in[i] ^ mask[i]
- }
+ xorBytes(out, in, mask[:])
}
}
@@ -321,9 +316,7 @@ func (g *gcm) auth(out, ciphertext, additionalData []byte, tagMask *[gcmTagSize]
putUint64(out, y.low)
putUint64(out[8:], y.high)
- for i := range tagMask {
- out[i] ^= tagMask[i]
- }
+ xorWords(out, out, tagMask[:])
}
func getUint64(data []byte) uint64 {
diff --git a/libgo/go/crypto/cipher/gcm_test.go b/libgo/go/crypto/cipher/gcm_test.go
index 02d4215900..0c502ce405 100644
--- a/libgo/go/crypto/cipher/gcm_test.go
+++ b/libgo/go/crypto/cipher/gcm_test.go
@@ -157,19 +157,3 @@ func TestAESGCM(t *testing.T) {
ct[0] ^= 0x80
}
}
-
-func BenchmarkAESGCM(b *testing.B) {
- buf := make([]byte, 1024)
- b.SetBytes(int64(len(buf)))
-
- var key [16]byte
- var nonce [12]byte
- aes, _ := aes.NewCipher(key[:])
- aesgcm, _ := cipher.NewGCM(aes)
- var out []byte
-
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- out = aesgcm.Seal(out[:0], nonce[:], buf, nonce[:])
- }
-}
diff --git a/libgo/go/crypto/cipher/ofb.go b/libgo/go/crypto/cipher/ofb.go
index 85e5f02b0a..e86ebcb237 100644
--- a/libgo/go/crypto/cipher/ofb.go
+++ b/libgo/go/crypto/cipher/ofb.go
@@ -8,6 +8,7 @@ package cipher
type ofb struct {
b Block
+ cipher []byte
out []byte
outUsed int
}
@@ -20,25 +21,46 @@ func NewOFB(b Block, iv []byte) Stream {
if len(iv) != blockSize {
return nil
}
-
+ bufSize := streamBufferSize
+ if bufSize < blockSize {
+ bufSize = blockSize
+ }
x := &ofb{
b: b,
- out: make([]byte, blockSize),
+ cipher: make([]byte, blockSize),
+ out: make([]byte, 0, bufSize),
outUsed: 0,
}
- b.Encrypt(x.out, iv)
+ copy(x.cipher, iv)
return x
}
+func (x *ofb) refill() {
+ bs := x.b.BlockSize()
+ remain := len(x.out) - x.outUsed
+ if remain > x.outUsed {
+ return
+ }
+ copy(x.out, x.out[x.outUsed:])
+ x.out = x.out[:cap(x.out)]
+ for remain < len(x.out)-bs {
+ x.b.Encrypt(x.cipher, x.cipher)
+ copy(x.out[remain:], x.cipher)
+ remain += bs
+ }
+ x.out = x.out[:remain]
+ x.outUsed = 0
+}
+
func (x *ofb) XORKeyStream(dst, src []byte) {
- for i, s := range src {
- if x.outUsed == len(x.out) {
- x.b.Encrypt(x.out, x.out)
- x.outUsed = 0
+ for len(src) > 0 {
+ if x.outUsed >= len(x.out)-x.b.BlockSize() {
+ x.refill()
}
-
- dst[i] = s ^ x.out[x.outUsed]
- x.outUsed++
+ n := xorBytes(dst, src, x.out[x.outUsed:])
+ dst = dst[n:]
+ src = src[n:]
+ x.outUsed += n
}
}
diff --git a/libgo/go/crypto/cipher/xor.go b/libgo/go/crypto/cipher/xor.go
new file mode 100644
index 0000000000..f88dc8914a
--- /dev/null
+++ b/libgo/go/crypto/cipher/xor.go
@@ -0,0 +1,84 @@
+// 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 cipher
+
+import (
+ "runtime"
+ "unsafe"
+)
+
+const wordSize = int(unsafe.Sizeof(uintptr(0)))
+const supportsUnaligned = runtime.GOARCH == "386" || runtime.GOARCH == "amd64"
+
+// fastXORBytes xors in bulk. It only works on architectures that
+// support unaligned read/writes.
+func fastXORBytes(dst, a, b []byte) int {
+ n := len(a)
+ if len(b) < n {
+ n = len(b)
+ }
+
+ w := n / wordSize
+ if w > 0 {
+ dw := *(*[]uintptr)(unsafe.Pointer(&dst))
+ aw := *(*[]uintptr)(unsafe.Pointer(&a))
+ bw := *(*[]uintptr)(unsafe.Pointer(&b))
+ for i := 0; i < w; i++ {
+ dw[i] = aw[i] ^ bw[i]
+ }
+ }
+
+ for i := (n - n%wordSize); i < n; i++ {
+ dst[i] = a[i] ^ b[i]
+ }
+
+ return n
+}
+
+func safeXORBytes(dst, a, b []byte) int {
+ n := len(a)
+ if len(b) < n {
+ n = len(b)
+ }
+ for i := 0; i < n; i++ {
+ dst[i] = a[i] ^ b[i]
+ }
+ return n
+}
+
+// xorBytes xors the bytes in a and b. The destination is assumed to have enough
+// space. Returns the number of bytes xor'd.
+func xorBytes(dst, a, b []byte) int {
+ if supportsUnaligned {
+ return fastXORBytes(dst, a, b)
+ } else {
+ // TODO(hanwen): if (dst, a, b) have common alignment
+ // we could still try fastXORBytes. It is not clear
+ // how often this happens, and it's only worth it if
+ // the block encryption itself is hardware
+ // accelerated.
+ return safeXORBytes(dst, a, b)
+ }
+}
+
+// fastXORWords XORs multiples of 4 or 8 bytes (depending on architecture.)
+// The arguments are assumed to be of equal length.
+func fastXORWords(dst, a, b []byte) {
+ dw := *(*[]uintptr)(unsafe.Pointer(&dst))
+ aw := *(*[]uintptr)(unsafe.Pointer(&a))
+ bw := *(*[]uintptr)(unsafe.Pointer(&b))
+ n := len(b) / wordSize
+ for i := 0; i < n; i++ {
+ dw[i] = aw[i] ^ bw[i]
+ }
+}
+
+func xorWords(dst, a, b []byte) {
+ if supportsUnaligned {
+ fastXORWords(dst, a, b)
+ } else {
+ safeXORBytes(dst, a, b)
+ }
+}
diff --git a/libgo/go/crypto/cipher/xor_test.go b/libgo/go/crypto/cipher/xor_test.go
new file mode 100644
index 0000000000..cc1c9d72d5
--- /dev/null
+++ b/libgo/go/crypto/cipher/xor_test.go
@@ -0,0 +1,28 @@
+// 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 cipher
+
+import (
+ "bytes"
+ "testing"
+)
+
+func TestXOR(t *testing.T) {
+ for alignP := 0; alignP < 2; alignP++ {
+ for alignQ := 0; alignQ < 2; alignQ++ {
+ for alignD := 0; alignD < 2; alignD++ {
+ p := make([]byte, 1024)[alignP:]
+ q := make([]byte, 1024)[alignQ:]
+ d1 := make([]byte, 1024+alignD)[alignD:]
+ d2 := make([]byte, 1024+alignD)[alignD:]
+ xorBytes(d1, p, q)
+ safeXORBytes(d2, p, q)
+ if bytes.Compare(d1, d2) != 0 {
+ t.Error("not equal")
+ }
+ }
+ }
+ }
+}
diff --git a/libgo/go/crypto/crypto.go b/libgo/go/crypto/crypto.go
index 4b03628e69..59b23e93f5 100644
--- a/libgo/go/crypto/crypto.go
+++ b/libgo/go/crypto/crypto.go
@@ -7,6 +7,7 @@ package crypto
import (
"hash"
+ "io"
"strconv"
)
@@ -14,8 +15,13 @@ import (
// package.
type Hash uint
+// HashFunc simply returns the value of h so that Hash implements SignerOpts.
+func (h Hash) HashFunc() Hash {
+ return h
+}
+
const (
- MD4 Hash = 1 + iota // import code.google.com/p/go.crypto/md4
+ MD4 Hash = 1 + iota // import golang.org/x/crypto/md4
MD5 // import crypto/md5
SHA1 // import crypto/sha1
SHA224 // import crypto/sha256
@@ -23,7 +29,11 @@ const (
SHA384 // import crypto/sha512
SHA512 // import crypto/sha512
MD5SHA1 // no implementation; MD5+SHA1 used for TLS RSA
- RIPEMD160 // import code.google.com/p/go.crypto/ripemd160
+ 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
maxHash
)
@@ -35,6 +45,10 @@ var digestSizes = []uint8{
SHA256: 32,
SHA384: 48,
SHA512: 64,
+ SHA3_224: 28,
+ SHA3_256: 32,
+ SHA3_384: 48,
+ SHA3_512: 64,
MD5SHA1: 36,
RIPEMD160: 20,
}
@@ -83,3 +97,30 @@ type PublicKey interface{}
// PrivateKey represents a private key using an unspecified algorithm.
type PrivateKey interface{}
+
+// Signer is an interface for an opaque private key that can be used for
+// signing operations. For example, an RSA key kept in a hardware module.
+type Signer interface {
+ // Public returns the public key corresponding to the opaque,
+ // private key.
+ Public() PublicKey
+
+ // Sign signs msg with the private key, possibly using entropy from
+ // rand. For an RSA key, the resulting signature should be either a
+ // PKCS#1 v1.5 or PSS signature (as indicated by opts). For an (EC)DSA
+ // key, it should be a DER-serialised, ASN.1 signature structure.
+ //
+ // Hash implements the SignerOpts interface and, in most cases, one can
+ // simply pass in the hash function used as opts. Sign may also attempt
+ // to type assert opts to other types in order to obtain algorithm
+ // specific values. See the documentation in each package for details.
+ Sign(rand io.Reader, msg []byte, opts SignerOpts) (signature []byte, err error)
+}
+
+// SignerOpts contains options for signing with a Signer.
+type SignerOpts interface {
+ // HashFunc returns an identifier for the hash function used to produce
+ // the message passed to Signer.Sign, or else zero to indicate that no
+ // hashing was done.
+ HashFunc() Hash
+}
diff --git a/libgo/go/crypto/dsa/dsa.go b/libgo/go/crypto/dsa/dsa.go
index 5a2a65744e..b7565a61b0 100644
--- a/libgo/go/crypto/dsa/dsa.go
+++ b/libgo/go/crypto/dsa/dsa.go
@@ -173,6 +173,16 @@ func GenerateKey(priv *PrivateKey, rand io.Reader) error {
return nil
}
+// fermatInverse calculates the inverse of k in GF(P) using Fermat's method.
+// This has better constant-time properties than Euclid's method (implemented
+// in math/big.Int.ModInverse) although math/big itself isn't strictly
+// constant-time so it's not perfect.
+func fermatInverse(k, P *big.Int) *big.Int {
+ two := big.NewInt(2)
+ pMinus2 := new(big.Int).Sub(P, two)
+ return new(big.Int).Exp(k, pMinus2, P)
+}
+
// Sign signs an arbitrary length hash (which should be the result of hashing a
// larger message) using the private key, priv. It returns the signature as a
// pair of integers. The security of the private key depends on the entropy of
@@ -205,7 +215,7 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err
}
}
- kInv := new(big.Int).ModInverse(k, priv.Q)
+ kInv := fermatInverse(k, priv.Q)
r = new(big.Int).Exp(priv.G, k, priv.P)
r.Mod(r, priv.Q)
diff --git a/libgo/go/crypto/ecdsa/ecdsa.go b/libgo/go/crypto/ecdsa/ecdsa.go
index d02f15c34d..d6135531bf 100644
--- a/libgo/go/crypto/ecdsa/ecdsa.go
+++ b/libgo/go/crypto/ecdsa/ecdsa.go
@@ -13,7 +13,9 @@ package ecdsa
// http://www.secg.org/download/aid-780/sec1-v2.pdf
import (
+ "crypto"
"crypto/elliptic"
+ "encoding/asn1"
"io"
"math/big"
)
@@ -30,6 +32,28 @@ type PrivateKey struct {
D *big.Int
}
+type ecdsaSignature struct {
+ R, S *big.Int
+}
+
+// Public returns the public key corresponding to priv.
+func (priv *PrivateKey) Public() crypto.PublicKey {
+ return &priv.PublicKey
+}
+
+// Sign signs msg with priv, reading randomness from rand. This method is
+// intended to support keys where the private part is kept in, for example, a
+// hardware module. Common uses should use the Sign function in this package
+// directly.
+func (priv *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) {
+ r, s, err := Sign(rand, priv, msg)
+ if err != nil {
+ return nil, err
+ }
+
+ return asn1.Marshal(ecdsaSignature{r, s})
+}
+
var one = new(big.Int).SetInt64(1)
// randFieldElement returns a random element of the field underlying the given
@@ -84,6 +108,16 @@ func hashToInt(hash []byte, c elliptic.Curve) *big.Int {
return ret
}
+// fermatInverse calculates the inverse of k in GF(P) using Fermat's method.
+// This has better constant-time properties than Euclid's method (implemented
+// in math/big.Int.ModInverse) although math/big itself isn't strictly
+// constant-time so it's not perfect.
+func fermatInverse(k, N *big.Int) *big.Int {
+ two := big.NewInt(2)
+ nMinus2 := new(big.Int).Sub(N, two)
+ return new(big.Int).Exp(k, nMinus2, N)
+}
+
// Sign signs an arbitrary length hash (which should be the result of hashing a
// larger message) using the private key, priv. It returns the signature as a
// pair of integers. The security of the private key depends on the entropy of
@@ -102,7 +136,7 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err
return
}
- kInv = new(big.Int).ModInverse(k, N)
+ kInv = fermatInverse(k, N)
r, _ = priv.Curve.ScalarBaseMult(k.Bytes())
r.Mod(r, N)
if r.Sign() != 0 {
diff --git a/libgo/go/crypto/hmac/hmac_test.go b/libgo/go/crypto/hmac/hmac_test.go
index d4860424eb..e80b7e0baa 100644
--- a/libgo/go/crypto/hmac/hmac_test.go
+++ b/libgo/go/crypto/hmac/hmac_test.go
@@ -15,10 +15,12 @@ import (
)
type hmacTest struct {
- hash func() hash.Hash
- key []byte
- in []byte
- out string
+ hash func() hash.Hash
+ key []byte
+ in []byte
+ out string
+ size int
+ blocksize int
}
var hmacTests = []hmacTest{
@@ -38,6 +40,8 @@ var hmacTests = []hmacTest{
},
[]byte("Sample #1"),
"4f4ca3d5d68ba7cc0a1208c9c61e9c5da0403c0a",
+ sha1.Size,
+ sha1.BlockSize,
},
{
sha1.New,
@@ -48,6 +52,8 @@ var hmacTests = []hmacTest{
},
[]byte("Sample #2"),
"0922d3405faa3d194f82a45830737d5cc6c75d24",
+ sha1.Size,
+ sha1.BlockSize,
},
{
sha1.New,
@@ -68,6 +74,8 @@ var hmacTests = []hmacTest{
},
[]byte("Sample #3"),
"bcf41eab8bb2d802f3d05caf7cb092ecf8d1a3aa",
+ sha1.Size,
+ sha1.BlockSize,
},
// Test from Plan 9.
@@ -76,6 +84,8 @@ var hmacTests = []hmacTest{
[]byte("Jefe"),
[]byte("what do ya want for nothing?"),
"750c783e6ab0b503eaa86e310a5db738",
+ md5.Size,
+ md5.BlockSize,
},
// Tests from RFC 4231
@@ -88,12 +98,16 @@ var hmacTests = []hmacTest{
},
[]byte("Hi There"),
"b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7",
+ sha256.Size,
+ sha256.BlockSize,
},
{
sha256.New,
[]byte("Jefe"),
[]byte("what do ya want for nothing?"),
"5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843",
+ sha256.Size,
+ sha256.BlockSize,
},
{
sha256.New,
@@ -112,6 +126,8 @@ var hmacTests = []hmacTest{
0xdd, 0xdd,
},
"773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe",
+ sha256.Size,
+ sha256.BlockSize,
},
{
sha256.New,
@@ -131,6 +147,8 @@ var hmacTests = []hmacTest{
0xcd, 0xcd,
},
"82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b",
+ sha256.Size,
+ sha256.BlockSize,
},
{
sha256.New,
@@ -155,6 +173,8 @@ var hmacTests = []hmacTest{
},
[]byte("Test Using Larger Than Block-Size Key - Hash Key First"),
"60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54",
+ sha256.Size,
+ sha256.BlockSize,
},
{
sha256.New,
@@ -181,6 +201,8 @@ var hmacTests = []hmacTest{
"and a larger than block-size data. The key needs to " +
"be hashed before being used by the HMAC algorithm."),
"9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2",
+ sha256.Size,
+ sha256.BlockSize,
},
// Tests from http://csrc.nist.gov/groups/ST/toolkit/examples.html
@@ -199,6 +221,8 @@ var hmacTests = []hmacTest{
},
[]byte("Sample message for keylen=blocklen"),
"5fd596ee78d5553c8ff4e72d266dfd192366da29",
+ sha1.Size,
+ sha1.BlockSize,
},
{
sha1.New,
@@ -209,6 +233,8 @@ var hmacTests = []hmacTest{
},
[]byte("Sample message for keylen<blocklen"),
"4c99ff0cb1b31bd33f8431dbaf4d17fcd356a807",
+ sha1.Size,
+ sha1.BlockSize,
},
{
sha1.New,
@@ -229,6 +255,8 @@ var hmacTests = []hmacTest{
},
[]byte("Sample message for keylen=blocklen"),
"2d51b2f7750e410584662e38f133435f4c4fd42a",
+ sha1.Size,
+ sha1.BlockSize,
},
{
sha256.New224,
@@ -244,6 +272,8 @@ var hmacTests = []hmacTest{
},
[]byte("Sample message for keylen=blocklen"),
"c7405e3ae058e8cd30b08b4140248581ed174cb34e1224bcc1efc81b",
+ sha256.Size224,
+ sha256.BlockSize,
},
{
sha256.New224,
@@ -255,6 +285,8 @@ var hmacTests = []hmacTest{
},
[]byte("Sample message for keylen<blocklen"),
"e3d249a8cfb67ef8b7a169e9a0a599714a2cecba65999a51beb8fbbe",
+ sha256.Size224,
+ sha256.BlockSize,
},
{
sha256.New224,
@@ -275,6 +307,8 @@ var hmacTests = []hmacTest{
},
[]byte("Sample message for keylen=blocklen"),
"91c52509e5af8531601ae6230099d90bef88aaefb961f4080abc014d",
+ sha256.Size224,
+ sha256.BlockSize,
},
{
sha256.New,
@@ -290,6 +324,8 @@ var hmacTests = []hmacTest{
},
[]byte("Sample message for keylen=blocklen"),
"8bb9a1db9806f20df7f77b82138c7914d174d59e13dc4d0169c9057b133e1d62",
+ sha256.Size,
+ sha256.BlockSize,
},
{
sha256.New,
@@ -301,6 +337,8 @@ var hmacTests = []hmacTest{
},
[]byte("Sample message for keylen<blocklen"),
"a28cf43130ee696a98f14a37678b56bcfcbdd9e5cf69717fecf5480f0ebdf790",
+ sha256.Size,
+ sha256.BlockSize,
},
{
sha256.New,
@@ -321,6 +359,8 @@ var hmacTests = []hmacTest{
},
[]byte("Sample message for keylen=blocklen"),
"bdccb6c72ddeadb500ae768386cb38cc41c63dbb0878ddb9c7a38a431b78378d",
+ sha256.Size,
+ sha256.BlockSize,
},
{
sha512.New384,
@@ -344,6 +384,8 @@ var hmacTests = []hmacTest{
},
[]byte("Sample message for keylen=blocklen"),
"63c5daa5e651847ca897c95814ab830bededc7d25e83eef9195cd45857a37f448947858f5af50cc2b1b730ddf29671a9",
+ sha512.Size384,
+ sha512.BlockSize,
},
{
sha512.New384,
@@ -357,6 +399,8 @@ var hmacTests = []hmacTest{
},
[]byte("Sample message for keylen<blocklen"),
"6eb242bdbb582ca17bebfa481b1e23211464d2b7f8c20b9ff2201637b93646af5ae9ac316e98db45d9cae773675eeed0",
+ sha512.Size384,
+ sha512.BlockSize,
},
{
sha512.New384,
@@ -389,6 +433,8 @@ var hmacTests = []hmacTest{
},
[]byte("Sample message for keylen=blocklen"),
"5b664436df69b0ca22551231a3f0a3d5b4f97991713cfa84bff4d0792eff96c27dccbbb6f79b65d548b40e8564cef594",
+ sha512.Size384,
+ sha512.BlockSize,
},
{
sha512.New,
@@ -414,6 +460,8 @@ var hmacTests = []hmacTest{
"fc25e240658ca785b7a811a8d3f7b4ca" +
"48cfa26a8a366bf2cd1f836b05fcb024bd36853081811d6c" +
"ea4216ebad79da1cfcb95ea4586b8a0ce356596a55fb1347",
+ sha512.Size,
+ sha512.BlockSize,
},
{
sha512.New,
@@ -431,6 +479,8 @@ var hmacTests = []hmacTest{
"fd44c18bda0bb0a6ce0e82b031bf2818" +
"f6539bd56ec00bdc10a8a2d730b3634de2545d639b0f2cf7" +
"10d0692c72a1896f1f211c2b922d1a96c392e07e7ea9fedc",
+ sha512.Size,
+ sha512.BlockSize,
},
{
sha512.New,
@@ -465,12 +515,20 @@ var hmacTests = []hmacTest{
"d93ec8d2de1ad2a9957cb9b83f14e76a" +
"d6b5e0cce285079a127d3b14bccb7aa7286d4ac0d4ce6421" +
"5f2bc9e6870b33d97438be4aaa20cda5c5a912b48b8e27f3",
+ sha512.Size,
+ sha512.BlockSize,
},
}
func TestHMAC(t *testing.T) {
for i, tt := range hmacTests {
h := New(tt.hash, tt.key)
+ if s := h.Size(); s != tt.size {
+ t.Errorf("Size: got %v, want %v", s, tt.size)
+ }
+ if b := h.BlockSize(); b != tt.blocksize {
+ t.Errorf("BlockSize: got %v, want %v", b, tt.blocksize)
+ }
for j := 0; j < 2; j++ {
n, err := h.Write(tt.in)
if n != len(tt.in) || err != nil {
diff --git a/libgo/go/crypto/md5/gen.go b/libgo/go/crypto/md5/gen.go
index ccaa7c13d3..8cd0a6358e 100644
--- a/libgo/go/crypto/md5/gen.go
+++ b/libgo/go/crypto/md5/gen.go
@@ -7,7 +7,7 @@
// This program generates md5block.go
// Invoke as
//
-// go run gen.go [-full] |gofmt >md5block.go
+// go run gen.go [-full] -output md5block.go
//
// The -full flag causes the generated code to do a full
// (16x) unrolling instead of a 4x unrolling.
@@ -15,18 +15,33 @@
package main
import (
+ "bytes"
"flag"
+ "go/format"
+ "io/ioutil"
"log"
- "os"
"strings"
"text/template"
)
+var filename = flag.String("output", "md5block.go", "output file name")
+
func main() {
flag.Parse()
+ var buf bytes.Buffer
+
t := template.Must(template.New("main").Funcs(funcs).Parse(program))
- if err := t.Execute(os.Stdout, data); err != nil {
+ if err := t.Execute(&buf, data); err != nil {
+ log.Fatal(err)
+ }
+
+ data, err := format.Source(buf.Bytes())
+ if err != nil {
+ log.Fatal(err)
+ }
+ err = ioutil.WriteFile(*filename, data, 0644)
+ if err != nil {
log.Fatal(err)
}
}
@@ -160,11 +175,12 @@ var data = Data{
},
}
-var program = `
-// DO NOT EDIT.
-// Generate with: go run gen.go{{if .Full}} -full{{end}} | gofmt >md5block.go
+var program = `// 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 !amd64,!386,!arm
+// DO NOT EDIT.
+// Generate with: go run gen.go{{if .Full}} -full{{end}} -output md5block.go
package md5
@@ -201,7 +217,7 @@ func init() {
littleEndian = *(*[4]byte)(unsafe.Pointer(&x)) == y
}
-func block(dig *digest, p []byte) {
+func blockGeneric(dig *digest, p []byte) {
a := dig.s[0]
b := dig.s[1]
c := dig.s[2]
diff --git a/libgo/go/crypto/md5/md5.go b/libgo/go/crypto/md5/md5.go
index 1a1f35fabc..8c50c6d0bf 100644
--- a/libgo/go/crypto/md5/md5.go
+++ b/libgo/go/crypto/md5/md5.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 gen.go -full -output md5block.go
+
// Package md5 implements the MD5 hash algorithm as defined in RFC 1321.
package md5
diff --git a/libgo/go/crypto/md5/md5_test.go b/libgo/go/crypto/md5/md5_test.go
index a8b7a1a525..e7faf4961e 100644
--- a/libgo/go/crypto/md5/md5_test.go
+++ b/libgo/go/crypto/md5/md5_test.go
@@ -5,6 +5,7 @@
package md5
import (
+ "crypto/rand"
"fmt"
"io"
"testing"
@@ -105,6 +106,18 @@ func TestLarge(t *testing.T) {
}
}
+// Tests that blockGeneric (pure Go) and block (in assembly for amd64, 386, arm) match.
+func TestBlockGeneric(t *testing.T) {
+ gen, asm := New().(*digest), New().(*digest)
+ buf := make([]byte, BlockSize*20) // arbitrary factor
+ rand.Read(buf)
+ blockGeneric(gen, buf)
+ block(asm, buf)
+ if *gen != *asm {
+ t.Error("block and blockGeneric resulted in different states")
+ }
+}
+
var bench = New()
var buf = make([]byte, 8192+1)
var sum = make([]byte, bench.Size())
diff --git a/libgo/go/crypto/md5/md5block.go b/libgo/go/crypto/md5/md5block.go
index 3e739e36ff..64e1e7c1ef 100644
--- a/libgo/go/crypto/md5/md5block.go
+++ b/libgo/go/crypto/md5/md5block.go
@@ -1,7 +1,9 @@
-// DO NOT EDIT.
-// Generate with: go run gen.go -full | gofmt >md5block.go
+// 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 !amd64,!386,!arm
+// DO NOT EDIT.
+// Generate with: go run gen.go -full -output md5block.go
package md5
@@ -20,7 +22,7 @@ func init() {
littleEndian = *(*[4]byte)(unsafe.Pointer(&x)) == y
}
-func block(dig *digest, p []byte) {
+func blockGeneric(dig *digest, p []byte) {
a := dig.s[0]
b := dig.s[1]
c := dig.s[2]
diff --git a/libgo/go/crypto/md5/md5block_decl.go b/libgo/go/crypto/md5/md5block_decl.go
index c4d6aaaf03..d7956a6d20 100644
--- a/libgo/go/crypto/md5/md5block_decl.go
+++ b/libgo/go/crypto/md5/md5block_decl.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 amd64 386 arm
+// +build amd64 amd64p32 386 arm
package md5
diff --git a/libgo/go/crypto/md5/md5block_generic.go b/libgo/go/crypto/md5/md5block_generic.go
new file mode 100644
index 0000000000..263463e51c
--- /dev/null
+++ b/libgo/go/crypto/md5/md5block_generic.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.
+
+// +build !amd64,!amd64p32,!386,!arm
+
+package md5
+
+var block = blockGeneric
diff --git a/libgo/go/crypto/rand/rand_linux.go b/libgo/go/crypto/rand/rand_linux.go
new file mode 100644
index 0000000000..8cb59c75df
--- /dev/null
+++ b/libgo/go/crypto/rand/rand_linux.go
@@ -0,0 +1,39 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rand
+
+import (
+ "internal/syscall"
+ "sync"
+)
+
+func init() {
+ altGetRandom = getRandomLinux
+}
+
+var (
+ once sync.Once
+ useSyscall bool
+)
+
+func pickStrategy() {
+ // Test whether we should use the system call or /dev/urandom.
+ // We'll fall back to urandom if:
+ // - the kernel is too old (before 3.17)
+ // - 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)
+ useSyscall = n == 1 && err == nil
+}
+
+func getRandomLinux(p []byte) (ok bool) {
+ once.Do(pickStrategy)
+ if !useSyscall {
+ return false
+ }
+ n, err := syscall.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 238ceee557..62d0fbdb35 100644
--- a/libgo/go/crypto/rand/rand_unix.go
+++ b/libgo/go/crypto/rand/rand_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 netbsd openbsd plan9
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris
// Unix cryptographically secure pseudorandom number
// generator.
@@ -20,6 +20,8 @@ import (
"time"
)
+const urandomDevice = "/dev/urandom"
+
// Easy implementation: read from /dev/urandom.
// This is sufficient on Linux, OS X, and FreeBSD.
@@ -27,7 +29,7 @@ func init() {
if runtime.GOOS == "plan9" {
Reader = newReader(nil)
} else {
- Reader = &devReader{name: "/dev/urandom"}
+ Reader = &devReader{name: urandomDevice}
}
}
@@ -38,7 +40,14 @@ type devReader struct {
mu sync.Mutex
}
+// altGetRandom if non-nil specifies an OS-specific function to get
+// urandom-style randomness.
+var altGetRandom func([]byte) (ok bool)
+
func (r *devReader) Read(b []byte) (n int, err error) {
+ if altGetRandom != nil && r.name == urandomDevice && altGetRandom(b) {
+ return len(b), nil
+ }
r.mu.Lock()
defer r.mu.Unlock()
if r.f == nil {
diff --git a/libgo/go/crypto/rand/util.go b/libgo/go/crypto/rand/util.go
index 0cd5e0e022..5f74407850 100644
--- a/libgo/go/crypto/rand/util.go
+++ b/libgo/go/crypto/rand/util.go
@@ -27,9 +27,11 @@ var smallPrimesProduct = new(big.Int).SetUint64(16294579238595022365)
// Prime returns a number, p, of the given size, such that p is prime
// with high probability.
+// Prime will return error for any error returned by rand.Read or if bits < 2.
func Prime(rand io.Reader, bits int) (p *big.Int, err error) {
- if bits < 1 {
- err = errors.New("crypto/rand: prime size must be positive")
+ if bits < 2 {
+ err = errors.New("crypto/rand: prime size must be at least 2-bit")
+ return
}
b := uint(bits % 8)
@@ -79,7 +81,7 @@ func Prime(rand io.Reader, bits int) (p *big.Int, err error) {
for delta := uint64(0); delta < 1<<20; delta += 2 {
m := mod + delta
for _, prime := range smallPrimes {
- if m%uint64(prime) == 0 {
+ if m%uint64(prime) == 0 && (bits > 6 || m != uint64(prime)) {
continue NextDelta
}
}
diff --git a/libgo/go/crypto/rand/util_test.go b/libgo/go/crypto/rand/util_test.go
new file mode 100644
index 0000000000..1e2a4dd84b
--- /dev/null
+++ b/libgo/go/crypto/rand/util_test.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 rand_test
+
+import (
+ "crypto/rand"
+ "math/big"
+ "testing"
+)
+
+// http://golang.org/issue/6849.
+func TestPrimeSmall(t *testing.T) {
+ for n := 2; n < 10; n++ {
+ p, err := rand.Prime(rand.Reader, n)
+ if err != nil {
+ t.Fatalf("Can't generate %d-bit prime: %v", n, err)
+ }
+ if p.BitLen() != n {
+ t.Fatalf("%v is not %d-bit", p, n)
+ }
+ if !p.ProbablyPrime(32) {
+ t.Fatalf("%v is not prime", p)
+ }
+ }
+}
+
+// Test that passing bits < 2 causes Prime to return nil, error
+func TestPrimeBitsLt2(t *testing.T) {
+ if p, err := rand.Prime(rand.Reader, 1); p != nil || err == nil {
+ t.Errorf("Prime should return nil, error when called with bits < 2")
+ }
+}
+
+func TestInt(t *testing.T) {
+ // start at 128 so the case of (max.BitLen() % 8) == 0 is covered
+ for n := 128; n < 140; n++ {
+ b := new(big.Int).SetInt64(int64(n))
+ if i, err := rand.Int(rand.Reader, b); err != nil {
+ t.Fatalf("Can't generate random value: %v, %v", i, err)
+ }
+ }
+}
+
+func testIntPanics(t *testing.T, b *big.Int) {
+ defer func() {
+ if err := recover(); err == nil {
+ t.Errorf("Int should panic when called with max <= 0: %v", b)
+ }
+ }()
+ rand.Int(rand.Reader, b)
+}
+
+// Test that passing a new big.Int as max causes Int to panic
+func TestIntEmptyMaxPanics(t *testing.T) {
+ b := new(big.Int)
+ testIntPanics(t, b)
+}
+
+// Test that passing a negative value as max causes Int to panic
+func TestIntNegativeMaxPanics(t *testing.T) {
+ b := new(big.Int).SetInt64(int64(-1))
+ testIntPanics(t, b)
+}
diff --git a/libgo/go/crypto/rc4/rc4.go b/libgo/go/crypto/rc4/rc4.go
index 3d717c63b0..9acb681bfb 100644
--- a/libgo/go/crypto/rc4/rc4.go
+++ b/libgo/go/crypto/rc4/rc4.go
@@ -50,3 +50,20 @@ func (c *Cipher) Reset() {
}
c.i, c.j = 0, 0
}
+
+// xorKeyStreamGeneric sets dst to the result of XORing src with the
+// key stream. Dst and src may be the same slice but otherwise should
+// not overlap.
+//
+// This is the pure Go version. rc4_{amd64,386,arm}* contain assembly
+// implementations. This is here for tests and to prevent bitrot.
+func (c *Cipher) xorKeyStreamGeneric(dst, src []byte) {
+ i, j := c.i, c.j
+ for k, v := range src {
+ i += 1
+ j += uint8(c.s[i])
+ c.s[i], c.s[j] = c.s[j], c.s[i]
+ dst[k] = v ^ uint8(c.s[uint8(c.s[i]+c.s[j])])
+ }
+ c.i, c.j = i, j
+}
diff --git a/libgo/go/crypto/rc4/rc4_asm.go b/libgo/go/crypto/rc4/rc4_asm.go
index c582a4488b..02e5b67d55 100644
--- a/libgo/go/crypto/rc4/rc4_asm.go
+++ b/libgo/go/crypto/rc4/rc4_asm.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 amd64 arm 386
+// +build amd64 amd64p32 arm,!nacl 386
package rc4
diff --git a/libgo/go/crypto/rc4/rc4_ref.go b/libgo/go/crypto/rc4/rc4_ref.go
index 13d52b95dd..e34bd34cf1 100644
--- a/libgo/go/crypto/rc4/rc4_ref.go
+++ b/libgo/go/crypto/rc4/rc4_ref.go
@@ -2,19 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !amd64,!arm,!386
+// +build !amd64,!amd64p32,!arm,!386 arm,nacl
package rc4
// XORKeyStream sets dst to the result of XORing src with the key stream.
// Dst and src may be the same slice but otherwise should not overlap.
func (c *Cipher) XORKeyStream(dst, src []byte) {
- i, j := c.i, c.j
- for k, v := range src {
- i += 1
- j += uint8(c.s[i])
- c.s[i], c.s[j] = c.s[j], c.s[i]
- dst[k] = v ^ byte(c.s[byte(c.s[i]+c.s[j])])
- }
- c.i, c.j = i, j
+ c.xorKeyStreamGeneric(dst, src)
}
diff --git a/libgo/go/crypto/rc4/rc4_test.go b/libgo/go/crypto/rc4/rc4_test.go
index 7b4df6791d..af79882463 100644
--- a/libgo/go/crypto/rc4/rc4_test.go
+++ b/libgo/go/crypto/rc4/rc4_test.go
@@ -117,19 +117,30 @@ func TestGolden(t *testing.T) {
}
func TestBlock(t *testing.T) {
+ testBlock(t, (*Cipher).XORKeyStream)
+}
+
+// Test the pure Go version.
+// Because we have assembly for amd64, 386, and arm, this prevents
+// bitrot of the reference implementations.
+func TestBlockGeneric(t *testing.T) {
+ testBlock(t, (*Cipher).xorKeyStreamGeneric)
+}
+
+func testBlock(t *testing.T, xor func(c *Cipher, dst, src []byte)) {
c1a, _ := NewCipher(golden[0].key)
c1b, _ := NewCipher(golden[1].key)
data1 := make([]byte, 1<<20)
for i := range data1 {
- c1a.XORKeyStream(data1[i:i+1], data1[i:i+1])
- c1b.XORKeyStream(data1[i:i+1], data1[i:i+1])
+ xor(c1a, data1[i:i+1], data1[i:i+1])
+ xor(c1b, data1[i:i+1], data1[i:i+1])
}
c2a, _ := NewCipher(golden[0].key)
c2b, _ := NewCipher(golden[1].key)
data2 := make([]byte, 1<<20)
- c2a.XORKeyStream(data2, data2)
- c2b.XORKeyStream(data2, data2)
+ xor(c2a, data2, data2)
+ xor(c2b, data2, data2)
if !bytes.Equal(data1, data2) {
t.Fatalf("bad block")
diff --git a/libgo/go/crypto/rsa/pkcs1v15.go b/libgo/go/crypto/rsa/pkcs1v15.go
index 1a055a3d62..59e8bb5b7b 100644
--- a/libgo/go/crypto/rsa/pkcs1v15.go
+++ b/libgo/go/crypto/rsa/pkcs1v15.go
@@ -53,11 +53,14 @@ func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (out [
if err := checkPub(&priv.PublicKey); err != nil {
return nil, err
}
- valid, out, err := decryptPKCS1v15(rand, priv, ciphertext)
- if err == nil && valid == 0 {
- err = ErrDecryption
+ valid, out, index, err := decryptPKCS1v15(rand, priv, ciphertext)
+ if err != nil {
+ return
}
-
+ if valid == 0 {
+ return nil, ErrDecryption
+ }
+ out = out[index:]
return
}
@@ -80,21 +83,32 @@ func DecryptPKCS1v15SessionKey(rand io.Reader, priv *PrivateKey, ciphertext []by
}
k := (priv.N.BitLen() + 7) / 8
if k-(len(key)+3+8) < 0 {
- err = ErrDecryption
- return
+ return ErrDecryption
}
- valid, msg, err := decryptPKCS1v15(rand, priv, ciphertext)
+ valid, em, index, err := decryptPKCS1v15(rand, priv, ciphertext)
if err != nil {
return
}
- valid &= subtle.ConstantTimeEq(int32(len(msg)), int32(len(key)))
- subtle.ConstantTimeCopy(valid, key, msg)
+ if len(em) != k {
+ // This should be impossible because decryptPKCS1v15 always
+ // returns the full slice.
+ return ErrDecryption
+ }
+
+ valid &= subtle.ConstantTimeEq(int32(len(em)-index), int32(len(key)))
+ subtle.ConstantTimeCopy(valid, key, em[len(em)-len(key):])
return
}
-func decryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (valid int, msg []byte, err error) {
+// decryptPKCS1v15 decrypts ciphertext using priv and blinds the operation if
+// rand is not nil. It returns one or zero in valid that indicates whether the
+// plaintext was correctly structured. In either case, the plaintext is
+// returned in em so that it may be read independently of whether it was valid
+// in order to maintain constant memory access patterns. If the plaintext was
+// valid then index contains the index of the original message in em.
+func decryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (valid int, em []byte, index int, err error) {
k := (priv.N.BitLen() + 7) / 8
if k < 11 {
err = ErrDecryption
@@ -107,7 +121,7 @@ func decryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (valid
return
}
- em := leftPad(m.Bytes(), k)
+ em = leftPad(m.Bytes(), k)
firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0)
secondByteIsTwo := subtle.ConstantTimeByteEq(em[1], 2)
@@ -115,8 +129,7 @@ func decryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (valid
// octets, followed by a 0, followed by the message.
// lookingForIndex: 1 iff we are still looking for the zero.
// index: the offset of the first zero byte.
- var lookingForIndex, index int
- lookingForIndex = 1
+ lookingForIndex := 1
for i := 2; i < len(em); i++ {
equals0 := subtle.ConstantTimeByteEq(em[i], 0)
@@ -129,8 +142,8 @@ func decryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (valid
validPS := subtle.ConstantTimeLessOrEq(2+8, index)
valid = firstByteIsZero & secondByteIsTwo & (^lookingForIndex & 1) & validPS
- msg = em[index+1:]
- return
+ index = subtle.ConstantTimeSelect(valid, index+1, 0)
+ return valid, em, index, nil
}
// nonZeroRandomBytes fills the given slice with non-zero random octets.
@@ -176,7 +189,8 @@ var hashPrefixes = map[crypto.Hash][]byte{
// SignPKCS1v15 calculates the signature of hashed using RSASSA-PKCS1-V1_5-SIGN from RSA PKCS#1 v1.5.
// Note that hashed must be the result of hashing the input message using the
-// given hash function.
+// given hash function. If hash is zero, hashed is signed directly. This isn't
+// advisable except for interoperability.
func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) (s []byte, err error) {
hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
if err != nil {
@@ -212,7 +226,8 @@ func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []b
// VerifyPKCS1v15 verifies an RSA PKCS#1 v1.5 signature.
// hashed is the result of hashing the input message using the given hash
// function and sig is the signature. A valid signature is indicated by
-// returning a nil error.
+// returning a nil error. If hash is zero then hashed is used directly. This
+// isn't advisable except for interoperability.
func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) (err error) {
hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
if err != nil {
@@ -249,6 +264,12 @@ func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte)
}
func pkcs1v15HashInfo(hash crypto.Hash, inLen int) (hashLen int, prefix []byte, err error) {
+ // Special case: crypto.Hash(0) is used to indicate that the data is
+ // signed directly.
+ if hash == 0 {
+ return inLen, nil, nil
+ }
+
hashLen = hash.Size()
if inLen != hashLen {
return 0, nil, errors.New("crypto/rsa: input must be hashed message")
diff --git a/libgo/go/crypto/rsa/pkcs1v15_test.go b/libgo/go/crypto/rsa/pkcs1v15_test.go
index 70bb228899..2dc5dbc2c8 100644
--- a/libgo/go/crypto/rsa/pkcs1v15_test.go
+++ b/libgo/go/crypto/rsa/pkcs1v15_test.go
@@ -205,6 +205,48 @@ func TestOverlongMessagePKCS1v15(t *testing.T) {
}
}
+func TestUnpaddedSignature(t *testing.T) {
+ msg := []byte("Thu Dec 19 18:06:16 EST 2013\n")
+ // This base64 value was generated with:
+ // % echo Thu Dec 19 18:06:16 EST 2013 > /tmp/msg
+ // % openssl rsautl -sign -inkey key -out /tmp/sig -in /tmp/msg
+ //
+ // Where "key" contains the RSA private key given at the bottom of this
+ // file.
+ expectedSig := decodeBase64("pX4DR8azytjdQ1rtUiC040FjkepuQut5q2ZFX1pTjBrOVKNjgsCDyiJDGZTCNoh9qpXYbhl7iEym30BWWwuiZg==")
+
+ sig, err := SignPKCS1v15(nil, rsaPrivateKey, crypto.Hash(0), msg)
+ if err != nil {
+ t.Fatalf("SignPKCS1v15 failed: %s", err)
+ }
+ if !bytes.Equal(sig, expectedSig) {
+ t.Fatalf("signature is not expected value: got %x, want %x", sig, expectedSig)
+ }
+ if err := VerifyPKCS1v15(&rsaPrivateKey.PublicKey, crypto.Hash(0), msg, sig); err != nil {
+ t.Fatalf("signature failed to verify: %s", err)
+ }
+}
+
+func TestShortSessionKey(t *testing.T) {
+ // This tests that attempting to decrypt a session key where the
+ // ciphertext is too small doesn't run outside the array bounds.
+ ciphertext, err := EncryptPKCS1v15(rand.Reader, &rsaPrivateKey.PublicKey, []byte{1})
+ if err != nil {
+ t.Fatalf("Failed to encrypt short message: %s", err)
+ }
+
+ var key [32]byte
+ if err := DecryptPKCS1v15SessionKey(nil, rsaPrivateKey, ciphertext, key[:]); err != nil {
+ t.Fatalf("Failed to decrypt short message: %s", err)
+ }
+
+ for _, v := range key {
+ if v != 0 {
+ t.Fatal("key was modified when ciphertext was invalid")
+ }
+ }
+}
+
// In order to generate new test vectors you'll need the PEM form of this key:
// -----BEGIN RSA PRIVATE KEY-----
// MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
diff --git a/libgo/go/crypto/rsa/pss.go b/libgo/go/crypto/rsa/pss.go
index f9abec3949..e9f2908250 100644
--- a/libgo/go/crypto/rsa/pss.go
+++ b/libgo/go/crypto/rsa/pss.go
@@ -4,7 +4,7 @@
package rsa
-// This file implementes the PSS signature scheme [1].
+// This file implements the PSS signature scheme [1].
//
// [1] http://www.rsa.com/rsalabs/pkcs/files/h11300-wp-pkcs-1v2-2-rsa-cryptography-standard.pdf
@@ -189,7 +189,7 @@ func emsaPSSVerify(mHash, em []byte, emBits, sLen int, hash hash.Hash) error {
// signPSSWithSalt calculates the signature of hashed using PSS [1] with specified salt.
// Note that hashed must be the result of hashing the input message using the
-// given hash funcion. salt is a random sequence of bytes whose length will be
+// given hash function. salt is a random sequence of bytes whose length will be
// later used to verify the signature.
func signPSSWithSalt(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed, salt []byte) (s []byte, err error) {
nBits := priv.N.BitLen()
@@ -222,6 +222,17 @@ type PSSOptions struct {
// signature. It can either be a number of bytes, or one of the special
// PSSSaltLength constants.
SaltLength int
+
+ // Hash, if not zero, overrides the hash function passed to SignPSS.
+ // This is the only way to specify the hash function when using the
+ // crypto.Signer interface.
+ Hash crypto.Hash
+}
+
+// HashFunc returns pssOpts.Hash so that PSSOptions implements
+// crypto.SignerOpts.
+func (pssOpts *PSSOptions) HashFunc() crypto.Hash {
+ return pssOpts.Hash
}
func (opts *PSSOptions) saltLength() int {
@@ -233,7 +244,7 @@ func (opts *PSSOptions) saltLength() int {
// SignPSS calculates the signature of hashed using RSASSA-PSS [1].
// Note that hashed must be the result of hashing the input message using the
-// given hash funcion. The opts argument may be nil, in which case sensible
+// given hash function. The opts argument may be nil, in which case sensible
// defaults are used.
func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte, opts *PSSOptions) (s []byte, err error) {
saltLength := opts.saltLength()
@@ -244,6 +255,10 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte,
saltLength = hash.Size()
}
+ if opts.Hash != 0 {
+ hash = opts.Hash
+ }
+
salt := make([]byte, saltLength)
if _, err = io.ReadFull(rand, salt); err != nil {
return
diff --git a/libgo/go/crypto/rsa/rsa.go b/libgo/go/crypto/rsa/rsa.go
index c7353ea311..2702311281 100644
--- a/libgo/go/crypto/rsa/rsa.go
+++ b/libgo/go/crypto/rsa/rsa.go
@@ -6,6 +6,7 @@
package rsa
import (
+ "crypto"
"crypto/rand"
"crypto/subtle"
"errors"
@@ -58,9 +59,27 @@ type PrivateKey struct {
Precomputed PrecomputedValues
}
+// Public returns the public key corresponding to priv.
+func (priv *PrivateKey) Public() crypto.PublicKey {
+ return &priv.PublicKey
+}
+
+// Sign signs msg with priv, reading randomness from rand. If opts is a
+// *PSSOptions then the PSS algorithm will be used, otherwise PKCS#1 v1.5 will
+// be used. This method is intended to support keys where the private part is
+// kept in, for example, a hardware module. Common uses should use the Sign*
+// functions in this package.
+func (priv *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) {
+ if pssOpts, ok := opts.(*PSSOptions); ok {
+ return SignPSS(rand, priv, pssOpts.Hash, msg, pssOpts)
+ }
+
+ return SignPKCS1v15(rand, priv, opts.HashFunc(), msg)
+}
+
type PrecomputedValues struct {
Dp, Dq *big.Int // D mod (P-1) (or mod Q-1)
- Qinv *big.Int // Q^-1 mod Q
+ Qinv *big.Int // Q^-1 mod P
// CRTValues is used for the 3rd and subsequent primes. Due to a
// historical accident, the CRT for the first two primes is handled
@@ -120,16 +139,18 @@ func (priv *PrivateKey) Validate() error {
return nil
}
-// GenerateKey generates an RSA keypair of the given bit size.
+// GenerateKey generates an RSA keypair of the given bit size using the
+// random source random (for example, crypto/rand.Reader).
func GenerateKey(random io.Reader, bits int) (priv *PrivateKey, err error) {
return GenerateMultiPrimeKey(random, 2, bits)
}
// GenerateMultiPrimeKey generates a multi-prime RSA keypair of the given bit
-// size, as suggested in [1]. Although the public keys are compatible
-// (actually, indistinguishable) from the 2-prime case, the private keys are
-// not. Thus it may not be possible to export multi-prime private keys in
-// certain formats or to subsequently import them into other code.
+// size and the given random source, as suggested in [1]. Although the public
+// keys are compatible (actually, indistinguishable) from the 2-prime case,
+// the private keys are not. Thus it may not be possible to export multi-prime
+// private keys in certain formats or to subsequently import them into other
+// code.
//
// Table 1 in [2] suggests maximum numbers of primes for a given size.
//
diff --git a/libgo/go/crypto/rsa/rsa_test.go b/libgo/go/crypto/rsa/rsa_test.go
index cf193c669f..4ee1c3a8b2 100644
--- a/libgo/go/crypto/rsa/rsa_test.go
+++ b/libgo/go/crypto/rsa/rsa_test.go
@@ -197,7 +197,7 @@ func TestEncryptOAEP(t *testing.T) {
public := PublicKey{n, test.e}
for j, message := range test.msgs {
- randomSource := bytes.NewBuffer(message.seed)
+ randomSource := bytes.NewReader(message.seed)
out, err := EncryptOAEP(sha1, randomSource, &public, message.in, nil)
if err != nil {
t.Errorf("#%d,%d error: %s", i, j, err)
diff --git a/libgo/go/crypto/sha1/sha1.go b/libgo/go/crypto/sha1/sha1.go
index 8eb3f7a798..9f1a96e364 100644
--- a/libgo/go/crypto/sha1/sha1.go
+++ b/libgo/go/crypto/sha1/sha1.go
@@ -62,16 +62,10 @@ func (d *digest) Write(p []byte) (nn int, err error) {
nn = len(p)
d.len += uint64(nn)
if d.nx > 0 {
- n := len(p)
- if n > chunk-d.nx {
- n = chunk - d.nx
- }
- for i := 0; i < n; i++ {
- d.x[d.nx+i] = p[i]
- }
+ n := copy(d.x[d.nx:], p)
d.nx += n
if d.nx == chunk {
- block(d, d.x[0:])
+ block(d, d.x[:])
d.nx = 0
}
p = p[n:]
diff --git a/libgo/go/crypto/sha1/sha1_test.go b/libgo/go/crypto/sha1/sha1_test.go
index c3868d702a..4a629518b7 100644
--- a/libgo/go/crypto/sha1/sha1_test.go
+++ b/libgo/go/crypto/sha1/sha1_test.go
@@ -7,6 +7,7 @@
package sha1
import (
+ "crypto/rand"
"fmt"
"io"
"testing"
@@ -76,6 +77,32 @@ func TestGolden(t *testing.T) {
}
}
+func TestSize(t *testing.T) {
+ c := New()
+ if got := c.Size(); got != Size {
+ t.Errorf("Size = %d; want %d", got, Size)
+ }
+}
+
+func TestBlockSize(t *testing.T) {
+ c := New()
+ if got := c.BlockSize(); got != BlockSize {
+ t.Errorf("BlockSize = %d; want %d", got, BlockSize)
+ }
+}
+
+// Tests that blockGeneric (pure Go) and block (in assembly for amd64, 386, arm) match.
+func TestBlockGeneric(t *testing.T) {
+ gen, asm := New().(*digest), New().(*digest)
+ buf := make([]byte, BlockSize*20) // arbitrary factor
+ rand.Read(buf)
+ blockGeneric(gen, buf)
+ block(asm, buf)
+ if *gen != *asm {
+ t.Error("block and blockGeneric resulted in different states")
+ }
+}
+
var bench = New()
var buf = make([]byte, 8192)
diff --git a/libgo/go/crypto/sha1/sha1block.go b/libgo/go/crypto/sha1/sha1block.go
index 92224fc0ef..fde3c981c0 100644
--- a/libgo/go/crypto/sha1/sha1block.go
+++ b/libgo/go/crypto/sha1/sha1block.go
@@ -2,12 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !amd64,!386
-
-// SHA1 block step.
-// In its own file so that a faster assembly or C version
-// can be substituted easily.
-
package sha1
const (
@@ -17,7 +11,9 @@ const (
_K3 = 0xCA62C1D6
)
-func block(dig *digest, p []byte) {
+// blockGeneric is a portable, pure Go version of the SHA1 block step.
+// It's used by sha1block_generic.go and tests.
+func blockGeneric(dig *digest, p []byte) {
var w [16]uint32
h0, h1, h2, h3, h4 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4]
diff --git a/libgo/go/crypto/sha1/sha1block_decl.go b/libgo/go/crypto/sha1/sha1block_decl.go
index 4cb157fff6..24e521af1f 100644
--- a/libgo/go/crypto/sha1/sha1block_decl.go
+++ b/libgo/go/crypto/sha1/sha1block_decl.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 amd64 386
+// +build amd64 amd64p32 arm 386
package sha1
diff --git a/libgo/go/crypto/sha1/sha1block_generic.go b/libgo/go/crypto/sha1/sha1block_generic.go
new file mode 100644
index 0000000000..696e26b625
--- /dev/null
+++ b/libgo/go/crypto/sha1/sha1block_generic.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.
+
+// +build !amd64,!amd64p32,!386,!arm
+
+package sha1
+
+var block = blockGeneric
diff --git a/libgo/go/crypto/sha256/sha256.go b/libgo/go/crypto/sha256/sha256.go
index d69ed24a3b..d84cebf2ff 100644
--- a/libgo/go/crypto/sha256/sha256.go
+++ b/libgo/go/crypto/sha256/sha256.go
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// Package sha256 implements the SHA224 and SHA256 hash algorithms as defined
-// in FIPS 180-2.
+// in FIPS 180-4.
package sha256
import (
@@ -106,16 +106,10 @@ func (d *digest) Write(p []byte) (nn int, err error) {
nn = len(p)
d.len += uint64(nn)
if d.nx > 0 {
- n := len(p)
- if n > chunk-d.nx {
- n = chunk - d.nx
- }
- for i := 0; i < n; i++ {
- d.x[d.nx+i] = p[i]
- }
+ n := copy(d.x[d.nx:], p)
d.nx += n
if d.nx == chunk {
- block(d, d.x[0:])
+ block(d, d.x[:])
d.nx = 0
}
p = p[n:]
diff --git a/libgo/go/crypto/sha256/sha256_test.go b/libgo/go/crypto/sha256/sha256_test.go
index bb1ec3b162..1d883d3905 100644
--- a/libgo/go/crypto/sha256/sha256_test.go
+++ b/libgo/go/crypto/sha256/sha256_test.go
@@ -132,6 +132,24 @@ func TestGolden(t *testing.T) {
}
}
+func TestSize(t *testing.T) {
+ c := New()
+ if got := c.Size(); got != Size {
+ t.Errorf("Size = %d; want %d", got, Size)
+ }
+ c = New224()
+ if got := c.Size(); got != Size224 {
+ t.Errorf("New224.Size = %d; want %d", got, Size224)
+ }
+}
+
+func TestBlockSize(t *testing.T) {
+ c := New()
+ if got := c.BlockSize(); got != BlockSize {
+ t.Errorf("BlockSize = %d want %d", got, BlockSize)
+ }
+}
+
var bench = New()
var buf = make([]byte, 8192)
diff --git a/libgo/go/crypto/sha256/sha256block.go b/libgo/go/crypto/sha256/sha256block.go
index 2ac49100ac..ca5efd156a 100644
--- a/libgo/go/crypto/sha256/sha256block.go
+++ b/libgo/go/crypto/sha256/sha256block.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 !386,!amd64
+
// SHA256 block step.
// In its own file so that a faster assembly or C version
// can be substituted easily.
diff --git a/libgo/go/crypto/sha256/sha256block_decl.go b/libgo/go/crypto/sha256/sha256block_decl.go
new file mode 100644
index 0000000000..a50c978710
--- /dev/null
+++ b/libgo/go/crypto/sha256/sha256block_decl.go
@@ -0,0 +1,11 @@
+// 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 386 amd64
+
+package sha256
+
+//go:noescape
+
+func block(dig *digest, p []byte)
diff --git a/libgo/go/crypto/sha512/sha512.go b/libgo/go/crypto/sha512/sha512.go
index d2ada51373..bca7a91e22 100644
--- a/libgo/go/crypto/sha512/sha512.go
+++ b/libgo/go/crypto/sha512/sha512.go
@@ -106,16 +106,10 @@ func (d *digest) Write(p []byte) (nn int, err error) {
nn = len(p)
d.len += uint64(nn)
if d.nx > 0 {
- n := len(p)
- if n > chunk-d.nx {
- n = chunk - d.nx
- }
- for i := 0; i < n; i++ {
- d.x[d.nx+i] = p[i]
- }
+ n := copy(d.x[d.nx:], p)
d.nx += n
if d.nx == chunk {
- block(d, d.x[0:])
+ block(d, d.x[:])
d.nx = 0
}
p = p[n:]
diff --git a/libgo/go/crypto/sha512/sha512_test.go b/libgo/go/crypto/sha512/sha512_test.go
index 167c20ad07..541860f701 100644
--- a/libgo/go/crypto/sha512/sha512_test.go
+++ b/libgo/go/crypto/sha512/sha512_test.go
@@ -132,6 +132,24 @@ func TestGolden(t *testing.T) {
}
}
+func TestSize(t *testing.T) {
+ c := New()
+ if got := c.Size(); got != Size {
+ t.Errorf("Size = %d; want %d", got, Size)
+ }
+ c = New384()
+ if got := c.Size(); got != Size384 {
+ t.Errorf("New384.Size = %d; want %d", got, Size384)
+ }
+}
+
+func TestBlockSize(t *testing.T) {
+ c := New()
+ if got := c.BlockSize(); got != BlockSize {
+ t.Errorf("BlockSize = %d; want %d", got, BlockSize)
+ }
+}
+
var bench = New()
var buf = make([]byte, 8192)
diff --git a/libgo/go/crypto/sha512/sha512block.go b/libgo/go/crypto/sha512/sha512block.go
index 3577b4f3df..648ae8f7e1 100644
--- a/libgo/go/crypto/sha512/sha512block.go
+++ b/libgo/go/crypto/sha512/sha512block.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 !amd64
+
// SHA512 block step.
// In its own file so that a faster assembly or C version
// can be substituted easily.
diff --git a/libgo/go/crypto/sha512/sha512block_decl.go b/libgo/go/crypto/sha512/sha512block_decl.go
new file mode 100644
index 0000000000..bef99de2e4
--- /dev/null
+++ b/libgo/go/crypto/sha512/sha512block_decl.go
@@ -0,0 +1,11 @@
+// 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 amd64
+
+package sha512
+
+//go:noescape
+
+func block(dig *digest, p []byte)
diff --git a/libgo/go/crypto/subtle/constant_time.go b/libgo/go/crypto/subtle/constant_time.go
index dfb658465e..6f80e7c58d 100644
--- a/libgo/go/crypto/subtle/constant_time.go
+++ b/libgo/go/crypto/subtle/constant_time.go
@@ -6,10 +6,14 @@
// code but require careful thought to use correctly.
package subtle
-// ConstantTimeCompare returns 1 iff the two equal length slices, x
+// ConstantTimeCompare returns 1 iff the two slices, x
// and y, have equal contents. The time taken is a function of the length of
// the slices and is independent of the contents.
func ConstantTimeCompare(x, y []byte) int {
+ if len(x) != len(y) {
+ return 0
+ }
+
var v byte
for i := 0; i < len(x); i++ {
@@ -45,15 +49,19 @@ func ConstantTimeEq(x, y int32) int {
return int(z & 1)
}
-// ConstantTimeCopy copies the contents of y into x iff v == 1. If v == 0, x is left unchanged.
-// Its behavior is undefined if v takes any other value.
+// ConstantTimeCopy copies the contents of y into x (a slice of equal length)
+// if v == 1. If v == 0, x is left unchanged. Its behavior is undefined if v
+// takes any other value.
func ConstantTimeCopy(v int, x, y []byte) {
+ if len(x) != len(y) {
+ panic("subtle: slices have different lengths")
+ }
+
xmask := byte(v - 1)
ymask := byte(^(v - 1))
for i := 0; i < len(x); i++ {
x[i] = x[i]&xmask | y[i]&ymask
}
- return
}
// ConstantTimeLessOrEq returns 1 if x <= y and 0 otherwise.
diff --git a/libgo/go/crypto/subtle/constant_time_test.go b/libgo/go/crypto/subtle/constant_time_test.go
index d8e321ec04..619a454441 100644
--- a/libgo/go/crypto/subtle/constant_time_test.go
+++ b/libgo/go/crypto/subtle/constant_time_test.go
@@ -18,6 +18,8 @@ var testConstantTimeCompareData = []TestConstantTimeCompareStruct{
{[]byte{}, []byte{}, 1},
{[]byte{0x11}, []byte{0x11}, 1},
{[]byte{0x12}, []byte{0x11}, 0},
+ {[]byte{0x11}, []byte{0x11, 0x12}, 0},
+ {[]byte{0x11, 0x12}, []byte{0x11}, 0},
}
func TestConstantTimeCompare(t *testing.T) {
diff --git a/libgo/go/crypto/tls/alert.go b/libgo/go/crypto/tls/alert.go
index 0856311e4c..3de4834d3f 100644
--- a/libgo/go/crypto/tls/alert.go
+++ b/libgo/go/crypto/tls/alert.go
@@ -35,6 +35,7 @@ const (
alertProtocolVersion alert = 70
alertInsufficientSecurity alert = 71
alertInternalError alert = 80
+ alertInappropriateFallback alert = 86
alertUserCanceled alert = 90
alertNoRenegotiation alert = 100
)
@@ -60,6 +61,7 @@ var alertText = map[alert]string{
alertProtocolVersion: "protocol version not supported",
alertInsufficientSecurity: "insufficient security level",
alertInternalError: "internal error",
+ alertInappropriateFallback: "inappropriate fallback",
alertUserCanceled: "user canceled",
alertNoRenegotiation: "no renegotiation",
}
diff --git a/libgo/go/crypto/tls/cipher_suites.go b/libgo/go/crypto/tls/cipher_suites.go
index 39a51459d2..226e06d68d 100644
--- a/libgo/go/crypto/tls/cipher_suites.go
+++ b/libgo/go/crypto/tls/cipher_suites.go
@@ -267,4 +267,9 @@ const (
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0xc014
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02f
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02b
+
+ // TLS_FALLBACK_SCSV isn't a standard cipher suite but an indicator
+ // that the client is doing version fallback. See
+ // https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00.
+ TLS_FALLBACK_SCSV uint16 = 0x5600
)
diff --git a/libgo/go/crypto/tls/common.go b/libgo/go/crypto/tls/common.go
index b7229d29f8..776b70c93c 100644
--- a/libgo/go/crypto/tls/common.go
+++ b/libgo/go/crypto/tls/common.go
@@ -5,9 +5,11 @@
package tls
import (
+ "container/list"
"crypto"
"crypto/rand"
"crypto/x509"
+ "fmt"
"io"
"math/big"
"strings"
@@ -64,27 +66,36 @@ const (
)
// TLS extension numbers
-var (
+const (
extensionServerName uint16 = 0
extensionStatusRequest uint16 = 5
extensionSupportedCurves uint16 = 10
extensionSupportedPoints uint16 = 11
extensionSignatureAlgorithms uint16 = 13
+ extensionALPN uint16 = 16
extensionSessionTicket uint16 = 35
extensionNextProtoNeg uint16 = 13172 // not IANA assigned
+ extensionRenegotiationInfo uint16 = 0xff01
)
-// TLS Elliptic Curves
+// TLS signaling cipher suite values
+const (
+ scsvRenegotiation uint16 = 0x00ff
+)
+
+// CurveID is the type of a TLS identifier for an elliptic curve. See
// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8
-var (
- curveP256 uint16 = 23
- curveP384 uint16 = 24
- curveP521 uint16 = 25
+type CurveID uint16
+
+const (
+ CurveP256 CurveID = 23
+ CurveP384 CurveID = 24
+ CurveP521 CurveID = 25
)
// TLS Elliptic Curve Point Formats
// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-9
-var (
+const (
pointFormatUncompressed uint8 = 0
)
@@ -145,6 +156,7 @@ var supportedClientCertSignatureAlgorithms = []signatureAndHash{
// 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, ...)
@@ -153,6 +165,14 @@ type ConnectionState struct {
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
+
+ // TLSUnique contains the "tls-unique" channel binding value (see RFC
+ // 5929, section 3). For resumed sessions this value will be nil
+ // because resumption does not include enough context (see
+ // https://secure-resumption.com/#channelbindings). This will change in
+ // future versions of Go once the TLS master-secret fix has been
+ // standardized and implemented.
+ TLSUnique []byte
}
// ClientAuthType declares the policy the server will follow for
@@ -167,12 +187,64 @@ const (
RequireAndVerifyClientCert
)
-// A Config structure is used to configure a TLS client or server. After one
-// has been passed to a TLS function it must not be modified.
+// 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
+}
+
+// ClientSessionCache is a cache of ClientSessionState objects that can be used
+// by a client to resume a TLS session with a given server. ClientSessionCache
+// implementations should expect to be called concurrently from different
+// goroutines.
+type ClientSessionCache interface {
+ // Get searches for a ClientSessionState associated with the given key.
+ // On return, ok is true if one was found.
+ Get(sessionKey string) (session *ClientSessionState, ok bool)
+
+ // Put adds the ClientSessionState to the cache with the given key.
+ Put(sessionKey string, cs *ClientSessionState)
+}
+
+// ClientHelloInfo contains information from a ClientHello message in order to
+// guide certificate selection in the GetCertificate callback.
+type ClientHelloInfo struct {
+ // CipherSuites lists the CipherSuites supported by the client (e.g.
+ // TLS_RSA_WITH_RC4_128_SHA).
+ CipherSuites []uint16
+
+ // ServerName indicates the name of the server requested by the client
+ // in order to support virtual hosting. ServerName is only set if the
+ // client is using SNI (see
+ // http://tools.ietf.org/html/rfc4366#section-3.1).
+ ServerName string
+
+ // SupportedCurves lists the elliptic curves supported by the client.
+ // SupportedCurves is set only if the Supported Elliptic Curves
+ // Extension is being used (see
+ // http://tools.ietf.org/html/rfc4492#section-5.1.1).
+ SupportedCurves []CurveID
+
+ // SupportedPoints lists the point formats supported by the client.
+ // SupportedPoints is set only if the Supported Point Formats Extension
+ // is being used (see
+ // http://tools.ietf.org/html/rfc4492#section-5.1.2).
+ SupportedPoints []uint8
+}
+
+// A Config structure is used to configure a TLS client or server.
+// After one has been passed to a TLS function it must not be
+// modified. A Config may be reused; the tls package will also not
+// modify it.
type Config struct {
// Rand provides the source of entropy for nonces and RSA blinding.
// If Rand is nil, TLS uses the cryptographic random reader in package
// crypto/rand.
+ // The Reader must be safe for use by multiple goroutines.
Rand io.Reader
// Time returns the current time as the number of seconds since the epoch.
@@ -192,6 +264,13 @@ type Config struct {
// for all connections.
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.
+ GetCertificate func(clientHello *ClientHelloInfo) (*Certificate, error)
+
// RootCAs defines the set of root certificate authorities
// that clients use when verifying server certificates.
// If RootCAs is nil, TLS uses the host's root CA set.
@@ -200,8 +279,9 @@ type Config struct {
// NextProtos is a list of supported, application level protocols.
NextProtos []string
- // ServerName is included in the client's handshake to support virtual
- // hosting.
+ // ServerName is used to verify the hostname on the returned
+ // certificates unless InsecureSkipVerify is given. It is also included
+ // in the client's handshake to support virtual hosting.
ServerName string
// ClientAuth determines the server's policy for
@@ -245,6 +325,10 @@ type Config struct {
// connections using that key are compromised.
SessionTicketKey [32]byte
+ // SessionCache is a cache of ClientSessionState entries for TLS session
+ // resumption.
+ ClientSessionCache ClientSessionCache
+
// MinVersion contains the minimum SSL/TLS version that is acceptable.
// If zero, then SSLv3 is taken as the minimum.
MinVersion uint16
@@ -254,6 +338,11 @@ type Config struct {
// which is currently TLS 1.2.
MaxVersion uint16
+ // CurvePreferences contains the elliptic curves that will be used in
+ // an ECDHE handshake, in preference order. If empty, the default will
+ // be used.
+ CurvePreferences []CurveID
+
serverInitOnce sync.Once // guards calling (*Config).serverInit
}
@@ -312,6 +401,15 @@ func (c *Config) maxVersion() uint16 {
return c.MaxVersion
}
+var defaultCurvePreferences = []CurveID{CurveP256, CurveP384, CurveP521}
+
+func (c *Config) curvePreferences() []CurveID {
+ if c == nil || len(c.CurvePreferences) == 0 {
+ return defaultCurvePreferences
+ }
+ return c.CurvePreferences
+}
+
// mutualVersion returns the protocol version to use given the advertised
// version of the peer.
func (c *Config) mutualVersion(vers uint16) (uint16, bool) {
@@ -327,22 +425,28 @@ func (c *Config) mutualVersion(vers uint16) (uint16, bool) {
return vers, true
}
-// getCertificateForName returns the best certificate for the given name,
-// defaulting to the first element of c.Certificates if there are no good
-// options.
-func (c *Config) getCertificateForName(name string) *Certificate {
+// 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 {
+ cert, err := c.GetCertificate(clientHello)
+ if cert != nil || err != nil {
+ return cert, err
+ }
+ }
+
if len(c.Certificates) == 1 || c.NameToCertificate == nil {
// There's only one choice, so no point doing any work.
- return &c.Certificates[0]
+ return &c.Certificates[0], nil
}
- name = strings.ToLower(name)
+ name := strings.ToLower(clientHello.ServerName)
for len(name) > 0 && name[len(name)-1] == '.' {
name = name[:len(name)-1]
}
if cert, ok := c.NameToCertificate[name]; ok {
- return cert
+ return cert, nil
}
// try replacing labels in the name with wildcards until we get a
@@ -352,12 +456,12 @@ func (c *Config) getCertificateForName(name string) *Certificate {
labels[i] = "*"
candidate := strings.Join(labels, ".")
if cert, ok := c.NameToCertificate[candidate]; ok {
- return cert
+ return cert, nil
}
}
// If nothing matches, return the first certificate.
- return &c.Certificates[0]
+ return &c.Certificates[0], nil
}
// BuildNameToCertificate parses c.Certificates and builds c.NameToCertificate
@@ -383,7 +487,12 @@ func (c *Config) BuildNameToCertificate() {
// A Certificate is a chain of one or more certificates, leaf first.
type Certificate struct {
Certificate [][]byte
- PrivateKey crypto.PrivateKey // supported types: *rsa.PrivateKey, *ecdsa.PrivateKey
+ // 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).
+ PrivateKey crypto.PrivateKey
// OCSPStaple contains an optional OCSP response which will be served
// to clients that request it.
OCSPStaple []byte
@@ -406,6 +515,77 @@ type handshakeMessage interface {
unmarshal([]byte) bool
}
+// lruSessionCache is a ClientSessionCache implementation that uses an LRU
+// caching strategy.
+type lruSessionCache struct {
+ sync.Mutex
+
+ m map[string]*list.Element
+ q *list.List
+ capacity int
+}
+
+type lruSessionCacheEntry struct {
+ sessionKey string
+ state *ClientSessionState
+}
+
+// NewLRUClientSessionCache returns a ClientSessionCache with the given
+// capacity that uses an LRU strategy. If capacity is < 1, a default capacity
+// is used instead.
+func NewLRUClientSessionCache(capacity int) ClientSessionCache {
+ const defaultSessionCacheCapacity = 64
+
+ if capacity < 1 {
+ capacity = defaultSessionCacheCapacity
+ }
+ return &lruSessionCache{
+ m: make(map[string]*list.Element),
+ q: list.New(),
+ capacity: capacity,
+ }
+}
+
+// Put adds the provided (sessionKey, cs) pair to the cache.
+func (c *lruSessionCache) Put(sessionKey string, cs *ClientSessionState) {
+ c.Lock()
+ defer c.Unlock()
+
+ if elem, ok := c.m[sessionKey]; ok {
+ entry := elem.Value.(*lruSessionCacheEntry)
+ entry.state = cs
+ c.q.MoveToFront(elem)
+ return
+ }
+
+ if c.q.Len() < c.capacity {
+ entry := &lruSessionCacheEntry{sessionKey, cs}
+ c.m[sessionKey] = c.q.PushFront(entry)
+ return
+ }
+
+ elem := c.q.Back()
+ entry := elem.Value.(*lruSessionCacheEntry)
+ delete(c.m, entry.sessionKey)
+ entry.sessionKey = sessionKey
+ entry.state = cs
+ c.q.MoveToFront(elem)
+ c.m[sessionKey] = elem
+}
+
+// Get returns the ClientSessionState value associated with a given key. It
+// returns (nil, false) if no value is found.
+func (c *lruSessionCache) Get(sessionKey string) (*ClientSessionState, bool) {
+ c.Lock()
+ defer c.Unlock()
+
+ if elem, ok := c.m[sessionKey]; ok {
+ c.q.MoveToFront(elem)
+ return elem.Value.(*lruSessionCacheEntry).state, true
+ }
+ return nil, false
+}
+
// TODO(jsing): Make these available to both crypto/x509 and crypto/tls.
type dsaSignature struct {
R, S *big.Int
@@ -435,3 +615,7 @@ func initDefaultCipherSuites() {
varDefaultCipherSuites[i] = 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)
+}
diff --git a/libgo/go/crypto/tls/conn.go b/libgo/go/crypto/tls/conn.go
index 2e64b88a68..ba8e4c22b7 100644
--- a/libgo/go/crypto/tls/conn.go
+++ b/libgo/go/crypto/tls/conn.go
@@ -12,6 +12,7 @@ import (
"crypto/subtle"
"crypto/x509"
"errors"
+ "fmt"
"io"
"net"
"sync"
@@ -27,6 +28,7 @@ type Conn struct {
// constant after handshake; protected by handshakeMutex
handshakeMutex sync.Mutex // handshakeMutex < in.Mutex, out.Mutex, errMutex
+ handshakeErr error // error resulting from handshake
vers uint16 // TLS version
haveVers bool // version has been negotiated
config *Config // configuration passed to constructor
@@ -40,13 +42,13 @@ type Conn struct {
verifiedChains [][]*x509.Certificate
// serverName contains the server name indicated by the client, if any.
serverName string
+ // firstFinished contains the first Finished hash sent during the
+ // handshake. This is the "tls-unique" channel binding value.
+ firstFinished [12]byte
clientProtocol string
clientProtocolFallback bool
- // first permanent error
- connErr
-
// input/output
in, out halfConn // in.Mutex < out.Mutex
rawInput *block // raw input, right off the wire
@@ -56,27 +58,6 @@ type Conn struct {
tmp [16]byte
}
-type connErr struct {
- mu sync.Mutex
- value error
-}
-
-func (e *connErr) setError(err error) error {
- e.mu.Lock()
- defer e.mu.Unlock()
-
- if e.value == nil {
- e.value = err
- }
- return err
-}
-
-func (e *connErr) error() error {
- e.mu.Lock()
- defer e.mu.Unlock()
- return e.value
-}
-
// Access to net.Conn methods.
// Cannot just embed net.Conn because that would
// export the struct field too.
@@ -104,7 +85,7 @@ func (c *Conn) SetReadDeadline(t time.Time) error {
return c.conn.SetReadDeadline(t)
}
-// SetWriteDeadline sets the write deadline on the underlying conneciton.
+// SetWriteDeadline sets the write deadline on the underlying connection.
// A zero value for t means Write will not time out.
// After a Write has timed out, the TLS state is corrupt and all future writes will return the same error.
func (c *Conn) SetWriteDeadline(t time.Time) error {
@@ -115,6 +96,8 @@ func (c *Conn) SetWriteDeadline(t time.Time) error {
// connection, either sending or receiving.
type halfConn struct {
sync.Mutex
+
+ err error // first permanent error
version uint16 // protocol version
cipher interface{} // cipher algorithm
mac macFunction
@@ -128,6 +111,18 @@ type halfConn struct {
inDigestBuf, outDigestBuf []byte
}
+func (hc *halfConn) setErrorLocked(err error) error {
+ hc.err = err
+ return err
+}
+
+func (hc *halfConn) error() error {
+ hc.Lock()
+ err := hc.err
+ hc.Unlock()
+ return err
+}
+
// prepareCipherSpec sets the encryption and MAC states
// that a subsequent changeCipherSpec will use.
func (hc *halfConn) prepareCipherSpec(version uint16, cipher interface{}, mac macFunction) {
@@ -459,6 +454,8 @@ func (b *block) readFromUntil(r io.Reader, n int) error {
m, err := r.Read(b.data[len(b.data):cap(b.data)])
b.data = b.data[0 : len(b.data)+m]
if len(b.data) >= n {
+ // TODO(bradfitz,agl): slightly suspicious
+ // that we're throwing away r.Read's err here.
break
}
if err != nil {
@@ -518,14 +515,17 @@ func (c *Conn) readRecord(want recordType) error {
// else application data. (We don't support renegotiation.)
switch want {
default:
- return c.sendAlert(alertInternalError)
+ c.sendAlert(alertInternalError)
+ return c.in.setErrorLocked(errors.New("tls: unknown record type requested"))
case recordTypeHandshake, recordTypeChangeCipherSpec:
if c.handshakeComplete {
- return c.sendAlert(alertInternalError)
+ c.sendAlert(alertInternalError)
+ return c.in.setErrorLocked(errors.New("tls: handshake or ChangeCipherSpec requested after handshake complete"))
}
case recordTypeApplicationData:
if !c.handshakeComplete {
- return c.sendAlert(alertInternalError)
+ c.sendAlert(alertInternalError)
+ return c.in.setErrorLocked(errors.New("tls: application data record requested before handshake complete"))
}
}
@@ -544,7 +544,7 @@ Again:
// err = io.ErrUnexpectedEOF
// }
if e, ok := err.(net.Error); !ok || !e.Temporary() {
- c.setError(err)
+ c.in.setErrorLocked(err)
}
return err
}
@@ -556,16 +556,18 @@ Again:
// an SSLv2 client.
if want == recordTypeHandshake && typ == 0x80 {
c.sendAlert(alertProtocolVersion)
- return errors.New("tls: unsupported SSLv2 handshake received")
+ return c.in.setErrorLocked(errors.New("tls: unsupported SSLv2 handshake received"))
}
vers := uint16(b.data[1])<<8 | uint16(b.data[2])
n := int(b.data[3])<<8 | int(b.data[4])
if c.haveVers && vers != c.vers {
- return c.sendAlert(alertProtocolVersion)
+ c.sendAlert(alertProtocolVersion)
+ return c.in.setErrorLocked(fmt.Errorf("tls: received record with version %x when expecting version %x", vers, c.vers))
}
if n > maxCiphertext {
- return c.sendAlert(alertRecordOverflow)
+ c.sendAlert(alertRecordOverflow)
+ return c.in.setErrorLocked(fmt.Errorf("tls: oversized record received with length %d", n))
}
if !c.haveVers {
// First message, be extra suspicious:
@@ -577,7 +579,8 @@ Again:
// well under a kilobyte. If the length is >= 12 kB,
// it's probably not real.
if (typ != recordTypeAlert && typ != want) || vers >= 0x1000 || n >= 0x3000 {
- return c.sendAlert(alertUnexpectedMessage)
+ c.sendAlert(alertUnexpectedMessage)
+ return c.in.setErrorLocked(fmt.Errorf("tls: first record does not look like a TLS handshake"))
}
}
if err := b.readFromUntil(c.conn, recordHeaderLen+n); err != nil {
@@ -585,7 +588,7 @@ Again:
err = io.ErrUnexpectedEOF
}
if e, ok := err.(net.Error); !ok || !e.Temporary() {
- c.setError(err)
+ c.in.setErrorLocked(err)
}
return err
}
@@ -594,27 +597,27 @@ Again:
b, c.rawInput = c.in.splitBlock(b, recordHeaderLen+n)
ok, off, err := c.in.decrypt(b)
if !ok {
- return c.sendAlert(err)
+ c.in.setErrorLocked(c.sendAlert(err))
}
b.off = off
data := b.data[b.off:]
if len(data) > maxPlaintext {
- c.sendAlert(alertRecordOverflow)
+ err := c.sendAlert(alertRecordOverflow)
c.in.freeBlock(b)
- return c.error()
+ return c.in.setErrorLocked(err)
}
switch typ {
default:
- c.sendAlert(alertUnexpectedMessage)
+ c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
case recordTypeAlert:
if len(data) != 2 {
- c.sendAlert(alertUnexpectedMessage)
+ c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
break
}
if alert(data[1]) == alertCloseNotify {
- c.setError(io.EOF)
+ c.in.setErrorLocked(io.EOF)
break
}
switch data[0] {
@@ -623,24 +626,24 @@ Again:
c.in.freeBlock(b)
goto Again
case alertLevelError:
- c.setError(&net.OpError{Op: "remote error", Err: alert(data[1])})
+ c.in.setErrorLocked(&net.OpError{Op: "remote error", Err: alert(data[1])})
default:
- c.sendAlert(alertUnexpectedMessage)
+ c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
}
case recordTypeChangeCipherSpec:
if typ != want || len(data) != 1 || data[0] != 1 {
- c.sendAlert(alertUnexpectedMessage)
+ c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
break
}
err := c.in.changeCipherSpec()
if err != nil {
- c.sendAlert(err.(alert))
+ c.in.setErrorLocked(c.sendAlert(err.(alert)))
}
case recordTypeApplicationData:
if typ != want {
- c.sendAlert(alertUnexpectedMessage)
+ c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
break
}
c.input = b
@@ -649,7 +652,7 @@ Again:
case recordTypeHandshake:
// TODO(rsc): Should at least pick off connection close.
if typ != want {
- return c.sendAlert(alertNoRenegotiation)
+ return c.in.setErrorLocked(c.sendAlert(alertNoRenegotiation))
}
c.hand.Write(data)
}
@@ -657,7 +660,7 @@ Again:
if b != nil {
c.in.freeBlock(b)
}
- return c.error()
+ return c.in.err
}
// sendAlert sends a TLS alert message.
@@ -673,7 +676,7 @@ func (c *Conn) sendAlertLocked(err alert) error {
c.writeRecord(recordTypeAlert, c.tmp[0:2])
// closeNotify is a special case in that it isn't an error:
if err != alertCloseNotify {
- return c.setError(&net.OpError{Op: "local error", Err: err})
+ return c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err})
}
return nil
}
@@ -759,7 +762,7 @@ func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) {
c.tmp[0] = alertLevelError
c.tmp[1] = byte(err.(alert))
c.writeRecord(recordTypeAlert, c.tmp[0:2])
- return n, c.setError(&net.OpError{Op: "local error", Err: err})
+ return n, c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err})
}
}
return
@@ -770,7 +773,7 @@ func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) {
// c.in.Mutex < L; c.out.Mutex < L.
func (c *Conn) readHandshake() (interface{}, error) {
for c.hand.Len() < 4 {
- if err := c.error(); err != nil {
+ if err := c.in.err; err != nil {
return nil, err
}
if err := c.readRecord(recordTypeHandshake); err != nil {
@@ -781,11 +784,10 @@ func (c *Conn) readHandshake() (interface{}, error) {
data := c.hand.Bytes()
n := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
if n > maxHandshake {
- c.sendAlert(alertInternalError)
- return nil, c.error()
+ return nil, c.in.setErrorLocked(c.sendAlert(alertInternalError))
}
for c.hand.Len() < 4+n {
- if err := c.error(); err != nil {
+ if err := c.in.err; err != nil {
return nil, err
}
if err := c.readRecord(recordTypeHandshake); err != nil {
@@ -799,6 +801,8 @@ func (c *Conn) readHandshake() (interface{}, error) {
m = new(clientHelloMsg)
case typeServerHello:
m = new(serverHelloMsg)
+ case typeNewSessionTicket:
+ m = new(newSessionTicketMsg)
case typeCertificate:
m = new(certificateMsg)
case typeCertificateRequest:
@@ -822,8 +826,7 @@ func (c *Conn) readHandshake() (interface{}, error) {
case typeFinished:
m = new(finishedMsg)
default:
- c.sendAlert(alertUnexpectedMessage)
- return nil, alertUnexpectedMessage
+ return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
}
// The handshake message unmarshallers
@@ -832,25 +835,24 @@ func (c *Conn) readHandshake() (interface{}, error) {
data = append([]byte(nil), data...)
if !m.unmarshal(data) {
- c.sendAlert(alertUnexpectedMessage)
- return nil, alertUnexpectedMessage
+ return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
}
return m, nil
}
// Write writes data to the connection.
func (c *Conn) Write(b []byte) (int, error) {
- if err := c.error(); err != nil {
- return 0, err
- }
-
if err := c.Handshake(); err != nil {
- return 0, c.setError(err)
+ return 0, err
}
c.out.Lock()
defer c.out.Unlock()
+ if err := c.out.err; err != nil {
+ return 0, err
+ }
+
if !c.handshakeComplete {
return 0, alertInternalError
}
@@ -869,14 +871,14 @@ func (c *Conn) Write(b []byte) (int, error) {
if _, ok := c.out.cipher.(cipher.BlockMode); ok {
n, err := c.writeRecord(recordTypeApplicationData, b[:1])
if err != nil {
- return n, c.setError(err)
+ return n, c.out.setErrorLocked(err)
}
m, b = 1, b[1:]
}
}
n, err := c.writeRecord(recordTypeApplicationData, b)
- return n + m, c.setError(err)
+ return n + m, c.out.setErrorLocked(err)
}
// Read can be made to time out and return a net.Error with Timeout() == true
@@ -885,6 +887,11 @@ func (c *Conn) Read(b []byte) (n int, err error) {
if err = c.Handshake(); err != nil {
return
}
+ if len(b) == 0 {
+ // Put this after Handshake, in case people were calling
+ // Read(nil) for the side effect of the Handshake.
+ return
+ }
c.in.Lock()
defer c.in.Unlock()
@@ -893,13 +900,13 @@ func (c *Conn) Read(b []byte) (n int, err error) {
// CBC IV. So this loop ignores a limited number of empty records.
const maxConsecutiveEmptyRecords = 100
for emptyRecordCount := 0; emptyRecordCount <= maxConsecutiveEmptyRecords; emptyRecordCount++ {
- for c.input == nil && c.error() == nil {
+ for c.input == nil && c.in.err == nil {
if err := c.readRecord(recordTypeApplicationData); err != nil {
// Soft error, like EAGAIN
return 0, err
}
}
- if err := c.error(); err != nil {
+ if err := c.in.err; err != nil {
return 0, err
}
@@ -909,6 +916,25 @@ func (c *Conn) Read(b []byte) (n int, err error) {
c.input = nil
}
+ // If a close-notify alert is waiting, read it so that
+ // we can return (n, EOF) instead of (n, nil), to signal
+ // to the HTTP response reading goroutine that the
+ // connection is now closed. This eliminates a race
+ // where the HTTP response reading goroutine would
+ // otherwise not observe the EOF until its next read,
+ // by which time a client goroutine might have already
+ // tried to reuse the HTTP connection for a new
+ // request.
+ // See https://codereview.appspot.com/76400046
+ // and http://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 {
+ if recErr := c.readRecord(recordTypeApplicationData); recErr != nil {
+ err = recErr // will be io.EOF on closeNotify
+ }
+ }
+
if n != 0 || err != nil {
return n, err
}
@@ -940,16 +966,19 @@ func (c *Conn) Close() error {
func (c *Conn) Handshake() error {
c.handshakeMutex.Lock()
defer c.handshakeMutex.Unlock()
- if err := c.error(); err != nil {
+ if err := c.handshakeErr; err != nil {
return err
}
if c.handshakeComplete {
return nil
}
+
if c.isClient {
- return c.clientHandshake()
+ c.handshakeErr = c.clientHandshake()
+ } else {
+ c.handshakeErr = c.serverHandshake()
}
- return c.serverHandshake()
+ return c.handshakeErr
}
// ConnectionState returns basic TLS details about the connection.
@@ -960,6 +989,7 @@ func (c *Conn) ConnectionState() ConnectionState {
var state ConnectionState
state.HandshakeComplete = c.handshakeComplete
if c.handshakeComplete {
+ state.Version = c.vers
state.NegotiatedProtocol = c.clientProtocol
state.DidResume = c.didResume
state.NegotiatedProtocolIsMutual = !c.clientProtocolFallback
@@ -967,6 +997,9 @@ func (c *Conn) ConnectionState() ConnectionState {
state.PeerCertificates = c.peerCertificates
state.VerifiedChains = c.verifiedChains
state.ServerName = c.serverName
+ if !c.didResume {
+ state.TLSUnique = c.firstFinished[:]
+ }
}
return state
@@ -988,10 +1021,10 @@ func (c *Conn) VerifyHostname(host string) error {
c.handshakeMutex.Lock()
defer c.handshakeMutex.Unlock()
if !c.isClient {
- return errors.New("VerifyHostname called on TLS server connection")
+ return errors.New("tls: VerifyHostname called on TLS server connection")
}
if !c.handshakeComplete {
- return errors.New("TLS handshake has not yet been performed")
+ return errors.New("tls: handshake has not yet been performed")
}
return c.peerCertificates[0].VerifyHostname(host)
}
diff --git a/libgo/go/crypto/tls/conn_test.go b/libgo/go/crypto/tls/conn_test.go
index 5c555147ca..ec802cad70 100644
--- a/libgo/go/crypto/tls/conn_test.go
+++ b/libgo/go/crypto/tls/conn_test.go
@@ -88,19 +88,31 @@ func TestCertificateSelection(t *testing.T) {
return -1
}
- if n := pointerToIndex(config.getCertificateForName("example.com")); n != 0 {
+ certificateForName := func(name string) *Certificate {
+ clientHello := &ClientHelloInfo{
+ ServerName: name,
+ }
+ if cert, err := config.getCertificate(clientHello); err != nil {
+ t.Errorf("unable to get certificate for name '%s': %s", name, err)
+ return nil
+ } else {
+ return cert
+ }
+ }
+
+ if n := pointerToIndex(certificateForName("example.com")); n != 0 {
t.Errorf("example.com returned certificate %d, not 0", n)
}
- if n := pointerToIndex(config.getCertificateForName("bar.example.com")); n != 1 {
+ if n := pointerToIndex(certificateForName("bar.example.com")); n != 1 {
t.Errorf("bar.example.com returned certificate %d, not 1", n)
}
- if n := pointerToIndex(config.getCertificateForName("foo.example.com")); n != 2 {
+ if n := pointerToIndex(certificateForName("foo.example.com")); n != 2 {
t.Errorf("foo.example.com returned certificate %d, not 2", n)
}
- if n := pointerToIndex(config.getCertificateForName("foo.bar.example.com")); n != 3 {
+ if n := pointerToIndex(certificateForName("foo.bar.example.com")); n != 3 {
t.Errorf("foo.bar.example.com returned certificate %d, not 3", n)
}
- if n := pointerToIndex(config.getCertificateForName("foo.bar.baz.example.com")); n != 0 {
+ if n := pointerToIndex(certificateForName("foo.bar.baz.example.com")); n != 0 {
t.Errorf("foo.bar.baz.example.com returned certificate %d, not 0", n)
}
}
diff --git a/libgo/go/crypto/tls/generate_cert.go b/libgo/go/crypto/tls/generate_cert.go
index b417ea4640..83f9916ff9 100644
--- a/libgo/go/crypto/tls/generate_cert.go
+++ b/libgo/go/crypto/tls/generate_cert.go
@@ -10,6 +10,8 @@
package main
import (
+ "crypto/ecdsa"
+ "crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
@@ -26,13 +28,41 @@ import (
)
var (
- host = flag.String("host", "", "Comma-separated hostnames and IPs to generate a certificate for")
- validFrom = flag.String("start-date", "", "Creation date formatted as Jan 1 15:04:05 2011")
- validFor = flag.Duration("duration", 365*24*time.Hour, "Duration that certificate is valid for")
- isCA = flag.Bool("ca", false, "whether this cert should be its own Certificate Authority")
- rsaBits = flag.Int("rsa-bits", 2048, "Size of RSA key to generate")
+ host = flag.String("host", "", "Comma-separated hostnames and IPs to generate a certificate for")
+ validFrom = flag.String("start-date", "", "Creation date formatted as Jan 1 15:04:05 2011")
+ validFor = flag.Duration("duration", 365*24*time.Hour, "Duration that certificate is valid for")
+ isCA = flag.Bool("ca", false, "whether this cert should be its own Certificate Authority")
+ rsaBits = flag.Int("rsa-bits", 2048, "Size of RSA key to generate. Ignored if --ecdsa-curve is set")
+ ecdsaCurve = flag.String("ecdsa-curve", "", "ECDSA curve to use to generate a key. Valid values are P224, P256, P384, P521")
)
+func publicKey(priv interface{}) interface{} {
+ switch k := priv.(type) {
+ case *rsa.PrivateKey:
+ return &k.PublicKey
+ case *ecdsa.PrivateKey:
+ return &k.PublicKey
+ default:
+ return nil
+ }
+}
+
+func pemBlockForKey(priv interface{}) *pem.Block {
+ switch k := priv.(type) {
+ case *rsa.PrivateKey:
+ return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}
+ case *ecdsa.PrivateKey:
+ b, err := x509.MarshalECPrivateKey(k)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Unable to marshal ECDSA private key: %v", err)
+ os.Exit(2)
+ }
+ return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
+ default:
+ return nil
+ }
+}
+
func main() {
flag.Parse()
@@ -40,10 +70,25 @@ func main() {
log.Fatalf("Missing required --host parameter")
}
- priv, err := rsa.GenerateKey(rand.Reader, *rsaBits)
+ var priv interface{}
+ var err error
+ switch *ecdsaCurve {
+ case "":
+ priv, err = rsa.GenerateKey(rand.Reader, *rsaBits)
+ case "P224":
+ priv, err = ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
+ case "P256":
+ priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ case "P384":
+ priv, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
+ case "P521":
+ priv, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
+ default:
+ fmt.Fprintf(os.Stderr, "Unrecognized elliptic curve: %q", *ecdsaCurve)
+ os.Exit(1)
+ }
if err != nil {
log.Fatalf("failed to generate private key: %s", err)
- return
}
var notBefore time.Time
@@ -59,14 +104,14 @@ func main() {
notAfter := notBefore.Add(*validFor)
- // end of ASN.1 time
- endOfTime := time.Date(2049, 12, 31, 23, 59, 59, 0, time.UTC)
- if notAfter.After(endOfTime) {
- notAfter = endOfTime
+ serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
+ serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
+ if err != nil {
+ log.Fatalf("failed to generate serial number: %s", err)
}
template := x509.Certificate{
- SerialNumber: new(big.Int).SetInt64(0),
+ SerialNumber: serialNumber,
Subject: pkix.Name{
Organization: []string{"Acme Co"},
},
@@ -92,16 +137,14 @@ func main() {
template.KeyUsage |= x509.KeyUsageCertSign
}
- derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
+ derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv)
if err != nil {
log.Fatalf("Failed to create certificate: %s", err)
- return
}
certOut, err := os.Create("cert.pem")
if err != nil {
log.Fatalf("failed to open cert.pem for writing: %s", err)
- return
}
pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
certOut.Close()
@@ -112,7 +155,7 @@ func main() {
log.Print("failed to open key.pem for writing:", err)
return
}
- pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
+ pem.Encode(keyOut, pemBlockForKey(priv))
keyOut.Close()
log.Print("written key.pem\n")
}
diff --git a/libgo/go/crypto/tls/handshake_client.go b/libgo/go/crypto/tls/handshake_client.go
index 85e4adefcb..7f662e9c9f 100644
--- a/libgo/go/crypto/tls/handshake_client.go
+++ b/libgo/go/crypto/tls/handshake_client.go
@@ -6,30 +6,60 @@ package tls
import (
"bytes"
+ "crypto"
"crypto/ecdsa"
"crypto/rsa"
"crypto/subtle"
"crypto/x509"
- "encoding/asn1"
"errors"
+ "fmt"
"io"
+ "net"
"strconv"
)
+type clientHandshakeState struct {
+ c *Conn
+ serverHello *serverHelloMsg
+ hello *clientHelloMsg
+ suite *cipherSuite
+ finishedHash finishedHash
+ masterSecret []byte
+ session *ClientSessionState
+}
+
func (c *Conn) clientHandshake() error {
if c.config == nil {
c.config = defaultConfig()
}
+ if len(c.config.ServerName) == 0 && !c.config.InsecureSkipVerify {
+ return errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config")
+ }
+
+ nextProtosLength := 0
+ for _, proto := range c.config.NextProtos {
+ if l := len(proto); l == 0 || l > 255 {
+ return errors.New("tls: invalid NextProtos value")
+ } else {
+ nextProtosLength += 1 + l
+ }
+ }
+ if nextProtosLength > 0xffff {
+ return errors.New("tls: NextProtos values too large")
+ }
+
hello := &clientHelloMsg{
- vers: c.config.maxVersion(),
- compressionMethods: []uint8{compressionNone},
- random: make([]byte, 32),
- ocspStapling: true,
- serverName: c.config.ServerName,
- supportedCurves: []uint16{curveP256, curveP384, curveP521},
- supportedPoints: []uint8{pointFormatUncompressed},
- nextProtoNeg: len(c.config.NextProtos) > 0,
+ vers: c.config.maxVersion(),
+ compressionMethods: []uint8{compressionNone},
+ random: make([]byte, 32),
+ ocspStapling: true,
+ serverName: c.config.ServerName,
+ supportedCurves: c.config.curvePreferences(),
+ supportedPoints: []uint8{pointFormatUncompressed},
+ nextProtoNeg: len(c.config.NextProtos) > 0,
+ secureRenegotiation: true,
+ alpnProtocols: c.config.NextProtos,
}
possibleCipherSuites := c.config.cipherSuites()
@@ -51,21 +81,61 @@ NextCipherSuite:
}
}
- t := uint32(c.config.time().Unix())
- hello.random[0] = byte(t >> 24)
- hello.random[1] = byte(t >> 16)
- hello.random[2] = byte(t >> 8)
- hello.random[3] = byte(t)
- _, err := io.ReadFull(c.config.rand(), hello.random[4:])
+ _, err := io.ReadFull(c.config.rand(), hello.random)
if err != nil {
c.sendAlert(alertInternalError)
- return errors.New("short read from Rand")
+ return errors.New("tls: short read from Rand: " + err.Error())
}
if hello.vers >= VersionTLS12 {
hello.signatureAndHashes = supportedSKXSignatureAlgorithms
}
+ var session *ClientSessionState
+ var cacheKey string
+ sessionCache := c.config.ClientSessionCache
+ if c.config.SessionTicketsDisabled {
+ sessionCache = nil
+ }
+
+ if sessionCache != nil {
+ hello.ticketSupported = true
+
+ // Try to resume a previously negotiated TLS session, if
+ // available.
+ cacheKey = clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
+ candidateSession, ok := sessionCache.Get(cacheKey)
+ if ok {
+ // Check that the ciphersuite/version used for the
+ // previous session are still valid.
+ cipherSuiteOk := false
+ for _, id := range hello.cipherSuites {
+ if id == candidateSession.cipherSuite {
+ cipherSuiteOk = true
+ break
+ }
+ }
+
+ versOk := candidateSession.vers >= c.config.minVersion() &&
+ candidateSession.vers <= c.config.maxVersion()
+ if versOk && cipherSuiteOk {
+ session = candidateSession
+ }
+ }
+ }
+
+ if session != nil {
+ hello.sessionTicket = session.sessionTicket
+ // A random session ID is used to detect when the
+ // server accepted the ticket and is resuming a session
+ // (see RFC 5077).
+ hello.sessionId = make([]byte, 16)
+ if _, err := io.ReadFull(c.config.rand(), hello.sessionId); err != nil {
+ c.sendAlert(alertInternalError)
+ return errors.New("tls: short read from Rand: " + err.Error())
+ }
+ }
+
c.writeRecord(recordTypeHandshake, hello.marshal())
msg, err := c.readHandshake()
@@ -74,51 +144,103 @@ NextCipherSuite:
}
serverHello, ok := msg.(*serverHelloMsg)
if !ok {
- return c.sendAlert(alertUnexpectedMessage)
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(serverHello, msg)
}
vers, ok := c.config.mutualVersion(serverHello.vers)
if !ok || vers < VersionTLS10 {
// TLS 1.0 is the minimum version supported as a client.
- return c.sendAlert(alertProtocolVersion)
+ c.sendAlert(alertProtocolVersion)
+ return fmt.Errorf("tls: server selected unsupported protocol version %x", serverHello.vers)
}
c.vers = vers
c.haveVers = true
- finishedHash := newFinishedHash(c.vers)
- finishedHash.Write(hello.marshal())
- finishedHash.Write(serverHello.marshal())
+ suite := mutualCipherSuite(c.config.cipherSuites(), serverHello.cipherSuite)
+ if suite == nil {
+ c.sendAlert(alertHandshakeFailure)
+ return fmt.Errorf("tls: server selected an unsupported cipher suite")
+ }
- if serverHello.compressionMethod != compressionNone {
- return c.sendAlert(alertUnexpectedMessage)
+ hs := &clientHandshakeState{
+ c: c,
+ serverHello: serverHello,
+ hello: hello,
+ suite: suite,
+ finishedHash: newFinishedHash(c.vers),
+ session: session,
}
- if !hello.nextProtoNeg && serverHello.nextProtoNeg {
- c.sendAlert(alertHandshakeFailure)
- return errors.New("server advertised unrequested NPN")
+ hs.finishedHash.Write(hs.hello.marshal())
+ hs.finishedHash.Write(hs.serverHello.marshal())
+
+ isResume, err := hs.processServerHello()
+ if err != nil {
+ return err
}
- suite := mutualCipherSuite(c.config.cipherSuites(), serverHello.cipherSuite)
- if suite == nil {
- return c.sendAlert(alertHandshakeFailure)
+ if isResume {
+ if err := hs.establishKeys(); err != nil {
+ return err
+ }
+ if err := hs.readSessionTicket(); err != nil {
+ return err
+ }
+ if err := hs.readFinished(c.firstFinished[:]); err != nil {
+ return err
+ }
+ if err := hs.sendFinished(nil); err != nil {
+ return err
+ }
+ } else {
+ if err := hs.doFullHandshake(); err != nil {
+ return err
+ }
+ if err := hs.establishKeys(); err != nil {
+ return err
+ }
+ if err := hs.sendFinished(c.firstFinished[:]); err != nil {
+ return err
+ }
+ if err := hs.readSessionTicket(); err != nil {
+ return err
+ }
+ if err := hs.readFinished(nil); err != nil {
+ return err
+ }
}
- msg, err = c.readHandshake()
+ if sessionCache != nil && hs.session != nil && session != hs.session {
+ sessionCache.Put(cacheKey, hs.session)
+ }
+
+ c.didResume = isResume
+ c.handshakeComplete = true
+ c.cipherSuite = suite.id
+ return nil
+}
+
+func (hs *clientHandshakeState) doFullHandshake() error {
+ c := hs.c
+
+ msg, err := c.readHandshake()
if err != nil {
return err
}
certMsg, ok := msg.(*certificateMsg)
if !ok || len(certMsg.certificates) == 0 {
- return c.sendAlert(alertUnexpectedMessage)
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(certMsg, msg)
}
- finishedHash.Write(certMsg.marshal())
+ hs.finishedHash.Write(certMsg.marshal())
certs := make([]*x509.Certificate, len(certMsg.certificates))
for i, asn1Data := range certMsg.certificates {
cert, err := x509.ParseCertificate(asn1Data)
if err != nil {
c.sendAlert(alertBadCertificate)
- return errors.New("failed to parse certificate from server: " + err.Error())
+ return errors.New("tls: failed to parse certificate from server: " + err.Error())
}
certs[i] = cert
}
@@ -148,21 +270,23 @@ NextCipherSuite:
case *rsa.PublicKey, *ecdsa.PublicKey:
break
default:
- return c.sendAlert(alertUnsupportedCertificate)
+ c.sendAlert(alertUnsupportedCertificate)
+ return fmt.Errorf("tls: server's certificate contains an unsupported type of public key: %T", certs[0].PublicKey)
}
c.peerCertificates = certs
- if serverHello.ocspStapling {
+ if hs.serverHello.ocspStapling {
msg, err = c.readHandshake()
if err != nil {
return err
}
cs, ok := msg.(*certificateStatusMsg)
if !ok {
- return c.sendAlert(alertUnexpectedMessage)
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(cs, msg)
}
- finishedHash.Write(cs.marshal())
+ hs.finishedHash.Write(cs.marshal())
if cs.statusType == statusTypeOCSP {
c.ocspResponse = cs.response
@@ -174,12 +298,12 @@ NextCipherSuite:
return err
}
- keyAgreement := suite.ka(c.vers)
+ keyAgreement := hs.suite.ka(c.vers)
skx, ok := msg.(*serverKeyExchangeMsg)
if ok {
- finishedHash.Write(skx.marshal())
- err = keyAgreement.processServerKeyExchange(c.config, hello, serverHello, certs[0], skx)
+ hs.finishedHash.Write(skx.marshal())
+ err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, certs[0], skx)
if err != nil {
c.sendAlert(alertUnexpectedMessage)
return err
@@ -208,7 +332,7 @@ NextCipherSuite:
// ClientCertificateType, unless there is some external
// arrangement to the contrary.
- finishedHash.Write(certReq.marshal())
+ hs.finishedHash.Write(certReq.marshal())
var rsaAvail, ecdsaAvail bool
for _, certType := range certReq.certificateTypes {
@@ -221,8 +345,8 @@ NextCipherSuite:
}
// We need to search our list of client certs for one
- // where SignatureAlgorithm is RSA and the Issuer is in
- // certReq.certificateAuthorities
+ // where SignatureAlgorithm is acceptable to the server and the
+ // Issuer is in certReq.certificateAuthorities
findCert:
for i, chain := range c.config.Certificates {
if !rsaAvail && !ecdsaAvail {
@@ -249,7 +373,7 @@ NextCipherSuite:
if len(certReq.certificateAuthorities) == 0 {
// they gave us an empty list, so just take the
- // first RSA cert from c.config.Certificates
+ // first cert from c.config.Certificates
chainToSend = &chain
break findCert
}
@@ -271,9 +395,10 @@ NextCipherSuite:
shd, ok := msg.(*serverHelloDoneMsg)
if !ok {
- return c.sendAlert(alertUnexpectedMessage)
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(shd, msg)
}
- finishedHash.Write(shd.marshal())
+ hs.finishedHash.Write(shd.marshal())
// If the server requested a certificate then we have to send a
// Certificate message, even if it's empty because we don't have a
@@ -283,17 +408,17 @@ NextCipherSuite:
if chainToSend != nil {
certMsg.certificates = chainToSend.Certificate
}
- finishedHash.Write(certMsg.marshal())
+ hs.finishedHash.Write(certMsg.marshal())
c.writeRecord(recordTypeHandshake, certMsg.marshal())
}
- preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hello, certs[0])
+ preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, certs[0])
if err != nil {
c.sendAlert(alertInternalError)
return err
}
if ckx != nil {
- finishedHash.Write(ckx.marshal())
+ hs.finishedHash.Write(ckx.marshal())
c.writeRecord(recordTypeHandshake, ckx.marshal())
}
@@ -303,109 +428,211 @@ NextCipherSuite:
hasSignatureAndHash: c.vers >= VersionTLS12,
}
- switch key := c.config.Certificates[0].PrivateKey.(type) {
- case *ecdsa.PrivateKey:
- digest, _, hashId := finishedHash.hashForClientCertificate(signatureECDSA)
- r, s, err := ecdsa.Sign(c.config.rand(), key, digest)
- if err == nil {
- signed, err = asn1.Marshal(ecdsaSignature{r, s})
- }
+ key, ok := chainToSend.PrivateKey.(crypto.Signer)
+ if !ok {
+ c.sendAlert(alertInternalError)
+ return fmt.Errorf("tls: client certificate private key of type %T does not implement crypto.Signer", chainToSend.PrivateKey)
+ }
+ 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
- case *rsa.PrivateKey:
- digest, hashFunc, hashId := finishedHash.hashForClientCertificate(signatureRSA)
- signed, err = rsa.SignPKCS1v15(c.config.rand(), key, hashFunc, digest)
+ 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
default:
- err = errors.New("unknown private key type")
+ err = fmt.Errorf("tls: unknown client certificate key type: %T", key)
}
if err != nil {
- return c.sendAlert(alertInternalError)
+ c.sendAlert(alertInternalError)
+ return errors.New("tls: failed to sign handshake with client certificate: " + err.Error())
}
certVerify.signature = signed
- finishedHash.Write(certVerify.marshal())
+ hs.finishedHash.Write(certVerify.marshal())
c.writeRecord(recordTypeHandshake, certVerify.marshal())
}
- masterSecret := masterFromPreMasterSecret(c.vers, preMasterSecret, hello.random, serverHello.random)
- clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
- keysFromMasterSecret(c.vers, masterSecret, hello.random, serverHello.random, suite.macLen, suite.keyLen, suite.ivLen)
+ hs.masterSecret = masterFromPreMasterSecret(c.vers, preMasterSecret, hs.hello.random, hs.serverHello.random)
+ return nil
+}
- var clientCipher interface{}
- var clientHash macFunction
- if suite.cipher != nil {
- clientCipher = suite.cipher(clientKey, clientIV, false /* not for reading */)
- clientHash = suite.mac(c.vers, clientMAC)
+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)
+ var clientCipher, serverCipher interface{}
+ var clientHash, serverHash macFunction
+ if hs.suite.cipher != nil {
+ clientCipher = hs.suite.cipher(clientKey, clientIV, false /* not for reading */)
+ clientHash = hs.suite.mac(c.vers, clientMAC)
+ serverCipher = hs.suite.cipher(serverKey, serverIV, true /* for reading */)
+ serverHash = hs.suite.mac(c.vers, serverMAC)
} else {
- clientCipher = suite.aead(clientKey, clientIV)
+ clientCipher = hs.suite.aead(clientKey, clientIV)
+ serverCipher = hs.suite.aead(serverKey, serverIV)
}
+
+ c.in.prepareCipherSpec(c.vers, serverCipher, serverHash)
c.out.prepareCipherSpec(c.vers, clientCipher, clientHash)
- c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
+ return nil
+}
- if serverHello.nextProtoNeg {
- nextProto := new(nextProtoMsg)
- proto, fallback := mutualProtocol(c.config.NextProtos, serverHello.nextProtos)
- nextProto.proto = proto
- c.clientProtocol = proto
- c.clientProtocolFallback = fallback
+func (hs *clientHandshakeState) serverResumedSession() bool {
+ // If the server responded with the same sessionId then it means the
+ // sessionTicket is being used to resume a TLS session.
+ return hs.session != nil && hs.hello.sessionId != nil &&
+ bytes.Equal(hs.serverHello.sessionId, hs.hello.sessionId)
+}
- finishedHash.Write(nextProto.marshal())
- c.writeRecord(recordTypeHandshake, nextProto.marshal())
+func (hs *clientHandshakeState) processServerHello() (bool, error) {
+ c := hs.c
+
+ if hs.serverHello.compressionMethod != compressionNone {
+ c.sendAlert(alertUnexpectedMessage)
+ return false, errors.New("tls: server selected unsupported compression format")
}
- finished := new(finishedMsg)
- finished.verifyData = finishedHash.clientSum(masterSecret)
- finishedHash.Write(finished.marshal())
- c.writeRecord(recordTypeHandshake, finished.marshal())
+ clientDidNPN := hs.hello.nextProtoNeg
+ clientDidALPN := len(hs.hello.alpnProtocols) > 0
+ serverHasNPN := hs.serverHello.nextProtoNeg
+ serverHasALPN := len(hs.serverHello.alpnProtocol) > 0
- var serverCipher interface{}
- var serverHash macFunction
- if suite.cipher != nil {
- serverCipher = suite.cipher(serverKey, serverIV, true /* for reading */)
- serverHash = suite.mac(c.vers, serverMAC)
- } else {
- serverCipher = suite.aead(serverKey, serverIV)
+ if !clientDidNPN && serverHasNPN {
+ c.sendAlert(alertHandshakeFailure)
+ return false, errors.New("server advertised unrequested NPN extension")
}
- c.in.prepareCipherSpec(c.vers, serverCipher, serverHash)
+
+ if !clientDidALPN && serverHasALPN {
+ c.sendAlert(alertHandshakeFailure)
+ return false, errors.New("server advertised unrequested ALPN extension")
+ }
+
+ if serverHasNPN && serverHasALPN {
+ c.sendAlert(alertHandshakeFailure)
+ return false, errors.New("server advertised both NPN and ALPN extensions")
+ }
+
+ if serverHasALPN {
+ c.clientProtocol = hs.serverHello.alpnProtocol
+ c.clientProtocolFallback = false
+ }
+
+ if hs.serverResumedSession() {
+ // Restore masterSecret and peerCerts from previous state
+ hs.masterSecret = hs.session.masterSecret
+ c.peerCertificates = hs.session.serverCertificates
+ return true, nil
+ }
+ return false, nil
+}
+
+func (hs *clientHandshakeState) readFinished(out []byte) error {
+ c := hs.c
+
c.readRecord(recordTypeChangeCipherSpec)
- if err := c.error(); err != nil {
+ if err := c.in.error(); err != nil {
return err
}
- msg, err = c.readHandshake()
+ msg, err := c.readHandshake()
if err != nil {
return err
}
serverFinished, ok := msg.(*finishedMsg)
if !ok {
- return c.sendAlert(alertUnexpectedMessage)
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(serverFinished, msg)
}
- verify := finishedHash.serverSum(masterSecret)
+ verify := hs.finishedHash.serverSum(hs.masterSecret)
if len(verify) != len(serverFinished.verifyData) ||
subtle.ConstantTimeCompare(verify, serverFinished.verifyData) != 1 {
- return c.sendAlert(alertHandshakeFailure)
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: server's Finished message was incorrect")
+ }
+ hs.finishedHash.Write(serverFinished.marshal())
+ copy(out, verify)
+ return nil
+}
+
+func (hs *clientHandshakeState) readSessionTicket() error {
+ if !hs.serverHello.ticketSupported {
+ return nil
+ }
+
+ c := hs.c
+ msg, err := c.readHandshake()
+ if err != nil {
+ return err
+ }
+ sessionTicketMsg, ok := msg.(*newSessionTicketMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(sessionTicketMsg, msg)
+ }
+ hs.finishedHash.Write(sessionTicketMsg.marshal())
+
+ hs.session = &ClientSessionState{
+ sessionTicket: sessionTicketMsg.ticket,
+ vers: c.vers,
+ cipherSuite: hs.suite.id,
+ masterSecret: hs.masterSecret,
+ serverCertificates: c.peerCertificates,
}
- c.handshakeComplete = true
- c.cipherSuite = suite.id
return nil
}
-// mutualProtocol finds the mutual Next Protocol Negotiation protocol given the
-// set of client and server supported protocols. The set of client supported
-// protocols must not be empty. It returns the resulting protocol and flag
+func (hs *clientHandshakeState) sendFinished(out []byte) error {
+ c := hs.c
+
+ c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
+ if hs.serverHello.nextProtoNeg {
+ nextProto := new(nextProtoMsg)
+ proto, fallback := mutualProtocol(c.config.NextProtos, hs.serverHello.nextProtos)
+ nextProto.proto = proto
+ c.clientProtocol = proto
+ c.clientProtocolFallback = fallback
+
+ hs.finishedHash.Write(nextProto.marshal())
+ c.writeRecord(recordTypeHandshake, nextProto.marshal())
+ }
+
+ finished := new(finishedMsg)
+ finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret)
+ hs.finishedHash.Write(finished.marshal())
+ c.writeRecord(recordTypeHandshake, finished.marshal())
+ copy(out, finished.verifyData)
+ return nil
+}
+
+// clientSessionCacheKey returns a key used to cache sessionTickets that could
+// be used to resume previously negotiated TLS sessions with a server.
+func clientSessionCacheKey(serverAddr net.Addr, config *Config) string {
+ if len(config.ServerName) > 0 {
+ return config.ServerName
+ }
+ return serverAddr.String()
+}
+
+// mutualProtocol finds the mutual Next Protocol Negotiation or ALPN protocol
+// given list of possible protocols and a list of the preference order. The
+// first list must not be empty. It returns the resulting protocol and flag
// indicating if the fallback case was reached.
-func mutualProtocol(clientProtos, serverProtos []string) (string, bool) {
- for _, s := range serverProtos {
- for _, c := range clientProtos {
+func mutualProtocol(protos, preferenceProtos []string) (string, bool) {
+ for _, s := range preferenceProtos {
+ for _, c := range protos {
if s == c {
return s, false
}
}
}
- return clientProtos[0], true
+ return protos[0], true
}
diff --git a/libgo/go/crypto/tls/handshake_client_test.go b/libgo/go/crypto/tls/handshake_client_test.go
index 6c564001b0..e5eaa7de20 100644
--- a/libgo/go/crypto/tls/handshake_client_test.go
+++ b/libgo/go/crypto/tls/handshake_client_test.go
@@ -6,3045 +6,485 @@ package tls
import (
"bytes"
- "flag"
+ "crypto/ecdsa"
+ "crypto/rsa"
+ "crypto/x509"
+ "encoding/pem"
+ "fmt"
"io"
"net"
"os"
+ "os/exec"
+ "path/filepath"
+ "strconv"
"testing"
+ "time"
)
-func testClientScript(t *testing.T, name string, clientScript [][]byte, config *Config) {
- c, s := net.Pipe()
- cli := Client(c, config)
- go func() {
- cli.Write([]byte("hello\n"))
- cli.Close()
- c.Close()
- }()
+// Note: see comment in handshake_test.go for details of how the reference
+// tests work.
- defer c.Close()
- for i, b := range clientScript {
- if i%2 == 1 {
- s.Write(b)
- continue
- }
- bb := make([]byte, len(b))
- _, err := io.ReadFull(s, bb)
+// blockingSource is an io.Reader that blocks a Read call until it's closed.
+type blockingSource chan bool
+
+func (b blockingSource) Read([]byte) (n int, err error) {
+ <-b
+ return 0, io.EOF
+}
+
+// clientTest represents a test of the TLS client handshake against a reference
+// implementation.
+type clientTest struct {
+ // name is a freeform string identifying the test and the file in which
+ // the expected results will be stored.
+ name string
+ // command, if not empty, contains a series of arguments for the
+ // command to run for the reference server.
+ command []string
+ // config, if not nil, contains a custom Config to use for this test.
+ config *Config
+ // cert, if not empty, contains a DER-encoded certificate for the
+ // reference server.
+ cert []byte
+ // key, if not nil, contains either a *rsa.PrivateKey or
+ // *ecdsa.PrivateKey which is the private key for the reference server.
+ key interface{}
+ // 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.
+ validate func(ConnectionState) error
+}
+
+var defaultServerCommand = []string{"openssl", "s_server"}
+
+// connFromCommand starts the reference server process, connects to it and
+// returns a recordingConn for the connection. The stdin return value is a
+// blockingSource for the stdin of the child process. It must be closed before
+// Waiting for child.
+func (test *clientTest) connFromCommand() (conn *recordingConn, child *exec.Cmd, stdin blockingSource, err error) {
+ cert := testRSACertificate
+ if len(test.cert) > 0 {
+ cert = test.cert
+ }
+ certPath := tempFile(string(cert))
+ defer os.Remove(certPath)
+
+ var key interface{} = testRSAPrivateKey
+ if test.key != nil {
+ key = test.key
+ }
+ var pemType string
+ var derBytes []byte
+ switch key := key.(type) {
+ case *rsa.PrivateKey:
+ pemType = "RSA"
+ derBytes = x509.MarshalPKCS1PrivateKey(key)
+ case *ecdsa.PrivateKey:
+ pemType = "EC"
+ var err error
+ derBytes, err = x509.MarshalECPrivateKey(key)
if err != nil {
- t.Fatalf("%s #%d: %s", name, i, err)
+ panic(err)
}
- if !bytes.Equal(b, bb) {
- t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", name, i, bb, b)
+ default:
+ panic("unknown key type")
+ }
+
+ var pemOut bytes.Buffer
+ pem.Encode(&pemOut, &pem.Block{Type: pemType + " PRIVATE KEY", Bytes: derBytes})
+
+ keyPath := tempFile(string(pemOut.Bytes()))
+ defer os.Remove(keyPath)
+
+ var command []string
+ if len(test.command) > 0 {
+ command = append(command, test.command...)
+ } else {
+ command = append(command, defaultServerCommand...)
+ }
+ command = append(command, "-cert", certPath, "-certform", "DER", "-key", keyPath)
+ // serverPort contains the port that OpenSSL will listen on. OpenSSL
+ // can't take "0" as an argument here so we have to pick a number and
+ // hope that it's not in use on the machine. Since this only occurs
+ // when -update is given and thus when there's a human watching the
+ // test, this isn't too bad.
+ const serverPort = 24323
+ command = append(command, "-accept", strconv.Itoa(serverPort))
+
+ cmd := exec.Command(command[0], command[1:]...)
+ stdin = blockingSource(make(chan bool))
+ cmd.Stdin = stdin
+ var out bytes.Buffer
+ cmd.Stdout = &out
+ cmd.Stderr = &out
+ if err := cmd.Start(); err != nil {
+ return nil, nil, nil, err
+ }
+
+ // OpenSSL does print an "ACCEPT" banner, but it does so *before*
+ // opening the listening socket, so we can't use that to wait until it
+ // has started listening. Thus we are forced to poll until we get a
+ // 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,
+ })
+ if err == nil {
+ break
}
+ time.Sleep((1 << i) * 5 * time.Millisecond)
+ }
+ if tcpConn == nil {
+ close(stdin)
+ out.WriteTo(os.Stdout)
+ cmd.Process.Kill()
+ return nil, nil, nil, cmd.Wait()
+ }
+
+ record := &recordingConn{
+ Conn: tcpConn,
}
+
+ return record, cmd, stdin, nil
}
-func TestHandshakeClientRSARC4(t *testing.T) {
- var config = *testConfig
- config.CipherSuites = []uint16{TLS_RSA_WITH_RC4_128_SHA}
- testClientScript(t, "RSA-RC4", rsaRC4ClientScript, &config)
+func (test *clientTest) dataPath() string {
+ return filepath.Join("testdata", "Client-"+test.name)
}
-func TestHandshakeClientECDHERSAAES(t *testing.T) {
- var config = *testConfig
- config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}
- testClientScript(t, "ECDHE-RSA-AES", ecdheRSAAESClientScript, &config)
+func (test *clientTest) loadData() (flows [][]byte, err error) {
+ in, err := os.Open(test.dataPath())
+ if err != nil {
+ return nil, err
+ }
+ defer in.Close()
+ return parseTestData(in)
}
-func TestHandshakeClientECDHECDSAAES(t *testing.T) {
- var config = *testConfig
- config.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA}
- config.Certificates = nil
- config.BuildNameToCertificate()
- testClientScript(t, "ECDHE-ECDSA-AES", ecdheECDSAAESClientScript, &config)
+func (test *clientTest) run(t *testing.T, write bool) {
+ var clientConn, serverConn net.Conn
+ var recordingConn *recordingConn
+ var childProcess *exec.Cmd
+ var stdin blockingSource
+
+ if write {
+ var err error
+ recordingConn, childProcess, stdin, err = test.connFromCommand()
+ if err != nil {
+ t.Fatalf("Failed to start subcommand: %s", err)
+ }
+ clientConn = recordingConn
+ } else {
+ clientConn, serverConn = net.Pipe()
+ }
+
+ config := test.config
+ if config == nil {
+ config = testConfig
+ }
+ client := Client(clientConn, config)
+
+ doneChan := make(chan bool)
+ go func() {
+ if _, err := client.Write([]byte("hello\n")); err != nil {
+ t.Logf("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)
+ }
+ }
+ client.Close()
+ clientConn.Close()
+ doneChan <- true
+ }()
+
+ if !write {
+ flows, err := test.loadData()
+ if err != nil {
+ t.Fatalf("%s: failed to load data from %s: %v", test.name, test.dataPath(), err)
+ }
+ for i, b := range flows {
+ if i%2 == 1 {
+ serverConn.Write(b)
+ continue
+ }
+ bb := make([]byte, len(b))
+ _, err := io.ReadFull(serverConn, bb)
+ if err != nil {
+ t.Fatalf("%s #%d: %s", test.name, i, err)
+ }
+ if !bytes.Equal(b, bb) {
+ t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", test.name, i, bb, b)
+ }
+ }
+ serverConn.Close()
+ }
+
+ <-doneChan
+
+ if write {
+ path := test.dataPath()
+ out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
+ if err != nil {
+ t.Fatalf("Failed to create output file: %s", err)
+ }
+ defer out.Close()
+ recordingConn.Close()
+ close(stdin)
+ childProcess.Process.Kill()
+ childProcess.Wait()
+ if len(recordingConn.flows) < 3 {
+ childProcess.Stdout.(*bytes.Buffer).WriteTo(os.Stdout)
+ t.Fatalf("Client connection didn't work")
+ }
+ recordingConn.WriteTo(out)
+ fmt.Printf("Wrote %s\n", path)
+ }
}
-func TestLongClientCerticiateChain(t *testing.T) {
- config := *testConfig
- cert, _ := X509KeyPair(testClientChainCertificate, testClientChainCertificate)
- config.Certificates = []Certificate{cert}
- testClientScript(t, "Long client certificate chains", clientChainCertificateScript, &config)
+func runClientTestForVersion(t *testing.T, template *clientTest, prefix, option string) {
+ test := *template
+ test.name = prefix + test.name
+ if len(test.command) == 0 {
+ test.command = defaultClientCommand
+ }
+ test.command = append([]string(nil), test.command...)
+ test.command = append(test.command, option)
+ test.run(t, *update)
}
-func TestHandshakeClientTLS11(t *testing.T) {
- var config = *testConfig
- config.MaxVersion = VersionTLS11
- config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}
- testClientScript(t, "TLS11-ECDHE-AES", tls11ECDHEAESClientScript, &config)
+func runClientTestTLS10(t *testing.T, template *clientTest) {
+ runClientTestForVersion(t, template, "TLSv10-", "-tls1")
}
-func TestHandshakeClientTLS12(t *testing.T) {
- config := *testConfig
- config.MaxVersion = VersionTLS12
- config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}
- cert, _ := X509KeyPair(testClientChainCertificate, testClientChainCertificate)
- config.Certificates = []Certificate{cert}
- testClientScript(t, "TLS12", clientTLS12Script, &config)
+func runClientTestTLS11(t *testing.T, template *clientTest) {
+ runClientTestForVersion(t, template, "TLSv11-", "-tls1_1")
}
-func TestHandshakeClientTLS12ClientCert(t *testing.T) {
- config := *testConfig
- config.MaxVersion = VersionTLS12
- config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}
- cert, _ := X509KeyPair(testClientChainCertificate, testClientChainCertificate)
- config.Certificates = []Certificate{cert}
- testClientScript(t, "TLS12ClientCert", clientTLS12ClientCertScript, &config)
+func runClientTestTLS12(t *testing.T, template *clientTest) {
+ runClientTestForVersion(t, template, "TLSv12-", "-tls1_2")
}
-var connect = flag.Bool("connect", false, "connect to a TLS server on :10443")
+func TestHandshakeClientRSARC4(t *testing.T) {
+ test := &clientTest{
+ name: "RSA-RC4",
+ command: []string{"openssl", "s_server", "-cipher", "RC4-SHA"},
+ }
+ runClientTestTLS10(t, test)
+ runClientTestTLS11(t, test)
+ runClientTestTLS12(t, test)
+}
-func TestRunClient(t *testing.T) {
- if !*connect {
- return
+func TestHandshakeClientECDHERSAAES(t *testing.T) {
+ test := &clientTest{
+ name: "ECDHE-RSA-AES",
+ command: []string{"openssl", "s_server", "-cipher", "ECDHE-RSA-AES128-SHA"},
}
+ runClientTestTLS10(t, test)
+ runClientTestTLS11(t, test)
+ runClientTestTLS12(t, test)
+}
- tcpConn, err := net.Dial("tcp", "127.0.0.1:10443")
- if err != nil {
- t.Fatal(err)
+func TestHandshakeClientECDHEECDSAAES(t *testing.T) {
+ test := &clientTest{
+ name: "ECDHE-ECDSA-AES",
+ command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-SHA"},
+ cert: testECDSACertificate,
+ key: testECDSAPrivateKey,
}
+ runClientTestTLS10(t, test)
+ runClientTestTLS11(t, test)
+ runClientTestTLS12(t, test)
+}
- record := &recordingConn{
- Conn: tcpConn,
+func TestHandshakeClientECDHEECDSAAESGCM(t *testing.T) {
+ test := &clientTest{
+ name: "ECDHE-ECDSA-AES-GCM",
+ command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-GCM-SHA256"},
+ cert: testECDSACertificate,
+ key: testECDSAPrivateKey,
}
+ runClientTestTLS12(t, test)
+}
+
+func TestHandshakeClientCertRSA(t *testing.T) {
+ config := *testConfig
+ cert, _ := X509KeyPair([]byte(clientCertificatePEM), []byte(clientKeyPEM))
+ config.Certificates = []Certificate{cert}
- config := GetTestConfig()
- conn := Client(record, config)
- if err := conn.Handshake(); err != nil {
- t.Fatalf("error from TLS handshake: %s", err)
+ test := &clientTest{
+ name: "ClientCert-RSA-RSA",
+ command: []string{"openssl", "s_server", "-cipher", "RC4-SHA", "-verify", "1"},
+ config: &config,
}
- conn.Write([]byte("hello\n"))
- conn.Close()
+ runClientTestTLS10(t, test)
+ runClientTestTLS12(t, test)
+
+ test = &clientTest{
+ name: "ClientCert-RSA-ECDSA",
+ command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-SHA", "-verify", "1"},
+ config: &config,
+ cert: testECDSACertificate,
+ key: testECDSAPrivateKey,
+ }
- record.WriteTo(os.Stdout)
+ runClientTestTLS10(t, test)
+ runClientTestTLS12(t, test)
}
-func TestEmptyRecords(t *testing.T) {
- // emptyRecordScript contains a TLS connection with an empty record as
- // the first application data from the server. This test ensures that
- // the empty record doesn't cause (0, nil) to be returned from
- // Conn.Read.
+func TestHandshakeClientCertECDSA(t *testing.T) {
config := *testConfig
- config.CipherSuites = []uint16{TLS_RSA_WITH_AES_256_CBC_SHA}
+ cert, _ := X509KeyPair([]byte(clientECDSACertificatePEM), []byte(clientECDSAKeyPEM))
+ config.Certificates = []Certificate{cert}
- c, s := net.Pipe()
- cli := Client(c, &config)
- go func() {
- buf := make([]byte, 1024)
- n, err := cli.Read(buf)
- defer c.Close()
- defer cli.Close()
+ test := &clientTest{
+ name: "ClientCert-ECDSA-RSA",
+ command: []string{"openssl", "s_server", "-cipher", "RC4-SHA", "-verify", "1"},
+ config: &config,
+ }
- if err != nil {
- t.Fatalf("error reading from tls.Client: %s", err)
- }
- const expectedLength = 197
- if n != expectedLength {
- t.Fatalf("incorrect length reading from tls.Client, got %d, want %d", n, expectedLength)
- }
- }()
+ runClientTestTLS10(t, test)
+ runClientTestTLS12(t, test)
- defer c.Close()
- for i, b := range emptyRecordScript {
- if i%2 == 1 {
- s.Write(b)
- continue
- }
- bb := make([]byte, len(b))
- _, err := io.ReadFull(s, bb)
+ test = &clientTest{
+ name: "ClientCert-ECDSA-ECDSA",
+ command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-SHA", "-verify", "1"},
+ config: &config,
+ cert: testECDSACertificate,
+ key: testECDSAPrivateKey,
+ }
+
+ runClientTestTLS10(t, test)
+ runClientTestTLS12(t, test)
+}
+
+func TestClientResumption(t *testing.T) {
+ serverConfig := &Config{
+ CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA},
+ Certificates: testConfig.Certificates,
+ }
+ clientConfig := &Config{
+ CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
+ InsecureSkipVerify: true,
+ ClientSessionCache: NewLRUClientSessionCache(32),
+ }
+
+ testResumeState := func(test string, didResume bool) {
+ hs, err := testHandshake(clientConfig, serverConfig)
if err != nil {
- t.Fatalf("#%d: %s", i, err)
+ t.Fatalf("%s: handshake failed: %s", test, err)
}
- if !bytes.Equal(b, bb) {
- t.Fatalf("#%d: mismatch on read: got:%x want:%x", i, bb, b)
+ if hs.DidResume != didResume {
+ t.Fatalf("%s resumed: %v, expected: %v", test, hs.DidResume, didResume)
}
}
-}
-// Script of interaction with gnutls implementation.
-// The values for this test are obtained by building and running in client mode:
-// % go test -test.run "TestRunClient" -connect
-// The recorded bytes are written to stdout.
-//
-// The server private key is:
-// -----BEGIN RSA PRIVATE KEY-----
-// MIIBPAIBAAJBAJ+zw4Qnlf8SMVIPFe9GEcStgOY2Ww/dgNdhjeD8ckUJNP5VZkVD
-// TGiXav6ooKXfX3j/7tdkuD8Ey2//Kv7+ue0CAwEAAQJAN6W31vDEP2DjdqhzCDDu
-// OA4NACqoiFqyblo7yc2tM4h4xMbC3Yx5UKMN9ZkCtX0gzrz6DyF47bdKcWBzNWCj
-// gQIhANEoojVt7hq+SQ6MCN6FTAysGgQf56Q3TYoJMoWvdiXVAiEAw3e3rc+VJpOz
-// rHuDo6bgpjUAAXM+v3fcpsfZSNO6V7kCIQCtbVjanpUwvZkMI9by02oUk9taki3b
-// PzPfAfNPYAbCJQIhAJXNQDWyqwn/lGmR11cqY2y9nZ1+5w3yHGatLrcDnQHxAiEA
-// vnlEGo8K85u+KwIOimM48ZG8oTk7iFdkqLJR1utT3aU=
-// -----END RSA PRIVATE KEY-----
-//
-// and certificate is:
-// -----BEGIN CERTIFICATE-----
-// MIICKzCCAdWgAwIBAgIJALE1E2URIMWSMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
-// BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
-// aWRnaXRzIFB0eSBMdGQwHhcNMTIwNDA2MTcxMDEzWhcNMTUwNDA2MTcxMDEzWjBF
-// MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50
-// ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJ+z
-// w4Qnlf8SMVIPFe9GEcStgOY2Ww/dgNdhjeD8ckUJNP5VZkVDTGiXav6ooKXfX3j/
-// 7tdkuD8Ey2//Kv7+ue0CAwEAAaOBpzCBpDAdBgNVHQ4EFgQUeKaXmmO1xaGlM7oi
-// fCNuWxt6zCswdQYDVR0jBG4wbIAUeKaXmmO1xaGlM7oifCNuWxt6zCuhSaRHMEUx
-// CzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRl
-// cm5ldCBXaWRnaXRzIFB0eSBMdGSCCQCxNRNlESDFkjAMBgNVHRMEBTADAQH/MA0G
-// CSqGSIb3DQEBBQUAA0EAhTZAc8G7GtrUWZ8tonAxRnTsg26oyDxRrzms7EC86CJG
-// HZnWRiok1IsFCEv7NRFukrt3uuQSu/TIXpyBqJdgTA==
-// -----END CERTIFICATE-----
-var rsaRC4ClientScript = [][]byte{
- {
- 0x16, 0x03, 0x01, 0x00, 0x4a, 0x01, 0x00, 0x00,
- 0x46, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05,
- 0x01, 0x00, 0x00, 0x1b, 0x00, 0x05, 0x00, 0x05,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
- 0x08, 0x00, 0x06, 0x00, 0x17, 0x00, 0x18, 0x00,
- 0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00,
- },
+ testResumeState("Handshake", false)
+ testResumeState("Resume", true)
- {
- 0x16, 0x03, 0x01, 0x00, 0x4a, 0x02, 0x00, 0x00,
- 0x46, 0x03, 0x01, 0x4d, 0x0a, 0x56, 0x16, 0xb5,
- 0x91, 0xd1, 0xcb, 0x80, 0x4d, 0xc7, 0x46, 0xf3,
- 0x37, 0x0c, 0xef, 0xea, 0x64, 0x11, 0x14, 0x56,
- 0x97, 0x9b, 0xc5, 0x67, 0x08, 0xb7, 0x13, 0xea,
- 0xf8, 0xc9, 0xb3, 0x20, 0xe2, 0xfc, 0x41, 0xf6,
- 0x96, 0x90, 0x9d, 0x43, 0x9b, 0xe9, 0x6e, 0xf8,
- 0x41, 0x16, 0xcc, 0xf3, 0xc7, 0xde, 0xda, 0x5a,
- 0xa1, 0x33, 0x69, 0xe2, 0xde, 0x5b, 0xaf, 0x2a,
- 0x92, 0xe7, 0xd4, 0xa0, 0x00, 0x05, 0x00, 0x16,
- 0x03, 0x01, 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xf3,
- 0x00, 0x01, 0xf0, 0x00, 0x01, 0xed, 0x30, 0x82,
- 0x01, 0xe9, 0x30, 0x82, 0x01, 0x52, 0x02, 0x01,
- 0x06, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
- 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x04, 0x05, 0x00,
- 0x30, 0x5b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
- 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31,
- 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08,
- 0x13, 0x0a, 0x51, 0x75, 0x65, 0x65, 0x6e, 0x73,
- 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x1a, 0x30, 0x18,
- 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x43,
- 0x72, 0x79, 0x70, 0x74, 0x53, 0x6f, 0x66, 0x74,
- 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64,
- 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04,
- 0x03, 0x13, 0x12, 0x54, 0x65, 0x73, 0x74, 0x20,
- 0x43, 0x41, 0x20, 0x28, 0x31, 0x30, 0x32, 0x34,
- 0x20, 0x62, 0x69, 0x74, 0x29, 0x30, 0x1e, 0x17,
- 0x0d, 0x30, 0x30, 0x31, 0x30, 0x31, 0x36, 0x32,
- 0x32, 0x33, 0x31, 0x30, 0x33, 0x5a, 0x17, 0x0d,
- 0x30, 0x33, 0x30, 0x31, 0x31, 0x34, 0x32, 0x32,
- 0x33, 0x31, 0x30, 0x33, 0x5a, 0x30, 0x63, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x51,
- 0x75, 0x65, 0x65, 0x6e, 0x73, 0x6c, 0x61, 0x6e,
- 0x64, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x11, 0x43, 0x72, 0x79, 0x70,
- 0x74, 0x53, 0x6f, 0x66, 0x74, 0x20, 0x50, 0x74,
- 0x79, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x23, 0x30,
- 0x21, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1a,
- 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x74,
- 0x65, 0x73, 0x74, 0x20, 0x63, 0x65, 0x72, 0x74,
- 0x20, 0x28, 0x35, 0x31, 0x32, 0x20, 0x62, 0x69,
- 0x74, 0x29, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48,
- 0x02, 0x41, 0x00, 0x9f, 0xb3, 0xc3, 0x84, 0x27,
- 0x95, 0xff, 0x12, 0x31, 0x52, 0x0f, 0x15, 0xef,
- 0x46, 0x11, 0xc4, 0xad, 0x80, 0xe6, 0x36, 0x5b,
- 0x0f, 0xdd, 0x80, 0xd7, 0x61, 0x8d, 0xe0, 0xfc,
- 0x72, 0x45, 0x09, 0x34, 0xfe, 0x55, 0x66, 0x45,
- 0x43, 0x4c, 0x68, 0x97, 0x6a, 0xfe, 0xa8, 0xa0,
- 0xa5, 0xdf, 0x5f, 0x78, 0xff, 0xee, 0xd7, 0x64,
- 0xb8, 0x3f, 0x04, 0xcb, 0x6f, 0xff, 0x2a, 0xfe,
- 0xfe, 0xb9, 0xed, 0x02, 0x03, 0x01, 0x00, 0x01,
- 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
- 0xf7, 0x0d, 0x01, 0x01, 0x04, 0x05, 0x00, 0x03,
- 0x81, 0x81, 0x00, 0x93, 0xd2, 0x0a, 0xc5, 0x41,
- 0xe6, 0x5a, 0xa9, 0x86, 0xf9, 0x11, 0x87, 0xe4,
- 0xdb, 0x45, 0xe2, 0xc5, 0x95, 0x78, 0x1a, 0x6c,
- 0x80, 0x6d, 0x73, 0x1f, 0xb4, 0x6d, 0x44, 0xa3,
- 0xba, 0x86, 0x88, 0xc8, 0x58, 0xcd, 0x1c, 0x06,
- 0x35, 0x6c, 0x44, 0x62, 0x88, 0xdf, 0xe4, 0xf6,
- 0x64, 0x61, 0x95, 0xef, 0x4a, 0xa6, 0x7f, 0x65,
- 0x71, 0xd7, 0x6b, 0x88, 0x39, 0xf6, 0x32, 0xbf,
- 0xac, 0x93, 0x67, 0x69, 0x51, 0x8c, 0x93, 0xec,
- 0x48, 0x5f, 0xc9, 0xb1, 0x42, 0xf9, 0x55, 0xd2,
- 0x7e, 0x4e, 0xf4, 0xf2, 0x21, 0x6b, 0x90, 0x57,
- 0xe6, 0xd7, 0x99, 0x9e, 0x41, 0xca, 0x80, 0xbf,
- 0x1a, 0x28, 0xa2, 0xca, 0x5b, 0x50, 0x4a, 0xed,
- 0x84, 0xe7, 0x82, 0xc7, 0xd2, 0xcf, 0x36, 0x9e,
- 0x6a, 0x67, 0xb9, 0x88, 0xa7, 0xf3, 0x8a, 0xd0,
- 0x04, 0xf8, 0xe8, 0xc6, 0x17, 0xe3, 0xc5, 0x29,
- 0xbc, 0x17, 0xf1, 0x16, 0x03, 0x01, 0x00, 0x04,
- 0x0e, 0x00, 0x00, 0x00,
- },
+ if _, err := io.ReadFull(serverConfig.rand(), serverConfig.SessionTicketKey[:]); err != nil {
+ t.Fatalf("Failed to invalidate SessionTicketKey")
+ }
+ testResumeState("InvalidSessionTicketKey", false)
+ testResumeState("ResumeAfterInvalidSessionTicketKey", true)
- {
- 0x16, 0x03, 0x01, 0x00, 0x46, 0x10, 0x00, 0x00,
- 0x42, 0x00, 0x40, 0x87, 0xa1, 0x1f, 0x14, 0xe1,
- 0xfb, 0x91, 0xac, 0x58, 0x2e, 0xf3, 0x71, 0xce,
- 0x01, 0x85, 0x2c, 0xc7, 0xfe, 0x84, 0x87, 0x82,
- 0xb7, 0x57, 0xdb, 0x37, 0x4d, 0x46, 0x83, 0x67,
- 0x52, 0x82, 0x51, 0x01, 0x95, 0x23, 0x68, 0x69,
- 0x6b, 0xd0, 0xa7, 0xa7, 0xe5, 0x88, 0xd0, 0x47,
- 0x71, 0xb8, 0xd2, 0x03, 0x05, 0x25, 0x56, 0x5c,
- 0x10, 0x08, 0xc6, 0x9b, 0xd4, 0x67, 0xcd, 0x28,
- 0xbe, 0x9c, 0x48, 0x14, 0x03, 0x01, 0x00, 0x01,
- 0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0xc1, 0xb8,
- 0xd3, 0x7f, 0xc5, 0xc2, 0x5a, 0x1d, 0x6d, 0x5b,
- 0x2d, 0x5c, 0x82, 0x87, 0xc2, 0x6f, 0x0d, 0x63,
- 0x7b, 0x72, 0x2b, 0xda, 0x69, 0xc4, 0xfe, 0x3c,
- 0x84, 0xa1, 0x5a, 0x62, 0x38, 0x37, 0xc6, 0x54,
- 0x25, 0x2a,
- },
+ clientConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA}
+ testResumeState("DifferentCipherSuite", false)
+ testResumeState("DifferentCipherSuiteRecovers", true)
- {
- 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
- 0x01, 0x00, 0x24, 0xea, 0x88, 0x9c, 0x00, 0xf6,
- 0x35, 0xb8, 0x42, 0x7f, 0x15, 0x17, 0x76, 0x5e,
- 0x4b, 0x24, 0xcb, 0x7e, 0xa0, 0x7b, 0xc3, 0x70,
- 0x52, 0x0a, 0x88, 0x2a, 0x7a, 0x45, 0x59, 0x90,
- 0x59, 0xac, 0xc6, 0xb5, 0x56, 0x55, 0x96,
- },
+ clientConfig.ClientSessionCache = nil
+ testResumeState("WithoutSessionCache", false)
}
-var ecdheRSAAESClientScript = [][]byte{
- {
- 0x16, 0x03, 0x01, 0x00, 0x4a, 0x01, 0x00, 0x00,
- 0x46, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xc0, 0x13,
- 0x01, 0x00, 0x00, 0x1b, 0x00, 0x05, 0x00, 0x05,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
- 0x08, 0x00, 0x06, 0x00, 0x17, 0x00, 0x18, 0x00,
- 0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x52, 0x02, 0x00, 0x00,
- 0x4e, 0x03, 0x01, 0x50, 0xad, 0x72, 0xb1, 0x14,
- 0x45, 0xce, 0x0a, 0x95, 0xf9, 0x63, 0xef, 0xa8,
- 0xe5, 0x07, 0x34, 0x04, 0xe9, 0x08, 0x0f, 0x38,
- 0xe4, 0x28, 0x27, 0x91, 0x07, 0x03, 0xe2, 0xfe,
- 0xe3, 0x25, 0xf7, 0x20, 0x08, 0x42, 0xa2, 0x01,
- 0x69, 0x53, 0xf0, 0xd9, 0x4c, 0xfa, 0x01, 0xa1,
- 0xce, 0x4b, 0xf8, 0x28, 0x21, 0xad, 0x06, 0xbe,
- 0xe0, 0x1b, 0x3b, 0xf7, 0xec, 0xd2, 0x52, 0xae,
- 0x2a, 0x57, 0xb7, 0xa8, 0xc0, 0x13, 0x00, 0x00,
- 0x06, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x16,
- 0x03, 0x01, 0x02, 0x39, 0x0b, 0x00, 0x02, 0x35,
- 0x00, 0x02, 0x32, 0x00, 0x02, 0x2f, 0x30, 0x82,
- 0x02, 0x2b, 0x30, 0x82, 0x01, 0xd5, 0xa0, 0x03,
- 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0xb1, 0x35,
- 0x13, 0x65, 0x11, 0x20, 0xc5, 0x92, 0x30, 0x0d,
- 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d,
- 0x31, 0x32, 0x30, 0x34, 0x30, 0x36, 0x31, 0x37,
- 0x31, 0x30, 0x31, 0x33, 0x5a, 0x17, 0x0d, 0x31,
- 0x35, 0x30, 0x34, 0x30, 0x36, 0x31, 0x37, 0x31,
- 0x30, 0x31, 0x33, 0x5a, 0x30, 0x45, 0x31, 0x0b,
- 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
- 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06,
- 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f,
- 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
- 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04,
- 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72,
- 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67,
- 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20,
- 0x4c, 0x74, 0x64, 0x30, 0x5c, 0x30, 0x0d, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30,
- 0x48, 0x02, 0x41, 0x00, 0x9f, 0xb3, 0xc3, 0x84,
- 0x27, 0x95, 0xff, 0x12, 0x31, 0x52, 0x0f, 0x15,
- 0xef, 0x46, 0x11, 0xc4, 0xad, 0x80, 0xe6, 0x36,
- 0x5b, 0x0f, 0xdd, 0x80, 0xd7, 0x61, 0x8d, 0xe0,
- 0xfc, 0x72, 0x45, 0x09, 0x34, 0xfe, 0x55, 0x66,
- 0x45, 0x43, 0x4c, 0x68, 0x97, 0x6a, 0xfe, 0xa8,
- 0xa0, 0xa5, 0xdf, 0x5f, 0x78, 0xff, 0xee, 0xd7,
- 0x64, 0xb8, 0x3f, 0x04, 0xcb, 0x6f, 0xff, 0x2a,
- 0xfe, 0xfe, 0xb9, 0xed, 0x02, 0x03, 0x01, 0x00,
- 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81, 0xa4, 0x30,
- 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
- 0x04, 0x14, 0x78, 0xa6, 0x97, 0x9a, 0x63, 0xb5,
- 0xc5, 0xa1, 0xa5, 0x33, 0xba, 0x22, 0x7c, 0x23,
- 0x6e, 0x5b, 0x1b, 0x7a, 0xcc, 0x2b, 0x30, 0x75,
- 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x6e, 0x30,
- 0x6c, 0x80, 0x14, 0x78, 0xa6, 0x97, 0x9a, 0x63,
- 0xb5, 0xc5, 0xa1, 0xa5, 0x33, 0xba, 0x22, 0x7c,
- 0x23, 0x6e, 0x5b, 0x1b, 0x7a, 0xcc, 0x2b, 0xa1,
- 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31, 0x0b, 0x30,
- 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
- 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
- 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d,
- 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
- 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
- 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
- 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
- 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
- 0x74, 0x64, 0x82, 0x09, 0x00, 0xb1, 0x35, 0x13,
- 0x65, 0x11, 0x20, 0xc5, 0x92, 0x30, 0x0c, 0x06,
- 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03,
- 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
- 0x05, 0x00, 0x03, 0x41, 0x00, 0x85, 0x36, 0x40,
- 0x73, 0xc1, 0xbb, 0x1a, 0xda, 0xd4, 0x59, 0x9f,
- 0x2d, 0xa2, 0x70, 0x31, 0x46, 0x74, 0xec, 0x83,
- 0x6e, 0xa8, 0xc8, 0x3c, 0x51, 0xaf, 0x39, 0xac,
- 0xec, 0x40, 0xbc, 0xe8, 0x22, 0x46, 0x1d, 0x99,
- 0xd6, 0x46, 0x2a, 0x24, 0xd4, 0x8b, 0x05, 0x08,
- 0x4b, 0xfb, 0x35, 0x11, 0x6e, 0x92, 0xbb, 0x77,
- 0xba, 0xe4, 0x12, 0xbb, 0xf4, 0xc8, 0x5e, 0x9c,
- 0x81, 0xa8, 0x97, 0x60, 0x4c, 0x16, 0x03, 0x01,
- 0x00, 0x8b, 0x0c, 0x00, 0x00, 0x87, 0x03, 0x00,
- 0x17, 0x41, 0x04, 0x1c, 0x8f, 0x9c, 0x6d, 0xe7,
- 0xab, 0x3e, 0xf8, 0x0a, 0x5d, 0xe1, 0x86, 0xb4,
- 0xe2, 0x8e, 0xb2, 0x1c, 0x3b, 0xd9, 0xb6, 0x08,
- 0x80, 0x58, 0x21, 0xe9, 0x0e, 0xc6, 0x66, 0x67,
- 0x97, 0xcb, 0xb9, 0x92, 0x07, 0x00, 0xc4, 0xe5,
- 0xec, 0x5f, 0xb4, 0xe2, 0x20, 0xa9, 0xc9, 0x62,
- 0xd0, 0x98, 0xd5, 0xe3, 0x53, 0xff, 0xd0, 0x0a,
- 0x6e, 0x29, 0x69, 0x39, 0x2a, 0x4b, 0x5c, 0xd8,
- 0x6c, 0xf5, 0xfe, 0x00, 0x40, 0x35, 0xa7, 0x26,
- 0x2e, 0xc2, 0x48, 0x93, 0x32, 0xf7, 0x7d, 0x0f,
- 0x0d, 0x77, 0x56, 0x9a, 0x85, 0x0c, 0xa6, 0x74,
- 0x06, 0xb8, 0x3d, 0x90, 0x56, 0x12, 0x63, 0xff,
- 0x00, 0x5e, 0x0f, 0xf7, 0x24, 0xf7, 0xdb, 0x48,
- 0x71, 0xe9, 0x2e, 0x03, 0xd3, 0xfa, 0x3a, 0xae,
- 0xa0, 0xc1, 0x77, 0x3c, 0x4c, 0x59, 0xce, 0x33,
- 0x1a, 0xd2, 0x47, 0x83, 0xfa, 0xea, 0xd8, 0x1e,
- 0x06, 0xe7, 0x7d, 0xa0, 0x9b, 0x16, 0x03, 0x01,
- 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x46, 0x10, 0x00, 0x00,
- 0x42, 0x41, 0x04, 0x1e, 0x18, 0x37, 0xef, 0x0d,
- 0x19, 0x51, 0x88, 0x35, 0x75, 0x71, 0xb5, 0xe5,
- 0x54, 0x5b, 0x12, 0x2e, 0x8f, 0x09, 0x67, 0xfd,
- 0xa7, 0x24, 0x20, 0x3e, 0xb2, 0x56, 0x1c, 0xce,
- 0x97, 0x28, 0x5e, 0xf8, 0x2b, 0x2d, 0x4f, 0x9e,
- 0xf1, 0x07, 0x9f, 0x6c, 0x4b, 0x5b, 0x83, 0x56,
- 0xe2, 0x32, 0x42, 0xe9, 0x58, 0xb6, 0xd7, 0x49,
- 0xa6, 0xb5, 0x68, 0x1a, 0x41, 0x03, 0x56, 0x6b,
- 0xdc, 0x5a, 0x89, 0x14, 0x03, 0x01, 0x00, 0x01,
- 0x01, 0x16, 0x03, 0x01, 0x00, 0x30, 0xd9, 0xa7,
- 0x80, 0x56, 0x3f, 0xa3, 0x8f, 0x96, 0x72, 0x4e,
- 0x4e, 0x6e, 0x23, 0x41, 0x8f, 0xda, 0x91, 0xb2,
- 0x9e, 0x63, 0x23, 0x82, 0x64, 0xcd, 0x07, 0x24,
- 0xd3, 0x40, 0x20, 0x22, 0x4c, 0xe3, 0xff, 0x38,
- 0xbb, 0x43, 0x9d, 0x57, 0x11, 0xd5, 0x46, 0xa5,
- 0x05, 0x29, 0x92, 0x02, 0xce, 0xdf,
- },
- {
- 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
- 0x01, 0x00, 0x90, 0xe7, 0xba, 0x0e, 0xb1, 0xda,
- 0x92, 0xb5, 0x77, 0x56, 0x38, 0xa6, 0x22, 0xc1,
- 0x72, 0xeb, 0x8a, 0x68, 0x09, 0xb6, 0x74, 0xad,
- 0xb3, 0x4a, 0xf2, 0xdd, 0x09, 0x9b, 0xc9, 0x4f,
- 0x84, 0x73, 0x8b, 0xd6, 0x97, 0x50, 0x23, 0x1c,
- 0xa0, 0xc2, 0x0c, 0x25, 0x18, 0xdd, 0x5e, 0x15,
- 0x4d, 0xd9, 0xef, 0x4f, 0x6a, 0x43, 0x61, 0x9c,
- 0x95, 0xde, 0x3c, 0x66, 0xc4, 0xc1, 0x33, 0x56,
- 0xdd, 0x2f, 0x90, 0xaf, 0x68, 0x5c, 0x9c, 0xa4,
- 0x90, 0x6d, 0xbf, 0x51, 0x1d, 0x68, 0xcb, 0x81,
- 0x77, 0x52, 0xa0, 0x93, 0x2a, 0xf8, 0xc7, 0x61,
- 0x87, 0x76, 0xca, 0x93, 0x9e, 0xd6, 0xee, 0x6f,
- 0x3f, 0xeb, 0x7d, 0x06, 0xdd, 0x73, 0x4e, 0x27,
- 0x16, 0x63, 0x92, 0xe4, 0xb2, 0x3f, 0x91, 0x23,
- 0x21, 0x97, 0x90, 0xce, 0x53, 0xb8, 0xb0, 0x9d,
- 0xbd, 0xbd, 0x33, 0x84, 0xad, 0x6b, 0x2e, 0x7b,
- 0xf5, 0xeb, 0x1d, 0x64, 0x37, 0x2e, 0x29, 0x4e,
- 0xb0, 0x93, 0xdb, 0x92, 0xc7, 0xaa, 0x94, 0xa5,
- 0x3b, 0x64, 0xd0,
- },
- {
- 0x17, 0x03, 0x01, 0x00, 0x20, 0x11, 0xd8, 0x6b,
- 0x3c, 0xf6, 0xbe, 0xf4, 0x54, 0x87, 0xec, 0x75,
- 0x0c, 0x44, 0xdb, 0x92, 0xfc, 0xde, 0x7e, 0x0f,
- 0x9f, 0x87, 0x87, 0x9c, 0x03, 0xd5, 0x07, 0x84,
- 0xe0, 0x3a, 0xf8, 0xae, 0x14, 0x17, 0x03, 0x01,
- 0x00, 0x20, 0xba, 0x54, 0xef, 0x5b, 0xce, 0xfd,
- 0x47, 0x76, 0x6d, 0xa1, 0x8b, 0xfd, 0x48, 0xde,
- 0x6e, 0x26, 0xc1, 0x0c, 0x9d, 0x54, 0xbf, 0x98,
- 0xf6, 0x1c, 0x80, 0xb9, 0xca, 0x93, 0x81, 0x0a,
- 0x2e, 0x06, 0x15, 0x03, 0x01, 0x00, 0x20, 0x93,
- 0x3e, 0x38, 0x17, 0xc9, 0x0a, 0xc3, 0xea, 0xd3,
- 0x92, 0x75, 0xa6, 0x53, 0x37, 0x4d, 0x74, 0x94,
- 0xbe, 0x01, 0xdc, 0x5c, 0x5a, 0x0f, 0x09, 0xf6,
- 0x57, 0x33, 0xc3, 0xbc, 0x3f, 0x7a, 0x4d,
- },
-}
+func TestLRUClientSessionCache(t *testing.T) {
+ // Initialize cache of capacity 4.
+ cache := NewLRUClientSessionCache(4)
+ cs := make([]ClientSessionState, 6)
+ keys := []string{"0", "1", "2", "3", "4", "5", "6"}
-var emptyRecordScript = [][]byte{
- {
- 0x16, 0x03, 0x01, 0x00, 0x4a, 0x01, 0x00, 0x00,
- 0x46, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x35,
- 0x01, 0x00, 0x00, 0x1b, 0x00, 0x05, 0x00, 0x05,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
- 0x08, 0x00, 0x06, 0x00, 0x17, 0x00, 0x18, 0x00,
- 0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x4a, 0x02, 0x00, 0x00,
- 0x46, 0x03, 0x01, 0x51, 0x71, 0x8e, 0x03, 0x02,
- 0xef, 0x09, 0xf2, 0x0e, 0xf5, 0x3b, 0x29, 0x9a,
- 0xa8, 0x8b, 0x46, 0xa3, 0xd4, 0xb4, 0xc1, 0x14,
- 0xc3, 0x19, 0x99, 0xba, 0x3d, 0x78, 0xcf, 0x50,
- 0xd1, 0xe7, 0x26, 0x20, 0xa0, 0x37, 0x6d, 0xc9,
- 0xae, 0x93, 0x33, 0x81, 0x20, 0xe3, 0xc1, 0x90,
- 0x64, 0x6e, 0x67, 0x93, 0xdb, 0xb4, 0x04, 0x16,
- 0xc4, 0x25, 0xdd, 0x10, 0x79, 0x3c, 0x18, 0x0a,
- 0x7c, 0xfd, 0x28, 0x65, 0x00, 0x35, 0x00, 0x16,
- 0x03, 0x01, 0x09, 0x9e, 0x0b, 0x00, 0x09, 0x9a,
- 0x00, 0x09, 0x97, 0x00, 0x04, 0xea, 0x30, 0x82,
- 0x04, 0xe6, 0x30, 0x82, 0x03, 0xce, 0xa0, 0x03,
- 0x02, 0x01, 0x02, 0x02, 0x11, 0x00, 0xff, 0xab,
- 0x02, 0x93, 0xe0, 0x72, 0x99, 0x18, 0x6c, 0x9e,
- 0x96, 0xb8, 0xb9, 0xf7, 0x47, 0xcb, 0x30, 0x0d,
- 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x41, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x46, 0x52, 0x31, 0x12, 0x30, 0x10,
- 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x09, 0x47,
- 0x41, 0x4e, 0x44, 0x49, 0x20, 0x53, 0x41, 0x53,
- 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04,
- 0x03, 0x13, 0x15, 0x47, 0x61, 0x6e, 0x64, 0x69,
- 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72,
- 0x64, 0x20, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41,
- 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x31,
- 0x31, 0x34, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
- 0x5a, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x31, 0x31,
- 0x34, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a,
- 0x30, 0x62, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
- 0x55, 0x04, 0x0b, 0x13, 0x18, 0x44, 0x6f, 0x6d,
- 0x61, 0x69, 0x6e, 0x20, 0x43, 0x6f, 0x6e, 0x74,
- 0x72, 0x6f, 0x6c, 0x20, 0x56, 0x61, 0x6c, 0x69,
- 0x64, 0x61, 0x74, 0x65, 0x64, 0x31, 0x24, 0x30,
- 0x22, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1b,
- 0x47, 0x61, 0x6e, 0x64, 0x69, 0x20, 0x53, 0x74,
- 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x57,
- 0x69, 0x6c, 0x64, 0x63, 0x61, 0x72, 0x64, 0x20,
- 0x53, 0x53, 0x4c, 0x31, 0x17, 0x30, 0x15, 0x06,
- 0x03, 0x55, 0x04, 0x03, 0x14, 0x0e, 0x2a, 0x2e,
- 0x66, 0x72, 0x65, 0x65, 0x6e, 0x6f, 0x64, 0x65,
- 0x2e, 0x6e, 0x65, 0x74, 0x30, 0x82, 0x01, 0x22,
- 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
- 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
- 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
- 0x02, 0x82, 0x01, 0x01, 0x00, 0xdc, 0xe3, 0xfd,
- 0xce, 0xc1, 0x66, 0x62, 0x28, 0x8b, 0x99, 0x65,
- 0x72, 0x52, 0x88, 0x93, 0x5b, 0x3f, 0x8d, 0xde,
- 0x2b, 0xb0, 0xa0, 0xf4, 0xbd, 0xb4, 0x07, 0x5f,
- 0x9e, 0x01, 0x47, 0x60, 0x57, 0x5f, 0xdf, 0xdc,
- 0x63, 0x28, 0x1c, 0x1e, 0x5b, 0xc8, 0xe6, 0x29,
- 0xdd, 0xeb, 0x26, 0x63, 0xd5, 0xbf, 0x83, 0xb2,
- 0x2d, 0xcd, 0x2c, 0xa0, 0xb6, 0x91, 0xad, 0xaf,
- 0x95, 0x21, 0x1d, 0x1f, 0x39, 0x8d, 0x3e, 0x17,
- 0xd6, 0xbd, 0x99, 0xf5, 0x6c, 0xd4, 0xcb, 0x79,
- 0x12, 0x3e, 0x11, 0xb9, 0x7e, 0x62, 0xbc, 0x2d,
- 0xbf, 0xe0, 0x55, 0x1b, 0x5c, 0x1e, 0xce, 0x31,
- 0xd9, 0xf8, 0x56, 0x68, 0x95, 0x2b, 0x15, 0x84,
- 0x35, 0xae, 0x98, 0x2c, 0x63, 0x01, 0xb2, 0x0d,
- 0xab, 0xa8, 0x61, 0xef, 0x7f, 0x15, 0x2c, 0x6d,
- 0xf7, 0x67, 0x1d, 0xb8, 0x8d, 0xf6, 0xa2, 0x1c,
- 0x4e, 0x85, 0xf0, 0xea, 0x1a, 0x2b, 0xc8, 0xac,
- 0x70, 0x86, 0x9a, 0xbb, 0x9e, 0x9d, 0xbd, 0xc9,
- 0x87, 0x2b, 0x9f, 0x5e, 0x40, 0x44, 0x9b, 0xba,
- 0x96, 0x45, 0x24, 0xbc, 0x49, 0xb8, 0xfe, 0x26,
- 0x3a, 0x1d, 0x1a, 0x0a, 0x3a, 0x90, 0x9c, 0x75,
- 0x51, 0x59, 0x89, 0x98, 0x1a, 0x56, 0xe1, 0x3a,
- 0x1a, 0xba, 0xff, 0xb4, 0x37, 0x7d, 0xd8, 0x99,
- 0xe2, 0xeb, 0x45, 0x27, 0xe2, 0x42, 0x42, 0x46,
- 0xbb, 0x00, 0x29, 0x9f, 0x30, 0xc9, 0x1e, 0x6c,
- 0xce, 0x59, 0x0e, 0xbe, 0x16, 0x03, 0x31, 0xec,
- 0x10, 0xc1, 0x6d, 0xca, 0x9d, 0x5f, 0x6d, 0xf1,
- 0x26, 0x11, 0xe5, 0x50, 0xa1, 0xbb, 0x67, 0xb2,
- 0xe0, 0x2b, 0xed, 0x76, 0x5b, 0xc7, 0x68, 0xc0,
- 0x18, 0xad, 0x91, 0x9e, 0xb5, 0xd4, 0x4d, 0x21,
- 0xcd, 0x98, 0xd9, 0xe0, 0x05, 0x0a, 0x4d, 0x24,
- 0xa3, 0xe6, 0x12, 0x04, 0xdd, 0x50, 0xe6, 0xc8,
- 0x7a, 0x69, 0xb9, 0x32, 0x43, 0x02, 0x03, 0x01,
- 0x00, 0x01, 0xa3, 0x82, 0x01, 0xb6, 0x30, 0x82,
- 0x01, 0xb2, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d,
- 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xb6,
- 0xa8, 0xff, 0xa2, 0xa8, 0x2f, 0xd0, 0xa6, 0xcd,
- 0x4b, 0xb1, 0x68, 0xf3, 0xe7, 0x50, 0x10, 0x31,
- 0xa7, 0x79, 0x21, 0x30, 0x1d, 0x06, 0x03, 0x55,
- 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x62, 0x37,
- 0xd4, 0x3c, 0xbf, 0xd9, 0xc2, 0x99, 0xf3, 0x28,
- 0x3e, 0xdb, 0xca, 0xee, 0xf3, 0xb3, 0xc8, 0x73,
- 0xb0, 0x3c, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d,
- 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02,
- 0x05, 0xa0, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d,
- 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00,
- 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04,
- 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01,
- 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b,
- 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30,
- 0x60, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x59,
- 0x30, 0x57, 0x30, 0x4b, 0x06, 0x0b, 0x2b, 0x06,
- 0x01, 0x04, 0x01, 0xb2, 0x31, 0x01, 0x02, 0x02,
- 0x1a, 0x30, 0x3c, 0x30, 0x3a, 0x06, 0x08, 0x2b,
- 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16,
- 0x2e, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
- 0x77, 0x77, 0x77, 0x2e, 0x67, 0x61, 0x6e, 0x64,
- 0x69, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x63, 0x6f,
- 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x73, 0x2f,
- 0x66, 0x72, 0x2f, 0x73, 0x73, 0x6c, 0x2f, 0x63,
- 0x70, 0x73, 0x2f, 0x70, 0x64, 0x66, 0x2f, 0x30,
- 0x08, 0x06, 0x06, 0x67, 0x81, 0x0c, 0x01, 0x02,
- 0x01, 0x30, 0x3c, 0x06, 0x03, 0x55, 0x1d, 0x1f,
- 0x04, 0x35, 0x30, 0x33, 0x30, 0x31, 0xa0, 0x2f,
- 0xa0, 0x2d, 0x86, 0x2b, 0x68, 0x74, 0x74, 0x70,
- 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x67,
- 0x61, 0x6e, 0x64, 0x69, 0x2e, 0x6e, 0x65, 0x74,
- 0x2f, 0x47, 0x61, 0x6e, 0x64, 0x69, 0x53, 0x74,
- 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x53, 0x53,
- 0x4c, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x6c, 0x30,
- 0x6a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
- 0x07, 0x01, 0x01, 0x04, 0x5e, 0x30, 0x5c, 0x30,
- 0x37, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
- 0x07, 0x30, 0x02, 0x86, 0x2b, 0x68, 0x74, 0x74,
- 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x74, 0x2e,
- 0x67, 0x61, 0x6e, 0x64, 0x69, 0x2e, 0x6e, 0x65,
- 0x74, 0x2f, 0x47, 0x61, 0x6e, 0x64, 0x69, 0x53,
- 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x53,
- 0x53, 0x4c, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x74,
- 0x30, 0x21, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
- 0x05, 0x07, 0x30, 0x01, 0x86, 0x15, 0x68, 0x74,
- 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73,
- 0x70, 0x2e, 0x67, 0x61, 0x6e, 0x64, 0x69, 0x2e,
- 0x6e, 0x65, 0x74, 0x30, 0x27, 0x06, 0x03, 0x55,
- 0x1d, 0x11, 0x04, 0x20, 0x30, 0x1e, 0x82, 0x0e,
- 0x2a, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x6e, 0x6f,
- 0x64, 0x65, 0x2e, 0x6e, 0x65, 0x74, 0x82, 0x0c,
- 0x66, 0x72, 0x65, 0x65, 0x6e, 0x6f, 0x64, 0x65,
- 0x2e, 0x6e, 0x65, 0x74, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
- 0x5b, 0x4a, 0x3a, 0x1d, 0x75, 0xe0, 0xc0, 0x9e,
- 0xc9, 0x16, 0x66, 0x7f, 0x73, 0x95, 0x6e, 0x35,
- 0xe4, 0x27, 0xfa, 0x8c, 0x9d, 0xee, 0xb1, 0x37,
- 0x42, 0x3f, 0x54, 0x6a, 0x9d, 0x41, 0x84, 0x57,
- 0xe1, 0x03, 0x3d, 0x69, 0x61, 0x77, 0x3b, 0x91,
- 0xa2, 0x70, 0x94, 0xb6, 0x8e, 0x41, 0x63, 0x70,
- 0xf2, 0x16, 0x04, 0x50, 0x05, 0x14, 0xfb, 0x59,
- 0x7d, 0x89, 0x09, 0x3f, 0xb6, 0xef, 0xca, 0x3c,
- 0x89, 0x88, 0x08, 0xe9, 0xa1, 0xf3, 0x33, 0x31,
- 0x05, 0x4d, 0x70, 0xff, 0xdd, 0xa7, 0xd2, 0xe2,
- 0xa0, 0x94, 0x3a, 0xf7, 0xc2, 0x9f, 0xad, 0x2b,
- 0x2e, 0x20, 0xfa, 0x6c, 0xe1, 0xfc, 0xe6, 0x62,
- 0x22, 0xa1, 0x38, 0x93, 0xec, 0x3e, 0xce, 0xfd,
- 0x1f, 0xdd, 0xd4, 0x7c, 0x39, 0x46, 0x8b, 0xb4,
- 0x64, 0xfa, 0xa1, 0x46, 0x87, 0x78, 0x2c, 0xd7,
- 0x9c, 0xdd, 0x60, 0xd6, 0xda, 0x8e, 0xd8, 0x29,
- 0x6d, 0x61, 0xa7, 0x29, 0x07, 0x76, 0xfc, 0xf9,
- 0xbd, 0xfd, 0x14, 0xeb, 0x44, 0x70, 0xff, 0xd0,
- 0x23, 0x99, 0x83, 0xc5, 0x5c, 0x56, 0x88, 0xaa,
- 0x34, 0xda, 0xa6, 0xb3, 0x9a, 0xbf, 0xda, 0x58,
- 0x1e, 0xa4, 0xb8, 0xc0, 0x40, 0x9d, 0xf0, 0xfc,
- 0xf1, 0x23, 0xc2, 0xbc, 0x59, 0xe1, 0x82, 0xed,
- 0x5d, 0xfb, 0x99, 0xaf, 0xf5, 0xf5, 0x15, 0xb8,
- 0x8b, 0x59, 0xce, 0xaa, 0xca, 0xdf, 0xdc, 0x94,
- 0x11, 0xe0, 0x96, 0xbf, 0x9f, 0x54, 0xa4, 0x9f,
- 0x54, 0x36, 0x4a, 0xe8, 0x93, 0xda, 0xf4, 0x8c,
- 0xb0, 0x6b, 0x8d, 0x4a, 0x9e, 0x11, 0xae, 0xcb,
- 0xcb, 0x33, 0x8a, 0x4d, 0xcd, 0x4e, 0xa5, 0x9b,
- 0xe9, 0x14, 0x46, 0x43, 0x9b, 0x96, 0x5f, 0x6d,
- 0xf2, 0xea, 0x40, 0xef, 0x14, 0xc3, 0x99, 0x9f,
- 0x23, 0x1e, 0xa5, 0x13, 0xab, 0x08, 0xea, 0x8f,
- 0x68, 0x5b, 0x7d, 0x71, 0xdf, 0x18, 0xd1, 0x57,
- 0x00, 0x04, 0xa7, 0x30, 0x82, 0x04, 0xa3, 0x30,
- 0x82, 0x03, 0x8b, 0xa0, 0x03, 0x02, 0x01, 0x02,
- 0x02, 0x10, 0x5a, 0xb6, 0x1d, 0xac, 0x1e, 0x4d,
- 0xa2, 0x06, 0x14, 0xc7, 0x55, 0x3d, 0x3d, 0xa9,
- 0xb2, 0xdc, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05,
- 0x00, 0x30, 0x81, 0x97, 0x31, 0x0b, 0x30, 0x09,
- 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
- 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
- 0x04, 0x08, 0x13, 0x02, 0x55, 0x54, 0x31, 0x17,
- 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13,
- 0x0e, 0x53, 0x61, 0x6c, 0x74, 0x20, 0x4c, 0x61,
- 0x6b, 0x65, 0x20, 0x43, 0x69, 0x74, 0x79, 0x31,
- 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a,
- 0x13, 0x15, 0x54, 0x68, 0x65, 0x20, 0x55, 0x53,
- 0x45, 0x52, 0x54, 0x52, 0x55, 0x53, 0x54, 0x20,
- 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31,
- 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b,
- 0x13, 0x18, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
- 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x75, 0x73, 0x65,
- 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63,
- 0x6f, 0x6d, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03,
- 0x55, 0x04, 0x03, 0x13, 0x16, 0x55, 0x54, 0x4e,
- 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x69, 0x72,
- 0x73, 0x74, 0x2d, 0x48, 0x61, 0x72, 0x64, 0x77,
- 0x61, 0x72, 0x65, 0x30, 0x1e, 0x17, 0x0d, 0x30,
- 0x38, 0x31, 0x30, 0x32, 0x33, 0x30, 0x30, 0x30,
- 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x30,
- 0x30, 0x35, 0x33, 0x30, 0x31, 0x30, 0x34, 0x38,
- 0x33, 0x38, 0x5a, 0x30, 0x41, 0x31, 0x0b, 0x30,
- 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
- 0x46, 0x52, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03,
- 0x55, 0x04, 0x0a, 0x13, 0x09, 0x47, 0x41, 0x4e,
- 0x44, 0x49, 0x20, 0x53, 0x41, 0x53, 0x31, 0x1e,
- 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
- 0x15, 0x47, 0x61, 0x6e, 0x64, 0x69, 0x20, 0x53,
- 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20,
- 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, 0x30, 0x82,
- 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
- 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82,
- 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xb6,
- 0x54, 0x3d, 0xa5, 0xdb, 0x0d, 0x22, 0x78, 0x50,
- 0x6a, 0x5a, 0x23, 0x89, 0x3f, 0x97, 0xa1, 0xd4,
- 0x07, 0x1a, 0xa9, 0x58, 0x08, 0x9b, 0xa0, 0x15,
- 0xc3, 0x32, 0xb6, 0xb7, 0xf1, 0xe8, 0xb9, 0xa5,
- 0x6f, 0xad, 0x37, 0xf6, 0x6e, 0x71, 0x1b, 0xb4,
- 0x75, 0x2d, 0x48, 0x5e, 0x9f, 0xc6, 0x15, 0xaa,
- 0x81, 0xef, 0xe5, 0xc4, 0x88, 0x95, 0x8a, 0x3a,
- 0x6c, 0x77, 0xcc, 0xb5, 0xcd, 0x65, 0xe4, 0x67,
- 0xe5, 0x73, 0xc9, 0x50, 0x52, 0x94, 0xc1, 0x27,
- 0x49, 0x3e, 0xa0, 0x6b, 0x41, 0x16, 0x41, 0xb6,
- 0x94, 0x99, 0x41, 0xae, 0x3e, 0xcb, 0xe2, 0x06,
- 0x46, 0x09, 0xe9, 0x4d, 0xbe, 0xc9, 0x4c, 0x55,
- 0xa9, 0x18, 0x7e, 0xa6, 0xdf, 0x6e, 0xfd, 0x4a,
- 0xb2, 0xcc, 0x6c, 0x4e, 0xd9, 0xc8, 0x50, 0x15,
- 0x93, 0xb3, 0xf2, 0xe9, 0xe3, 0xc2, 0x6a, 0xad,
- 0x3a, 0xd5, 0xfb, 0xc3, 0x79, 0x50, 0x9f, 0x25,
- 0x79, 0x29, 0xb2, 0x47, 0x64, 0x7c, 0x20, 0x3e,
- 0xe2, 0x08, 0x4d, 0x93, 0x29, 0x14, 0xb6, 0x34,
- 0x6e, 0xcf, 0x71, 0x46, 0x7e, 0x76, 0x10, 0xf4,
- 0xfd, 0x6c, 0xaa, 0x01, 0xd2, 0xc2, 0x06, 0xde,
- 0x92, 0x83, 0xcc, 0x58, 0x90, 0x2e, 0x92, 0xde,
- 0x1e, 0x65, 0xb7, 0x63, 0x2f, 0x3d, 0xb2, 0xeb,
- 0x70, 0x8c, 0x4c, 0xe0, 0xbe, 0x15, 0x9d, 0xde,
- 0xc1, 0x4d, 0x56, 0xf8, 0x0b, 0xc6, 0x8e, 0x07,
- 0xb9, 0x5d, 0xdf, 0x95, 0xf0, 0x7b, 0x40, 0x1f,
- 0x1a, 0x2c, 0xd7, 0x9c, 0x2b, 0x4b, 0x76, 0xf4,
- 0x59, 0xf5, 0x43, 0xc1, 0x2c, 0x66, 0x10, 0x9e,
- 0x9e, 0x66, 0x96, 0x60, 0x9d, 0x1c, 0x74, 0x1b,
- 0x4e, 0x18, 0x5c, 0x08, 0xb0, 0x6e, 0x6c, 0xca,
- 0x69, 0x1a, 0x02, 0xe9, 0xbb, 0xca, 0x78, 0xef,
- 0x66, 0x2e, 0xe3, 0x32, 0xfd, 0x41, 0x5c, 0x95,
- 0x74, 0x81, 0x4d, 0xf4, 0xda, 0xfe, 0x4b, 0x02,
- 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x3e,
- 0x30, 0x82, 0x01, 0x3a, 0x30, 0x1f, 0x06, 0x03,
- 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80,
- 0x14, 0xa1, 0x72, 0x5f, 0x26, 0x1b, 0x28, 0x98,
- 0x43, 0x95, 0x5d, 0x07, 0x37, 0xd5, 0x85, 0x96,
- 0x9d, 0x4b, 0xd2, 0xc3, 0x45, 0x30, 0x1d, 0x06,
- 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
- 0xb6, 0xa8, 0xff, 0xa2, 0xa8, 0x2f, 0xd0, 0xa6,
- 0xcd, 0x4b, 0xb1, 0x68, 0xf3, 0xe7, 0x50, 0x10,
- 0x31, 0xa7, 0x79, 0x21, 0x30, 0x0e, 0x06, 0x03,
- 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04,
- 0x03, 0x02, 0x01, 0x06, 0x30, 0x12, 0x06, 0x03,
- 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08,
- 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00,
- 0x30, 0x18, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04,
- 0x11, 0x30, 0x0f, 0x30, 0x0d, 0x06, 0x0b, 0x2b,
- 0x06, 0x01, 0x04, 0x01, 0xb2, 0x31, 0x01, 0x02,
- 0x02, 0x1a, 0x30, 0x44, 0x06, 0x03, 0x55, 0x1d,
- 0x1f, 0x04, 0x3d, 0x30, 0x3b, 0x30, 0x39, 0xa0,
- 0x37, 0xa0, 0x35, 0x86, 0x33, 0x68, 0x74, 0x74,
- 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e,
- 0x75, 0x73, 0x65, 0x72, 0x74, 0x72, 0x75, 0x73,
- 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x55, 0x54,
- 0x4e, 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x69,
- 0x72, 0x73, 0x74, 0x2d, 0x48, 0x61, 0x72, 0x64,
- 0x77, 0x61, 0x72, 0x65, 0x2e, 0x63, 0x72, 0x6c,
- 0x30, 0x74, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
- 0x05, 0x07, 0x01, 0x01, 0x04, 0x68, 0x30, 0x66,
- 0x30, 0x3d, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
- 0x05, 0x07, 0x30, 0x02, 0x86, 0x31, 0x68, 0x74,
- 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x74,
- 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x72, 0x75,
- 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x55,
- 0x54, 0x4e, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75,
- 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,
- 0x5f, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x74, 0x30,
- 0x25, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
- 0x07, 0x30, 0x01, 0x86, 0x19, 0x68, 0x74, 0x74,
- 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70,
- 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x72, 0x75,
- 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x0d,
- 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01,
- 0x01, 0x00, 0x19, 0x53, 0xbf, 0x03, 0x3d, 0x9b,
- 0xe2, 0x6b, 0x5a, 0xfd, 0xba, 0x49, 0x1f, 0x4f,
- 0xec, 0xe1, 0xc6, 0x82, 0x39, 0x3c, 0xd2, 0x03,
- 0x04, 0x0f, 0xab, 0x7b, 0x3e, 0x82, 0xa9, 0x85,
- 0x10, 0x1f, 0xf4, 0xde, 0x32, 0xaf, 0x58, 0x3f,
- 0xff, 0x70, 0xf3, 0x30, 0x1d, 0x97, 0x2d, 0x4c,
- 0x9a, 0xe2, 0xec, 0x0c, 0x3e, 0x14, 0x2d, 0x2f,
- 0x98, 0x48, 0x9d, 0xae, 0x16, 0x6a, 0xac, 0x2d,
- 0x42, 0xaa, 0xb5, 0x64, 0xa4, 0x70, 0xbb, 0xeb,
- 0x73, 0x94, 0x7b, 0x46, 0x4c, 0xe7, 0x7a, 0x14,
- 0x76, 0x5b, 0x4c, 0x1d, 0x84, 0xa1, 0x20, 0x74,
- 0x1f, 0x2e, 0x4b, 0x5c, 0x70, 0x88, 0xdc, 0xbd,
- 0xf7, 0x19, 0x3d, 0xed, 0x59, 0x0d, 0xe2, 0x3f,
- 0x26, 0xe2, 0x9c, 0xac, 0xa4, 0x3c, 0x95, 0x1c,
- 0xf8, 0xbe, 0x8c, 0x03, 0xae, 0xf0, 0xe5, 0x9c,
- 0x4d, 0xbc, 0xc7, 0x9b, 0x58, 0x00, 0xbf, 0xaf,
- 0xad, 0xfa, 0x37, 0x6e, 0x71, 0x6d, 0x18, 0x34,
- 0x0e, 0xc1, 0xea, 0x6a, 0xf8, 0x0d, 0xdf, 0x69,
- 0x54, 0x56, 0x15, 0xf2, 0x28, 0xb3, 0xfe, 0xa4,
- 0x63, 0xec, 0xc5, 0x04, 0x64, 0x60, 0xbb, 0xfe,
- 0x2a, 0xf0, 0xf4, 0x87, 0xa1, 0xb0, 0xae, 0xbd,
- 0xaa, 0xe4, 0x2f, 0xe3, 0x03, 0x0b, 0x2f, 0x66,
- 0x5f, 0x85, 0xa4, 0x32, 0x7b, 0x46, 0xed, 0x25,
- 0x0c, 0xe7, 0xf1, 0xb7, 0xe7, 0x19, 0xfd, 0x60,
- 0xba, 0x5f, 0x87, 0x77, 0xde, 0x98, 0x07, 0x96,
- 0xe4, 0x5e, 0xea, 0x63, 0x7d, 0xa8, 0xde, 0x55,
- 0xda, 0x61, 0x5c, 0x3c, 0x90, 0x83, 0x43, 0x04,
- 0x07, 0x3c, 0xdd, 0xf3, 0xf8, 0x9f, 0x06, 0x52,
- 0x0a, 0xde, 0xc7, 0xb6, 0x7b, 0x8f, 0xe1, 0x11,
- 0xf7, 0x04, 0x7a, 0x35, 0xff, 0x6a, 0xbc, 0x5b,
- 0xc7, 0x50, 0x49, 0x08, 0x70, 0x6f, 0x94, 0x43,
- 0xcd, 0x9e, 0xc7, 0x70, 0xf1, 0xdb, 0xd0, 0x6d,
- 0xda, 0x8f, 0x16, 0x03, 0x01, 0x00, 0x0e, 0x0d,
- 0x00, 0x00, 0x06, 0x03, 0x01, 0x02, 0x40, 0x00,
- 0x00, 0x0e, 0x00, 0x00, 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x02, 0xbe, 0x0b, 0x00, 0x02,
- 0xba, 0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30,
- 0x82, 0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0,
- 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85,
- 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30,
- 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45,
- 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
- 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30,
- 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a,
- 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61,
- 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
- 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74,
- 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69,
- 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74,
- 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17,
- 0x0d, 0x31, 0x30, 0x30, 0x34, 0x32, 0x34, 0x30,
- 0x39, 0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d,
- 0x31, 0x31, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39,
- 0x30, 0x39, 0x33, 0x38, 0x5a, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30,
- 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81,
- 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81,
- 0x00, 0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5, 0xe5,
- 0xbf, 0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe, 0xe6,
- 0x2b, 0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d, 0x8a,
- 0x7a, 0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7, 0xa5,
- 0x65, 0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c, 0xb5,
- 0xb4, 0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b, 0x7e,
- 0x62, 0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe, 0x12,
- 0x5c, 0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf, 0xfa,
- 0x58, 0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04, 0xd3,
- 0xd0, 0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4, 0x54,
- 0x9f, 0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00, 0xfe,
- 0x18, 0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d, 0x7d,
- 0xf1, 0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb, 0x51,
- 0xc9, 0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32, 0x66,
- 0x01, 0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71, 0x9a,
- 0x1d, 0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda, 0x2d,
- 0x79, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81,
- 0xa7, 0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06, 0x03,
- 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1,
- 0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb,
- 0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e,
- 0x18, 0x88, 0x39, 0x30, 0x75, 0x06, 0x03, 0x55,
- 0x1d, 0x23, 0x04, 0x6e, 0x30, 0x6c, 0x80, 0x14,
- 0xb1, 0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28,
- 0xdb, 0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26,
- 0x8e, 0x18, 0x88, 0x39, 0xa1, 0x49, 0xa4, 0x47,
- 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
- 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31,
- 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08,
- 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53,
- 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f,
- 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49,
- 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20,
- 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20,
- 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x82,
- 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f,
- 0xb8, 0xca, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d,
- 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff,
- 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
- 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03,
- 0x81, 0x81, 0x00, 0x08, 0x6c, 0x45, 0x24, 0xc7,
- 0x6b, 0xb1, 0x59, 0xab, 0x0c, 0x52, 0xcc, 0xf2,
- 0xb0, 0x14, 0xd7, 0x87, 0x9d, 0x7a, 0x64, 0x75,
- 0xb5, 0x5a, 0x95, 0x66, 0xe4, 0xc5, 0x2b, 0x8e,
- 0xae, 0x12, 0x66, 0x1f, 0xeb, 0x4f, 0x38, 0xb3,
- 0x6e, 0x60, 0xd3, 0x92, 0xfd, 0xf7, 0x41, 0x08,
- 0xb5, 0x25, 0x13, 0xb1, 0x18, 0x7a, 0x24, 0xfb,
- 0x30, 0x1d, 0xba, 0xed, 0x98, 0xb9, 0x17, 0xec,
- 0xe7, 0xd7, 0x31, 0x59, 0xdb, 0x95, 0xd3, 0x1d,
- 0x78, 0xea, 0x50, 0x56, 0x5c, 0xd5, 0x82, 0x5a,
- 0x2d, 0x5a, 0x5f, 0x33, 0xc4, 0xb6, 0xd8, 0xc9,
- 0x75, 0x90, 0x96, 0x8c, 0x0f, 0x52, 0x98, 0xb5,
- 0xcd, 0x98, 0x1f, 0x89, 0x20, 0x5f, 0xf2, 0xa0,
- 0x1c, 0xa3, 0x1b, 0x96, 0x94, 0xdd, 0xa9, 0xfd,
- 0x57, 0xe9, 0x70, 0xe8, 0x26, 0x6d, 0x71, 0x99,
- 0x9b, 0x26, 0x6e, 0x38, 0x50, 0x29, 0x6c, 0x90,
- 0xa7, 0xbd, 0xd9, 0x16, 0x03, 0x01, 0x01, 0x06,
- 0x10, 0x00, 0x01, 0x02, 0x01, 0x00, 0x25, 0x48,
- 0x6c, 0x0a, 0xde, 0x9d, 0x3a, 0x57, 0xe4, 0x2e,
- 0xb9, 0xfc, 0xb4, 0x46, 0x1f, 0x20, 0x4f, 0x58,
- 0x4d, 0x12, 0x08, 0xb4, 0x3e, 0x4c, 0xf5, 0xa8,
- 0xa5, 0x16, 0x40, 0x29, 0x19, 0x04, 0x4d, 0xf9,
- 0x54, 0x3a, 0x32, 0xd7, 0x79, 0xf2, 0x0e, 0xc1,
- 0x7b, 0x0c, 0x62, 0x71, 0xbb, 0xb4, 0x8c, 0xe7,
- 0x84, 0xd5, 0xf8, 0x11, 0x77, 0x7f, 0x87, 0x6c,
- 0xfc, 0x25, 0xf3, 0x2d, 0x97, 0x3d, 0x1f, 0xf5,
- 0xfc, 0x64, 0x94, 0x9f, 0xdd, 0x90, 0x82, 0xdd,
- 0x11, 0x74, 0x74, 0x59, 0xa2, 0x1a, 0x71, 0xb2,
- 0x55, 0x6d, 0x18, 0xca, 0x85, 0x47, 0x8b, 0x79,
- 0x73, 0x06, 0x24, 0x38, 0xc3, 0x34, 0x98, 0x84,
- 0x62, 0x81, 0xd8, 0xad, 0x54, 0xad, 0x13, 0xa5,
- 0xf4, 0xe4, 0x82, 0x85, 0xd3, 0xe3, 0x9e, 0xeb,
- 0xb5, 0xf5, 0x95, 0x83, 0x0e, 0xb9, 0x7d, 0xb6,
- 0xda, 0x0c, 0xf6, 0x14, 0x6a, 0x60, 0x8c, 0x75,
- 0x56, 0xf0, 0xe9, 0x60, 0xe0, 0x4c, 0xf4, 0x4e,
- 0x84, 0x8b, 0x4f, 0xf4, 0x2f, 0xde, 0xb7, 0xec,
- 0x61, 0xd3, 0x77, 0x07, 0x6e, 0x41, 0x57, 0xc9,
- 0xd9, 0x1d, 0x75, 0xee, 0x42, 0x63, 0xdc, 0x58,
- 0xad, 0xfc, 0xc7, 0xe1, 0x77, 0x49, 0xb1, 0x58,
- 0x21, 0x96, 0x00, 0x55, 0x90, 0x6b, 0xf6, 0x2a,
- 0x5a, 0x19, 0x25, 0x93, 0x59, 0x9d, 0xaf, 0x79,
- 0x9b, 0x18, 0x5d, 0xf6, 0x5d, 0x64, 0x4b, 0x9a,
- 0xf4, 0xde, 0xf2, 0x7f, 0xbd, 0x93, 0x7e, 0x45,
- 0x3e, 0x17, 0xae, 0xbf, 0x52, 0xe1, 0xba, 0x8e,
- 0x0b, 0xbc, 0x1e, 0x91, 0x9d, 0xf1, 0x4e, 0x0b,
- 0xab, 0x9e, 0x5c, 0x4c, 0x6f, 0xf7, 0xf3, 0x8d,
- 0x8c, 0x6d, 0xeb, 0x46, 0x05, 0x36, 0x7e, 0x2f,
- 0x9c, 0xa1, 0x86, 0x15, 0xe1, 0xe4, 0xb4, 0x20,
- 0x06, 0x44, 0x7b, 0x3c, 0x8b, 0x13, 0x96, 0xf5,
- 0x02, 0xb1, 0x4f, 0x3c, 0x2d, 0x4a, 0x16, 0x03,
- 0x01, 0x00, 0x86, 0x0f, 0x00, 0x00, 0x82, 0x00,
- 0x80, 0x52, 0xb1, 0x0d, 0xfc, 0x85, 0x34, 0x56,
- 0xb9, 0xdf, 0xa7, 0x8e, 0xf4, 0xfd, 0x02, 0x46,
- 0x8a, 0x23, 0xcc, 0x53, 0x3b, 0x0f, 0xa7, 0x61,
- 0xf3, 0xb5, 0xbf, 0xfe, 0x59, 0x77, 0x10, 0xd6,
- 0x56, 0x93, 0x19, 0x6b, 0x2c, 0xf1, 0x35, 0x71,
- 0xe3, 0x36, 0x2f, 0xa0, 0x90, 0x4e, 0x5a, 0xdf,
- 0x8d, 0x06, 0x88, 0xcf, 0xb1, 0x06, 0x56, 0x8b,
- 0x74, 0x8f, 0x02, 0x8e, 0x10, 0xd2, 0xab, 0x8d,
- 0x3f, 0x3e, 0x02, 0xf1, 0x1a, 0x80, 0x6d, 0x0f,
- 0x9e, 0x77, 0xd8, 0xfa, 0x92, 0xb3, 0x16, 0x40,
- 0xeb, 0x9e, 0xca, 0xd7, 0xe4, 0x31, 0xcc, 0x63,
- 0x5f, 0xe2, 0x4c, 0x85, 0x0e, 0xf2, 0xdd, 0xd3,
- 0xfe, 0x7e, 0xa7, 0x60, 0x1c, 0xb4, 0x00, 0xd8,
- 0xbe, 0x4b, 0x9b, 0x66, 0x78, 0x0f, 0xfb, 0x3b,
- 0x52, 0x30, 0x2b, 0x8b, 0xd9, 0xef, 0x82, 0x0a,
- 0xa4, 0x18, 0x1d, 0xb0, 0xb5, 0xbf, 0x54, 0x97,
- 0x0c, 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16,
- 0x03, 0x01, 0x00, 0x30, 0xa1, 0x74, 0x22, 0xd8,
- 0x86, 0x6a, 0xbe, 0x53, 0x34, 0x1d, 0xb3, 0x73,
- 0xff, 0x51, 0xc0, 0xce, 0x8e, 0x7d, 0x9b, 0xab,
- 0xcb, 0x8b, 0x79, 0xae, 0x04, 0x01, 0xa7, 0xf2,
- 0x8e, 0x9d, 0xab, 0xa3, 0x73, 0x80, 0x5c, 0xff,
- 0x96, 0x20, 0xbb, 0x8d, 0xc0, 0x02, 0x66, 0x6c,
- 0x83, 0x4b, 0x78, 0x20,
- },
- {
- 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
- 0x01, 0x00, 0x30, 0x29, 0xd4, 0xfd, 0x03, 0x8b,
- 0x30, 0x20, 0xf7, 0xca, 0xc0, 0x6c, 0x83, 0x5d,
- 0x73, 0xcb, 0x81, 0x60, 0xe0, 0x9a, 0x09, 0xcb,
- 0x33, 0x03, 0x80, 0x81, 0x4e, 0x84, 0x47, 0xd5,
- 0x74, 0x6c, 0x3b, 0xb5, 0xc0, 0x48, 0x0d, 0x52,
- 0xdd, 0xbe, 0xc2, 0x06, 0xf5, 0x79, 0x2b, 0x3e,
- 0x99, 0x56, 0x94, 0x17, 0x03, 0x01, 0x00, 0x20,
- 0x26, 0x46, 0x90, 0x9d, 0xef, 0x59, 0x00, 0xb6,
- 0x70, 0xe8, 0x1e, 0x1a, 0x80, 0x8b, 0x04, 0xb2,
- 0xfc, 0x51, 0xf8, 0x93, 0xbe, 0x00, 0x28, 0xba,
- 0xb8, 0xdc, 0x51, 0x7e, 0x92, 0x80, 0xfa, 0xf2,
- 0x17, 0x03, 0x01, 0x00, 0xe0, 0xb8, 0x2e, 0xc4,
- 0x6b, 0x3f, 0xda, 0x39, 0x87, 0x7f, 0x03, 0x43,
- 0x28, 0xdd, 0xb9, 0xf9, 0x9e, 0x16, 0xf5, 0xce,
- 0x3f, 0x7e, 0x6a, 0x7b, 0xb3, 0x60, 0x14, 0xe1,
- 0xea, 0x54, 0xc5, 0xe6, 0x05, 0x0a, 0x6c, 0xe0,
- 0xef, 0x58, 0x29, 0x8a, 0x77, 0x64, 0x77, 0x5d,
- 0x9c, 0xe2, 0xe0, 0x3c, 0x6d, 0x87, 0x82, 0xbe,
- 0x47, 0x63, 0xd4, 0xfd, 0x0c, 0x25, 0xc4, 0xb1,
- 0xfe, 0x29, 0x6f, 0x84, 0xfb, 0xab, 0x6e, 0xa7,
- 0xf9, 0x22, 0x89, 0x97, 0x5b, 0x91, 0x0a, 0x07,
- 0xe0, 0xef, 0x3d, 0x67, 0xee, 0x87, 0xa8, 0x33,
- 0x02, 0x64, 0x33, 0xca, 0x15, 0x10, 0xb9, 0x57,
- 0xd8, 0xe5, 0x1a, 0x4b, 0xe3, 0x45, 0xc1, 0x62,
- 0x85, 0x50, 0xf1, 0x79, 0x54, 0xe1, 0x2e, 0x25,
- 0x01, 0x3c, 0xdb, 0x2d, 0x39, 0x14, 0x2f, 0x9b,
- 0xd0, 0x1d, 0xc1, 0xac, 0x73, 0x7d, 0xa4, 0xed,
- 0x89, 0x98, 0xb1, 0xae, 0x8a, 0x9e, 0xc8, 0xa7,
- 0xfe, 0x55, 0x27, 0xb5, 0xb5, 0xa2, 0xec, 0x7e,
- 0xe3, 0x6b, 0x45, 0x19, 0xfa, 0x20, 0x1c, 0x33,
- 0x83, 0x22, 0x33, 0x97, 0xd2, 0x5a, 0xc4, 0xf8,
- 0x9a, 0x03, 0x13, 0x85, 0xf2, 0x2b, 0x04, 0x59,
- 0x27, 0xd7, 0x0b, 0x42, 0x47, 0x9b, 0x7d, 0x4d,
- 0xb2, 0x1a, 0x85, 0x7f, 0x97, 0xc2, 0xf2, 0x10,
- 0xf0, 0xfa, 0x4e, 0x4b, 0x62, 0x43, 0x3a, 0x09,
- 0x2e, 0xcd, 0x8f, 0xa8, 0xb6, 0x0b, 0x5f, 0x34,
- 0xd7, 0x3b, 0xba, 0xd9, 0xe5, 0x01, 0x2d, 0x35,
- 0xae, 0xc5, 0x4c, 0xab, 0x40, 0x64, 0xc2, 0xc9,
- 0x8c, 0x69, 0x44, 0xf4, 0xb8, 0xb5, 0x3a, 0x05,
- 0x3c, 0x29, 0x19, 0xb4, 0x09, 0x17, 0x03, 0x01,
- 0x00, 0x20, 0xc8, 0xc5, 0xb7, 0xe3, 0xd2, 0x3e,
- 0x27, 0xb5, 0x71, 0x8f, 0x52, 0x0b, 0xce, 0x17,
- 0x64, 0x86, 0xa4, 0x34, 0x16, 0x1b, 0x61, 0x64,
- 0x7c, 0xb3, 0xf2, 0xe5, 0x3e, 0xfd, 0xdd, 0xfb,
- 0x40, 0x78, 0x17, 0x03, 0x01, 0x00, 0x50, 0x8e,
- 0x79, 0xf0, 0x8e, 0x76, 0x5d, 0x34, 0x09, 0xdc,
- 0xec, 0x6d, 0xc3, 0x43, 0x1d, 0xcb, 0x2d, 0xaa,
- 0x08, 0x7a, 0x51, 0x94, 0x4e, 0xc5, 0x26, 0xe4,
- 0x0b, 0x8e, 0x8f, 0x51, 0xf2, 0x9f, 0xeb, 0xc3,
- 0x18, 0x43, 0x95, 0x15, 0xfc, 0x59, 0x18, 0x25,
- 0x47, 0xb6, 0x4a, 0x6e, 0xa3, 0xa4, 0x3b, 0xa3,
- 0x47, 0x34, 0x74, 0x6b, 0xc5, 0x3d, 0x41, 0x14,
- 0x64, 0xd5, 0x69, 0x5f, 0x77, 0xf3, 0x7c, 0x41,
- 0xc6, 0xed, 0x2e, 0xcf, 0xff, 0x40, 0xf2, 0xce,
- 0xbb, 0xa7, 0x4e, 0x73, 0x88, 0x98, 0x10,
- },
- {
- 0x15, 0x03, 0x01, 0x00, 0x20, 0x1a, 0xbc, 0x70,
- 0x24, 0xf8, 0xfb, 0xf2, 0x4a, 0xf9, 0x44, 0x1e,
- 0x58, 0xf8, 0xaa, 0x41, 0x24, 0xe8, 0x80, 0x33,
- 0x45, 0x18, 0xa1, 0x5d, 0xee, 0x16, 0x80, 0xae,
- 0x40, 0x41, 0x8e, 0x41, 0x9b,
- },
-}
+ // Add 4 entries to the cache and look them up.
+ for i := 0; i < 4; i++ {
+ cache.Put(keys[i], &cs[i])
+ }
+ for i := 0; i < 4; i++ {
+ if s, ok := cache.Get(keys[i]); !ok || s != &cs[i] {
+ t.Fatalf("session cache failed lookup for added key: %s", keys[i])
+ }
+ }
-var tls11ECDHEAESClientScript = [][]byte{
- {
- 0x16, 0x03, 0x01, 0x00, 0x4a, 0x01, 0x00, 0x00,
- 0x46, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xc0, 0x13,
- 0x01, 0x00, 0x00, 0x1b, 0x00, 0x05, 0x00, 0x05,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
- 0x08, 0x00, 0x06, 0x00, 0x17, 0x00, 0x18, 0x00,
- 0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00,
- },
- {
- 0x16, 0x03, 0x02, 0x00, 0x54, 0x02, 0x00, 0x00,
- 0x50, 0x03, 0x02, 0x51, 0x9f, 0xa2, 0x21, 0x1a,
- 0xb7, 0x75, 0x42, 0x69, 0xd3, 0x14, 0xdd, 0x05,
- 0x1e, 0xda, 0x13, 0x71, 0x8d, 0x6a, 0x45, 0x97,
- 0xcb, 0xee, 0x0e, 0x77, 0x01, 0x0d, 0x6e, 0xe5,
- 0x22, 0x70, 0x16, 0x20, 0x69, 0xfc, 0xa6, 0x9a,
- 0xe8, 0x21, 0xcc, 0x46, 0x65, 0x05, 0xb4, 0x48,
- 0x0f, 0x34, 0x63, 0x2c, 0xac, 0xa4, 0xf5, 0x4b,
- 0x64, 0xd1, 0x07, 0x13, 0xa7, 0xe4, 0x5b, 0xa3,
- 0x4d, 0x31, 0x41, 0x53, 0xc0, 0x13, 0x00, 0x00,
- 0x08, 0x00, 0x0b, 0x00, 0x04, 0x03, 0x00, 0x01,
- 0x02, 0x16, 0x03, 0x02, 0x02, 0x39, 0x0b, 0x00,
- 0x02, 0x35, 0x00, 0x02, 0x32, 0x00, 0x02, 0x2f,
- 0x30, 0x82, 0x02, 0x2b, 0x30, 0x82, 0x01, 0xd5,
- 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00,
- 0xb1, 0x35, 0x13, 0x65, 0x11, 0x20, 0xc5, 0x92,
- 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
- 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30,
- 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
- 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
- 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
- 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
- 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
- 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e,
- 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
- 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
- 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e,
- 0x17, 0x0d, 0x31, 0x32, 0x30, 0x34, 0x30, 0x36,
- 0x31, 0x37, 0x31, 0x30, 0x31, 0x33, 0x5a, 0x17,
- 0x0d, 0x31, 0x35, 0x30, 0x34, 0x30, 0x36, 0x31,
- 0x37, 0x31, 0x30, 0x31, 0x33, 0x5a, 0x30, 0x45,
- 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
- 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30,
- 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a,
- 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61,
- 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
- 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74,
- 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69,
- 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74,
- 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x5c, 0x30,
- 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b,
- 0x00, 0x30, 0x48, 0x02, 0x41, 0x00, 0x9f, 0xb3,
- 0xc3, 0x84, 0x27, 0x95, 0xff, 0x12, 0x31, 0x52,
- 0x0f, 0x15, 0xef, 0x46, 0x11, 0xc4, 0xad, 0x80,
- 0xe6, 0x36, 0x5b, 0x0f, 0xdd, 0x80, 0xd7, 0x61,
- 0x8d, 0xe0, 0xfc, 0x72, 0x45, 0x09, 0x34, 0xfe,
- 0x55, 0x66, 0x45, 0x43, 0x4c, 0x68, 0x97, 0x6a,
- 0xfe, 0xa8, 0xa0, 0xa5, 0xdf, 0x5f, 0x78, 0xff,
- 0xee, 0xd7, 0x64, 0xb8, 0x3f, 0x04, 0xcb, 0x6f,
- 0xff, 0x2a, 0xfe, 0xfe, 0xb9, 0xed, 0x02, 0x03,
- 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
- 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
- 0x04, 0x16, 0x04, 0x14, 0x78, 0xa6, 0x97, 0x9a,
- 0x63, 0xb5, 0xc5, 0xa1, 0xa5, 0x33, 0xba, 0x22,
- 0x7c, 0x23, 0x6e, 0x5b, 0x1b, 0x7a, 0xcc, 0x2b,
- 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
- 0x6e, 0x30, 0x6c, 0x80, 0x14, 0x78, 0xa6, 0x97,
- 0x9a, 0x63, 0xb5, 0xc5, 0xa1, 0xa5, 0x33, 0xba,
- 0x22, 0x7c, 0x23, 0x6e, 0x5b, 0x1b, 0x7a, 0xcc,
- 0x2b, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0xb1,
- 0x35, 0x13, 0x65, 0x11, 0x20, 0xc5, 0x92, 0x30,
- 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
- 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x01, 0x05, 0x05, 0x00, 0x03, 0x41, 0x00, 0x85,
- 0x36, 0x40, 0x73, 0xc1, 0xbb, 0x1a, 0xda, 0xd4,
- 0x59, 0x9f, 0x2d, 0xa2, 0x70, 0x31, 0x46, 0x74,
- 0xec, 0x83, 0x6e, 0xa8, 0xc8, 0x3c, 0x51, 0xaf,
- 0x39, 0xac, 0xec, 0x40, 0xbc, 0xe8, 0x22, 0x46,
- 0x1d, 0x99, 0xd6, 0x46, 0x2a, 0x24, 0xd4, 0x8b,
- 0x05, 0x08, 0x4b, 0xfb, 0x35, 0x11, 0x6e, 0x92,
- 0xbb, 0x77, 0xba, 0xe4, 0x12, 0xbb, 0xf4, 0xc8,
- 0x5e, 0x9c, 0x81, 0xa8, 0x97, 0x60, 0x4c, 0x16,
- 0x03, 0x02, 0x00, 0x8b, 0x0c, 0x00, 0x00, 0x87,
- 0x03, 0x00, 0x17, 0x41, 0x04, 0x34, 0xde, 0x50,
- 0x32, 0x8f, 0x25, 0x6b, 0x37, 0x2c, 0x36, 0x24,
- 0x27, 0x0e, 0xf9, 0x67, 0xb4, 0xf8, 0x29, 0x1c,
- 0xa5, 0xa4, 0x59, 0x9a, 0xca, 0x40, 0x26, 0x15,
- 0x61, 0x72, 0x34, 0x4a, 0xd3, 0x0c, 0xac, 0x69,
- 0xcb, 0x2a, 0x9e, 0xf8, 0x80, 0xfb, 0x7a, 0xc4,
- 0xd4, 0x4b, 0x91, 0x1b, 0xbe, 0x24, 0x26, 0xad,
- 0x19, 0x24, 0xbe, 0x32, 0x58, 0xfb, 0xc7, 0x77,
- 0xce, 0x7e, 0x71, 0x51, 0x1a, 0x00, 0x40, 0x1a,
- 0x0b, 0xe8, 0x91, 0x84, 0x64, 0x54, 0xb6, 0x19,
- 0xe8, 0xd4, 0x43, 0x7c, 0x09, 0x0c, 0x2e, 0xba,
- 0x42, 0xb9, 0x74, 0xc3, 0x6c, 0x06, 0x9b, 0xa6,
- 0x7e, 0x92, 0xe9, 0xee, 0x7c, 0x74, 0xa9, 0xd3,
- 0x63, 0xf0, 0x16, 0x20, 0x60, 0x71, 0x8e, 0x24,
- 0xc7, 0x7f, 0xc5, 0x5b, 0x9c, 0x19, 0x0c, 0x80,
- 0x15, 0x61, 0xbf, 0xb6, 0xed, 0x5b, 0x7b, 0x90,
- 0xc5, 0x05, 0x13, 0x72, 0x45, 0x79, 0xdf, 0x16,
- 0x03, 0x02, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00,
- },
- {
- 0x16, 0x03, 0x02, 0x00, 0x46, 0x10, 0x00, 0x00,
- 0x42, 0x41, 0x04, 0x1e, 0x18, 0x37, 0xef, 0x0d,
- 0x19, 0x51, 0x88, 0x35, 0x75, 0x71, 0xb5, 0xe5,
- 0x54, 0x5b, 0x12, 0x2e, 0x8f, 0x09, 0x67, 0xfd,
- 0xa7, 0x24, 0x20, 0x3e, 0xb2, 0x56, 0x1c, 0xce,
- 0x97, 0x28, 0x5e, 0xf8, 0x2b, 0x2d, 0x4f, 0x9e,
- 0xf1, 0x07, 0x9f, 0x6c, 0x4b, 0x5b, 0x83, 0x56,
- 0xe2, 0x32, 0x42, 0xe9, 0x58, 0xb6, 0xd7, 0x49,
- 0xa6, 0xb5, 0x68, 0x1a, 0x41, 0x03, 0x56, 0x6b,
- 0xdc, 0x5a, 0x89, 0x14, 0x03, 0x02, 0x00, 0x01,
- 0x01, 0x16, 0x03, 0x02, 0x00, 0x40, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x50,
- 0x32, 0x26, 0x51, 0xbd, 0xbd, 0x3c, 0x4f, 0x72,
- 0xbf, 0xbc, 0x91, 0x70, 0x4b, 0x5d, 0x43, 0x4a,
- 0x65, 0x26, 0x0d, 0xaa, 0xed, 0x00, 0x91, 0xaf,
- 0x4f, 0x47, 0x09, 0xaa, 0x79, 0xc4, 0x47, 0x21,
- 0x71, 0xd8, 0x2b, 0xc1, 0x51, 0xc8, 0xef, 0xed,
- 0x67, 0xde, 0x97, 0xef, 0x18, 0x53,
- },
- {
- 0x14, 0x03, 0x02, 0x00, 0x01, 0x01, 0x16, 0x03,
- 0x02, 0x00, 0x40, 0x72, 0x20, 0xbf, 0xd1, 0xbd,
- 0x83, 0x53, 0x57, 0xb0, 0x4e, 0xac, 0xba, 0x1a,
- 0x2b, 0x2d, 0xeb, 0x8a, 0x48, 0x17, 0xfa, 0x69,
- 0xf9, 0xb5, 0x94, 0x8e, 0x6f, 0x9c, 0xda, 0x59,
- 0xba, 0x6c, 0x7c, 0x82, 0xe2, 0x53, 0xa9, 0x46,
- 0xdc, 0x33, 0xa0, 0x9b, 0xf0, 0x1e, 0xf1, 0x53,
- 0x83, 0x48, 0xbf, 0x5e, 0xef, 0x03, 0x2b, 0x50,
- 0x7a, 0xa6, 0xf8, 0xc3, 0x9e, 0x24, 0x43, 0x3a,
- 0xdf, 0x44, 0x3e,
- },
- {
- 0x17, 0x03, 0x02, 0x00, 0x30, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x0b, 0x8f,
- 0x6b, 0xf9, 0xd3, 0x9f, 0x2b, 0x49, 0xe0, 0x62,
- 0x9a, 0x0b, 0x3e, 0xa2, 0x72, 0x8b, 0x96, 0x0c,
- 0x41, 0x09, 0x95, 0x9e, 0x6b, 0x26, 0xa1, 0x46,
- 0xca, 0xb8, 0xb6, 0xd2, 0xd4, 0x15, 0x03, 0x02,
- 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xa0, 0xd4, 0x84, 0xc6, 0x7e, 0x1c,
- 0x2f, 0xbd, 0x6b, 0x45, 0x31, 0x1d, 0x7d, 0x8f,
- 0x31, 0x39, 0x5a, 0x4e, 0xaa, 0xf1, 0x0a, 0x8a,
- 0x6c, 0x33, 0x59, 0x19, 0xd8, 0x75, 0x80, 0xab,
- 0x93, 0x81,
- },
-}
+ // Add 2 more entries to the cache. First 2 should be evicted.
+ for i := 4; i < 6; i++ {
+ cache.Put(keys[i], &cs[i])
+ }
+ for i := 0; i < 2; i++ {
+ if s, ok := cache.Get(keys[i]); ok || s != nil {
+ t.Fatalf("session cache should have evicted key: %s", keys[i])
+ }
+ }
-var clientChainCertificateScript = [][]byte{
- {
- 0x16, 0x03, 0x01, 0x00, 0x4a, 0x01, 0x00, 0x00,
- 0x46, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05,
- 0x01, 0x00, 0x00, 0x1b, 0x00, 0x05, 0x00, 0x05,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
- 0x08, 0x00, 0x06, 0x00, 0x17, 0x00, 0x18, 0x00,
- 0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x4a, 0x02, 0x00, 0x00,
- 0x46, 0x03, 0x01, 0x51, 0xa2, 0x9b, 0x8b, 0xd4,
- 0xe6, 0x33, 0xa2, 0x70, 0x38, 0x37, 0xba, 0x55,
- 0x86, 0xcf, 0x87, 0xea, 0x6d, 0x2c, 0x3e, 0x17,
- 0xc2, 0x09, 0xf8, 0x4d, 0xb0, 0x5d, 0x93, 0x2b,
- 0x15, 0x99, 0x0c, 0x20, 0x5d, 0x61, 0x21, 0x2c,
- 0xed, 0x49, 0x32, 0x29, 0x08, 0x6e, 0x21, 0x58,
- 0x00, 0xdb, 0x34, 0xb7, 0x37, 0xcd, 0x27, 0x75,
- 0x31, 0x1e, 0x6c, 0x74, 0xa6, 0xef, 0xa2, 0xc4,
- 0x2b, 0x6c, 0xc3, 0x03, 0x00, 0x05, 0x00, 0x16,
- 0x03, 0x01, 0x03, 0xef, 0x0b, 0x00, 0x03, 0xeb,
- 0x00, 0x03, 0xe8, 0x00, 0x03, 0xe5, 0x30, 0x82,
- 0x03, 0xe1, 0x30, 0x82, 0x02, 0xc9, 0xa0, 0x03,
- 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0xcc, 0x22,
- 0x4c, 0x4b, 0x98, 0xa2, 0x88, 0xfc, 0x30, 0x0d,
- 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0x86,
- 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
- 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30,
- 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x02,
- 0x4e, 0x59, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
- 0x55, 0x04, 0x07, 0x0c, 0x08, 0x42, 0x72, 0x6f,
- 0x6f, 0x6b, 0x6c, 0x79, 0x6e, 0x31, 0x21, 0x30,
- 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18,
- 0x4d, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69,
- 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41,
- 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
- 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
- 0x03, 0x0c, 0x08, 0x6d, 0x79, 0x63, 0x61, 0x2e,
- 0x6f, 0x72, 0x67, 0x31, 0x21, 0x30, 0x1f, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x09, 0x01, 0x16, 0x12, 0x6a, 0x76, 0x73, 0x68,
- 0x61, 0x68, 0x69, 0x64, 0x40, 0x67, 0x6d, 0x61,
- 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e,
- 0x17, 0x0d, 0x31, 0x33, 0x30, 0x35, 0x32, 0x36,
- 0x32, 0x31, 0x30, 0x35, 0x30, 0x31, 0x5a, 0x17,
- 0x0d, 0x32, 0x33, 0x30, 0x35, 0x32, 0x34, 0x32,
- 0x31, 0x30, 0x35, 0x30, 0x31, 0x5a, 0x30, 0x81,
- 0x86, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
- 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0b,
- 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c,
- 0x02, 0x4e, 0x59, 0x31, 0x11, 0x30, 0x0f, 0x06,
- 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x42, 0x72,
- 0x6f, 0x6f, 0x6b, 0x6c, 0x79, 0x6e, 0x31, 0x21,
- 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c,
- 0x18, 0x4d, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74,
- 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20,
- 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
- 0x79, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55,
- 0x04, 0x03, 0x0c, 0x08, 0x6d, 0x79, 0x63, 0x61,
- 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x21, 0x30, 0x1f,
- 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x09, 0x01, 0x16, 0x12, 0x6a, 0x76, 0x73,
- 0x68, 0x61, 0x68, 0x69, 0x64, 0x40, 0x67, 0x6d,
- 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x30,
- 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
- 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30,
- 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00,
- 0xf0, 0xfb, 0xad, 0x80, 0x5e, 0x37, 0xd3, 0x6d,
- 0xee, 0x2e, 0xcc, 0xbc, 0x0c, 0xd7, 0x56, 0x4b,
- 0x56, 0x45, 0xcd, 0x28, 0xb6, 0x22, 0xe9, 0xe2,
- 0x0f, 0xd1, 0x87, 0x2a, 0x27, 0xce, 0x77, 0x8d,
- 0x6e, 0x0e, 0x0f, 0xfb, 0x66, 0xe1, 0xb5, 0x0e,
- 0x9a, 0xb6, 0x05, 0x8e, 0xb3, 0xe1, 0xc5, 0x77,
- 0x86, 0x5b, 0x46, 0xd2, 0x0b, 0x92, 0x03, 0x1b,
- 0x89, 0x0c, 0x1b, 0x10, 0x0e, 0x99, 0x8f, 0xe2,
- 0x17, 0xe8, 0xc2, 0x30, 0x00, 0x47, 0xd6, 0xfc,
- 0xf9, 0x0f, 0x3b, 0x75, 0x34, 0x8d, 0x4d, 0xb0,
- 0x99, 0xb7, 0xa0, 0x6d, 0xa0, 0xb6, 0xad, 0xda,
- 0x07, 0x5e, 0x38, 0x2e, 0x02, 0xe4, 0x30, 0x6d,
- 0xae, 0x13, 0x72, 0xd4, 0xc8, 0xce, 0x14, 0x07,
- 0xae, 0x23, 0x8c, 0x8f, 0x9e, 0x8c, 0x60, 0xd6,
- 0x06, 0xb9, 0xef, 0x00, 0x18, 0xc0, 0x1d, 0x25,
- 0x1e, 0xda, 0x3e, 0x2f, 0xcf, 0x2b, 0x56, 0x84,
- 0x9e, 0x30, 0x21, 0xc7, 0x29, 0xf6, 0x03, 0x8a,
- 0x24, 0xf9, 0x34, 0xac, 0x65, 0x9d, 0x80, 0x36,
- 0xc8, 0x3b, 0x15, 0x10, 0xbd, 0x51, 0xe9, 0xbc,
- 0x02, 0xe1, 0xe9, 0xb3, 0x5a, 0x9a, 0x99, 0x41,
- 0x1b, 0x27, 0xa0, 0x4d, 0x50, 0x9e, 0x27, 0x7f,
- 0xa1, 0x7d, 0x09, 0x87, 0xbd, 0x8a, 0xca, 0x5f,
- 0xb1, 0xa5, 0x08, 0xb8, 0x04, 0xd4, 0x52, 0x89,
- 0xaa, 0xe0, 0x7d, 0x42, 0x2e, 0x2f, 0x15, 0xee,
- 0x66, 0x57, 0x0f, 0x13, 0x19, 0x45, 0xa8, 0x4b,
- 0x5d, 0x81, 0x66, 0xcc, 0x12, 0x37, 0x94, 0x5e,
- 0xfd, 0x3c, 0x10, 0x81, 0x51, 0x3f, 0xfa, 0x0f,
- 0xdd, 0xa1, 0x89, 0x03, 0xa9, 0x78, 0x91, 0xf5,
- 0x3b, 0xf3, 0xbc, 0xac, 0xbe, 0x93, 0x30, 0x2e,
- 0xbe, 0xca, 0x7f, 0x46, 0xd3, 0x28, 0xb4, 0x4e,
- 0x91, 0x7b, 0x5b, 0x43, 0x6c, 0xaf, 0x9b, 0x5c,
- 0x6a, 0x6d, 0x5a, 0xdb, 0x79, 0x5e, 0x6a, 0x6b,
- 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x50, 0x30,
- 0x4e, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
- 0x04, 0x16, 0x04, 0x14, 0x6b, 0x1e, 0x00, 0xa8,
- 0x9f, 0xfa, 0x7d, 0x00, 0xf9, 0xe0, 0x9d, 0x0f,
- 0x90, 0x8c, 0x90, 0xa8, 0xa1, 0x37, 0x6b, 0xda,
- 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
- 0x18, 0x30, 0x16, 0x80, 0x14, 0x6b, 0x1e, 0x00,
- 0xa8, 0x9f, 0xfa, 0x7d, 0x00, 0xf9, 0xe0, 0x9d,
- 0x0f, 0x90, 0x8c, 0x90, 0xa8, 0xa1, 0x37, 0x6b,
- 0xda, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13,
- 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
- 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82,
- 0x01, 0x01, 0x00, 0xcd, 0x6f, 0x73, 0x4d, 0x56,
- 0x0b, 0xf3, 0x2e, 0x1c, 0xe2, 0x02, 0x0c, 0x14,
- 0xbb, 0x2f, 0xdd, 0x3c, 0x43, 0xfe, 0xdf, 0x94,
- 0x2d, 0xa9, 0x89, 0x81, 0x51, 0xf8, 0x5f, 0xa7,
- 0xa0, 0x13, 0xaa, 0xcc, 0xb0, 0x18, 0xe2, 0x57,
- 0x3e, 0x0d, 0x29, 0x93, 0xe8, 0x95, 0xd5, 0x1b,
- 0x53, 0xd2, 0x51, 0xf2, 0xbd, 0xf5, 0x9e, 0x7b,
- 0x22, 0x65, 0x62, 0x5c, 0xc4, 0x4c, 0x1d, 0xe8,
- 0xe9, 0xc3, 0xd4, 0x2b, 0xe7, 0x78, 0xcb, 0x10,
- 0xf3, 0xfe, 0x06, 0x83, 0xdc, 0x3a, 0x1e, 0x62,
- 0x10, 0xc0, 0x46, 0x77, 0xc6, 0x9d, 0x9f, 0xab,
- 0x96, 0x25, 0x5c, 0xfb, 0x26, 0xc1, 0x15, 0x1f,
- 0xa5, 0x33, 0xee, 0x4f, 0x9a, 0x14, 0x6a, 0x14,
- 0x97, 0x93, 0x2b, 0x95, 0x0b, 0xdc, 0xa8, 0xd7,
- 0x69, 0x2e, 0xf0, 0x01, 0x0e, 0xfd, 0x4e, 0xd0,
- 0xd9, 0xa8, 0xe5, 0x65, 0xde, 0xfb, 0xca, 0xca,
- 0x1c, 0x5f, 0xf9, 0x53, 0xa0, 0x87, 0xe7, 0x33,
- 0x9b, 0x2f, 0xcf, 0xe4, 0x13, 0xfc, 0xec, 0x7a,
- 0x6c, 0xb0, 0x90, 0x13, 0x9b, 0xb6, 0xc5, 0x03,
- 0xf6, 0x0e, 0x5e, 0xe2, 0xe4, 0x26, 0xc1, 0x7e,
- 0x53, 0xfe, 0x69, 0xa3, 0xc7, 0xd8, 0x8e, 0x6e,
- 0x94, 0x32, 0xa0, 0xde, 0xca, 0xb6, 0xcc, 0xd6,
- 0x01, 0xd5, 0x78, 0x40, 0x28, 0x63, 0x9b, 0xee,
- 0xcf, 0x09, 0x3b, 0x35, 0x04, 0xf0, 0x14, 0x02,
- 0xf6, 0x80, 0x0e, 0x90, 0xb2, 0x94, 0xd2, 0x25,
- 0x16, 0xb8, 0x7a, 0x76, 0x87, 0x84, 0x9f, 0x84,
- 0xc5, 0xaf, 0xc2, 0x6d, 0x68, 0x7a, 0x84, 0x9c,
- 0xc6, 0x8a, 0x63, 0x60, 0x87, 0x6a, 0x25, 0xc1,
- 0xa1, 0x78, 0x0f, 0xba, 0xe8, 0x5f, 0xe1, 0xba,
- 0xac, 0xa4, 0x6f, 0xdd, 0x09, 0x3f, 0x12, 0xcb,
- 0x1d, 0xf3, 0xcf, 0x48, 0xd7, 0xd3, 0x26, 0xe8,
- 0x9c, 0xc3, 0x53, 0xb3, 0xba, 0xdc, 0x32, 0x99,
- 0x98, 0x96, 0xd6, 0x16, 0x03, 0x01, 0x00, 0x99,
- 0x0d, 0x00, 0x00, 0x91, 0x03, 0x01, 0x02, 0x40,
- 0x00, 0x8b, 0x00, 0x89, 0x30, 0x81, 0x86, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x02, 0x4e,
- 0x59, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55,
- 0x04, 0x07, 0x0c, 0x08, 0x42, 0x72, 0x6f, 0x6f,
- 0x6b, 0x6c, 0x79, 0x6e, 0x31, 0x21, 0x30, 0x1f,
- 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x4d,
- 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
- 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75,
- 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31,
- 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03,
- 0x0c, 0x08, 0x6d, 0x79, 0x63, 0x61, 0x2e, 0x6f,
- 0x72, 0x67, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09,
- 0x01, 0x16, 0x12, 0x6a, 0x76, 0x73, 0x68, 0x61,
- 0x68, 0x69, 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69,
- 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0e, 0x00, 0x00,
- 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x0a, 0xfb, 0x0b, 0x00, 0x0a,
- 0xf7, 0x00, 0x0a, 0xf4, 0x00, 0x03, 0x7e, 0x30,
- 0x82, 0x03, 0x7a, 0x30, 0x82, 0x02, 0x62, 0x02,
- 0x09, 0x00, 0xb4, 0x47, 0x58, 0x57, 0x2b, 0x67,
- 0xc8, 0xc2, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05,
- 0x00, 0x30, 0x81, 0x80, 0x31, 0x0b, 0x30, 0x09,
- 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
- 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
- 0x04, 0x08, 0x0c, 0x02, 0x4e, 0x59, 0x31, 0x11,
- 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c,
- 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b, 0x6c, 0x79,
- 0x6e, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x0c, 0x0c, 0x4d, 0x79, 0x20, 0x43,
- 0x41, 0x20, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74,
- 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
- 0x03, 0x0c, 0x0e, 0x6d, 0x79, 0x63, 0x61, 0x63,
- 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x6f,
- 0x6d, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01,
- 0x16, 0x12, 0x6a, 0x76, 0x73, 0x68, 0x61, 0x68,
- 0x69, 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c,
- 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d,
- 0x31, 0x33, 0x30, 0x35, 0x32, 0x36, 0x32, 0x31,
- 0x34, 0x34, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31,
- 0x33, 0x30, 0x36, 0x32, 0x35, 0x32, 0x31, 0x34,
- 0x34, 0x30, 0x30, 0x5a, 0x30, 0x7d, 0x31, 0x0b,
- 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
- 0x02, 0x55, 0x53, 0x31, 0x11, 0x30, 0x0f, 0x06,
- 0x03, 0x55, 0x04, 0x08, 0x0c, 0x08, 0x4e, 0x65,
- 0x77, 0x20, 0x59, 0x6f, 0x72, 0x6b, 0x31, 0x11,
- 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c,
- 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b, 0x6c, 0x79,
- 0x6e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x0c, 0x07, 0x4d, 0x79, 0x20, 0x4c,
- 0x65, 0x61, 0x66, 0x31, 0x13, 0x30, 0x11, 0x06,
- 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0a, 0x6d, 0x79,
- 0x6c, 0x65, 0x61, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
- 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16,
- 0x12, 0x6a, 0x76, 0x73, 0x68, 0x61, 0x68, 0x69,
- 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e,
- 0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22, 0x30,
- 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82,
- 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02,
- 0x82, 0x01, 0x01, 0x00, 0xa0, 0xa3, 0xef, 0xc1,
- 0x44, 0x7d, 0xa2, 0xe3, 0x71, 0x98, 0x27, 0x63,
- 0xb3, 0x1d, 0x71, 0x50, 0xa6, 0x34, 0x15, 0xcb,
- 0xc9, 0x2a, 0xc3, 0xea, 0xe4, 0x9e, 0x9c, 0x49,
- 0xa6, 0x01, 0x9b, 0x7e, 0xa9, 0xb5, 0x7a, 0xff,
- 0x15, 0x92, 0x71, 0xc8, 0x97, 0x9c, 0x25, 0xb7,
- 0x79, 0x2b, 0xff, 0xab, 0xc6, 0xb1, 0xa7, 0x00,
- 0x90, 0xb2, 0x8b, 0xd7, 0x71, 0xd5, 0xc2, 0x3a,
- 0xe6, 0x82, 0x42, 0x37, 0x89, 0x41, 0x04, 0xb0,
- 0xba, 0xc7, 0x5b, 0x8a, 0x43, 0x9f, 0x97, 0x39,
- 0x0c, 0x0f, 0xd5, 0x6d, 0x9e, 0x8d, 0xeb, 0xc0,
- 0x26, 0xc5, 0x18, 0xe8, 0x7a, 0x3d, 0x32, 0x2e,
- 0x38, 0x90, 0x40, 0x5b, 0x39, 0x2c, 0x07, 0xcb,
- 0x24, 0x10, 0xc5, 0xc9, 0x3b, 0xe3, 0x66, 0x47,
- 0x57, 0xb9, 0x6a, 0xad, 0x44, 0xf8, 0xd0, 0x70,
- 0x62, 0x3b, 0x8e, 0xed, 0x60, 0x5f, 0x22, 0xf8,
- 0xb8, 0x0c, 0xc9, 0x41, 0x2b, 0xc9, 0x80, 0x6e,
- 0x4e, 0x1b, 0xe1, 0x20, 0xfc, 0x47, 0xa4, 0xac,
- 0xc3, 0x3f, 0xe6, 0xc2, 0x81, 0x79, 0x03, 0x37,
- 0x25, 0x89, 0xca, 0xd6, 0xa5, 0x46, 0x91, 0x63,
- 0x41, 0xc5, 0x3e, 0xd5, 0xed, 0x7f, 0x4f, 0x8d,
- 0x06, 0xc0, 0x89, 0x00, 0xbe, 0x37, 0x7b, 0x7e,
- 0x73, 0xca, 0x70, 0x00, 0x14, 0x34, 0xbe, 0x47,
- 0xbc, 0xb2, 0x6a, 0x28, 0xa5, 0x29, 0x84, 0xa8,
- 0x9d, 0xc8, 0x1e, 0x77, 0x66, 0x1f, 0x9f, 0xaa,
- 0x2b, 0x47, 0xdb, 0xdd, 0x6b, 0x9c, 0xa8, 0xfc,
- 0x82, 0x36, 0x94, 0x62, 0x0d, 0x5c, 0x3f, 0xb2,
- 0x01, 0xb4, 0xa5, 0xb8, 0xc6, 0x0e, 0x94, 0x5b,
- 0xec, 0x5e, 0xbb, 0x7a, 0x63, 0x24, 0xf1, 0xf9,
- 0xd6, 0x50, 0x08, 0xc1, 0xa3, 0xcc, 0x90, 0x07,
- 0x5b, 0x04, 0x04, 0x42, 0x74, 0xcf, 0x37, 0xfa,
- 0xf0, 0xa5, 0xd9, 0xd3, 0x86, 0x89, 0x89, 0x18,
- 0xf3, 0x4c, 0xe2, 0x11, 0x02, 0x03, 0x01, 0x00,
- 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
- 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00,
- 0x03, 0x82, 0x01, 0x01, 0x00, 0x90, 0xbb, 0xf9,
- 0x5e, 0xba, 0x17, 0x1f, 0xac, 0x21, 0x9f, 0x6b,
- 0x4a, 0x46, 0xd0, 0x6d, 0x3c, 0x8f, 0x3d, 0xf8,
- 0x5e, 0x3e, 0x72, 0xaf, 0xa0, 0x1a, 0xf3, 0xff,
- 0x89, 0xac, 0x5b, 0x7a, 0xe2, 0x91, 0x2a, 0x23,
- 0x85, 0xc6, 0x4d, 0x47, 0x67, 0x01, 0x08, 0xa8,
- 0x05, 0x1d, 0x01, 0x60, 0x50, 0x5f, 0x59, 0xad,
- 0xfe, 0x7b, 0xc6, 0x0c, 0x54, 0x90, 0x68, 0x70,
- 0x67, 0x2e, 0xed, 0x87, 0xf8, 0x69, 0x8a, 0xac,
- 0x32, 0xfe, 0x6f, 0x90, 0x19, 0x2a, 0x64, 0x8d,
- 0x82, 0x66, 0x05, 0x43, 0x88, 0xee, 0xf2, 0x30,
- 0xed, 0xa4, 0x8f, 0xbf, 0xd6, 0x57, 0x20, 0xd4,
- 0x43, 0x1d, 0x52, 0x96, 0x6f, 0xae, 0x09, 0x96,
- 0x01, 0x52, 0x38, 0xe3, 0xaf, 0x99, 0xd7, 0xdc,
- 0x14, 0x99, 0xc4, 0x8b, 0x0e, 0x04, 0x0f, 0xb3,
- 0x14, 0x14, 0xd4, 0xa5, 0x93, 0xe1, 0xc9, 0x8a,
- 0x81, 0xef, 0x63, 0xfc, 0x36, 0x77, 0x05, 0x06,
- 0xf0, 0x2a, 0x04, 0x0a, 0xbe, 0x2e, 0xce, 0x81,
- 0x3d, 0x23, 0xa1, 0xda, 0xd8, 0xeb, 0xc6, 0xea,
- 0x5e, 0xcf, 0x28, 0x36, 0x51, 0x31, 0x95, 0x5e,
- 0x40, 0x04, 0xed, 0xac, 0xc1, 0xc8, 0x56, 0x69,
- 0x87, 0xec, 0x3b, 0x03, 0x3e, 0x9d, 0x0f, 0x4c,
- 0x4c, 0xeb, 0xd7, 0xba, 0x26, 0xdf, 0xe3, 0xde,
- 0x10, 0xee, 0x93, 0x62, 0x8d, 0x73, 0x52, 0x6e,
- 0xff, 0x37, 0x36, 0x98, 0x7b, 0x2d, 0x56, 0x4c,
- 0xba, 0x09, 0xb8, 0xa7, 0xf0, 0x3b, 0x16, 0x81,
- 0xca, 0xdb, 0x43, 0xab, 0xec, 0x4c, 0x6e, 0x7c,
- 0xc1, 0x0b, 0x22, 0x22, 0x43, 0x1d, 0xb6, 0x0c,
- 0xc1, 0xb9, 0xcf, 0xe4, 0x53, 0xee, 0x1d, 0x3e,
- 0x88, 0xa7, 0x13, 0xbe, 0x7f, 0xbd, 0xae, 0x72,
- 0xcf, 0xcd, 0x63, 0xd2, 0xc3, 0x18, 0x58, 0x92,
- 0xa2, 0xad, 0xb5, 0x09, 0x9d, 0x91, 0x03, 0xdd,
- 0x3c, 0xe2, 0x1c, 0xde, 0x78, 0x00, 0x03, 0x88,
- 0x30, 0x82, 0x03, 0x84, 0x30, 0x82, 0x02, 0x6c,
- 0x02, 0x09, 0x00, 0xab, 0xed, 0xa6, 0xe4, 0x4a,
- 0x2b, 0x2b, 0xf8, 0x30, 0x0d, 0x06, 0x09, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
- 0x05, 0x00, 0x30, 0x81, 0x86, 0x31, 0x0b, 0x30,
- 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
- 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
- 0x55, 0x04, 0x08, 0x0c, 0x02, 0x4e, 0x59, 0x31,
- 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07,
- 0x0c, 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b, 0x6c,
- 0x79, 0x6e, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
- 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x4d, 0x79, 0x20,
- 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
- 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68,
- 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x11, 0x30,
- 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
- 0x6d, 0x79, 0x63, 0x61, 0x2e, 0x6f, 0x72, 0x67,
- 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16,
- 0x12, 0x6a, 0x76, 0x73, 0x68, 0x61, 0x68, 0x69,
- 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e,
- 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x31,
- 0x33, 0x30, 0x35, 0x32, 0x36, 0x32, 0x31, 0x31,
- 0x38, 0x34, 0x30, 0x5a, 0x17, 0x0d, 0x31, 0x33,
- 0x30, 0x36, 0x32, 0x35, 0x32, 0x31, 0x31, 0x38,
- 0x34, 0x30, 0x5a, 0x30, 0x81, 0x80, 0x31, 0x0b,
- 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
- 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06,
- 0x03, 0x55, 0x04, 0x08, 0x0c, 0x02, 0x4e, 0x59,
- 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
- 0x07, 0x0c, 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b,
- 0x6c, 0x79, 0x6e, 0x31, 0x15, 0x30, 0x13, 0x06,
- 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0c, 0x4d, 0x79,
- 0x20, 0x43, 0x41, 0x20, 0x43, 0x6c, 0x69, 0x65,
- 0x6e, 0x74, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03,
- 0x55, 0x04, 0x03, 0x0c, 0x0e, 0x6d, 0x79, 0x63,
- 0x61, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e,
- 0x63, 0x6f, 0x6d, 0x31, 0x21, 0x30, 0x1f, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x09, 0x01, 0x16, 0x12, 0x6a, 0x76, 0x73, 0x68,
- 0x61, 0x68, 0x69, 0x64, 0x40, 0x67, 0x6d, 0x61,
- 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82,
- 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
- 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82,
- 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xce,
- 0x13, 0xf0, 0x72, 0xb0, 0x61, 0xc8, 0x18, 0x37,
- 0x8a, 0x41, 0x3d, 0x20, 0xa1, 0x1c, 0xcb, 0xbf,
- 0xf6, 0x3b, 0x74, 0x26, 0x2a, 0x96, 0x11, 0xec,
- 0x53, 0xa1, 0xcc, 0x7d, 0x77, 0x56, 0x45, 0x0f,
- 0x36, 0xb7, 0xf2, 0x48, 0x92, 0x1a, 0x62, 0xcc,
- 0xb6, 0xc0, 0xa1, 0x2f, 0x44, 0x2b, 0xc1, 0x89,
- 0xcb, 0x6e, 0x1e, 0xdb, 0x57, 0x92, 0xd5, 0x97,
- 0x60, 0x8c, 0x41, 0x2c, 0xd9, 0x20, 0xfe, 0xe9,
- 0x1f, 0x8e, 0xfc, 0x7f, 0x02, 0x44, 0x0f, 0x28,
- 0x81, 0xd6, 0x0c, 0xcd, 0xbc, 0xf0, 0x57, 0x6c,
- 0xcc, 0xa7, 0xba, 0x06, 0xa0, 0xa6, 0x91, 0xda,
- 0xef, 0x46, 0x8a, 0x60, 0x0f, 0x52, 0x6c, 0x90,
- 0x6c, 0x8c, 0x44, 0xaf, 0xb0, 0x9d, 0x90, 0xba,
- 0x21, 0x58, 0xa0, 0x3c, 0xee, 0x54, 0xb5, 0x29,
- 0x26, 0x1f, 0x0a, 0xac, 0xef, 0x48, 0x68, 0x33,
- 0xd0, 0x33, 0xd0, 0x8b, 0x1a, 0xec, 0x6e, 0x2f,
- 0xb5, 0x4a, 0x53, 0xc2, 0x1a, 0xd2, 0xf1, 0x50,
- 0x05, 0x59, 0x5c, 0xd9, 0xda, 0x03, 0x0a, 0x47,
- 0xb7, 0xdd, 0xf7, 0x3a, 0x69, 0xf5, 0x4e, 0xea,
- 0x4a, 0xc2, 0xca, 0x54, 0xb0, 0x8b, 0x76, 0xe1,
- 0x02, 0x2d, 0x52, 0x67, 0xb9, 0xdd, 0x50, 0xc9,
- 0x3b, 0x07, 0x24, 0x22, 0x6a, 0x00, 0x1d, 0x58,
- 0x83, 0xa8, 0xec, 0x95, 0xf1, 0xda, 0xe2, 0x73,
- 0xa0, 0xa1, 0x72, 0x60, 0x9e, 0x86, 0x53, 0xcb,
- 0x45, 0xa8, 0xc2, 0xa0, 0x50, 0xa0, 0x53, 0xd6,
- 0xfc, 0x18, 0x84, 0xb5, 0x4a, 0x26, 0xd0, 0xa2,
- 0xaa, 0xd0, 0xff, 0xb6, 0xfe, 0x3a, 0x9c, 0xb5,
- 0x19, 0x3b, 0x3f, 0xe1, 0x48, 0x0d, 0xa4, 0x09,
- 0x4f, 0x83, 0xc9, 0xc0, 0xc9, 0xa6, 0x0b, 0x58,
- 0x1f, 0x1c, 0x7b, 0xac, 0xa2, 0x42, 0xbc, 0x61,
- 0xf4, 0x21, 0x8a, 0x00, 0xda, 0x14, 0xa0, 0x60,
- 0x03, 0xfe, 0x93, 0x12, 0x6c, 0x56, 0xcd, 0x02,
- 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
- 0x25, 0x29, 0x3b, 0x1e, 0xc3, 0x58, 0x32, 0xe6,
- 0x23, 0xc8, 0xee, 0x18, 0xf0, 0x1d, 0x62, 0x6d,
- 0x3b, 0x59, 0x99, 0x3a, 0xfe, 0x49, 0x72, 0x07,
- 0x3f, 0x58, 0x93, 0xdb, 0xc0, 0xaf, 0xb0, 0xb3,
- 0x5c, 0xd1, 0x5c, 0x98, 0xc8, 0xea, 0x4a, 0xe4,
- 0x58, 0x73, 0x0d, 0x57, 0xc5, 0x13, 0x7c, 0x5c,
- 0x79, 0x66, 0xda, 0x04, 0x1d, 0xe5, 0x98, 0xda,
- 0x35, 0x47, 0x44, 0xb0, 0xd2, 0x7a, 0x66, 0x9d,
- 0xcd, 0x41, 0xa5, 0x8f, 0xa1, 0x11, 0xb2, 0x1a,
- 0x87, 0xc0, 0xcd, 0x55, 0xed, 0xb4, 0x7b, 0x33,
- 0x72, 0xeb, 0xf7, 0xe3, 0x7b, 0x8b, 0x02, 0x86,
- 0xe9, 0x2b, 0x26, 0x32, 0x9f, 0x99, 0xf1, 0xcb,
- 0x93, 0xab, 0xb9, 0x16, 0xb3, 0x9a, 0xb2, 0x22,
- 0x13, 0x21, 0x1f, 0x5b, 0xcc, 0xa2, 0x59, 0xbb,
- 0x69, 0xf2, 0xb8, 0x07, 0x80, 0xce, 0x0c, 0xf7,
- 0x98, 0x4c, 0x85, 0xc2, 0x96, 0x6a, 0x22, 0x05,
- 0xe9, 0xbe, 0x48, 0xb0, 0x02, 0x5b, 0x69, 0x28,
- 0x18, 0x88, 0x96, 0xe3, 0xd7, 0xc6, 0x7a, 0xd3,
- 0xe9, 0x99, 0xff, 0x9d, 0xc3, 0x61, 0x4d, 0x9a,
- 0x96, 0xf2, 0xc6, 0x33, 0x4d, 0xe5, 0x5d, 0x5a,
- 0x68, 0x64, 0x5a, 0x82, 0x35, 0x65, 0x25, 0xe3,
- 0x8c, 0x5b, 0xb0, 0xf6, 0x96, 0x56, 0xbc, 0xbf,
- 0x97, 0x76, 0x4b, 0x66, 0x44, 0x81, 0xa4, 0xc4,
- 0xa7, 0x31, 0xc5, 0xa1, 0x4f, 0xe8, 0xa4, 0xca,
- 0x20, 0xf5, 0x01, 0x5b, 0x99, 0x4f, 0x5a, 0xf4,
- 0xf0, 0x78, 0xbf, 0x71, 0x49, 0xd5, 0xf1, 0xc1,
- 0xa2, 0x18, 0xfd, 0x72, 0x5b, 0x16, 0xe8, 0x92,
- 0xc7, 0x37, 0x48, 0xaf, 0xee, 0x24, 0xfc, 0x35,
- 0x0b, 0xc2, 0xdd, 0x05, 0xc7, 0x6e, 0xa3, 0x29,
- 0xbb, 0x29, 0x7d, 0xd3, 0x2b, 0x94, 0x80, 0xc3,
- 0x40, 0x53, 0x0e, 0x03, 0x54, 0x3d, 0x7b, 0x8b,
- 0xce, 0xf9, 0xa4, 0x03, 0x27, 0x63, 0xec, 0x51,
- 0x00, 0x03, 0xe5, 0x30, 0x82, 0x03, 0xe1, 0x30,
- 0x82, 0x02, 0xc9, 0xa0, 0x03, 0x02, 0x01, 0x02,
- 0x02, 0x09, 0x00, 0xcc, 0x22, 0x4c, 0x4b, 0x98,
- 0xa2, 0x88, 0xfc, 0x30, 0x0d, 0x06, 0x09, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
- 0x05, 0x00, 0x30, 0x81, 0x86, 0x31, 0x0b, 0x30,
- 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
- 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
- 0x55, 0x04, 0x08, 0x0c, 0x02, 0x4e, 0x59, 0x31,
- 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07,
- 0x0c, 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b, 0x6c,
- 0x79, 0x6e, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
- 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x4d, 0x79, 0x20,
- 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
- 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68,
- 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x11, 0x30,
- 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
- 0x6d, 0x79, 0x63, 0x61, 0x2e, 0x6f, 0x72, 0x67,
- 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16,
- 0x12, 0x6a, 0x76, 0x73, 0x68, 0x61, 0x68, 0x69,
- 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e,
- 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x31,
- 0x33, 0x30, 0x35, 0x32, 0x36, 0x32, 0x31, 0x30,
- 0x35, 0x30, 0x31, 0x5a, 0x17, 0x0d, 0x32, 0x33,
- 0x30, 0x35, 0x32, 0x34, 0x32, 0x31, 0x30, 0x35,
- 0x30, 0x31, 0x5a, 0x30, 0x81, 0x86, 0x31, 0x0b,
- 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
- 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06,
- 0x03, 0x55, 0x04, 0x08, 0x0c, 0x02, 0x4e, 0x59,
- 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
- 0x07, 0x0c, 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b,
- 0x6c, 0x79, 0x6e, 0x31, 0x21, 0x30, 0x1f, 0x06,
- 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x4d, 0x79,
- 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
- 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74,
- 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x11,
- 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
- 0x08, 0x6d, 0x79, 0x63, 0x61, 0x2e, 0x6f, 0x72,
- 0x67, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01,
- 0x16, 0x12, 0x6a, 0x76, 0x73, 0x68, 0x61, 0x68,
- 0x69, 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c,
- 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22,
- 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
- 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
- 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
- 0x02, 0x82, 0x01, 0x01, 0x00, 0xf0, 0xfb, 0xad,
- 0x80, 0x5e, 0x37, 0xd3, 0x6d, 0xee, 0x2e, 0xcc,
- 0xbc, 0x0c, 0xd7, 0x56, 0x4b, 0x56, 0x45, 0xcd,
- 0x28, 0xb6, 0x22, 0xe9, 0xe2, 0x0f, 0xd1, 0x87,
- 0x2a, 0x27, 0xce, 0x77, 0x8d, 0x6e, 0x0e, 0x0f,
- 0xfb, 0x66, 0xe1, 0xb5, 0x0e, 0x9a, 0xb6, 0x05,
- 0x8e, 0xb3, 0xe1, 0xc5, 0x77, 0x86, 0x5b, 0x46,
- 0xd2, 0x0b, 0x92, 0x03, 0x1b, 0x89, 0x0c, 0x1b,
- 0x10, 0x0e, 0x99, 0x8f, 0xe2, 0x17, 0xe8, 0xc2,
- 0x30, 0x00, 0x47, 0xd6, 0xfc, 0xf9, 0x0f, 0x3b,
- 0x75, 0x34, 0x8d, 0x4d, 0xb0, 0x99, 0xb7, 0xa0,
- 0x6d, 0xa0, 0xb6, 0xad, 0xda, 0x07, 0x5e, 0x38,
- 0x2e, 0x02, 0xe4, 0x30, 0x6d, 0xae, 0x13, 0x72,
- 0xd4, 0xc8, 0xce, 0x14, 0x07, 0xae, 0x23, 0x8c,
- 0x8f, 0x9e, 0x8c, 0x60, 0xd6, 0x06, 0xb9, 0xef,
- 0x00, 0x18, 0xc0, 0x1d, 0x25, 0x1e, 0xda, 0x3e,
- 0x2f, 0xcf, 0x2b, 0x56, 0x84, 0x9e, 0x30, 0x21,
- 0xc7, 0x29, 0xf6, 0x03, 0x8a, 0x24, 0xf9, 0x34,
- 0xac, 0x65, 0x9d, 0x80, 0x36, 0xc8, 0x3b, 0x15,
- 0x10, 0xbd, 0x51, 0xe9, 0xbc, 0x02, 0xe1, 0xe9,
- 0xb3, 0x5a, 0x9a, 0x99, 0x41, 0x1b, 0x27, 0xa0,
- 0x4d, 0x50, 0x9e, 0x27, 0x7f, 0xa1, 0x7d, 0x09,
- 0x87, 0xbd, 0x8a, 0xca, 0x5f, 0xb1, 0xa5, 0x08,
- 0xb8, 0x04, 0xd4, 0x52, 0x89, 0xaa, 0xe0, 0x7d,
- 0x42, 0x2e, 0x2f, 0x15, 0xee, 0x66, 0x57, 0x0f,
- 0x13, 0x19, 0x45, 0xa8, 0x4b, 0x5d, 0x81, 0x66,
- 0xcc, 0x12, 0x37, 0x94, 0x5e, 0xfd, 0x3c, 0x10,
- 0x81, 0x51, 0x3f, 0xfa, 0x0f, 0xdd, 0xa1, 0x89,
- 0x03, 0xa9, 0x78, 0x91, 0xf5, 0x3b, 0xf3, 0xbc,
- 0xac, 0xbe, 0x93, 0x30, 0x2e, 0xbe, 0xca, 0x7f,
- 0x46, 0xd3, 0x28, 0xb4, 0x4e, 0x91, 0x7b, 0x5b,
- 0x43, 0x6c, 0xaf, 0x9b, 0x5c, 0x6a, 0x6d, 0x5a,
- 0xdb, 0x79, 0x5e, 0x6a, 0x6b, 0x02, 0x03, 0x01,
- 0x00, 0x01, 0xa3, 0x50, 0x30, 0x4e, 0x30, 0x1d,
- 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
- 0x14, 0x6b, 0x1e, 0x00, 0xa8, 0x9f, 0xfa, 0x7d,
- 0x00, 0xf9, 0xe0, 0x9d, 0x0f, 0x90, 0x8c, 0x90,
- 0xa8, 0xa1, 0x37, 0x6b, 0xda, 0x30, 0x1f, 0x06,
- 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
- 0x80, 0x14, 0x6b, 0x1e, 0x00, 0xa8, 0x9f, 0xfa,
- 0x7d, 0x00, 0xf9, 0xe0, 0x9d, 0x0f, 0x90, 0x8c,
- 0x90, 0xa8, 0xa1, 0x37, 0x6b, 0xda, 0x30, 0x0c,
- 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30,
- 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
- 0xcd, 0x6f, 0x73, 0x4d, 0x56, 0x0b, 0xf3, 0x2e,
- 0x1c, 0xe2, 0x02, 0x0c, 0x14, 0xbb, 0x2f, 0xdd,
- 0x3c, 0x43, 0xfe, 0xdf, 0x94, 0x2d, 0xa9, 0x89,
- 0x81, 0x51, 0xf8, 0x5f, 0xa7, 0xa0, 0x13, 0xaa,
- 0xcc, 0xb0, 0x18, 0xe2, 0x57, 0x3e, 0x0d, 0x29,
- 0x93, 0xe8, 0x95, 0xd5, 0x1b, 0x53, 0xd2, 0x51,
- 0xf2, 0xbd, 0xf5, 0x9e, 0x7b, 0x22, 0x65, 0x62,
- 0x5c, 0xc4, 0x4c, 0x1d, 0xe8, 0xe9, 0xc3, 0xd4,
- 0x2b, 0xe7, 0x78, 0xcb, 0x10, 0xf3, 0xfe, 0x06,
- 0x83, 0xdc, 0x3a, 0x1e, 0x62, 0x10, 0xc0, 0x46,
- 0x77, 0xc6, 0x9d, 0x9f, 0xab, 0x96, 0x25, 0x5c,
- 0xfb, 0x26, 0xc1, 0x15, 0x1f, 0xa5, 0x33, 0xee,
- 0x4f, 0x9a, 0x14, 0x6a, 0x14, 0x97, 0x93, 0x2b,
- 0x95, 0x0b, 0xdc, 0xa8, 0xd7, 0x69, 0x2e, 0xf0,
- 0x01, 0x0e, 0xfd, 0x4e, 0xd0, 0xd9, 0xa8, 0xe5,
- 0x65, 0xde, 0xfb, 0xca, 0xca, 0x1c, 0x5f, 0xf9,
- 0x53, 0xa0, 0x87, 0xe7, 0x33, 0x9b, 0x2f, 0xcf,
- 0xe4, 0x13, 0xfc, 0xec, 0x7a, 0x6c, 0xb0, 0x90,
- 0x13, 0x9b, 0xb6, 0xc5, 0x03, 0xf6, 0x0e, 0x5e,
- 0xe2, 0xe4, 0x26, 0xc1, 0x7e, 0x53, 0xfe, 0x69,
- 0xa3, 0xc7, 0xd8, 0x8e, 0x6e, 0x94, 0x32, 0xa0,
- 0xde, 0xca, 0xb6, 0xcc, 0xd6, 0x01, 0xd5, 0x78,
- 0x40, 0x28, 0x63, 0x9b, 0xee, 0xcf, 0x09, 0x3b,
- 0x35, 0x04, 0xf0, 0x14, 0x02, 0xf6, 0x80, 0x0e,
- 0x90, 0xb2, 0x94, 0xd2, 0x25, 0x16, 0xb8, 0x7a,
- 0x76, 0x87, 0x84, 0x9f, 0x84, 0xc5, 0xaf, 0xc2,
- 0x6d, 0x68, 0x7a, 0x84, 0x9c, 0xc6, 0x8a, 0x63,
- 0x60, 0x87, 0x6a, 0x25, 0xc1, 0xa1, 0x78, 0x0f,
- 0xba, 0xe8, 0x5f, 0xe1, 0xba, 0xac, 0xa4, 0x6f,
- 0xdd, 0x09, 0x3f, 0x12, 0xcb, 0x1d, 0xf3, 0xcf,
- 0x48, 0xd7, 0xd3, 0x26, 0xe8, 0x9c, 0xc3, 0x53,
- 0xb3, 0xba, 0xdc, 0x32, 0x99, 0x98, 0x96, 0xd6,
- 0x16, 0x03, 0x01, 0x01, 0x06, 0x10, 0x00, 0x01,
- 0x02, 0x01, 0x00, 0x6e, 0xea, 0x15, 0x6f, 0x21,
- 0xbd, 0x2d, 0x14, 0xde, 0x9d, 0x02, 0xeb, 0xdf,
- 0x3b, 0x09, 0x75, 0xaf, 0x32, 0x80, 0x0c, 0xe2,
- 0xc2, 0x7b, 0x0d, 0xca, 0x24, 0x96, 0xf6, 0x3e,
- 0xa5, 0x97, 0xba, 0x0c, 0x50, 0x7e, 0xb3, 0x68,
- 0x58, 0xc6, 0xd8, 0xec, 0xab, 0xa9, 0xd9, 0x3a,
- 0xb1, 0x49, 0xea, 0x2f, 0xd7, 0xdb, 0x15, 0x1b,
- 0xb5, 0xaf, 0xec, 0xcc, 0x40, 0x5c, 0xe6, 0x0f,
- 0xc4, 0x33, 0x71, 0xe7, 0x41, 0xc0, 0x04, 0x89,
- 0x60, 0x3e, 0xb7, 0xe6, 0xda, 0x38, 0x62, 0x27,
- 0x6a, 0xd9, 0xfb, 0x93, 0x94, 0x9d, 0xc1, 0x63,
- 0x92, 0x5c, 0x88, 0x19, 0x38, 0x81, 0x79, 0x9d,
- 0x59, 0x48, 0x5e, 0xd3, 0xc8, 0xea, 0xcb, 0x6e,
- 0x66, 0x66, 0x03, 0xdc, 0x0c, 0x2d, 0x95, 0xb1,
- 0x4d, 0x68, 0xc7, 0xc5, 0x6e, 0xfa, 0x94, 0x14,
- 0xdf, 0x2c, 0x70, 0x69, 0x04, 0xf4, 0x69, 0xf1,
- 0xf0, 0x07, 0xbd, 0x23, 0x53, 0x63, 0xb3, 0x41,
- 0xec, 0xa7, 0x10, 0xa5, 0x04, 0x84, 0x24, 0xb5,
- 0xf5, 0x0c, 0x0f, 0x5d, 0x02, 0x47, 0x79, 0x60,
- 0x76, 0xbb, 0xdf, 0x60, 0xa6, 0xd7, 0x4d, 0x08,
- 0x7d, 0xa6, 0x85, 0x4f, 0x61, 0xac, 0x96, 0x3d,
- 0xbc, 0xaf, 0x07, 0xb0, 0x7c, 0xb6, 0x23, 0x3e,
- 0x1f, 0x0a, 0x62, 0x77, 0x97, 0x77, 0xae, 0x33,
- 0x55, 0x0f, 0x85, 0xdf, 0xdc, 0xbe, 0xc6, 0xe0,
- 0xe0, 0x14, 0x83, 0x4c, 0x50, 0xf0, 0xe5, 0x2d,
- 0xdc, 0x0b, 0x74, 0x7f, 0xc3, 0x28, 0x98, 0x16,
- 0xda, 0x74, 0xe6, 0x40, 0xc2, 0xf0, 0xea, 0xc0,
- 0x00, 0xd5, 0xfc, 0x16, 0xe4, 0x43, 0xa1, 0xfc,
- 0x31, 0x19, 0x81, 0x62, 0xec, 0x2b, 0xfe, 0xcc,
- 0xe8, 0x19, 0xed, 0xa1, 0x1e, 0x6a, 0x49, 0x73,
- 0xde, 0xc4, 0xe9, 0x22, 0x0a, 0x21, 0xde, 0x45,
- 0x1e, 0x55, 0x12, 0xd9, 0x44, 0xef, 0x4e, 0xaa,
- 0x5e, 0x26, 0x57, 0x16, 0x03, 0x01, 0x01, 0x06,
- 0x0f, 0x00, 0x01, 0x02, 0x01, 0x00, 0x23, 0xde,
- 0xb0, 0x39, 0x60, 0xe9, 0x82, 0xb8, 0xed, 0x17,
- 0x78, 0xd2, 0x37, 0x0e, 0x85, 0x69, 0xda, 0xcc,
- 0x9f, 0x54, 0x4d, 0xda, 0xce, 0xe8, 0x5a, 0xeb,
- 0x3c, 0x61, 0x4c, 0x7a, 0x84, 0x1f, 0x21, 0x03,
- 0xb3, 0x8a, 0x74, 0x3b, 0x6a, 0x9e, 0x4f, 0x44,
- 0xd9, 0x75, 0x0a, 0xd8, 0x7e, 0x56, 0xa3, 0xef,
- 0x5a, 0xfe, 0x8a, 0x35, 0xce, 0x29, 0x18, 0xfe,
- 0xa6, 0x61, 0x8e, 0x8f, 0x00, 0x90, 0x2d, 0x85,
- 0xe3, 0x6c, 0x0e, 0x8d, 0x8c, 0x27, 0x80, 0x8c,
- 0x9f, 0x51, 0xe9, 0xd3, 0xe6, 0x7d, 0x70, 0xe9,
- 0xfb, 0xcb, 0xb8, 0x24, 0x94, 0x30, 0x9b, 0xba,
- 0x01, 0x14, 0x49, 0x9f, 0xaf, 0x09, 0xd8, 0x26,
- 0x1b, 0x23, 0xa4, 0xb8, 0xd9, 0x44, 0x0a, 0xdc,
- 0x4e, 0x27, 0xe7, 0x32, 0xf5, 0x9c, 0xf3, 0x8d,
- 0xa0, 0xc5, 0xc4, 0xbe, 0x92, 0x02, 0x85, 0x4f,
- 0x33, 0x8f, 0xa7, 0xf7, 0x87, 0xa9, 0x44, 0xf3,
- 0x64, 0xbd, 0x32, 0x04, 0xeb, 0xc5, 0xc3, 0x62,
- 0xe9, 0xda, 0x2f, 0x95, 0x5c, 0xf7, 0x58, 0x3e,
- 0xad, 0x35, 0xd7, 0x7e, 0xad, 0xdd, 0x32, 0x8d,
- 0xce, 0x81, 0x08, 0xad, 0x49, 0xf7, 0xdb, 0xf7,
- 0xaf, 0xe3, 0xc6, 0xb2, 0xdd, 0x76, 0x0c, 0xcf,
- 0x0f, 0x87, 0x79, 0x90, 0x10, 0x79, 0xc6, 0xc8,
- 0x7b, 0xe6, 0x23, 0xf2, 0xda, 0x33, 0xca, 0xe1,
- 0xf0, 0x59, 0x42, 0x43, 0x03, 0x56, 0x19, 0xe3,
- 0x8b, 0xe6, 0xa8, 0x70, 0xbc, 0x80, 0xfa, 0x24,
- 0xae, 0x03, 0x13, 0x30, 0x0d, 0x1f, 0xab, 0xb7,
- 0x82, 0xd9, 0x24, 0x90, 0x80, 0xbf, 0x75, 0xe1,
- 0x0d, 0x1c, 0xb2, 0xfe, 0x92, 0x2c, 0x4d, 0x21,
- 0xe9, 0x5d, 0xa1, 0x68, 0xf3, 0x16, 0xd8, 0x3f,
- 0xb2, 0xc3, 0x00, 0x3e, 0xd8, 0x42, 0x25, 0x5c,
- 0x90, 0x11, 0xc0, 0x1b, 0xd4, 0x26, 0x5c, 0x37,
- 0x47, 0xbd, 0xf8, 0x1e, 0x34, 0xa9, 0x14, 0x03,
- 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01, 0x00,
- 0x24, 0x8f, 0x94, 0x7e, 0x01, 0xee, 0xd5, 0x4f,
- 0x83, 0x41, 0x31, 0xc0, 0x36, 0x81, 0x46, 0xc3,
- 0xc0, 0xcc, 0x9c, 0xea, 0x0f, 0x29, 0x04, 0x10,
- 0x43, 0x1e, 0x08, 0x6e, 0x08, 0xce, 0xb2, 0x62,
- 0xa6, 0x0f, 0x68, 0x9f, 0x99,
- },
- {
- 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
- 0x01, 0x00, 0x24, 0xd9, 0x46, 0x5b, 0xbf, 0xfd,
- 0x8a, 0xa1, 0x08, 0xd5, 0xf3, 0x0c, 0x1c, 0xd8,
- 0xa8, 0xb3, 0xe5, 0x89, 0x83, 0x9e, 0x23, 0x47,
- 0x81, 0x66, 0x77, 0x11, 0x98, 0xe5, 0xf4, 0xac,
- 0x06, 0xe9, 0x4c, 0x05, 0x8b, 0xc4, 0x16,
- },
- {
- 0x17, 0x03, 0x01, 0x00, 0x1a, 0xc5, 0x28, 0xfd,
- 0x71, 0xc0, 0xe6, 0x89, 0xb8, 0x82, 0x92, 0x1b,
- 0xdd, 0x39, 0xe5, 0xbf, 0x41, 0x82, 0x1f, 0xc1,
- 0xbc, 0x85, 0xe5, 0x32, 0x1b, 0x93, 0x46, 0x15,
- 0x03, 0x01, 0x00, 0x16, 0x1a, 0x8b, 0x10, 0x42,
- 0x12, 0xb2, 0xbd, 0xd3, 0xf1, 0x74, 0x1f, 0xc2,
- 0x10, 0x08, 0xc2, 0x79, 0x99, 0x2c, 0x55, 0xef,
- 0x4a, 0xbd,
- },
-}
+ // Touch entry 2. LRU should evict 3 next.
+ cache.Get(keys[2])
+ cache.Put(keys[0], &cs[0])
+ if s, ok := cache.Get(keys[3]); ok || s != nil {
+ t.Fatalf("session cache should have evicted key 3")
+ }
-// $ openssl s_server -tls1_2 -cert server.crt -key server.key \
-// -cipher ECDHE-RSA-AES128-SHA -port 10443
-// $ go test -test.run "TestRunClient" -connect -ciphersuites=0xc013 \
-// -minversion=0x0303 -maxversion=0x0303
-var clientTLS12Script = [][]byte{
- {
- 0x16, 0x03, 0x01, 0x00, 0x58, 0x01, 0x00, 0x00,
- 0x54, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xc0, 0x13,
- 0x01, 0x00, 0x00, 0x29, 0x00, 0x05, 0x00, 0x05,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
- 0x08, 0x00, 0x06, 0x00, 0x17, 0x00, 0x18, 0x00,
- 0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00,
- 0x0d, 0x00, 0x0a, 0x00, 0x08, 0x04, 0x01, 0x04,
- 0x03, 0x02, 0x01, 0x02, 0x03,
- },
- {
- 0x16, 0x03, 0x03, 0x00, 0x54, 0x02, 0x00, 0x00,
- 0x50, 0x03, 0x03, 0x52, 0x65, 0x67, 0xbd, 0xe8,
- 0x72, 0x03, 0x6a, 0x52, 0x8d, 0x28, 0x2c, 0x9a,
- 0x53, 0xff, 0xc2, 0xa1, 0x62, 0x5f, 0x54, 0xfb,
- 0x73, 0x00, 0xcf, 0x4d, 0x28, 0x36, 0xc2, 0xee,
- 0xfd, 0x78, 0xf0, 0x20, 0x6f, 0xbe, 0x49, 0xec,
- 0x5b, 0x6f, 0xf9, 0x53, 0x42, 0x69, 0x0d, 0x6d,
- 0x8b, 0x68, 0x2e, 0xca, 0x3c, 0x3c, 0x88, 0x9e,
- 0x8b, 0xf9, 0x32, 0x65, 0x09, 0xd6, 0xa0, 0x7d,
- 0xea, 0xc6, 0xd5, 0xc4, 0xc0, 0x13, 0x00, 0x00,
- 0x08, 0x00, 0x0b, 0x00, 0x04, 0x03, 0x00, 0x01,
- 0x02, 0x16, 0x03, 0x03, 0x02, 0x39, 0x0b, 0x00,
- 0x02, 0x35, 0x00, 0x02, 0x32, 0x00, 0x02, 0x2f,
- 0x30, 0x82, 0x02, 0x2b, 0x30, 0x82, 0x01, 0xd5,
- 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00,
- 0xb1, 0x35, 0x13, 0x65, 0x11, 0x20, 0xc5, 0x92,
- 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
- 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30,
- 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
- 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
- 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
- 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
- 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
- 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e,
- 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
- 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
- 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e,
- 0x17, 0x0d, 0x31, 0x32, 0x30, 0x34, 0x30, 0x36,
- 0x31, 0x37, 0x31, 0x30, 0x31, 0x33, 0x5a, 0x17,
- 0x0d, 0x31, 0x35, 0x30, 0x34, 0x30, 0x36, 0x31,
- 0x37, 0x31, 0x30, 0x31, 0x33, 0x5a, 0x30, 0x45,
- 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
- 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30,
- 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a,
- 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61,
- 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
- 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74,
- 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69,
- 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74,
- 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x5c, 0x30,
- 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b,
- 0x00, 0x30, 0x48, 0x02, 0x41, 0x00, 0x9f, 0xb3,
- 0xc3, 0x84, 0x27, 0x95, 0xff, 0x12, 0x31, 0x52,
- 0x0f, 0x15, 0xef, 0x46, 0x11, 0xc4, 0xad, 0x80,
- 0xe6, 0x36, 0x5b, 0x0f, 0xdd, 0x80, 0xd7, 0x61,
- 0x8d, 0xe0, 0xfc, 0x72, 0x45, 0x09, 0x34, 0xfe,
- 0x55, 0x66, 0x45, 0x43, 0x4c, 0x68, 0x97, 0x6a,
- 0xfe, 0xa8, 0xa0, 0xa5, 0xdf, 0x5f, 0x78, 0xff,
- 0xee, 0xd7, 0x64, 0xb8, 0x3f, 0x04, 0xcb, 0x6f,
- 0xff, 0x2a, 0xfe, 0xfe, 0xb9, 0xed, 0x02, 0x03,
- 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
- 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
- 0x04, 0x16, 0x04, 0x14, 0x78, 0xa6, 0x97, 0x9a,
- 0x63, 0xb5, 0xc5, 0xa1, 0xa5, 0x33, 0xba, 0x22,
- 0x7c, 0x23, 0x6e, 0x5b, 0x1b, 0x7a, 0xcc, 0x2b,
- 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
- 0x6e, 0x30, 0x6c, 0x80, 0x14, 0x78, 0xa6, 0x97,
- 0x9a, 0x63, 0xb5, 0xc5, 0xa1, 0xa5, 0x33, 0xba,
- 0x22, 0x7c, 0x23, 0x6e, 0x5b, 0x1b, 0x7a, 0xcc,
- 0x2b, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0xb1,
- 0x35, 0x13, 0x65, 0x11, 0x20, 0xc5, 0x92, 0x30,
- 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
- 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x01, 0x05, 0x05, 0x00, 0x03, 0x41, 0x00, 0x85,
- 0x36, 0x40, 0x73, 0xc1, 0xbb, 0x1a, 0xda, 0xd4,
- 0x59, 0x9f, 0x2d, 0xa2, 0x70, 0x31, 0x46, 0x74,
- 0xec, 0x83, 0x6e, 0xa8, 0xc8, 0x3c, 0x51, 0xaf,
- 0x39, 0xac, 0xec, 0x40, 0xbc, 0xe8, 0x22, 0x46,
- 0x1d, 0x99, 0xd6, 0x46, 0x2a, 0x24, 0xd4, 0x8b,
- 0x05, 0x08, 0x4b, 0xfb, 0x35, 0x11, 0x6e, 0x92,
- 0xbb, 0x77, 0xba, 0xe4, 0x12, 0xbb, 0xf4, 0xc8,
- 0x5e, 0x9c, 0x81, 0xa8, 0x97, 0x60, 0x4c, 0x16,
- 0x03, 0x03, 0x00, 0x8d, 0x0c, 0x00, 0x00, 0x89,
- 0x03, 0x00, 0x17, 0x41, 0x04, 0x48, 0x93, 0x62,
- 0x6a, 0xf8, 0x7c, 0x94, 0xcc, 0xcc, 0x0a, 0x9b,
- 0x5e, 0x11, 0xad, 0x0b, 0x30, 0xc4, 0x5d, 0xf7,
- 0x63, 0x24, 0xc1, 0xb0, 0x40, 0x5f, 0xff, 0x9f,
- 0x0d, 0x7e, 0xd5, 0xa5, 0xd0, 0x4f, 0x80, 0x16,
- 0xa8, 0x66, 0x18, 0x31, 0x1f, 0x81, 0xb2, 0x9a,
- 0x41, 0x62, 0x5b, 0xcf, 0x73, 0xac, 0x4a, 0x64,
- 0xb5, 0xc1, 0x46, 0x4d, 0x8a, 0xac, 0x25, 0xba,
- 0x81, 0x7f, 0xbe, 0x64, 0x68, 0x04, 0x01, 0x00,
- 0x40, 0x4e, 0x3f, 0x1e, 0x04, 0x4c, 0xef, 0xd2,
- 0xa6, 0x82, 0xe6, 0x7c, 0x76, 0x23, 0x17, 0xb9,
- 0xe7, 0x52, 0x15, 0x6b, 0x3d, 0xb2, 0xb1, 0x17,
- 0x7d, 0xe6, 0xde, 0x06, 0x87, 0x30, 0xb0, 0xb5,
- 0x57, 0xae, 0xdf, 0xb2, 0xdc, 0x8d, 0xab, 0x76,
- 0x9c, 0xaa, 0x45, 0x6d, 0x23, 0x5d, 0xc1, 0xa8,
- 0x7b, 0x79, 0x79, 0xb1, 0x3c, 0xdc, 0xf5, 0x33,
- 0x2c, 0xa1, 0x62, 0x3e, 0xbd, 0xf5, 0x5d, 0x6c,
- 0x87, 0x16, 0x03, 0x03, 0x00, 0x04, 0x0e, 0x00,
- 0x00, 0x00,
- },
- {
- 0x16, 0x03, 0x03, 0x00, 0x46, 0x10, 0x00, 0x00,
- 0x42, 0x41, 0x04, 0x1e, 0x18, 0x37, 0xef, 0x0d,
- 0x19, 0x51, 0x88, 0x35, 0x75, 0x71, 0xb5, 0xe5,
- 0x54, 0x5b, 0x12, 0x2e, 0x8f, 0x09, 0x67, 0xfd,
- 0xa7, 0x24, 0x20, 0x3e, 0xb2, 0x56, 0x1c, 0xce,
- 0x97, 0x28, 0x5e, 0xf8, 0x2b, 0x2d, 0x4f, 0x9e,
- 0xf1, 0x07, 0x9f, 0x6c, 0x4b, 0x5b, 0x83, 0x56,
- 0xe2, 0x32, 0x42, 0xe9, 0x58, 0xb6, 0xd7, 0x49,
- 0xa6, 0xb5, 0x68, 0x1a, 0x41, 0x03, 0x56, 0x6b,
- 0xdc, 0x5a, 0x89, 0x14, 0x03, 0x03, 0x00, 0x01,
- 0x01, 0x16, 0x03, 0x03, 0x00, 0x40, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0x17,
- 0x54, 0x51, 0xb6, 0x1d, 0x8e, 0xe4, 0x6b, 0xed,
- 0x5b, 0xa1, 0x27, 0x7f, 0xdc, 0xa9, 0xa5, 0xcf,
- 0x38, 0xe6, 0x5d, 0x17, 0x34, 0xf9, 0xc0, 0x07,
- 0xb8, 0xbe, 0x56, 0xe6, 0xd6, 0x6a, 0xb6, 0x26,
- 0x4e, 0x45, 0x8d, 0x48, 0xe9, 0xc6, 0xb1, 0xa1,
- 0xea, 0xdc, 0xb1, 0x37, 0xd9, 0xf6,
- },
- {
- 0x14, 0x03, 0x03, 0x00, 0x01, 0x01, 0x16, 0x03,
- 0x03, 0x00, 0x40, 0x00, 0x68, 0xc5, 0x27, 0xd5,
- 0x3d, 0xba, 0x04, 0xde, 0x63, 0xf1, 0x5b, 0xc3,
- 0x86, 0xb9, 0x82, 0xc7, 0xb3, 0x90, 0x31, 0xea,
- 0x15, 0xe1, 0x42, 0x76, 0x7d, 0x90, 0xcb, 0xc9,
- 0xd1, 0x05, 0xe6, 0x8c, 0x76, 0xc7, 0x9a, 0x35,
- 0x67, 0xa2, 0x70, 0x9a, 0x8a, 0x6c, 0xb5, 0x6b,
- 0xc7, 0x87, 0xf3, 0x65, 0x0a, 0xa0, 0x98, 0xba,
- 0x57, 0xbb, 0x31, 0x7b, 0x1f, 0x1a, 0xf7, 0x2a,
- 0xf3, 0x12, 0xf6,
- },
- {
- 0x17, 0x03, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x10, 0x80,
- 0x54, 0x1e, 0x72, 0xd3, 0x1a, 0x86, 0x1c, 0xc4,
- 0x4a, 0x9b, 0xd4, 0x80, 0xd2, 0x03, 0x35, 0x0d,
- 0xe4, 0x12, 0xc2, 0x3d, 0x79, 0x4a, 0x2c, 0xba,
- 0xc2, 0xad, 0xf3, 0xd2, 0x16, 0x15, 0x03, 0x03,
- 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x04, 0x9b, 0x68, 0x78, 0x92, 0x28,
- 0x62, 0x02, 0x65, 0x87, 0x90, 0xe4, 0x32, 0xd7,
- 0x72, 0x08, 0x70, 0xb8, 0x52, 0x32, 0x1f, 0x97,
- 0xd4, 0x6a, 0xc6, 0x28, 0x83, 0xb0, 0x1d, 0x6e,
- 0x16, 0xd5,
- },
-}
+ // Update entry 0 in place.
+ cache.Put(keys[0], &cs[3])
+ if s, ok := cache.Get(keys[0]); !ok || s != &cs[3] {
+ t.Fatalf("session cache failed update for key 0")
+ }
-// $ openssl s_server -tls1_2 -cert server.crt -key server.key \
-// -port 10443 -verify 0
-// $ go test -test.run "TestRunClient" -connect -ciphersuites=0xc02f \
-// -maxversion=0x0303
-var clientTLS12ClientCertScript = [][]byte{
- {
- 0x16, 0x03, 0x01, 0x00, 0x58, 0x01, 0x00, 0x00,
- 0x54, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xc0, 0x2f,
- 0x01, 0x00, 0x00, 0x29, 0x00, 0x05, 0x00, 0x05,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
- 0x08, 0x00, 0x06, 0x00, 0x17, 0x00, 0x18, 0x00,
- 0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00,
- 0x0d, 0x00, 0x0a, 0x00, 0x08, 0x04, 0x01, 0x04,
- 0x03, 0x02, 0x01, 0x02, 0x03,
- },
- {
- 0x16, 0x03, 0x03, 0x00, 0x54, 0x02, 0x00, 0x00,
- 0x50, 0x03, 0x03, 0x52, 0x65, 0x67, 0xe0, 0xe8,
- 0xf1, 0x13, 0x2a, 0x83, 0x28, 0xa8, 0x2e, 0x76,
- 0x69, 0xe6, 0x89, 0x55, 0x6c, 0x48, 0x49, 0x2e,
- 0x00, 0xf6, 0x87, 0x6c, 0x13, 0xa1, 0xd4, 0xaa,
- 0xd0, 0x76, 0x3b, 0x20, 0xe4, 0xd6, 0x5b, 0x1d,
- 0x11, 0xf2, 0x42, 0xf2, 0x82, 0x0c, 0x0d, 0x66,
- 0x6d, 0xec, 0x52, 0xf8, 0x4a, 0xd9, 0x45, 0xcf,
- 0xe4, 0x4a, 0xba, 0x8b, 0xf1, 0xab, 0x55, 0xe4,
- 0x57, 0x18, 0xa9, 0x36, 0xc0, 0x2f, 0x00, 0x00,
- 0x08, 0x00, 0x0b, 0x00, 0x04, 0x03, 0x00, 0x01,
- 0x02, 0x16, 0x03, 0x03, 0x02, 0x39, 0x0b, 0x00,
- 0x02, 0x35, 0x00, 0x02, 0x32, 0x00, 0x02, 0x2f,
- 0x30, 0x82, 0x02, 0x2b, 0x30, 0x82, 0x01, 0xd5,
- 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00,
- 0xb1, 0x35, 0x13, 0x65, 0x11, 0x20, 0xc5, 0x92,
- 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
- 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30,
- 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
- 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
- 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
- 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
- 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
- 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e,
- 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
- 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
- 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e,
- 0x17, 0x0d, 0x31, 0x32, 0x30, 0x34, 0x30, 0x36,
- 0x31, 0x37, 0x31, 0x30, 0x31, 0x33, 0x5a, 0x17,
- 0x0d, 0x31, 0x35, 0x30, 0x34, 0x30, 0x36, 0x31,
- 0x37, 0x31, 0x30, 0x31, 0x33, 0x5a, 0x30, 0x45,
- 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
- 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30,
- 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a,
- 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61,
- 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
- 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74,
- 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69,
- 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74,
- 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x5c, 0x30,
- 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b,
- 0x00, 0x30, 0x48, 0x02, 0x41, 0x00, 0x9f, 0xb3,
- 0xc3, 0x84, 0x27, 0x95, 0xff, 0x12, 0x31, 0x52,
- 0x0f, 0x15, 0xef, 0x46, 0x11, 0xc4, 0xad, 0x80,
- 0xe6, 0x36, 0x5b, 0x0f, 0xdd, 0x80, 0xd7, 0x61,
- 0x8d, 0xe0, 0xfc, 0x72, 0x45, 0x09, 0x34, 0xfe,
- 0x55, 0x66, 0x45, 0x43, 0x4c, 0x68, 0x97, 0x6a,
- 0xfe, 0xa8, 0xa0, 0xa5, 0xdf, 0x5f, 0x78, 0xff,
- 0xee, 0xd7, 0x64, 0xb8, 0x3f, 0x04, 0xcb, 0x6f,
- 0xff, 0x2a, 0xfe, 0xfe, 0xb9, 0xed, 0x02, 0x03,
- 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
- 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
- 0x04, 0x16, 0x04, 0x14, 0x78, 0xa6, 0x97, 0x9a,
- 0x63, 0xb5, 0xc5, 0xa1, 0xa5, 0x33, 0xba, 0x22,
- 0x7c, 0x23, 0x6e, 0x5b, 0x1b, 0x7a, 0xcc, 0x2b,
- 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
- 0x6e, 0x30, 0x6c, 0x80, 0x14, 0x78, 0xa6, 0x97,
- 0x9a, 0x63, 0xb5, 0xc5, 0xa1, 0xa5, 0x33, 0xba,
- 0x22, 0x7c, 0x23, 0x6e, 0x5b, 0x1b, 0x7a, 0xcc,
- 0x2b, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0xb1,
- 0x35, 0x13, 0x65, 0x11, 0x20, 0xc5, 0x92, 0x30,
- 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
- 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x01, 0x05, 0x05, 0x00, 0x03, 0x41, 0x00, 0x85,
- 0x36, 0x40, 0x73, 0xc1, 0xbb, 0x1a, 0xda, 0xd4,
- 0x59, 0x9f, 0x2d, 0xa2, 0x70, 0x31, 0x46, 0x74,
- 0xec, 0x83, 0x6e, 0xa8, 0xc8, 0x3c, 0x51, 0xaf,
- 0x39, 0xac, 0xec, 0x40, 0xbc, 0xe8, 0x22, 0x46,
- 0x1d, 0x99, 0xd6, 0x46, 0x2a, 0x24, 0xd4, 0x8b,
- 0x05, 0x08, 0x4b, 0xfb, 0x35, 0x11, 0x6e, 0x92,
- 0xbb, 0x77, 0xba, 0xe4, 0x12, 0xbb, 0xf4, 0xc8,
- 0x5e, 0x9c, 0x81, 0xa8, 0x97, 0x60, 0x4c, 0x16,
- 0x03, 0x03, 0x00, 0x8d, 0x0c, 0x00, 0x00, 0x89,
- 0x03, 0x00, 0x17, 0x41, 0x04, 0xaa, 0xf0, 0x0c,
- 0xa3, 0x60, 0xcf, 0x69, 0x1e, 0xad, 0x16, 0x9a,
- 0x01, 0x40, 0xc6, 0x22, 0xc4, 0xbb, 0x06, 0x3b,
- 0x84, 0x65, 0xea, 0xc7, 0xa2, 0x96, 0x79, 0x17,
- 0x2f, 0xc7, 0xbe, 0x56, 0x39, 0xe4, 0x79, 0xf3,
- 0xad, 0x17, 0xf3, 0x7e, 0xe2, 0x7b, 0xa2, 0x6f,
- 0x3f, 0x96, 0xea, 0xe5, 0x0e, 0xea, 0x39, 0x79,
- 0x77, 0xeb, 0x14, 0x18, 0xbb, 0x7c, 0x95, 0xda,
- 0xa7, 0x51, 0x09, 0xba, 0xd7, 0x04, 0x01, 0x00,
- 0x40, 0x82, 0x3e, 0xce, 0xee, 0x7e, 0xba, 0x3b,
- 0x51, 0xb1, 0xba, 0x71, 0x2e, 0x54, 0xa9, 0xb9,
- 0xe2, 0xb1, 0x59, 0x17, 0xa1, 0xac, 0x76, 0xb4,
- 0x4e, 0xf1, 0xae, 0x65, 0x17, 0x2b, 0x43, 0x06,
- 0x31, 0x29, 0x0b, 0xa0, 0x1e, 0xb6, 0xfa, 0x35,
- 0xe8, 0x63, 0x06, 0xde, 0x13, 0x89, 0x83, 0x69,
- 0x3b, 0xc2, 0x15, 0x73, 0x1c, 0xc5, 0x07, 0xe9,
- 0x38, 0x9b, 0x06, 0x81, 0x1b, 0x97, 0x7c, 0xa6,
- 0x89, 0x16, 0x03, 0x03, 0x00, 0x30, 0x0d, 0x00,
- 0x00, 0x28, 0x03, 0x01, 0x02, 0x40, 0x00, 0x20,
- 0x06, 0x01, 0x06, 0x02, 0x06, 0x03, 0x05, 0x01,
- 0x05, 0x02, 0x05, 0x03, 0x04, 0x01, 0x04, 0x02,
- 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x03, 0x03,
- 0x02, 0x01, 0x02, 0x02, 0x02, 0x03, 0x01, 0x01,
- 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
- },
- {
- 0x16, 0x03, 0x03, 0x0a, 0xfb, 0x0b, 0x00, 0x0a,
- 0xf7, 0x00, 0x0a, 0xf4, 0x00, 0x03, 0x7e, 0x30,
- 0x82, 0x03, 0x7a, 0x30, 0x82, 0x02, 0x62, 0x02,
- 0x09, 0x00, 0xb4, 0x47, 0x58, 0x57, 0x2b, 0x67,
- 0xc8, 0xc2, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05,
- 0x00, 0x30, 0x81, 0x80, 0x31, 0x0b, 0x30, 0x09,
- 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
- 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
- 0x04, 0x08, 0x0c, 0x02, 0x4e, 0x59, 0x31, 0x11,
- 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c,
- 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b, 0x6c, 0x79,
- 0x6e, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x0c, 0x0c, 0x4d, 0x79, 0x20, 0x43,
- 0x41, 0x20, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74,
- 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
- 0x03, 0x0c, 0x0e, 0x6d, 0x79, 0x63, 0x61, 0x63,
- 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x6f,
- 0x6d, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01,
- 0x16, 0x12, 0x6a, 0x76, 0x73, 0x68, 0x61, 0x68,
- 0x69, 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c,
- 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d,
- 0x31, 0x33, 0x30, 0x35, 0x32, 0x36, 0x32, 0x31,
- 0x34, 0x34, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31,
- 0x33, 0x30, 0x36, 0x32, 0x35, 0x32, 0x31, 0x34,
- 0x34, 0x30, 0x30, 0x5a, 0x30, 0x7d, 0x31, 0x0b,
- 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
- 0x02, 0x55, 0x53, 0x31, 0x11, 0x30, 0x0f, 0x06,
- 0x03, 0x55, 0x04, 0x08, 0x0c, 0x08, 0x4e, 0x65,
- 0x77, 0x20, 0x59, 0x6f, 0x72, 0x6b, 0x31, 0x11,
- 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c,
- 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b, 0x6c, 0x79,
- 0x6e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x0c, 0x07, 0x4d, 0x79, 0x20, 0x4c,
- 0x65, 0x61, 0x66, 0x31, 0x13, 0x30, 0x11, 0x06,
- 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0a, 0x6d, 0x79,
- 0x6c, 0x65, 0x61, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
- 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16,
- 0x12, 0x6a, 0x76, 0x73, 0x68, 0x61, 0x68, 0x69,
- 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e,
- 0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22, 0x30,
- 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82,
- 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02,
- 0x82, 0x01, 0x01, 0x00, 0xa0, 0xa3, 0xef, 0xc1,
- 0x44, 0x7d, 0xa2, 0xe3, 0x71, 0x98, 0x27, 0x63,
- 0xb3, 0x1d, 0x71, 0x50, 0xa6, 0x34, 0x15, 0xcb,
- 0xc9, 0x2a, 0xc3, 0xea, 0xe4, 0x9e, 0x9c, 0x49,
- 0xa6, 0x01, 0x9b, 0x7e, 0xa9, 0xb5, 0x7a, 0xff,
- 0x15, 0x92, 0x71, 0xc8, 0x97, 0x9c, 0x25, 0xb7,
- 0x79, 0x2b, 0xff, 0xab, 0xc6, 0xb1, 0xa7, 0x00,
- 0x90, 0xb2, 0x8b, 0xd7, 0x71, 0xd5, 0xc2, 0x3a,
- 0xe6, 0x82, 0x42, 0x37, 0x89, 0x41, 0x04, 0xb0,
- 0xba, 0xc7, 0x5b, 0x8a, 0x43, 0x9f, 0x97, 0x39,
- 0x0c, 0x0f, 0xd5, 0x6d, 0x9e, 0x8d, 0xeb, 0xc0,
- 0x26, 0xc5, 0x18, 0xe8, 0x7a, 0x3d, 0x32, 0x2e,
- 0x38, 0x90, 0x40, 0x5b, 0x39, 0x2c, 0x07, 0xcb,
- 0x24, 0x10, 0xc5, 0xc9, 0x3b, 0xe3, 0x66, 0x47,
- 0x57, 0xb9, 0x6a, 0xad, 0x44, 0xf8, 0xd0, 0x70,
- 0x62, 0x3b, 0x8e, 0xed, 0x60, 0x5f, 0x22, 0xf8,
- 0xb8, 0x0c, 0xc9, 0x41, 0x2b, 0xc9, 0x80, 0x6e,
- 0x4e, 0x1b, 0xe1, 0x20, 0xfc, 0x47, 0xa4, 0xac,
- 0xc3, 0x3f, 0xe6, 0xc2, 0x81, 0x79, 0x03, 0x37,
- 0x25, 0x89, 0xca, 0xd6, 0xa5, 0x46, 0x91, 0x63,
- 0x41, 0xc5, 0x3e, 0xd5, 0xed, 0x7f, 0x4f, 0x8d,
- 0x06, 0xc0, 0x89, 0x00, 0xbe, 0x37, 0x7b, 0x7e,
- 0x73, 0xca, 0x70, 0x00, 0x14, 0x34, 0xbe, 0x47,
- 0xbc, 0xb2, 0x6a, 0x28, 0xa5, 0x29, 0x84, 0xa8,
- 0x9d, 0xc8, 0x1e, 0x77, 0x66, 0x1f, 0x9f, 0xaa,
- 0x2b, 0x47, 0xdb, 0xdd, 0x6b, 0x9c, 0xa8, 0xfc,
- 0x82, 0x36, 0x94, 0x62, 0x0d, 0x5c, 0x3f, 0xb2,
- 0x01, 0xb4, 0xa5, 0xb8, 0xc6, 0x0e, 0x94, 0x5b,
- 0xec, 0x5e, 0xbb, 0x7a, 0x63, 0x24, 0xf1, 0xf9,
- 0xd6, 0x50, 0x08, 0xc1, 0xa3, 0xcc, 0x90, 0x07,
- 0x5b, 0x04, 0x04, 0x42, 0x74, 0xcf, 0x37, 0xfa,
- 0xf0, 0xa5, 0xd9, 0xd3, 0x86, 0x89, 0x89, 0x18,
- 0xf3, 0x4c, 0xe2, 0x11, 0x02, 0x03, 0x01, 0x00,
- 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
- 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00,
- 0x03, 0x82, 0x01, 0x01, 0x00, 0x90, 0xbb, 0xf9,
- 0x5e, 0xba, 0x17, 0x1f, 0xac, 0x21, 0x9f, 0x6b,
- 0x4a, 0x46, 0xd0, 0x6d, 0x3c, 0x8f, 0x3d, 0xf8,
- 0x5e, 0x3e, 0x72, 0xaf, 0xa0, 0x1a, 0xf3, 0xff,
- 0x89, 0xac, 0x5b, 0x7a, 0xe2, 0x91, 0x2a, 0x23,
- 0x85, 0xc6, 0x4d, 0x47, 0x67, 0x01, 0x08, 0xa8,
- 0x05, 0x1d, 0x01, 0x60, 0x50, 0x5f, 0x59, 0xad,
- 0xfe, 0x7b, 0xc6, 0x0c, 0x54, 0x90, 0x68, 0x70,
- 0x67, 0x2e, 0xed, 0x87, 0xf8, 0x69, 0x8a, 0xac,
- 0x32, 0xfe, 0x6f, 0x90, 0x19, 0x2a, 0x64, 0x8d,
- 0x82, 0x66, 0x05, 0x43, 0x88, 0xee, 0xf2, 0x30,
- 0xed, 0xa4, 0x8f, 0xbf, 0xd6, 0x57, 0x20, 0xd4,
- 0x43, 0x1d, 0x52, 0x96, 0x6f, 0xae, 0x09, 0x96,
- 0x01, 0x52, 0x38, 0xe3, 0xaf, 0x99, 0xd7, 0xdc,
- 0x14, 0x99, 0xc4, 0x8b, 0x0e, 0x04, 0x0f, 0xb3,
- 0x14, 0x14, 0xd4, 0xa5, 0x93, 0xe1, 0xc9, 0x8a,
- 0x81, 0xef, 0x63, 0xfc, 0x36, 0x77, 0x05, 0x06,
- 0xf0, 0x2a, 0x04, 0x0a, 0xbe, 0x2e, 0xce, 0x81,
- 0x3d, 0x23, 0xa1, 0xda, 0xd8, 0xeb, 0xc6, 0xea,
- 0x5e, 0xcf, 0x28, 0x36, 0x51, 0x31, 0x95, 0x5e,
- 0x40, 0x04, 0xed, 0xac, 0xc1, 0xc8, 0x56, 0x69,
- 0x87, 0xec, 0x3b, 0x03, 0x3e, 0x9d, 0x0f, 0x4c,
- 0x4c, 0xeb, 0xd7, 0xba, 0x26, 0xdf, 0xe3, 0xde,
- 0x10, 0xee, 0x93, 0x62, 0x8d, 0x73, 0x52, 0x6e,
- 0xff, 0x37, 0x36, 0x98, 0x7b, 0x2d, 0x56, 0x4c,
- 0xba, 0x09, 0xb8, 0xa7, 0xf0, 0x3b, 0x16, 0x81,
- 0xca, 0xdb, 0x43, 0xab, 0xec, 0x4c, 0x6e, 0x7c,
- 0xc1, 0x0b, 0x22, 0x22, 0x43, 0x1d, 0xb6, 0x0c,
- 0xc1, 0xb9, 0xcf, 0xe4, 0x53, 0xee, 0x1d, 0x3e,
- 0x88, 0xa7, 0x13, 0xbe, 0x7f, 0xbd, 0xae, 0x72,
- 0xcf, 0xcd, 0x63, 0xd2, 0xc3, 0x18, 0x58, 0x92,
- 0xa2, 0xad, 0xb5, 0x09, 0x9d, 0x91, 0x03, 0xdd,
- 0x3c, 0xe2, 0x1c, 0xde, 0x78, 0x00, 0x03, 0x88,
- 0x30, 0x82, 0x03, 0x84, 0x30, 0x82, 0x02, 0x6c,
- 0x02, 0x09, 0x00, 0xab, 0xed, 0xa6, 0xe4, 0x4a,
- 0x2b, 0x2b, 0xf8, 0x30, 0x0d, 0x06, 0x09, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
- 0x05, 0x00, 0x30, 0x81, 0x86, 0x31, 0x0b, 0x30,
- 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
- 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
- 0x55, 0x04, 0x08, 0x0c, 0x02, 0x4e, 0x59, 0x31,
- 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07,
- 0x0c, 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b, 0x6c,
- 0x79, 0x6e, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
- 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x4d, 0x79, 0x20,
- 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
- 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68,
- 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x11, 0x30,
- 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
- 0x6d, 0x79, 0x63, 0x61, 0x2e, 0x6f, 0x72, 0x67,
- 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16,
- 0x12, 0x6a, 0x76, 0x73, 0x68, 0x61, 0x68, 0x69,
- 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e,
- 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x31,
- 0x33, 0x30, 0x35, 0x32, 0x36, 0x32, 0x31, 0x31,
- 0x38, 0x34, 0x30, 0x5a, 0x17, 0x0d, 0x31, 0x33,
- 0x30, 0x36, 0x32, 0x35, 0x32, 0x31, 0x31, 0x38,
- 0x34, 0x30, 0x5a, 0x30, 0x81, 0x80, 0x31, 0x0b,
- 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
- 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06,
- 0x03, 0x55, 0x04, 0x08, 0x0c, 0x02, 0x4e, 0x59,
- 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
- 0x07, 0x0c, 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b,
- 0x6c, 0x79, 0x6e, 0x31, 0x15, 0x30, 0x13, 0x06,
- 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0c, 0x4d, 0x79,
- 0x20, 0x43, 0x41, 0x20, 0x43, 0x6c, 0x69, 0x65,
- 0x6e, 0x74, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03,
- 0x55, 0x04, 0x03, 0x0c, 0x0e, 0x6d, 0x79, 0x63,
- 0x61, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e,
- 0x63, 0x6f, 0x6d, 0x31, 0x21, 0x30, 0x1f, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x09, 0x01, 0x16, 0x12, 0x6a, 0x76, 0x73, 0x68,
- 0x61, 0x68, 0x69, 0x64, 0x40, 0x67, 0x6d, 0x61,
- 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82,
- 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
- 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82,
- 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xce,
- 0x13, 0xf0, 0x72, 0xb0, 0x61, 0xc8, 0x18, 0x37,
- 0x8a, 0x41, 0x3d, 0x20, 0xa1, 0x1c, 0xcb, 0xbf,
- 0xf6, 0x3b, 0x74, 0x26, 0x2a, 0x96, 0x11, 0xec,
- 0x53, 0xa1, 0xcc, 0x7d, 0x77, 0x56, 0x45, 0x0f,
- 0x36, 0xb7, 0xf2, 0x48, 0x92, 0x1a, 0x62, 0xcc,
- 0xb6, 0xc0, 0xa1, 0x2f, 0x44, 0x2b, 0xc1, 0x89,
- 0xcb, 0x6e, 0x1e, 0xdb, 0x57, 0x92, 0xd5, 0x97,
- 0x60, 0x8c, 0x41, 0x2c, 0xd9, 0x20, 0xfe, 0xe9,
- 0x1f, 0x8e, 0xfc, 0x7f, 0x02, 0x44, 0x0f, 0x28,
- 0x81, 0xd6, 0x0c, 0xcd, 0xbc, 0xf0, 0x57, 0x6c,
- 0xcc, 0xa7, 0xba, 0x06, 0xa0, 0xa6, 0x91, 0xda,
- 0xef, 0x46, 0x8a, 0x60, 0x0f, 0x52, 0x6c, 0x90,
- 0x6c, 0x8c, 0x44, 0xaf, 0xb0, 0x9d, 0x90, 0xba,
- 0x21, 0x58, 0xa0, 0x3c, 0xee, 0x54, 0xb5, 0x29,
- 0x26, 0x1f, 0x0a, 0xac, 0xef, 0x48, 0x68, 0x33,
- 0xd0, 0x33, 0xd0, 0x8b, 0x1a, 0xec, 0x6e, 0x2f,
- 0xb5, 0x4a, 0x53, 0xc2, 0x1a, 0xd2, 0xf1, 0x50,
- 0x05, 0x59, 0x5c, 0xd9, 0xda, 0x03, 0x0a, 0x47,
- 0xb7, 0xdd, 0xf7, 0x3a, 0x69, 0xf5, 0x4e, 0xea,
- 0x4a, 0xc2, 0xca, 0x54, 0xb0, 0x8b, 0x76, 0xe1,
- 0x02, 0x2d, 0x52, 0x67, 0xb9, 0xdd, 0x50, 0xc9,
- 0x3b, 0x07, 0x24, 0x22, 0x6a, 0x00, 0x1d, 0x58,
- 0x83, 0xa8, 0xec, 0x95, 0xf1, 0xda, 0xe2, 0x73,
- 0xa0, 0xa1, 0x72, 0x60, 0x9e, 0x86, 0x53, 0xcb,
- 0x45, 0xa8, 0xc2, 0xa0, 0x50, 0xa0, 0x53, 0xd6,
- 0xfc, 0x18, 0x84, 0xb5, 0x4a, 0x26, 0xd0, 0xa2,
- 0xaa, 0xd0, 0xff, 0xb6, 0xfe, 0x3a, 0x9c, 0xb5,
- 0x19, 0x3b, 0x3f, 0xe1, 0x48, 0x0d, 0xa4, 0x09,
- 0x4f, 0x83, 0xc9, 0xc0, 0xc9, 0xa6, 0x0b, 0x58,
- 0x1f, 0x1c, 0x7b, 0xac, 0xa2, 0x42, 0xbc, 0x61,
- 0xf4, 0x21, 0x8a, 0x00, 0xda, 0x14, 0xa0, 0x60,
- 0x03, 0xfe, 0x93, 0x12, 0x6c, 0x56, 0xcd, 0x02,
- 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
- 0x25, 0x29, 0x3b, 0x1e, 0xc3, 0x58, 0x32, 0xe6,
- 0x23, 0xc8, 0xee, 0x18, 0xf0, 0x1d, 0x62, 0x6d,
- 0x3b, 0x59, 0x99, 0x3a, 0xfe, 0x49, 0x72, 0x07,
- 0x3f, 0x58, 0x93, 0xdb, 0xc0, 0xaf, 0xb0, 0xb3,
- 0x5c, 0xd1, 0x5c, 0x98, 0xc8, 0xea, 0x4a, 0xe4,
- 0x58, 0x73, 0x0d, 0x57, 0xc5, 0x13, 0x7c, 0x5c,
- 0x79, 0x66, 0xda, 0x04, 0x1d, 0xe5, 0x98, 0xda,
- 0x35, 0x47, 0x44, 0xb0, 0xd2, 0x7a, 0x66, 0x9d,
- 0xcd, 0x41, 0xa5, 0x8f, 0xa1, 0x11, 0xb2, 0x1a,
- 0x87, 0xc0, 0xcd, 0x55, 0xed, 0xb4, 0x7b, 0x33,
- 0x72, 0xeb, 0xf7, 0xe3, 0x7b, 0x8b, 0x02, 0x86,
- 0xe9, 0x2b, 0x26, 0x32, 0x9f, 0x99, 0xf1, 0xcb,
- 0x93, 0xab, 0xb9, 0x16, 0xb3, 0x9a, 0xb2, 0x22,
- 0x13, 0x21, 0x1f, 0x5b, 0xcc, 0xa2, 0x59, 0xbb,
- 0x69, 0xf2, 0xb8, 0x07, 0x80, 0xce, 0x0c, 0xf7,
- 0x98, 0x4c, 0x85, 0xc2, 0x96, 0x6a, 0x22, 0x05,
- 0xe9, 0xbe, 0x48, 0xb0, 0x02, 0x5b, 0x69, 0x28,
- 0x18, 0x88, 0x96, 0xe3, 0xd7, 0xc6, 0x7a, 0xd3,
- 0xe9, 0x99, 0xff, 0x9d, 0xc3, 0x61, 0x4d, 0x9a,
- 0x96, 0xf2, 0xc6, 0x33, 0x4d, 0xe5, 0x5d, 0x5a,
- 0x68, 0x64, 0x5a, 0x82, 0x35, 0x65, 0x25, 0xe3,
- 0x8c, 0x5b, 0xb0, 0xf6, 0x96, 0x56, 0xbc, 0xbf,
- 0x97, 0x76, 0x4b, 0x66, 0x44, 0x81, 0xa4, 0xc4,
- 0xa7, 0x31, 0xc5, 0xa1, 0x4f, 0xe8, 0xa4, 0xca,
- 0x20, 0xf5, 0x01, 0x5b, 0x99, 0x4f, 0x5a, 0xf4,
- 0xf0, 0x78, 0xbf, 0x71, 0x49, 0xd5, 0xf1, 0xc1,
- 0xa2, 0x18, 0xfd, 0x72, 0x5b, 0x16, 0xe8, 0x92,
- 0xc7, 0x37, 0x48, 0xaf, 0xee, 0x24, 0xfc, 0x35,
- 0x0b, 0xc2, 0xdd, 0x05, 0xc7, 0x6e, 0xa3, 0x29,
- 0xbb, 0x29, 0x7d, 0xd3, 0x2b, 0x94, 0x80, 0xc3,
- 0x40, 0x53, 0x0e, 0x03, 0x54, 0x3d, 0x7b, 0x8b,
- 0xce, 0xf9, 0xa4, 0x03, 0x27, 0x63, 0xec, 0x51,
- 0x00, 0x03, 0xe5, 0x30, 0x82, 0x03, 0xe1, 0x30,
- 0x82, 0x02, 0xc9, 0xa0, 0x03, 0x02, 0x01, 0x02,
- 0x02, 0x09, 0x00, 0xcc, 0x22, 0x4c, 0x4b, 0x98,
- 0xa2, 0x88, 0xfc, 0x30, 0x0d, 0x06, 0x09, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
- 0x05, 0x00, 0x30, 0x81, 0x86, 0x31, 0x0b, 0x30,
- 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
- 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
- 0x55, 0x04, 0x08, 0x0c, 0x02, 0x4e, 0x59, 0x31,
- 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07,
- 0x0c, 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b, 0x6c,
- 0x79, 0x6e, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
- 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x4d, 0x79, 0x20,
- 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
- 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68,
- 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x11, 0x30,
- 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
- 0x6d, 0x79, 0x63, 0x61, 0x2e, 0x6f, 0x72, 0x67,
- 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16,
- 0x12, 0x6a, 0x76, 0x73, 0x68, 0x61, 0x68, 0x69,
- 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e,
- 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x31,
- 0x33, 0x30, 0x35, 0x32, 0x36, 0x32, 0x31, 0x30,
- 0x35, 0x30, 0x31, 0x5a, 0x17, 0x0d, 0x32, 0x33,
- 0x30, 0x35, 0x32, 0x34, 0x32, 0x31, 0x30, 0x35,
- 0x30, 0x31, 0x5a, 0x30, 0x81, 0x86, 0x31, 0x0b,
- 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
- 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06,
- 0x03, 0x55, 0x04, 0x08, 0x0c, 0x02, 0x4e, 0x59,
- 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
- 0x07, 0x0c, 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b,
- 0x6c, 0x79, 0x6e, 0x31, 0x21, 0x30, 0x1f, 0x06,
- 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x4d, 0x79,
- 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
- 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74,
- 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x11,
- 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
- 0x08, 0x6d, 0x79, 0x63, 0x61, 0x2e, 0x6f, 0x72,
- 0x67, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01,
- 0x16, 0x12, 0x6a, 0x76, 0x73, 0x68, 0x61, 0x68,
- 0x69, 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c,
- 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22,
- 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
- 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
- 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
- 0x02, 0x82, 0x01, 0x01, 0x00, 0xf0, 0xfb, 0xad,
- 0x80, 0x5e, 0x37, 0xd3, 0x6d, 0xee, 0x2e, 0xcc,
- 0xbc, 0x0c, 0xd7, 0x56, 0x4b, 0x56, 0x45, 0xcd,
- 0x28, 0xb6, 0x22, 0xe9, 0xe2, 0x0f, 0xd1, 0x87,
- 0x2a, 0x27, 0xce, 0x77, 0x8d, 0x6e, 0x0e, 0x0f,
- 0xfb, 0x66, 0xe1, 0xb5, 0x0e, 0x9a, 0xb6, 0x05,
- 0x8e, 0xb3, 0xe1, 0xc5, 0x77, 0x86, 0x5b, 0x46,
- 0xd2, 0x0b, 0x92, 0x03, 0x1b, 0x89, 0x0c, 0x1b,
- 0x10, 0x0e, 0x99, 0x8f, 0xe2, 0x17, 0xe8, 0xc2,
- 0x30, 0x00, 0x47, 0xd6, 0xfc, 0xf9, 0x0f, 0x3b,
- 0x75, 0x34, 0x8d, 0x4d, 0xb0, 0x99, 0xb7, 0xa0,
- 0x6d, 0xa0, 0xb6, 0xad, 0xda, 0x07, 0x5e, 0x38,
- 0x2e, 0x02, 0xe4, 0x30, 0x6d, 0xae, 0x13, 0x72,
- 0xd4, 0xc8, 0xce, 0x14, 0x07, 0xae, 0x23, 0x8c,
- 0x8f, 0x9e, 0x8c, 0x60, 0xd6, 0x06, 0xb9, 0xef,
- 0x00, 0x18, 0xc0, 0x1d, 0x25, 0x1e, 0xda, 0x3e,
- 0x2f, 0xcf, 0x2b, 0x56, 0x84, 0x9e, 0x30, 0x21,
- 0xc7, 0x29, 0xf6, 0x03, 0x8a, 0x24, 0xf9, 0x34,
- 0xac, 0x65, 0x9d, 0x80, 0x36, 0xc8, 0x3b, 0x15,
- 0x10, 0xbd, 0x51, 0xe9, 0xbc, 0x02, 0xe1, 0xe9,
- 0xb3, 0x5a, 0x9a, 0x99, 0x41, 0x1b, 0x27, 0xa0,
- 0x4d, 0x50, 0x9e, 0x27, 0x7f, 0xa1, 0x7d, 0x09,
- 0x87, 0xbd, 0x8a, 0xca, 0x5f, 0xb1, 0xa5, 0x08,
- 0xb8, 0x04, 0xd4, 0x52, 0x89, 0xaa, 0xe0, 0x7d,
- 0x42, 0x2e, 0x2f, 0x15, 0xee, 0x66, 0x57, 0x0f,
- 0x13, 0x19, 0x45, 0xa8, 0x4b, 0x5d, 0x81, 0x66,
- 0xcc, 0x12, 0x37, 0x94, 0x5e, 0xfd, 0x3c, 0x10,
- 0x81, 0x51, 0x3f, 0xfa, 0x0f, 0xdd, 0xa1, 0x89,
- 0x03, 0xa9, 0x78, 0x91, 0xf5, 0x3b, 0xf3, 0xbc,
- 0xac, 0xbe, 0x93, 0x30, 0x2e, 0xbe, 0xca, 0x7f,
- 0x46, 0xd3, 0x28, 0xb4, 0x4e, 0x91, 0x7b, 0x5b,
- 0x43, 0x6c, 0xaf, 0x9b, 0x5c, 0x6a, 0x6d, 0x5a,
- 0xdb, 0x79, 0x5e, 0x6a, 0x6b, 0x02, 0x03, 0x01,
- 0x00, 0x01, 0xa3, 0x50, 0x30, 0x4e, 0x30, 0x1d,
- 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
- 0x14, 0x6b, 0x1e, 0x00, 0xa8, 0x9f, 0xfa, 0x7d,
- 0x00, 0xf9, 0xe0, 0x9d, 0x0f, 0x90, 0x8c, 0x90,
- 0xa8, 0xa1, 0x37, 0x6b, 0xda, 0x30, 0x1f, 0x06,
- 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
- 0x80, 0x14, 0x6b, 0x1e, 0x00, 0xa8, 0x9f, 0xfa,
- 0x7d, 0x00, 0xf9, 0xe0, 0x9d, 0x0f, 0x90, 0x8c,
- 0x90, 0xa8, 0xa1, 0x37, 0x6b, 0xda, 0x30, 0x0c,
- 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30,
- 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
- 0xcd, 0x6f, 0x73, 0x4d, 0x56, 0x0b, 0xf3, 0x2e,
- 0x1c, 0xe2, 0x02, 0x0c, 0x14, 0xbb, 0x2f, 0xdd,
- 0x3c, 0x43, 0xfe, 0xdf, 0x94, 0x2d, 0xa9, 0x89,
- 0x81, 0x51, 0xf8, 0x5f, 0xa7, 0xa0, 0x13, 0xaa,
- 0xcc, 0xb0, 0x18, 0xe2, 0x57, 0x3e, 0x0d, 0x29,
- 0x93, 0xe8, 0x95, 0xd5, 0x1b, 0x53, 0xd2, 0x51,
- 0xf2, 0xbd, 0xf5, 0x9e, 0x7b, 0x22, 0x65, 0x62,
- 0x5c, 0xc4, 0x4c, 0x1d, 0xe8, 0xe9, 0xc3, 0xd4,
- 0x2b, 0xe7, 0x78, 0xcb, 0x10, 0xf3, 0xfe, 0x06,
- 0x83, 0xdc, 0x3a, 0x1e, 0x62, 0x10, 0xc0, 0x46,
- 0x77, 0xc6, 0x9d, 0x9f, 0xab, 0x96, 0x25, 0x5c,
- 0xfb, 0x26, 0xc1, 0x15, 0x1f, 0xa5, 0x33, 0xee,
- 0x4f, 0x9a, 0x14, 0x6a, 0x14, 0x97, 0x93, 0x2b,
- 0x95, 0x0b, 0xdc, 0xa8, 0xd7, 0x69, 0x2e, 0xf0,
- 0x01, 0x0e, 0xfd, 0x4e, 0xd0, 0xd9, 0xa8, 0xe5,
- 0x65, 0xde, 0xfb, 0xca, 0xca, 0x1c, 0x5f, 0xf9,
- 0x53, 0xa0, 0x87, 0xe7, 0x33, 0x9b, 0x2f, 0xcf,
- 0xe4, 0x13, 0xfc, 0xec, 0x7a, 0x6c, 0xb0, 0x90,
- 0x13, 0x9b, 0xb6, 0xc5, 0x03, 0xf6, 0x0e, 0x5e,
- 0xe2, 0xe4, 0x26, 0xc1, 0x7e, 0x53, 0xfe, 0x69,
- 0xa3, 0xc7, 0xd8, 0x8e, 0x6e, 0x94, 0x32, 0xa0,
- 0xde, 0xca, 0xb6, 0xcc, 0xd6, 0x01, 0xd5, 0x78,
- 0x40, 0x28, 0x63, 0x9b, 0xee, 0xcf, 0x09, 0x3b,
- 0x35, 0x04, 0xf0, 0x14, 0x02, 0xf6, 0x80, 0x0e,
- 0x90, 0xb2, 0x94, 0xd2, 0x25, 0x16, 0xb8, 0x7a,
- 0x76, 0x87, 0x84, 0x9f, 0x84, 0xc5, 0xaf, 0xc2,
- 0x6d, 0x68, 0x7a, 0x84, 0x9c, 0xc6, 0x8a, 0x63,
- 0x60, 0x87, 0x6a, 0x25, 0xc1, 0xa1, 0x78, 0x0f,
- 0xba, 0xe8, 0x5f, 0xe1, 0xba, 0xac, 0xa4, 0x6f,
- 0xdd, 0x09, 0x3f, 0x12, 0xcb, 0x1d, 0xf3, 0xcf,
- 0x48, 0xd7, 0xd3, 0x26, 0xe8, 0x9c, 0xc3, 0x53,
- 0xb3, 0xba, 0xdc, 0x32, 0x99, 0x98, 0x96, 0xd6,
- 0x16, 0x03, 0x03, 0x00, 0x46, 0x10, 0x00, 0x00,
- 0x42, 0x41, 0x04, 0x1e, 0x18, 0x37, 0xef, 0x0d,
- 0x19, 0x51, 0x88, 0x35, 0x75, 0x71, 0xb5, 0xe5,
- 0x54, 0x5b, 0x12, 0x2e, 0x8f, 0x09, 0x67, 0xfd,
- 0xa7, 0x24, 0x20, 0x3e, 0xb2, 0x56, 0x1c, 0xce,
- 0x97, 0x28, 0x5e, 0xf8, 0x2b, 0x2d, 0x4f, 0x9e,
- 0xf1, 0x07, 0x9f, 0x6c, 0x4b, 0x5b, 0x83, 0x56,
- 0xe2, 0x32, 0x42, 0xe9, 0x58, 0xb6, 0xd7, 0x49,
- 0xa6, 0xb5, 0x68, 0x1a, 0x41, 0x03, 0x56, 0x6b,
- 0xdc, 0x5a, 0x89, 0x16, 0x03, 0x03, 0x01, 0x08,
- 0x0f, 0x00, 0x01, 0x04, 0x04, 0x01, 0x01, 0x00,
- 0x7e, 0xe4, 0x65, 0x02, 0x8e, 0xb3, 0x34, 0x6a,
- 0x47, 0x71, 0xd1, 0xb0, 0x8d, 0x3c, 0x0c, 0xe1,
- 0xde, 0x7e, 0x5f, 0xb4, 0x15, 0x2d, 0x32, 0x0a,
- 0x2a, 0xdb, 0x9b, 0x40, 0xba, 0xce, 0x8b, 0xf5,
- 0x74, 0xc1, 0x68, 0x20, 0x7c, 0x87, 0x23, 0x13,
- 0xc3, 0x13, 0xa7, 0xdb, 0xec, 0x59, 0xa0, 0x40,
- 0x9e, 0x64, 0x03, 0x60, 0xac, 0x76, 0xff, 0x01,
- 0x34, 0x7b, 0x32, 0x26, 0xd9, 0x41, 0x31, 0x93,
- 0xaa, 0x30, 0x51, 0x83, 0x85, 0x40, 0xeb, 0x4e,
- 0x66, 0x39, 0x83, 0xb1, 0x30, 0x0d, 0x96, 0x01,
- 0xee, 0x81, 0x53, 0x5e, 0xec, 0xa9, 0xc9, 0xdf,
- 0x7e, 0xc1, 0x09, 0x47, 0x8b, 0x35, 0xdb, 0x10,
- 0x15, 0xd4, 0xc7, 0x5a, 0x39, 0xe3, 0xc0, 0xf3,
- 0x93, 0x38, 0x11, 0xdc, 0x71, 0xbb, 0xc7, 0x62,
- 0x2b, 0x85, 0xad, 0x6b, 0x4f, 0x09, 0xb3, 0x31,
- 0xa8, 0xe5, 0xd1, 0xb3, 0xa9, 0x21, 0x37, 0x50,
- 0xc8, 0x7d, 0xc3, 0xd2, 0xf7, 0x00, 0xd3, 0xdb,
- 0x0f, 0x82, 0xf2, 0x43, 0xcf, 0x36, 0x6c, 0x98,
- 0x63, 0xd8, 0x1d, 0xb3, 0xf3, 0xde, 0x63, 0x79,
- 0x64, 0xf0, 0xdb, 0x46, 0x04, 0xe1, 0x1c, 0x57,
- 0x0f, 0x9e, 0x96, 0xb9, 0x93, 0x45, 0x71, 0x1c,
- 0x8b, 0x65, 0x7d, 0x1e, 0xad, 0xbd, 0x03, 0x51,
- 0xae, 0x44, 0xef, 0x97, 0x45, 0x0d, 0x8d, 0x41,
- 0x5c, 0x80, 0x7b, 0xe6, 0xe0, 0xbc, 0xa6, 0x72,
- 0x95, 0xa0, 0x97, 0xe1, 0xbb, 0xc0, 0xcc, 0xe5,
- 0x1e, 0xc3, 0xbe, 0xd7, 0x42, 0x2a, 0xf3, 0x75,
- 0x8a, 0x44, 0x67, 0x3c, 0xe5, 0x68, 0x78, 0xe5,
- 0x40, 0x1f, 0xf0, 0x89, 0x57, 0xda, 0xee, 0x45,
- 0xf4, 0x44, 0x81, 0x01, 0x77, 0xf0, 0x4a, 0x14,
- 0xb1, 0x3f, 0x60, 0x2b, 0xeb, 0x42, 0x38, 0xa6,
- 0xfb, 0xe5, 0x4d, 0x71, 0xdc, 0x7d, 0x0a, 0x72,
- 0x56, 0x28, 0x9d, 0xa6, 0x8e, 0x74, 0x2d, 0xbd,
- 0x14, 0x03, 0x03, 0x00, 0x01, 0x01, 0x16, 0x03,
- 0x03, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x31, 0x4d, 0x58, 0x94, 0x0b,
- 0x0b, 0x06, 0x5f, 0xae, 0x57, 0x17, 0x98, 0x86,
- 0xaa, 0x49, 0x17, 0x7f, 0xbd, 0x41, 0x05, 0xa5,
- 0x74, 0x1c, 0x58, 0xc8, 0x38, 0x2d, 0x99, 0x5d,
- 0xe5, 0x12, 0x43,
- },
- {
- 0x14, 0x03, 0x03, 0x00, 0x01, 0x01, 0x16, 0x03,
- 0x03, 0x00, 0x28, 0xf2, 0x60, 0xc2, 0x75, 0x27,
- 0x64, 0xf4, 0x05, 0x98, 0xc9, 0xd3, 0xa8, 0x00,
- 0x4c, 0xa0, 0x49, 0x82, 0x68, 0xf1, 0x21, 0x05,
- 0x7b, 0x4b, 0x25, 0x3e, 0xe1, 0x5f, 0x0f, 0x84,
- 0x26, 0x2d, 0x16, 0x2e, 0xc0, 0xfd, 0xdf, 0x0a,
- 0xf4, 0xba, 0x19,
- },
- {
- 0x17, 0x03, 0x03, 0x00, 0x1e, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x35, 0xef, 0x9d,
- 0x6a, 0x86, 0x98, 0xc5, 0xca, 0x55, 0xca, 0x89,
- 0x29, 0xb4, 0x55, 0xd4, 0x41, 0x08, 0x96, 0xe0,
- 0xf3, 0x39, 0xfc, 0x15, 0x03, 0x03, 0x00, 0x1a,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
- 0x02, 0x63, 0x1b, 0xaa, 0xc6, 0xc9, 0x6d, 0x72,
- 0x24, 0x10, 0x55, 0xa9, 0x8c, 0x3b, 0x23, 0xce,
- 0xd8, 0x4a,
- },
+ // Adding a nil entry is valid.
+ cache.Put(keys[0], nil)
+ if s, ok := cache.Get(keys[0]); !ok || s != nil {
+ t.Fatalf("failed to add nil entry to cache")
+ }
}
-var testClientChainCertificate = fromHex(
- "2d2d2d2d2d424547494e2050524956415445204b" +
- "45592d2d2d2d2d0a4d494945766749424144414e" +
- "42676b71686b6947397730424151454641415343" +
- "424b67776767536b41674541416f494241514367" +
- "6f2b2f4252483269343347590a4a324f7a485846" +
- "51706a515679386b71772b726b6e70784a706747" +
- "6266716d31657638566b6e48496c35776c74336b" +
- "722f367647736163416b4c4b4c313348560a776a" +
- "726d676b493369554545734c7248573470446e35" +
- "633544412f56625a364e3638416d78526a6f656a" +
- "30794c6a6951514673354c41664c4a4244467954" +
- "766a0a5a6b64587557717452506a51634749376a" +
- "75316758794c3475417a4a5153764a6747354f47" +
- "2b45672f45656b724d4d2f35734b4265514d334a" +
- "596e4b317156470a6b574e427854375637583950" +
- "6a5162416951432b4e33742b6338707741425130" +
- "766b6538736d6f6f70536d45714a3349486e646d" +
- "48352b714b306662335775630a715079434e7052" +
- "694456772f7367473070626a4744705262374636" +
- "37656d4d6b38666e5755416a426f387951423173" +
- "4542454a307a7a6636384b585a3034614a0a6952" +
- "6a7a544f495241674d424141454367674542414a" +
- "4b613676326b5a3144596146786e586d7369624c" +
- "386734426f67514c6a42307362524a6d746b6b4d" +
- "54370a685343325873537551522f446c654d7148" +
- "664555786731784a717579597643544d44585972" +
- "473667354a5051744d4432465a424a7239626c65" +
- "467138386c706a0a543766514e793571354c2b4f" +
- "682f6b62433835436e623641753641656978776d" +
- "2b6e77665a4f3766726b6278306d35516b715975" +
- "5739392f452b69502b454e570a76396a68773436" +
- "76515065563236494b79717656462b4f7362722f" +
- "6152316138707948336361566e3579594a433346" +
- "5855756c6f5a77516331714a6b4c434c4c0a375a" +
- "49744f525a78514c486d4d4a654d44722f5a4942" +
- "34675467645650636145375a4d5141714d6d3066" +
- "4c6b6d7671723149526b77642f6831455a645650" +
- "79320a742f6b6b43413039566336663749556575" +
- "6f67706d705a50303130564e376b6277394a6348" +
- "75544561564543675945417a47395679426e6d62" +
- "6858496c57764f0a71583747524f2f5231636a2b" +
- "6b564e35377876674b54756b35592b7a4d774a48" +
- "32626c57435945513251753974446c476854756b" +
- "664273385746772b6e6263460a7a6f706d535245" +
- "6c6d464d2f6141536d464733574e5a7072696a68" +
- "504b77726338376470636b31703131635a415478" +
- "5a413168566d43743457616343673634690a4d74" +
- "64507a334e2f34416147664956794d2b69624949" +
- "35332f515543675945417953693556735a356f6a" +
- "644a795077426e6c6142554231686f2b336b7068" +
- "70770a7264572b2b4d796b51494a345564534437" +
- "3052486e5a315839754359713978616671746c51" +
- "664c44395963442f436d665264706461586c5673" +
- "5249467a5a556c0a454630557149644e77337046" +
- "68634f4a6d6e5a3241434470434342476f763542" +
- "6e3068302b3137686a4b376f69315833716e4542" +
- "7857326c7462593476556a500a44394c5330666e" +
- "4a76703043675942504a527330714c4a4a464333" +
- "6669796b712f57574d38727474354b364a584b50" +
- "734b674b53644144577a7463316645434d0a7a65" +
- "2b394a6a5a376b4d77557063666a644c2b745047" +
- "3455563048326c524375635735414131396d7058" +
- "50367454494733713737655a6b416e65516f6163" +
- "41340a716c3073583051476c6a5763414e30464b" +
- "6f4759733975582b6378445a6e7265362f52392f" +
- "3930567766443237454c57546373677734633463" +
- "514b42675143420a6f5432326e745a5a59396d6e" +
- "72455a36752f492f4a332f35664e396737783733" +
- "3177746e463745745a5361575453587364597256" +
- "466b564f6362505135494a6f0a714a6a7249372b" +
- "474a4d69376f6a4c69642f4c45656f31764f3163" +
- "454158334f43723236554e38612f6c7434394f5a" +
- "69354c337348556b756c475951755671650a6737" +
- "6e6e4632437749544c34503645486443575a4461" +
- "7a4136626d7375524f2b6462536e335a6c567651" +
- "4b42674859524c5a665458536c44755264776977" +
- "746b0a513148546b6d6b57694156726c4f577864" +
- "5858456d546130303045574c46446145797a7358" +
- "7834424863357166776b5a4e746b634a56396e58" +
- "63536e647441530a35767a427a676e797a4f7962" +
- "68315878484a3966427472414f3847555878446c" +
- "6634394457616753393449763072596e616b7656" +
- "2f673039786875415763366e0a5365757230576b" +
- "5376453847666653734d485149584c456b0a2d2d" +
- "2d2d2d454e442050524956415445204b45592d2d" +
- "2d2d2d0a2d2d2d2d2d424547494e204345525449" +
- "4649434154452d2d2d2d2d0a4d494944656a4343" +
- "416d494343514330523168584b326649776a414e" +
- "42676b71686b6947397730424151554641444342" +
- "6744454c4d416b474131554542684d430a56564d" +
- "78437a414a42674e564241674d416b355a4d5245" +
- "77447759445651514844416843636d3976613278" +
- "35626a45564d424d47413155454367774d54586b" +
- "670a51304567513278705a5735304d5263774651" +
- "5944565151444441357465574e68593278705a57" +
- "35304c6d4e76625445684d423847435371475349" +
- "62334451454a0a41525953616e5a7a6147466f61" +
- "5752415a32316861577775593239744d42345844" +
- "54457a4d4455794e6a49784e4451774d466f5844" +
- "54457a4d4459794e5449780a4e4451774d466f77" +
- "6654454c4d416b474131554542684d4356564d78" +
- "4554415042674e564241674d4345356c6479425a" +
- "62334a724d52457744775944565151480a444168" +
- "43636d397661327835626a45514d413447413155" +
- "454367774854586b67544756685a6a45544d4245" +
- "47413155454177774b62586c735a57466d4c6d4e" +
- "760a625445684d42384743537147534962334451" +
- "454a41525953616e5a7a6147466f615752415a32" +
- "316861577775593239744d494942496a414e4267" +
- "6b71686b69470a397730424151454641414f4341" +
- "5138414d49494243674b43415145416f4b507677" +
- "5552396f754e786d43646a73783178554b593046" +
- "63764a4b735071354a36630a536159426d333670" +
- "7458722f465a4a78794a65634a6264354b2f2b72" +
- "7872476e414a43796939647831634936356f4a43" +
- "4e346c42424c43367831754b51352b580a4f5177" +
- "50315732656a6576414a73555936486f394d6934" +
- "346b4542624f5377487979515178636b3734325a" +
- "4856376c7172555434304842694f343774594638" +
- "690a2b4c674d7955457279594275546876684950" +
- "7848704b7a44502b624367586b444e79574a7974" +
- "616c5270466a5163552b3165312f543430477749" +
- "6b41766a64370a666e504b634141554e4c354876" +
- "4c4a714b4b5570684b6964794235335a682b6671" +
- "697448323931726e4b6a38676a61555967316350" +
- "374942744b5734786736550a572b78657533706a" +
- "4a504835316c41497761504d6b41646242415243" +
- "644d38332b76436c32644f4769596b5938307a69" +
- "45514944415141424d413047435371470a534962" +
- "3344514542425155414134494241514351752f6c" +
- "65756863667243476661307047304730386a7a33" +
- "34586a357972364161382f2b4a72467436347045" +
- "710a493458475455646e4151696f425230425946" +
- "42665761332b6538594d564a426f634763753759" +
- "6634615971734d7635766b426b715a4932435a67" +
- "5644694f37790a4d4f326b6a372f575679445551" +
- "7831536c6d2b75435a5942556a6a6a72356e5833" +
- "42535a7849734f42412b7a46425455705a506879" +
- "597142373250384e6e63460a427641714241712b" +
- "4c73364250534f6832746a72787570657a796732" +
- "55544756586b414537617a4279465a70682b7737" +
- "417a36644430784d363965364a742f6a0a336844" +
- "756b324b4e63314a752f7a63326d487374566b79" +
- "364362696e384473576763726251367673544735" +
- "3877517369496b4d6474677a4275632f6b552b34" +
- "640a506f696e4537352f766135797a38316a3073" +
- "4d59574a4b697262554a6e5a454433547a69484e" +
- "35340a2d2d2d2d2d454e44204345525449464943" +
- "4154452d2d2d2d2d0a2d2d2d2d2d424547494e20" +
- "43455254494649434154452d2d2d2d2d0a4d4949" +
- "4468444343416d7743435143723761626b536973" +
- "722b44414e42676b71686b694739773042415155" +
- "4641444342686a454c4d416b474131554542684d" +
- "430a56564d78437a414a42674e564241674d416b" +
- "355a4d524577447759445651514844416843636d" +
- "397661327835626a45684d423847413155454367" +
- "775954586b670a5132567964476c6d61574e6864" +
- "4755675158563061473979615852354d52457744" +
- "775944565151444441687465574e684c6d39795a" +
- "7a45684d423847435371470a534962334451454a" +
- "41525953616e5a7a6147466f615752415a323168" +
- "61577775593239744d4234584454457a4d445579" +
- "4e6a49784d5467304d466f584454457a0a4d4459" +
- "794e5449784d5467304d466f7767594178437a41" +
- "4a42674e5642415954416c56544d517377435159" +
- "445651514944414a4f575445524d413847413155" +
- "450a42777749516e4a7662327473655734784654" +
- "415442674e5642416f4d4445313549454e424945" +
- "4e7361575675644445584d425547413155454177" +
- "774f62586c6a0a59574e73615756756443356a62" +
- "3230784954416642676b71686b69473977304243" +
- "514557456d70326332686861476c6b5147647459" +
- "576c734c6d4e76625443430a415349774451594a" +
- "4b6f5a496876634e415145424251414467674550" +
- "4144434341516f4367674542414d345438484b77" +
- "596367594e34704250534368484d752f0a396a74" +
- "304a697157456578546f63783964315a46447a61" +
- "33386b6953476d4c4d747343684c30517277596e" +
- "4c6268376256354c566c32434d51537a5a495037" +
- "700a4834373866774a454479694231677a4e7650" +
- "4258624d796e75676167707048613730614b5941" +
- "3953624a42736a455376734a3251756946596f44" +
- "7a75564c55700a4a68384b724f3949614450514d" +
- "39434c477578754c37564b553849613076465142" +
- "566c6332646f44436b6533336663366166564f36" +
- "6b7243796c5377693362680a416931535a376e64" +
- "554d6b37427951696167416457494f6f374a5878" +
- "32754a7a6f4b4679594a364755387446714d4b67" +
- "554b425431767759684c564b4a7443690a717444" +
- "2f747634366e4c555a4f7a2f685341326b43552b" +
- "447963444a7067745948787837724b4a43764748" +
- "3049596f41326853675941502b6b784a73567330" +
- "430a417745414154414e42676b71686b69473977" +
- "30424151554641414f43415145414a536b374873" +
- "4e594d75596a794f3459384231696254745a6d54" +
- "722b535849480a5031695432384376734c4e6330" +
- "567959794f704b3546687a445666464533786365" +
- "5762614242336c6d4e6f3152305377306e706d6e" +
- "63314270592b68456249610a6838444e56653230" +
- "657a4e79362f666a6534734368756b724a6a4b66" +
- "6d66484c6b36753546724f617369495449523962" +
- "7a4b4a5a75326e79754165417a677a330a6d4579" +
- "4677705a7149675870766b6977416c74704b4269" +
- "496c755058786e7254365a6e2f6e634e68545a71" +
- "573873597a54655664576d686b576f49315a5358" +
- "6a0a6a46757739705a57764c2b58646b746d5249" +
- "476b784b637878614650364b544b495055425735" +
- "6c5057765477654c397853645878776149592f58" +
- "4a62467569530a787a6449722b346b2f44554c77" +
- "7430467832366a4b62737066644d726c49444451" +
- "464d4f413151396534764f2b6151444a32507355" +
- "513d3d0a2d2d2d2d2d454e442043455254494649" +
- "434154452d2d2d2d2d0a2d2d2d2d2d424547494e" +
- "2043455254494649434154452d2d2d2d2d0a4d49" +
- "49443454434341736d67417749424167494a414d" +
- "7769544575596f6f6a384d413047435371475349" +
- "623344514542425155414d4947474d5173774351" +
- "59440a5651514745774a56557a454c4d416b4741" +
- "31554543417743546c6b784554415042674e5642" +
- "41634d43454a796232397262486c754d53457748" +
- "7759445651514b0a4442684e655342445a584a30" +
- "61575a70593246305a5342426458526f62334a70" +
- "64486b784554415042674e5642414d4d43473135" +
- "5932457562334a6e4d5345770a4877594a4b6f5a" +
- "496876634e41516b4246684a71646e4e6f595768" +
- "705a45426e625746706243356a62323077486863" +
- "4e4d544d774e5449324d6a45774e5441780a5768" +
- "634e4d6a4d774e5449304d6a45774e544178576a" +
- "4342686a454c4d416b474131554542684d435656" +
- "4d78437a414a42674e564241674d416b355a4d52" +
- "45770a447759445651514844416843636d397661" +
- "327835626a45684d423847413155454367775954" +
- "586b675132567964476c6d61574e686447556751" +
- "585630614739790a615852354d52457744775944" +
- "565151444441687465574e684c6d39795a7a4568" +
- "4d42384743537147534962334451454a41525953" +
- "616e5a7a6147466f615752410a5a323168615777" +
- "75593239744d494942496a414e42676b71686b69" +
- "47397730424151454641414f43415138414d4949" +
- "4243674b434151454138507574674634330a3032" +
- "33754c737938444e645753315a467a5369324975" +
- "6e69443947484b69664f6434317544672f375a75" +
- "4731447071324259367a34635633686c74473067" +
- "75530a4178754a4442735144706d503468666f77" +
- "6a4141523962382b5138376454534e5462435a74" +
- "3642746f4c6174326764654f4334433544427472" +
- "684e79314d6a4f0a46416575493479506e6f7867" +
- "31676135377741597742306c48746f2b4c383872" +
- "566f53654d4348484b665944696954354e4b786c" +
- "6e59413279447356454c31520a3662774334656d" +
- "7a5770715a5152736e6f4531516e69642f6f5830" +
- "4a6837324b796c2b7870516934424e5253696172" +
- "67665549754c7858755a6c635045786c460a7145" +
- "74646757624d456a65555876303845494652502f" +
- "6f503361474a41366c346b665537383779737670" +
- "4d774c72374b663062544b4c524f6b5874625132" +
- "79760a6d31787162567262655635716177494441" +
- "5141426f314177546a416442674e564851344546" +
- "67515561783441714a2f3666514435344a30506b" +
- "497951714b45330a61396f77487759445652306a" +
- "42426777466f415561783441714a2f3666514435" +
- "344a30506b497951714b453361396f7744415944" +
- "5652305442415577417745420a2f7a414e42676b" +
- "71686b6947397730424151554641414f43415145" +
- "417a57397a5456594c387934633467494d464c73" +
- "76335478442f742b554c616d4a675648340a5836" +
- "65674536724d73426a69567a344e4b5a506f6c64" +
- "556255394a52387233316e6e73695a574a637845" +
- "7764364f6e443143766e654d7351382f34476739" +
- "77360a486d495177455a33787032667135596c58" +
- "50736d775255667054507554356f55616853586b" +
- "7975564339796f31326b753841454f2f55375132" +
- "616a6c5a6437370a79736f63582f6c546f49666e" +
- "4d3573767a2b51542f4f7836624c435145357532" +
- "78515032446c376935436242666c502b61615048" +
- "324935756c444b67337371320a7a4e5942315868" +
- "414b474f623773384a4f7a554538425143396f41" +
- "4f6b4c4b55306955577548703268345366684d57" +
- "76776d316f656f5363786f706a594964710a4a63" +
- "476865412b3636462f687571796b6239304a5078" +
- "4c4c48665050534e66544a75696377314f7a7574" +
- "77796d5a695731673d3d0a2d2d2d2d2d454e4420" +
- "43455254494649434154452d2d2d2d2d0a",
-)
+func TestHandshakeClientALPNMatch(t *testing.T) {
+ config := *testConfig
+ config.NextProtos = []string{"proto2", "proto1"}
+
+ test := &clientTest{
+ name: "ALPN",
+ // Note that this needs OpenSSL 1.0.2 because that is the first
+ // version that supports the -alpn flag.
+ command: []string{"openssl", "s_server", "-alpn", "proto1,proto2"},
+ config: &config,
+ validate: func(state ConnectionState) error {
+ // The server's preferences should override the client.
+ if state.NegotiatedProtocol != "proto1" {
+ return fmt.Errorf("Got protocol %q, wanted proto1", state.NegotiatedProtocol)
+ }
+ return nil
+ },
+ }
+ runClientTestTLS12(t, test)
+}
-// Script of interaction with openssl implementation:
-//
-// openssl s_server -cipher ECDHE-ECDSA-AES128-SHA \
-// -key server.key -cert server.crt -port 10443
-//
-// The values for this test are obtained by building and running in client mode:
-// % go test -test.run "TestRunClient" -connect -ciphersuites=0xc009
-// The recorded bytes are written to stdout.
-//
-// The server private key is:
-//
-// -----BEGIN EC PARAMETERS-----
-// BgUrgQQAIw==
-// -----END EC PARAMETERS-----
-// -----BEGIN EC PRIVATE KEY-----
-// MIHcAgEBBEIBmIPpCa0Kyeo9M/nq5mHxeFIGlw+MqakWcvHu3Keo7xK9ZWG7JG3a
-// XfS01efjqSZJvF2DoL+Sly4A5iBn0Me9mdegBwYFK4EEACOhgYkDgYYABADEoe2+
-// mPkLSHM2fsMWVhEi8j1TwztNIT3Na3Xm9rDcmt8mwbyyh/ByMnyzZC8ckLzqaCMQ
-// fv7jJcBIOmngKG3TNwDvBGLdDaCccGKD2IHTZDGqnpcxvZawaMCbI952ZD8aXH/p
-// Eg5YWLZfcN2b2OrV1/XVzLm2nzBmW2aaIOIn5b/+Ow==
-// -----END EC PRIVATE KEY-----
-//
-// and certificate is:
-//
-// -----BEGIN CERTIFICATE-----
-// MIICADCCAWICCQC4vy1HoNLr9DAJBgcqhkjOPQQBMEUxCzAJBgNVBAYTAkFVMRMw
-// EQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0
-// eSBMdGQwHhcNMTIxMTIyMTUwNjMyWhcNMjIxMTIwMTUwNjMyWjBFMQswCQYDVQQG
-// EwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lk
-// Z2l0cyBQdHkgTHRkMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAxKHtvpj5C0hz
-// Nn7DFlYRIvI9U8M7TSE9zWt15vaw3JrfJsG8sofwcjJ8s2QvHJC86mgjEH7+4yXA
-// SDpp4Cht0zcA7wRi3Q2gnHBig9iB02Qxqp6XMb2WsGjAmyPedmQ/Glx/6RIOWFi2
-// X3Ddm9jq1df11cy5tp8wZltmmiDiJ+W//jswCQYHKoZIzj0EAQOBjAAwgYgCQgGI
-// ok/r4kXFSH0brPXtmJ2uR3DAXhu2L73xtk23YUDTEaLO7gt+kn7/dp3DO36lP876
-// EOJZ7EctfKzaTpcOFaBv0AJCAU38vmcTnC0FDr0/o4wlwTMTgw2UBrvUN3r27HrJ
-// hi7d1xFpf4V8Vt77MXgr5Md4Da7Lvp5ONiQxe2oPOZUSB48q
-// -----END CERTIFICATE-----
-var ecdheECDSAAESClientScript = [][]byte{
- {
- 0x16, 0x03, 0x01, 0x00, 0x4a, 0x01, 0x00, 0x00,
- 0x46, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xc0, 0x09,
- 0x01, 0x00, 0x00, 0x1b, 0x00, 0x05, 0x00, 0x05,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
- 0x08, 0x00, 0x06, 0x00, 0x17, 0x00, 0x18, 0x00,
- 0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x54, 0x02, 0x00, 0x00,
- 0x50, 0x03, 0x01, 0x50, 0xd7, 0x19, 0xc9, 0x03,
- 0xc2, 0x3a, 0xc6, 0x1f, 0x0a, 0x84, 0x9e, 0xd7,
- 0xf4, 0x7e, 0x07, 0x6d, 0xa8, 0xe4, 0xa9, 0x4f,
- 0x22, 0x50, 0xa2, 0x19, 0x24, 0x44, 0x42, 0x65,
- 0xaa, 0xba, 0x3a, 0x20, 0x90, 0x70, 0xb7, 0xe5,
- 0x57, 0xed, 0xb1, 0xb1, 0x43, 0x4b, 0xa1, 0x4e,
- 0xee, 0x7a, 0x5b, 0x88, 0xf6, 0xa6, 0x73, 0x3b,
- 0xcb, 0xa7, 0xbd, 0x57, 0x50, 0xf2, 0x72, 0x8c,
- 0xbc, 0x45, 0x73, 0xaa, 0xc0, 0x09, 0x00, 0x00,
- 0x08, 0x00, 0x0b, 0x00, 0x04, 0x03, 0x00, 0x01,
- 0x02, 0x16, 0x03, 0x01, 0x02, 0x0e, 0x0b, 0x00,
- 0x02, 0x0a, 0x00, 0x02, 0x07, 0x00, 0x02, 0x04,
- 0x30, 0x82, 0x02, 0x00, 0x30, 0x82, 0x01, 0x62,
- 0x02, 0x09, 0x00, 0xb8, 0xbf, 0x2d, 0x47, 0xa0,
- 0xd2, 0xeb, 0xf4, 0x30, 0x09, 0x06, 0x07, 0x2a,
- 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01, 0x30, 0x45,
- 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
- 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30,
- 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a,
- 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61,
- 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
- 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74,
- 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69,
- 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74,
- 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17,
- 0x0d, 0x31, 0x32, 0x31, 0x31, 0x32, 0x32, 0x31,
- 0x35, 0x30, 0x36, 0x33, 0x32, 0x5a, 0x17, 0x0d,
- 0x32, 0x32, 0x31, 0x31, 0x32, 0x30, 0x31, 0x35,
- 0x30, 0x36, 0x33, 0x32, 0x5a, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x30, 0x81, 0x9b, 0x30,
- 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d,
- 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00,
- 0x23, 0x03, 0x81, 0x86, 0x00, 0x04, 0x00, 0xc4,
- 0xa1, 0xed, 0xbe, 0x98, 0xf9, 0x0b, 0x48, 0x73,
- 0x36, 0x7e, 0xc3, 0x16, 0x56, 0x11, 0x22, 0xf2,
- 0x3d, 0x53, 0xc3, 0x3b, 0x4d, 0x21, 0x3d, 0xcd,
- 0x6b, 0x75, 0xe6, 0xf6, 0xb0, 0xdc, 0x9a, 0xdf,
- 0x26, 0xc1, 0xbc, 0xb2, 0x87, 0xf0, 0x72, 0x32,
- 0x7c, 0xb3, 0x64, 0x2f, 0x1c, 0x90, 0xbc, 0xea,
- 0x68, 0x23, 0x10, 0x7e, 0xfe, 0xe3, 0x25, 0xc0,
- 0x48, 0x3a, 0x69, 0xe0, 0x28, 0x6d, 0xd3, 0x37,
- 0x00, 0xef, 0x04, 0x62, 0xdd, 0x0d, 0xa0, 0x9c,
- 0x70, 0x62, 0x83, 0xd8, 0x81, 0xd3, 0x64, 0x31,
- 0xaa, 0x9e, 0x97, 0x31, 0xbd, 0x96, 0xb0, 0x68,
- 0xc0, 0x9b, 0x23, 0xde, 0x76, 0x64, 0x3f, 0x1a,
- 0x5c, 0x7f, 0xe9, 0x12, 0x0e, 0x58, 0x58, 0xb6,
- 0x5f, 0x70, 0xdd, 0x9b, 0xd8, 0xea, 0xd5, 0xd7,
- 0xf5, 0xd5, 0xcc, 0xb9, 0xb6, 0x9f, 0x30, 0x66,
- 0x5b, 0x66, 0x9a, 0x20, 0xe2, 0x27, 0xe5, 0xbf,
- 0xfe, 0x3b, 0x30, 0x09, 0x06, 0x07, 0x2a, 0x86,
- 0x48, 0xce, 0x3d, 0x04, 0x01, 0x03, 0x81, 0x8c,
- 0x00, 0x30, 0x81, 0x88, 0x02, 0x42, 0x01, 0x88,
- 0xa2, 0x4f, 0xeb, 0xe2, 0x45, 0xc5, 0x48, 0x7d,
- 0x1b, 0xac, 0xf5, 0xed, 0x98, 0x9d, 0xae, 0x47,
- 0x70, 0xc0, 0x5e, 0x1b, 0xb6, 0x2f, 0xbd, 0xf1,
- 0xb6, 0x4d, 0xb7, 0x61, 0x40, 0xd3, 0x11, 0xa2,
- 0xce, 0xee, 0x0b, 0x7e, 0x92, 0x7e, 0xff, 0x76,
- 0x9d, 0xc3, 0x3b, 0x7e, 0xa5, 0x3f, 0xce, 0xfa,
- 0x10, 0xe2, 0x59, 0xec, 0x47, 0x2d, 0x7c, 0xac,
- 0xda, 0x4e, 0x97, 0x0e, 0x15, 0xa0, 0x6f, 0xd0,
- 0x02, 0x42, 0x01, 0x4d, 0xfc, 0xbe, 0x67, 0x13,
- 0x9c, 0x2d, 0x05, 0x0e, 0xbd, 0x3f, 0xa3, 0x8c,
- 0x25, 0xc1, 0x33, 0x13, 0x83, 0x0d, 0x94, 0x06,
- 0xbb, 0xd4, 0x37, 0x7a, 0xf6, 0xec, 0x7a, 0xc9,
- 0x86, 0x2e, 0xdd, 0xd7, 0x11, 0x69, 0x7f, 0x85,
- 0x7c, 0x56, 0xde, 0xfb, 0x31, 0x78, 0x2b, 0xe4,
- 0xc7, 0x78, 0x0d, 0xae, 0xcb, 0xbe, 0x9e, 0x4e,
- 0x36, 0x24, 0x31, 0x7b, 0x6a, 0x0f, 0x39, 0x95,
- 0x12, 0x07, 0x8f, 0x2a, 0x16, 0x03, 0x01, 0x00,
- 0xd6, 0x0c, 0x00, 0x00, 0xd2, 0x03, 0x00, 0x17,
- 0x41, 0x04, 0x33, 0xed, 0xe1, 0x10, 0x3d, 0xe2,
- 0xb0, 0x81, 0x5e, 0x01, 0x1b, 0x00, 0x4a, 0x7d,
- 0xdc, 0xc5, 0x78, 0x02, 0xb1, 0x9a, 0x78, 0x92,
- 0x34, 0xd9, 0x23, 0xcc, 0x01, 0xfb, 0x0c, 0x49,
- 0x1c, 0x4a, 0x59, 0x8a, 0x80, 0x1b, 0x34, 0xf0,
- 0xe8, 0x87, 0x1b, 0x7c, 0xfb, 0x72, 0xf5, 0xea,
- 0xf9, 0xf3, 0xff, 0xa6, 0x3e, 0x4e, 0xac, 0xbc,
- 0xee, 0x14, 0x2b, 0x87, 0xd4, 0x0b, 0xda, 0x19,
- 0x60, 0x2b, 0x00, 0x8b, 0x30, 0x81, 0x88, 0x02,
- 0x42, 0x01, 0x75, 0x46, 0x4f, 0x97, 0x9f, 0xc5,
- 0xf9, 0x4c, 0x38, 0xcf, 0x3b, 0x37, 0x1a, 0x6b,
- 0x53, 0xfc, 0x05, 0x73, 0x7d, 0x98, 0x2c, 0x5b,
- 0x76, 0xd4, 0x37, 0x1f, 0x50, 0x6d, 0xad, 0xc6,
- 0x0f, 0x8f, 0x7b, 0xcc, 0x60, 0x8e, 0x04, 0x00,
- 0x21, 0x80, 0xa8, 0xa5, 0x98, 0xf2, 0x42, 0xf2,
- 0xc3, 0xf6, 0x44, 0x50, 0xc4, 0x7a, 0xae, 0x6f,
- 0x74, 0xa0, 0x7f, 0x07, 0x7a, 0x0b, 0xbb, 0x41,
- 0x9e, 0x3c, 0x0b, 0x02, 0x42, 0x01, 0xbe, 0x64,
- 0xaa, 0x12, 0x03, 0xfb, 0xd8, 0x4f, 0x93, 0xf9,
- 0x92, 0x54, 0x0d, 0x9c, 0x9d, 0x53, 0x88, 0x19,
- 0x69, 0x94, 0xfc, 0xd6, 0xf7, 0x60, 0xcf, 0x70,
- 0x64, 0x15, 0x1b, 0x02, 0x22, 0x56, 0xb0, 0x2c,
- 0xb1, 0x72, 0x4c, 0x9e, 0x7b, 0xf0, 0x53, 0x97,
- 0x43, 0xac, 0x11, 0x62, 0xe5, 0x5a, 0xf1, 0x7e,
- 0x87, 0x8f, 0x5c, 0x43, 0x1d, 0xae, 0x56, 0x28,
- 0xdb, 0x76, 0x15, 0xd8, 0x1c, 0x73, 0xce, 0x16,
- 0x03, 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x46, 0x10, 0x00, 0x00,
- 0x42, 0x41, 0x04, 0x1e, 0x18, 0x37, 0xef, 0x0d,
- 0x19, 0x51, 0x88, 0x35, 0x75, 0x71, 0xb5, 0xe5,
- 0x54, 0x5b, 0x12, 0x2e, 0x8f, 0x09, 0x67, 0xfd,
- 0xa7, 0x24, 0x20, 0x3e, 0xb2, 0x56, 0x1c, 0xce,
- 0x97, 0x28, 0x5e, 0xf8, 0x2b, 0x2d, 0x4f, 0x9e,
- 0xf1, 0x07, 0x9f, 0x6c, 0x4b, 0x5b, 0x83, 0x56,
- 0xe2, 0x32, 0x42, 0xe9, 0x58, 0xb6, 0xd7, 0x49,
- 0xa6, 0xb5, 0x68, 0x1a, 0x41, 0x03, 0x56, 0x6b,
- 0xdc, 0x5a, 0x89, 0x14, 0x03, 0x01, 0x00, 0x01,
- 0x01, 0x16, 0x03, 0x01, 0x00, 0x30, 0x1a, 0x45,
- 0x92, 0x3b, 0xac, 0x8d, 0x91, 0x89, 0xd3, 0x2c,
- 0xf4, 0x3c, 0x5f, 0x70, 0xf1, 0x79, 0xa5, 0x6a,
- 0xcf, 0x97, 0x8f, 0x3f, 0x73, 0x08, 0xca, 0x3f,
- 0x55, 0xb0, 0x28, 0xd1, 0x6f, 0xcd, 0x9b, 0xca,
- 0xb6, 0xb7, 0xd0, 0xa5, 0x21, 0x5b, 0x08, 0xf8,
- 0x42, 0xe2, 0xdf, 0x25, 0x6a, 0x16,
- },
- {
- 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
- 0x01, 0x00, 0x30, 0x30, 0x83, 0xb6, 0x51, 0x8a,
- 0x85, 0x4a, 0xee, 0xe4, 0xb6, 0xae, 0xf3, 0xc1,
- 0xdc, 0xd2, 0x04, 0xb3, 0xd0, 0x25, 0x47, 0x5f,
- 0xac, 0x83, 0xa3, 0x7d, 0xcf, 0x47, 0x92, 0xed,
- 0x92, 0x6c, 0xd1, 0x6e, 0xfd, 0x63, 0xf5, 0x2d,
- 0x89, 0xd8, 0x04, 0x8c, 0x62, 0x71, 0xae, 0x5e,
- 0x32, 0x48, 0xf8,
- },
- {
- 0x17, 0x03, 0x01, 0x00, 0x20, 0xcf, 0x5e, 0xba,
- 0xf4, 0x47, 0x32, 0x35, 0x9b, 0x85, 0xdc, 0xb3,
- 0xff, 0x77, 0x90, 0xd9, 0x2b, 0xbd, 0x59, 0x2a,
- 0x33, 0xe4, 0x6e, 0x9b, 0xfc, 0x1c, 0x73, 0x3f,
- 0x5e, 0x1e, 0xe3, 0xa4, 0xc2, 0x17, 0x03, 0x01,
- 0x00, 0x20, 0x05, 0xdf, 0x2d, 0x9b, 0x29, 0x7f,
- 0x97, 0xcd, 0x49, 0x04, 0x53, 0x22, 0x1a, 0xa1,
- 0xa1, 0xe6, 0x38, 0x3a, 0x56, 0x37, 0x1f, 0xd8,
- 0x3a, 0x12, 0x2c, 0xf0, 0xeb, 0x61, 0x35, 0x76,
- 0xe5, 0xf0, 0x15, 0x03, 0x01, 0x00, 0x20, 0xa5,
- 0x56, 0xb5, 0x49, 0x4b, 0xc2, 0xd4, 0x4c, 0xf6,
- 0x95, 0x15, 0x7d, 0x41, 0x1d, 0x5c, 0x00, 0x0e,
- 0x20, 0xb1, 0x0a, 0xbc, 0xc9, 0x2a, 0x09, 0x17,
- 0xb4, 0xaa, 0x1c, 0x79, 0xda, 0x79, 0x27,
- },
+func TestHandshakeClientALPNNoMatch(t *testing.T) {
+ config := *testConfig
+ config.NextProtos = []string{"proto3"}
+
+ test := &clientTest{
+ name: "ALPN-NoMatch",
+ // Note that this needs OpenSSL 1.0.2 because that is the first
+ // version that supports the -alpn flag.
+ command: []string{"openssl", "s_server", "-alpn", "proto1,proto2"},
+ config: &config,
+ validate: func(state ConnectionState) error {
+ // There's no overlap so OpenSSL will not select a protocol.
+ if state.NegotiatedProtocol != "" {
+ return fmt.Errorf("Got protocol %q, wanted ''", state.NegotiatedProtocol)
+ }
+ return nil
+ },
+ }
+ runClientTestTLS12(t, test)
}
diff --git a/libgo/go/crypto/tls/handshake_messages.go b/libgo/go/crypto/tls/handshake_messages.go
index 83952000f6..5d14871a34 100644
--- a/libgo/go/crypto/tls/handshake_messages.go
+++ b/libgo/go/crypto/tls/handshake_messages.go
@@ -7,20 +7,22 @@ package tls
import "bytes"
type clientHelloMsg struct {
- raw []byte
- vers uint16
- random []byte
- sessionId []byte
- cipherSuites []uint16
- compressionMethods []uint8
- nextProtoNeg bool
- serverName string
- ocspStapling bool
- supportedCurves []uint16
- supportedPoints []uint8
- ticketSupported bool
- sessionTicket []uint8
- signatureAndHashes []signatureAndHash
+ raw []byte
+ vers uint16
+ random []byte
+ sessionId []byte
+ cipherSuites []uint16
+ compressionMethods []uint8
+ nextProtoNeg bool
+ serverName string
+ ocspStapling bool
+ supportedCurves []CurveID
+ supportedPoints []uint8
+ ticketSupported bool
+ sessionTicket []uint8
+ signatureAndHashes []signatureAndHash
+ secureRenegotiation bool
+ alpnProtocols []string
}
func (m *clientHelloMsg) equal(i interface{}) bool {
@@ -38,11 +40,13 @@ func (m *clientHelloMsg) equal(i interface{}) bool {
m.nextProtoNeg == m1.nextProtoNeg &&
m.serverName == m1.serverName &&
m.ocspStapling == m1.ocspStapling &&
- eqUint16s(m.supportedCurves, m1.supportedCurves) &&
+ eqCurveIDs(m.supportedCurves, m1.supportedCurves) &&
bytes.Equal(m.supportedPoints, m1.supportedPoints) &&
m.ticketSupported == m1.ticketSupported &&
bytes.Equal(m.sessionTicket, m1.sessionTicket) &&
- eqSignatureAndHashes(m.signatureAndHashes, m1.signatureAndHashes)
+ eqSignatureAndHashes(m.signatureAndHashes, m1.signatureAndHashes) &&
+ m.secureRenegotiation == m1.secureRenegotiation &&
+ eqStrings(m.alpnProtocols, m1.alpnProtocols)
}
func (m *clientHelloMsg) marshal() []byte {
@@ -80,6 +84,21 @@ func (m *clientHelloMsg) marshal() []byte {
extensionsLength += 2 + 2*len(m.signatureAndHashes)
numExtensions++
}
+ if m.secureRenegotiation {
+ extensionsLength += 1
+ numExtensions++
+ }
+ if len(m.alpnProtocols) > 0 {
+ extensionsLength += 2
+ for _, s := range m.alpnProtocols {
+ if l := len(s); l == 0 || l > 255 {
+ panic("invalid ALPN protocol")
+ }
+ extensionsLength++
+ extensionsLength += len(s)
+ }
+ numExtensions++
+ }
if numExtensions > 0 {
extensionsLength += 4 * numExtensions
length += 2 + extensionsLength
@@ -114,13 +133,13 @@ func (m *clientHelloMsg) marshal() []byte {
}
if m.nextProtoNeg {
z[0] = byte(extensionNextProtoNeg >> 8)
- z[1] = byte(extensionNextProtoNeg)
+ z[1] = byte(extensionNextProtoNeg & 0xff)
// The length is always 0
z = z[4:]
}
if len(m.serverName) > 0 {
z[0] = byte(extensionServerName >> 8)
- z[1] = byte(extensionServerName)
+ z[1] = byte(extensionServerName & 0xff)
l := len(m.serverName) + 5
z[2] = byte(l >> 8)
z[3] = byte(l)
@@ -224,6 +243,34 @@ func (m *clientHelloMsg) marshal() []byte {
z = z[2:]
}
}
+ if m.secureRenegotiation {
+ z[0] = byte(extensionRenegotiationInfo >> 8)
+ z[1] = byte(extensionRenegotiationInfo & 0xff)
+ z[2] = 0
+ z[3] = 1
+ z = z[5:]
+ }
+ if len(m.alpnProtocols) > 0 {
+ z[0] = byte(extensionALPN >> 8)
+ z[1] = byte(extensionALPN & 0xff)
+ lengths := z[2:]
+ z = z[6:]
+
+ stringsLength := 0
+ for _, s := range m.alpnProtocols {
+ l := len(s)
+ z[0] = byte(l)
+ copy(z[1:], s)
+ z = z[1+l:]
+ stringsLength += 1 + l
+ }
+
+ lengths[2] = byte(stringsLength >> 8)
+ lengths[3] = byte(stringsLength)
+ stringsLength += 2
+ lengths[0] = byte(stringsLength >> 8)
+ lengths[1] = byte(stringsLength)
+ }
m.raw = x
@@ -256,6 +303,9 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
m.cipherSuites = make([]uint16, numCipherSuites)
for i := 0; i < numCipherSuites; i++ {
m.cipherSuites[i] = uint16(data[2+2*i])<<8 | uint16(data[3+2*i])
+ if m.cipherSuites[i] == scsvRenegotiation {
+ m.secureRenegotiation = true
+ }
}
data = data[2+cipherSuiteLen:]
if len(data) < 1 {
@@ -275,6 +325,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
m.ticketSupported = false
m.sessionTicket = nil
m.signatureAndHashes = nil
+ m.alpnProtocols = nil
if len(data) == 0 {
// ClientHello is optionally followed by extension data
@@ -341,10 +392,10 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
return false
}
numCurves := l / 2
- m.supportedCurves = make([]uint16, numCurves)
+ m.supportedCurves = make([]CurveID, numCurves)
d := data[2:]
for i := 0; i < numCurves; i++ {
- m.supportedCurves[i] = uint16(d[0])<<8 | uint16(d[1])
+ m.supportedCurves[i] = CurveID(d[0])<<8 | CurveID(d[1])
d = d[2:]
}
case extensionSupportedPoints:
@@ -379,6 +430,29 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
m.signatureAndHashes[i].signature = d[1]
d = d[2:]
}
+ case extensionRenegotiationInfo + 1:
+ if length != 1 || data[0] != 0 {
+ return false
+ }
+ m.secureRenegotiation = true
+ case extensionALPN:
+ if length < 2 {
+ return false
+ }
+ l := int(data[0])<<8 | int(data[1])
+ if l != length-2 {
+ return false
+ }
+ d := data[2:length]
+ for len(d) != 0 {
+ stringLen := int(d[0])
+ d = d[1:]
+ if stringLen == 0 || stringLen > len(d) {
+ return false
+ }
+ m.alpnProtocols = append(m.alpnProtocols, string(d[:stringLen]))
+ d = d[stringLen:]
+ }
}
data = data[length:]
}
@@ -387,16 +461,18 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
}
type serverHelloMsg struct {
- raw []byte
- vers uint16
- random []byte
- sessionId []byte
- cipherSuite uint16
- compressionMethod uint8
- nextProtoNeg bool
- nextProtos []string
- ocspStapling bool
- ticketSupported bool
+ raw []byte
+ vers uint16
+ random []byte
+ sessionId []byte
+ cipherSuite uint16
+ compressionMethod uint8
+ nextProtoNeg bool
+ nextProtos []string
+ ocspStapling bool
+ ticketSupported bool
+ secureRenegotiation bool
+ alpnProtocol string
}
func (m *serverHelloMsg) equal(i interface{}) bool {
@@ -414,7 +490,9 @@ func (m *serverHelloMsg) equal(i interface{}) bool {
m.nextProtoNeg == m1.nextProtoNeg &&
eqStrings(m.nextProtos, m1.nextProtos) &&
m.ocspStapling == m1.ocspStapling &&
- m.ticketSupported == m1.ticketSupported
+ m.ticketSupported == m1.ticketSupported &&
+ m.secureRenegotiation == m1.secureRenegotiation &&
+ m.alpnProtocol == m1.alpnProtocol
}
func (m *serverHelloMsg) marshal() []byte {
@@ -441,6 +519,18 @@ func (m *serverHelloMsg) marshal() []byte {
if m.ticketSupported {
numExtensions++
}
+ if m.secureRenegotiation {
+ extensionsLength += 1
+ numExtensions++
+ }
+ if alpnLen := len(m.alpnProtocol); alpnLen > 0 {
+ if alpnLen >= 256 {
+ panic("invalid ALPN protocol")
+ }
+ extensionsLength += 2 + 1 + alpnLen
+ numExtensions++
+ }
+
if numExtensions > 0 {
extensionsLength += 4 * numExtensions
length += 2 + extensionsLength
@@ -469,7 +559,7 @@ func (m *serverHelloMsg) marshal() []byte {
}
if m.nextProtoNeg {
z[0] = byte(extensionNextProtoNeg >> 8)
- z[1] = byte(extensionNextProtoNeg)
+ z[1] = byte(extensionNextProtoNeg & 0xff)
z[2] = byte(nextProtoLen >> 8)
z[3] = byte(nextProtoLen)
z = z[4:]
@@ -494,6 +584,27 @@ func (m *serverHelloMsg) marshal() []byte {
z[1] = byte(extensionSessionTicket)
z = z[4:]
}
+ if m.secureRenegotiation {
+ z[0] = byte(extensionRenegotiationInfo >> 8)
+ z[1] = byte(extensionRenegotiationInfo & 0xff)
+ z[2] = 0
+ z[3] = 1
+ z = z[5:]
+ }
+ if alpnLen := len(m.alpnProtocol); alpnLen > 0 {
+ z[0] = byte(extensionALPN >> 8)
+ z[1] = byte(extensionALPN & 0xff)
+ l := 2 + 1 + alpnLen
+ z[2] = byte(l >> 8)
+ z[3] = byte(l)
+ l -= 2
+ z[4] = byte(l >> 8)
+ z[5] = byte(l)
+ l -= 1
+ z[6] = byte(l)
+ copy(z[7:], []byte(m.alpnProtocol))
+ z = z[7+alpnLen:]
+ }
m.raw = x
@@ -524,6 +635,7 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
m.nextProtos = nil
m.ocspStapling = false
m.ticketSupported = false
+ m.alpnProtocol = ""
if len(data) == 0 {
// ServerHello is optionally followed by extension data
@@ -573,6 +685,27 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
return false
}
m.ticketSupported = true
+ case extensionRenegotiationInfo:
+ if length != 1 || data[0] != 0 {
+ return false
+ }
+ m.secureRenegotiation = true
+ case extensionALPN:
+ d := data[:length]
+ if len(d) < 3 {
+ return false
+ }
+ l := int(d[0])<<8 | int(d[1])
+ if l != len(d)-2 {
+ return false
+ }
+ d = d[2:]
+ l = int(d[0])
+ if l != len(d)-1 {
+ return false
+ }
+ d = d[1:]
+ m.alpnProtocol = string(d)
}
data = data[length:]
}
@@ -1255,6 +1388,18 @@ func eqUint16s(x, y []uint16) bool {
return true
}
+func eqCurveIDs(x, y []CurveID) bool {
+ if len(x) != len(y) {
+ return false
+ }
+ for i, v := range x {
+ if y[i] != v {
+ return false
+ }
+ }
+ return true
+}
+
func eqStrings(x, y []string) bool {
if len(x) != len(y) {
return false
diff --git a/libgo/go/crypto/tls/handshake_messages_test.go b/libgo/go/crypto/tls/handshake_messages_test.go
index 4f569eeb13..a96e95c3f0 100644
--- a/libgo/go/crypto/tls/handshake_messages_test.go
+++ b/libgo/go/crypto/tls/handshake_messages_test.go
@@ -125,9 +125,9 @@ func (*clientHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {
}
m.ocspStapling = rand.Intn(10) > 5
m.supportedPoints = randomBytes(rand.Intn(5)+1, rand)
- m.supportedCurves = make([]uint16, rand.Intn(5)+1)
+ m.supportedCurves = make([]CurveID, rand.Intn(5)+1)
for i := range m.supportedCurves {
- m.supportedCurves[i] = uint16(rand.Intn(30000))
+ m.supportedCurves[i] = CurveID(rand.Intn(30000))
}
if rand.Intn(10) > 5 {
m.ticketSupported = true
@@ -138,6 +138,10 @@ func (*clientHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {
if rand.Intn(10) > 5 {
m.signatureAndHashes = supportedSKXSignatureAlgorithms
}
+ m.alpnProtocols = make([]string, rand.Intn(5))
+ for i := range m.alpnProtocols {
+ m.alpnProtocols[i] = randomString(rand.Intn(20)+1, rand)
+ }
return reflect.ValueOf(m)
}
@@ -166,6 +170,7 @@ func (*serverHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {
if rand.Intn(10) > 5 {
m.ticketSupported = true
}
+ m.alpnProtocol = randomString(rand.Intn(32)+1, rand)
return reflect.ValueOf(m)
}
diff --git a/libgo/go/crypto/tls/handshake_server.go b/libgo/go/crypto/tls/handshake_server.go
index c9ccf675cd..0d907656c6 100644
--- a/libgo/go/crypto/tls/handshake_server.go
+++ b/libgo/go/crypto/tls/handshake_server.go
@@ -12,6 +12,7 @@ import (
"crypto/x509"
"encoding/asn1"
"errors"
+ "fmt"
"io"
)
@@ -56,10 +57,10 @@ func (c *Conn) serverHandshake() error {
if err := hs.establishKeys(); err != nil {
return err
}
- if err := hs.sendFinished(); err != nil {
+ if err := hs.sendFinished(c.firstFinished[:]); err != nil {
return err
}
- if err := hs.readFinished(); err != nil {
+ if err := hs.readFinished(nil); err != nil {
return err
}
c.didResume = true
@@ -72,13 +73,13 @@ func (c *Conn) serverHandshake() error {
if err := hs.establishKeys(); err != nil {
return err
}
- if err := hs.readFinished(); err != nil {
+ if err := hs.readFinished(c.firstFinished[:]); err != nil {
return err
}
if err := hs.sendSessionTicket(); err != nil {
return err
}
- if err := hs.sendFinished(); err != nil {
+ if err := hs.sendFinished(nil); err != nil {
return err
}
}
@@ -100,11 +101,13 @@ func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) {
var ok bool
hs.clientHello, ok = msg.(*clientHelloMsg)
if !ok {
- return false, c.sendAlert(alertUnexpectedMessage)
+ c.sendAlert(alertUnexpectedMessage)
+ return false, unexpectedMessageError(hs.clientHello, msg)
}
c.vers, ok = config.mutualVersion(hs.clientHello.vers)
if !ok {
- return false, c.sendAlert(alertProtocolVersion)
+ c.sendAlert(alertProtocolVersion)
+ return false, fmt.Errorf("tls: client offered an unsupported, maximum protocol version of %x", hs.clientHello.vers)
}
c.haveVers = true
@@ -114,12 +117,14 @@ func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) {
hs.hello = new(serverHelloMsg)
supportedCurve := false
+ preferredCurves := config.curvePreferences()
Curves:
for _, curve := range hs.clientHello.supportedCurves {
- switch curve {
- case curveP256, curveP384, curveP521:
- supportedCurve = true
- break Curves
+ for _, supported := range preferredCurves {
+ if supported == curve {
+ supportedCurve = true
+ break Curves
+ }
}
}
@@ -142,39 +147,55 @@ Curves:
}
if !foundCompression {
- return false, c.sendAlert(alertHandshakeFailure)
+ c.sendAlert(alertHandshakeFailure)
+ return false, errors.New("tls: client does not support uncompressed connections")
}
hs.hello.vers = c.vers
- t := uint32(config.time().Unix())
hs.hello.random = make([]byte, 32)
- hs.hello.random[0] = byte(t >> 24)
- hs.hello.random[1] = byte(t >> 16)
- hs.hello.random[2] = byte(t >> 8)
- hs.hello.random[3] = byte(t)
- _, err = io.ReadFull(config.rand(), hs.hello.random[4:])
+ _, err = io.ReadFull(config.rand(), hs.hello.random)
if err != nil {
- return false, c.sendAlert(alertInternalError)
+ c.sendAlert(alertInternalError)
+ return false, err
}
+ hs.hello.secureRenegotiation = hs.clientHello.secureRenegotiation
hs.hello.compressionMethod = compressionNone
if len(hs.clientHello.serverName) > 0 {
c.serverName = hs.clientHello.serverName
}
- // 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.
- if hs.clientHello.nextProtoNeg && len(config.NextProtos) > 0 {
- hs.hello.nextProtoNeg = true
- hs.hello.nextProtos = config.NextProtos
+
+ if len(hs.clientHello.alpnProtocols) > 0 {
+ if selectedProto, fallback := mutualProtocol(hs.clientHello.alpnProtocols, c.config.NextProtos); !fallback {
+ hs.hello.alpnProtocol = selectedProto
+ c.clientProtocol = selectedProto
+ }
+ } else {
+ // 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.
+ if hs.clientHello.nextProtoNeg && len(config.NextProtos) > 0 {
+ hs.hello.nextProtoNeg = true
+ hs.hello.nextProtos = config.NextProtos
+ }
}
if len(config.Certificates) == 0 {
- return false, c.sendAlert(alertInternalError)
+ c.sendAlert(alertInternalError)
+ return false, errors.New("tls: no certificates configured")
}
hs.cert = &config.Certificates[0]
if len(hs.clientHello.serverName) > 0 {
- hs.cert = config.getCertificateForName(hs.clientHello.serverName)
+ chi := &ClientHelloInfo{
+ CipherSuites: hs.clientHello.cipherSuites,
+ ServerName: hs.clientHello.serverName,
+ SupportedCurves: hs.clientHello.supportedCurves,
+ SupportedPoints: hs.clientHello.supportedPoints,
+ }
+ if hs.cert, err = config.getCertificate(chi); err != nil {
+ c.sendAlert(alertInternalError)
+ return false, err
+ }
}
_, hs.ecdsaOk = hs.cert.PrivateKey.(*ecdsa.PrivateKey)
@@ -199,7 +220,20 @@ Curves:
}
if hs.suite == nil {
- return false, c.sendAlert(alertHandshakeFailure)
+ c.sendAlert(alertHandshakeFailure)
+ return false, errors.New("tls: no cipher suite supported by both client and server")
+ }
+
+ // See https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00.
+ for _, id := range hs.clientHello.cipherSuites {
+ if id == TLS_FALLBACK_SCSV {
+ // The client is doing a fallback connection.
+ if hs.clientHello.vers < c.config.MaxVersion {
+ c.sendAlert(alertInappropriateFallback)
+ return false, errors.New("tls: client using inppropriate protocol fallback")
+ }
+ break
+ }
}
return false, nil
@@ -209,6 +243,10 @@ Curves:
func (hs *serverHandshakeState) checkForResumption() bool {
c := hs.c
+ if c.config.SessionTicketsDisabled {
+ return false
+ }
+
var ok bool
if hs.sessionState, ok = c.decryptTicket(hs.clientHello.sessionTicket); !ok {
return false
@@ -349,7 +387,8 @@ func (hs *serverHandshakeState) doFullHandshake() error {
// certificate message, even if it's empty.
if config.ClientAuth >= RequestClientCert {
if certMsg, ok = msg.(*certificateMsg); !ok {
- return c.sendAlert(alertHandshakeFailure)
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(certMsg, msg)
}
hs.finishedHash.Write(certMsg.marshal())
@@ -376,7 +415,8 @@ func (hs *serverHandshakeState) doFullHandshake() error {
// Get client key exchange
ckx, ok := msg.(*clientKeyExchangeMsg)
if !ok {
- return c.sendAlert(alertUnexpectedMessage)
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(ckx, msg)
}
hs.finishedHash.Write(ckx.marshal())
@@ -393,7 +433,8 @@ func (hs *serverHandshakeState) doFullHandshake() error {
}
certVerify, ok := msg.(*certificateVerifyMsg)
if !ok {
- return c.sendAlert(alertUnexpectedMessage)
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(certVerify, msg)
}
switch key := pub.(type) {
@@ -458,11 +499,11 @@ func (hs *serverHandshakeState) establishKeys() error {
return nil
}
-func (hs *serverHandshakeState) readFinished() error {
+func (hs *serverHandshakeState) readFinished(out []byte) error {
c := hs.c
c.readRecord(recordTypeChangeCipherSpec)
- if err := c.error(); err != nil {
+ if err := c.in.error(); err != nil {
return err
}
@@ -473,7 +514,8 @@ func (hs *serverHandshakeState) readFinished() error {
}
nextProto, ok := msg.(*nextProtoMsg)
if !ok {
- return c.sendAlert(alertUnexpectedMessage)
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(nextProto, msg)
}
hs.finishedHash.Write(nextProto.marshal())
c.clientProtocol = nextProto.proto
@@ -485,16 +527,19 @@ func (hs *serverHandshakeState) readFinished() error {
}
clientFinished, ok := msg.(*finishedMsg)
if !ok {
- return c.sendAlert(alertUnexpectedMessage)
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(clientFinished, msg)
}
verify := hs.finishedHash.clientSum(hs.masterSecret)
if len(verify) != len(clientFinished.verifyData) ||
subtle.ConstantTimeCompare(verify, clientFinished.verifyData) != 1 {
- return c.sendAlert(alertHandshakeFailure)
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: client's Finished message is incorrect")
}
hs.finishedHash.Write(clientFinished.marshal())
+ copy(out, verify)
return nil
}
@@ -524,7 +569,7 @@ func (hs *serverHandshakeState) sendSessionTicket() error {
return nil
}
-func (hs *serverHandshakeState) sendFinished() error {
+func (hs *serverHandshakeState) sendFinished(out []byte) error {
c := hs.c
c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
@@ -535,6 +580,7 @@ func (hs *serverHandshakeState) sendFinished() error {
c.writeRecord(recordTypeHandshake, finished.marshal())
c.cipherSuite = hs.suite.id
+ copy(out, finished.verifyData)
return nil
}
@@ -594,7 +640,8 @@ func (hs *serverHandshakeState) processCertsFromClient(certificates [][]byte) (c
case *ecdsa.PublicKey, *rsa.PublicKey:
pub = key
default:
- return nil, c.sendAlert(alertUnsupportedCertificate)
+ c.sendAlert(alertUnsupportedCertificate)
+ return nil, fmt.Errorf("tls: client's certificate contains an unsupported public key of type %T", certs[0].PublicKey)
}
c.peerCertificates = certs
return pub, nil
diff --git a/libgo/go/crypto/tls/handshake_server_test.go b/libgo/go/crypto/tls/handshake_server_test.go
index c08eba7f17..0338af457e 100644
--- a/libgo/go/crypto/tls/handshake_server_test.go
+++ b/libgo/go/crypto/tls/handshake_server_test.go
@@ -9,23 +9,22 @@ import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rsa"
- "crypto/x509"
"encoding/hex"
"encoding/pem"
- "flag"
+ "errors"
"fmt"
"io"
- "log"
"math/big"
"net"
"os"
- "strconv"
+ "os/exec"
+ "path/filepath"
"strings"
- "sync"
"testing"
"time"
)
+// zeroSource is an io.Reader that returns an unlimited number of zero bytes.
type zeroSource struct{}
func (zeroSource) Read(b []byte) (n int, err error) {
@@ -39,22 +38,22 @@ func (zeroSource) Read(b []byte) (n int, err error) {
var testConfig *Config
func init() {
- testConfig = new(Config)
- testConfig.Time = func() time.Time { return time.Unix(0, 0) }
- testConfig.Rand = zeroSource{}
- testConfig.Certificates = make([]Certificate, 2)
+ testConfig = &Config{
+ Time: func() time.Time { return time.Unix(0, 0) },
+ Rand: zeroSource{},
+ Certificates: make([]Certificate, 2),
+ InsecureSkipVerify: true,
+ MinVersion: VersionSSL30,
+ MaxVersion: VersionTLS12,
+ }
testConfig.Certificates[0].Certificate = [][]byte{testRSACertificate}
testConfig.Certificates[0].PrivateKey = testRSAPrivateKey
testConfig.Certificates[1].Certificate = [][]byte{testSNICertificate}
testConfig.Certificates[1].PrivateKey = testRSAPrivateKey
testConfig.BuildNameToCertificate()
- testConfig.CipherSuites = []uint16{TLS_RSA_WITH_RC4_128_SHA}
- testConfig.InsecureSkipVerify = true
- testConfig.MinVersion = VersionSSL30
- testConfig.MaxVersion = VersionTLS10
}
-func testClientHelloFailure(t *testing.T, m handshakeMessage, expected error) {
+func testClientHelloFailure(t *testing.T, m handshakeMessage, expectedSubStr string) {
// Create in-memory network connection,
// send message to server. Should return
// expected error.
@@ -69,20 +68,20 @@ func testClientHelloFailure(t *testing.T, m handshakeMessage, expected error) {
}()
err := Server(s, testConfig).Handshake()
s.Close()
- if e, ok := err.(*net.OpError); !ok || e.Err != expected {
- t.Errorf("Got error: %s; expected: %s", err, expected)
+ 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{}, alertUnexpectedMessage)
+ testClientHelloFailure(t, &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}, alertProtocolVersion)
+ testClientHelloFailure(t, &clientHelloMsg{vers: v}, "unsupported, maximum protocol version")
}
}
@@ -92,7 +91,7 @@ func TestNoSuiteOverlap(t *testing.T) {
cipherSuites: []uint16{0xff00},
compressionMethods: []uint8{0},
}
- testClientHelloFailure(t, clientHello, alertHandshakeFailure)
+ testClientHelloFailure(t, clientHello, "no cipher suite supported by both client and server")
}
func TestNoCompressionOverlap(t *testing.T) {
@@ -101,7 +100,7 @@ func TestNoCompressionOverlap(t *testing.T) {
cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
compressionMethods: []uint8{0xff},
}
- testClientHelloFailure(t, clientHello, alertHandshakeFailure)
+ testClientHelloFailure(t, clientHello, "client does not support uncompressed connections")
}
func TestTLS12OnlyCipherSuites(t *testing.T) {
@@ -121,7 +120,7 @@ func TestTLS12OnlyCipherSuites(t *testing.T) {
TLS_RSA_WITH_RC4_128_SHA,
},
compressionMethods: []uint8{compressionNone},
- supportedCurves: []uint16{curveP256, curveP384, curveP521},
+ supportedCurves: []CurveID{CurveP256, CurveP384, CurveP521},
supportedPoints: []uint8{pointFormatUncompressed},
}
@@ -178,10 +177,12 @@ func TestClose(t *testing.T) {
func testHandshake(clientConfig, serverConfig *Config) (state ConnectionState, err error) {
c, s := net.Pipe()
+ done := make(chan bool)
go func() {
cli := Client(c, clientConfig)
cli.Handshake()
c.Close()
+ done <- true
}()
server := Server(s, serverConfig)
err = server.Handshake()
@@ -189,9 +190,27 @@ func testHandshake(clientConfig, serverConfig *Config) (state ConnectionState, e
state = server.ConnectionState()
}
s.Close()
+ <-done
return
}
+func TestVersion(t *testing.T) {
+ serverConfig := &Config{
+ Certificates: testConfig.Certificates,
+ MaxVersion: VersionTLS11,
+ }
+ clientConfig := &Config{
+ InsecureSkipVerify: true,
+ }
+ state, err := testHandshake(clientConfig, serverConfig)
+ if err != nil {
+ t.Fatalf("handshake failed: %s", err)
+ }
+ if state.Version != VersionTLS11 {
+ t.Fatalf("Incorrect version %x, should be %x", state.Version, VersionTLS11)
+ }
+}
+
func TestCipherSuitePreference(t *testing.T) {
serverConfig := &Config{
CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA},
@@ -221,2920 +240,496 @@ func TestCipherSuitePreference(t *testing.T) {
}
}
-func testServerScript(t *testing.T, name string, serverScript [][]byte, config *Config, peers []*x509.Certificate) {
- c, s := net.Pipe()
- srv := Server(s, config)
- pchan := make(chan []*x509.Certificate, 1)
- go func() {
- srv.Write([]byte("hello, world\n"))
- srv.Close()
- s.Close()
- st := srv.ConnectionState()
- pchan <- st.PeerCertificates
- }()
+// Note: see comment in handshake_test.go for details of how the reference
+// tests work.
+
+// serverTest represents a test of the TLS server handshake against a reference
+// implementation.
+type serverTest struct {
+ // name is a freeform string identifying the test and the file in which
+ // the expected results will be stored.
+ name string
+ // command, if not empty, contains a series of arguments for the
+ // command to run for the reference server.
+ command []string
+ // expectedPeerCerts contains a list of PEM blocks of expected
+ // certificates from the client.
+ 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
+ // validate, if not nil, is a function that will be called with the
+ // ConnectionState of the resulting connection. It returns false if the
+ // ConnectionState is unacceptable.
+ validate func(ConnectionState) error
+}
+
+var defaultClientCommand = []string{"openssl", "s_client", "-no_ticket"}
+
+// connFromCommand starts opens a listening socket and starts the reference
+// client to connect to it. It returns a recordingConn that wraps the resulting
+// connection.
+func (test *serverTest) connFromCommand() (conn *recordingConn, child *exec.Cmd, err error) {
+ l, err := net.ListenTCP("tcp", &net.TCPAddr{
+ IP: net.IPv4(127, 0, 0, 1),
+ Port: 0,
+ })
+ if err != nil {
+ return nil, nil, err
+ }
+ defer l.Close()
- for i, b := range serverScript {
- if i%2 == 0 {
- c.Write(b)
- continue
- }
- bb := make([]byte, len(b))
- n, err := io.ReadFull(c, bb)
+ port := l.Addr().(*net.TCPAddr).Port
+
+ var command []string
+ command = append(command, test.command...)
+ if len(command) == 0 {
+ command = defaultClientCommand
+ }
+ command = append(command, "-connect")
+ command = append(command, fmt.Sprintf("127.0.0.1:%d", port))
+ cmd := exec.Command(command[0], command[1:]...)
+ cmd.Stdin = nil
+ var output bytes.Buffer
+ cmd.Stdout = &output
+ cmd.Stderr = &output
+ if err := cmd.Start(); err != nil {
+ return nil, nil, err
+ }
+
+ connChan := make(chan interface{})
+ go func() {
+ tcpConn, err := l.Accept()
if err != nil {
- t.Fatalf("%s #%d: %s\nRead %d, wanted %d, got %x, wanted %x\n", name, i, err, n, len(bb), bb[:n], b)
+ connChan <- err
}
- if !bytes.Equal(b, bb) {
- t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", name, i, bb, b)
- }
- }
- c.Close()
-
- if peers != nil {
- gotpeers := <-pchan
- if len(peers) == len(gotpeers) {
- for i := range peers {
- if !peers[i].Equal(gotpeers[i]) {
- t.Fatalf("%s: mismatch on peer cert %d", name, i)
- }
- }
- } else {
- t.Fatalf("%s: mismatch on peer list length: %d (wanted) != %d (got)", name, len(peers), len(gotpeers))
+ connChan <- tcpConn
+ }()
+
+ var tcpConn net.Conn
+ select {
+ case connOrError := <-connChan:
+ if err, ok := connOrError.(error); ok {
+ return nil, nil, err
}
+ tcpConn = connOrError.(net.Conn)
+ case <-time.After(2 * time.Second):
+ output.WriteTo(os.Stdout)
+ return nil, nil, errors.New("timed out waiting for connection from child process")
}
-}
-func TestHandshakeServerRSARC4(t *testing.T) {
- testServerScript(t, "RSA-RC4", rsaRC4ServerScript, testConfig, nil)
-}
-
-func TestHandshakeServerRSA3DES(t *testing.T) {
- des3Config := new(Config)
- *des3Config = *testConfig
- des3Config.CipherSuites = []uint16{TLS_RSA_WITH_3DES_EDE_CBC_SHA}
- testServerScript(t, "RSA-3DES", rsaDES3ServerScript, des3Config, nil)
-}
+ record := &recordingConn{
+ Conn: tcpConn,
+ }
-func TestHandshakeServerRSAAES(t *testing.T) {
- aesConfig := new(Config)
- *aesConfig = *testConfig
- aesConfig.CipherSuites = []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}
- testServerScript(t, "RSA-AES", rsaAESServerScript, aesConfig, nil)
+ return record, cmd, nil
}
-func TestHandshakeServerECDHEECDSAAES(t *testing.T) {
- ecdsaConfig := new(Config)
- *ecdsaConfig = *testConfig
- ecdsaConfig.Certificates = make([]Certificate, 1)
- ecdsaConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
- ecdsaConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
- ecdsaConfig.BuildNameToCertificate()
- ecdsaConfig.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA}
- testServerScript(t, "ECDHE-ECDSA-AES", ecdheECDSAAESServerScript, ecdsaConfig, nil)
+func (test *serverTest) dataPath() string {
+ return filepath.Join("testdata", "Server-"+test.name)
}
-func TestHandshakeServerSSLv3(t *testing.T) {
- testServerScript(t, "SSLv3", sslv3ServerScript, testConfig, nil)
+func (test *serverTest) loadData() (flows [][]byte, err error) {
+ in, err := os.Open(test.dataPath())
+ if err != nil {
+ return nil, err
+ }
+ defer in.Close()
+ return parseTestData(in)
}
-// TestHandshakeServerSNI involves a client sending an SNI extension of
-// "snitest.com", which happens to match the CN of testSNICertificate. The test
-// verifies that the server correctly selects that certificate.
-func TestHandshakeServerSNI(t *testing.T) {
- testServerScript(t, "SNI", selectCertificateBySNIScript, testConfig, nil)
-}
+func (test *serverTest) run(t *testing.T, write bool) {
+ var clientConn, serverConn net.Conn
+ var recordingConn *recordingConn
+ var childProcess *exec.Cmd
-func TestResumption(t *testing.T) {
- testServerScript(t, "IssueTicket", issueSessionTicketTest, testConfig, nil)
- testServerScript(t, "Resume", serverResumeTest, testConfig, nil)
-}
+ if write {
+ var err error
+ recordingConn, childProcess, err = test.connFromCommand()
+ if err != nil {
+ t.Fatalf("Failed to start subcommand: %s", err)
+ }
+ serverConn = recordingConn
+ } else {
+ clientConn, serverConn = net.Pipe()
+ }
+ config := test.config
+ if config == nil {
+ config = testConfig
+ }
+ server := Server(serverConn, config)
+ connStateChan := make(chan ConnectionState, 1)
+ go func() {
+ var err error
+ if _, err = server.Write([]byte("hello, world\n")); err != nil {
+ t.Logf("Error from Server.Write: %s", err)
+ }
+ if len(test.expectHandshakeErrorIncluding) > 0 {
+ if err == nil {
+ t.Errorf("Error expected, but no error returned")
+ } else if s := err.Error(); !strings.Contains(s, test.expectHandshakeErrorIncluding) {
+ t.Errorf("Error expected containing '%s' but got '%s'", test.expectHandshakeErrorIncluding, s)
+ }
+ }
+ server.Close()
+ serverConn.Close()
+ connStateChan <- server.ConnectionState()
+ }()
-func TestTLS12ClientCertServer(t *testing.T) {
- config := *testConfig
- config.MaxVersion = VersionTLS12
- config.ClientAuth = RequireAnyClientCert
- config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA}
+ 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())
+ }
+ }
+ for i, b := range flows {
+ if i%2 == 0 {
+ clientConn.Write(b)
+ continue
+ }
+ 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)
+ }
+ }
+ }
+ clientConn.Close()
+ }
- testServerScript(t, "TLS12", tls12ServerScript, &config, nil)
-}
+ connState := <-connStateChan
+ peerCerts := connState.PeerCertificates
+ if len(peerCerts) == len(test.expectedPeerCerts) {
+ for i, peerCert := range peerCerts {
+ block, _ := pem.Decode([]byte(test.expectedPeerCerts[i]))
+ if !bytes.Equal(block.Bytes, peerCert.Raw) {
+ t.Fatalf("%s: mismatch on peer cert %d", test.name, i+1)
+ }
+ }
+ } else {
+ t.Fatalf("%s: mismatch on peer list length: %d (wanted) != %d (got)", test.name, len(test.expectedPeerCerts), len(peerCerts))
+ }
-type clientauthTest struct {
- name string
- clientauth ClientAuthType
- peers []*x509.Certificate
- script [][]byte
-}
+ if test.validate != nil {
+ if err := test.validate(connState); err != nil {
+ t.Fatalf("validate callback returned error: %s", err)
+ }
+ }
-func TestClientAuthRSA(t *testing.T) {
- for _, cat := range clientauthRSATests {
- t.Log("running", cat.name)
- cfg := new(Config)
- *cfg = *testConfig
- cfg.ClientAuth = cat.clientauth
- testServerScript(t, cat.name, cat.script, cfg, cat.peers)
+ if write {
+ path := test.dataPath()
+ out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
+ if err != nil {
+ t.Fatalf("Failed to create output file: %s", err)
+ }
+ defer out.Close()
+ recordingConn.Close()
+ if len(recordingConn.flows) < 3 {
+ childProcess.Stdout.(*bytes.Buffer).WriteTo(os.Stdout)
+ if len(test.expectHandshakeErrorIncluding) == 0 {
+ t.Fatalf("Handshake failed")
+ }
+ }
+ recordingConn.WriteTo(out)
+ fmt.Printf("Wrote %s\n", path)
+ childProcess.Wait()
}
}
-func TestClientAuthECDSA(t *testing.T) {
- for _, cat := range clientauthECDSATests {
- t.Log("running", cat.name)
- cfg := new(Config)
- *cfg = *testConfig
- cfg.Certificates = make([]Certificate, 1)
- cfg.Certificates[0].Certificate = [][]byte{testECDSACertificate}
- cfg.Certificates[0].PrivateKey = testECDSAPrivateKey
- cfg.BuildNameToCertificate()
- cfg.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA}
- cfg.ClientAuth = cat.clientauth
- testServerScript(t, cat.name, cat.script, cfg, cat.peers)
+func runServerTestForVersion(t *testing.T, template *serverTest, prefix, option string) {
+ test := *template
+ test.name = prefix + test.name
+ if len(test.command) == 0 {
+ test.command = defaultClientCommand
}
+ test.command = append([]string(nil), test.command...)
+ test.command = append(test.command, option)
+ test.run(t, *update)
}
-// TestCipherSuiteCertPreferance ensures that we select an RSA ciphersuite with
-// an RSA certificate and an ECDSA ciphersuite with an ECDSA certificate.
-func TestCipherSuiteCertPreferance(t *testing.T) {
- var config = *testConfig
- config.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}
- config.MaxVersion = VersionTLS11
- config.PreferServerCipherSuites = true
- testServerScript(t, "CipherSuiteCertPreference", tls11ECDHEAESServerScript, &config, nil)
-
- config = *testConfig
- config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA}
- config.Certificates = []Certificate{
- Certificate{
- Certificate: [][]byte{testECDSACertificate},
- PrivateKey: testECDSAPrivateKey,
- },
- }
- config.BuildNameToCertificate()
- config.PreferServerCipherSuites = true
- testServerScript(t, "CipherSuiteCertPreference2", ecdheECDSAAESServerScript, &config, nil)
+func runServerTestSSLv3(t *testing.T, template *serverTest) {
+ runServerTestForVersion(t, template, "SSLv3-", "-ssl3")
}
-func TestTLS11Server(t *testing.T) {
- var config = *testConfig
- config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}
- config.MaxVersion = VersionTLS11
- testServerScript(t, "TLS11", tls11ECDHEAESServerScript, &config, nil)
+func runServerTestTLS10(t *testing.T, template *serverTest) {
+ runServerTestForVersion(t, template, "TLSv10-", "-tls1")
}
-func TestAESGCM(t *testing.T) {
- var config = *testConfig
- config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}
- config.MaxVersion = VersionTLS12
- testServerScript(t, "AES-GCM", aesGCMServerScript, &config, nil)
+func runServerTestTLS11(t *testing.T, template *serverTest) {
+ runServerTestForVersion(t, template, "TLSv11-", "-tls1_1")
}
-// recordingConn is a net.Conn that records the traffic that passes through it.
-// WriteTo can be used to produce Go code that contains the recorded traffic.
-type recordingConn struct {
- net.Conn
- lock sync.Mutex
- flows [][]byte
- currentlyReading bool
+func runServerTestTLS12(t *testing.T, template *serverTest) {
+ runServerTestForVersion(t, template, "TLSv12-", "-tls1_2")
}
-func (r *recordingConn) Read(b []byte) (n int, err error) {
- if n, err = r.Conn.Read(b); n == 0 {
- return
+func TestHandshakeServerRSARC4(t *testing.T) {
+ test := &serverTest{
+ name: "RSA-RC4",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "RC4-SHA"},
}
- b = b[:n]
+ runServerTestSSLv3(t, test)
+ runServerTestTLS10(t, test)
+ runServerTestTLS11(t, test)
+ runServerTestTLS12(t, test)
+}
- r.lock.Lock()
- defer r.lock.Unlock()
+func TestHandshakeServerRSA3DES(t *testing.T) {
+ test := &serverTest{
+ name: "RSA-3DES",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "DES-CBC3-SHA"},
+ }
+ runServerTestSSLv3(t, test)
+ runServerTestTLS10(t, test)
+ runServerTestTLS12(t, test)
+}
- if l := len(r.flows); l == 0 || !r.currentlyReading {
- buf := make([]byte, len(b))
- copy(buf, b)
- r.flows = append(r.flows, buf)
- } else {
- r.flows[l-1] = append(r.flows[l-1], b[:n]...)
+func TestHandshakeServerRSAAES(t *testing.T) {
+ test := &serverTest{
+ name: "RSA-AES",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA"},
}
- r.currentlyReading = true
- return
+ runServerTestSSLv3(t, test)
+ runServerTestTLS10(t, test)
+ runServerTestTLS12(t, test)
}
-func (r *recordingConn) Write(b []byte) (n int, err error) {
- if n, err = r.Conn.Write(b); n == 0 {
- return
+func TestHandshakeServerAESGCM(t *testing.T) {
+ test := &serverTest{
+ name: "RSA-AES-GCM",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-RSA-AES128-GCM-SHA256"},
}
- b = b[:n]
+ runServerTestTLS12(t, test)
+}
- r.lock.Lock()
- defer r.lock.Unlock()
+func TestHandshakeServerECDHEECDSAAES(t *testing.T) {
+ config := *testConfig
+ config.Certificates = make([]Certificate, 1)
+ config.Certificates[0].Certificate = [][]byte{testECDSACertificate}
+ config.Certificates[0].PrivateKey = testECDSAPrivateKey
+ config.BuildNameToCertificate()
- if l := len(r.flows); l == 0 || r.currentlyReading {
- buf := make([]byte, len(b))
- copy(buf, b)
- r.flows = append(r.flows, buf)
- } else {
- r.flows[l-1] = append(r.flows[l-1], b[:n]...)
+ test := &serverTest{
+ name: "ECDHE-ECDSA-AES",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-ECDSA-AES256-SHA"},
+ config: &config,
}
- r.currentlyReading = false
- return
+ runServerTestTLS10(t, test)
+ runServerTestTLS12(t, test)
}
-// WriteTo writes Go source code to w that contains the recorded traffic.
-func (r *recordingConn) WriteTo(w io.Writer) {
- fmt.Fprintf(w, "var changeMe = [][]byte {\n")
- for _, buf := range r.flows {
- fmt.Fprintf(w, "\t{")
- for i, b := range buf {
- if i%8 == 0 {
- fmt.Fprintf(w, "\n\t\t")
+func TestHandshakeServerALPN(t *testing.T) {
+ config := *testConfig
+ config.NextProtos = []string{"proto1", "proto2"}
+
+ test := &serverTest{
+ name: "ALPN",
+ // Note that this needs OpenSSL 1.0.2 because that is the first
+ // version that supports the -alpn flag.
+ command: []string{"openssl", "s_client", "-alpn", "proto2,proto1"},
+ config: &config,
+ validate: func(state ConnectionState) error {
+ // The server's preferences should override the client.
+ if state.NegotiatedProtocol != "proto1" {
+ return fmt.Errorf("Got protocol %q, wanted proto1", state.NegotiatedProtocol)
}
- fmt.Fprintf(w, "0x%02x, ", b)
- }
- fmt.Fprintf(w, "\n\t},\n")
+ return nil
+ },
}
- fmt.Fprintf(w, "}\n")
+ runServerTestTLS12(t, test)
}
-var serve = flag.Bool("serve", false, "run a TLS server on :10443")
-var testCipherSuites = flag.String("ciphersuites",
- "0x"+strconv.FormatInt(int64(TLS_RSA_WITH_RC4_128_SHA), 16),
- "cipher suites to accept in serving mode")
-var testMinVersion = flag.String("minversion",
- "0x"+strconv.FormatInt(int64(VersionSSL30), 16),
- "minimum version to negotiate")
-var testMaxVersion = flag.String("maxversion",
- "0x"+strconv.FormatInt(int64(VersionTLS10), 16),
- "maximum version to negotiate")
-var testClientAuth = flag.Int("clientauth", 0, "value for tls.Config.ClientAuth")
-
-func GetTestConfig() *Config {
- var config = *testConfig
-
- minVersion, err := strconv.ParseUint(*testMinVersion, 0, 64)
- if err != nil {
- panic(err)
- }
- config.MinVersion = uint16(minVersion)
- maxVersion, err := strconv.ParseUint(*testMaxVersion, 0, 64)
- if err != nil {
- panic(err)
+func TestHandshakeServerALPNNoMatch(t *testing.T) {
+ config := *testConfig
+ config.NextProtos = []string{"proto3"}
+
+ test := &serverTest{
+ name: "ALPN-NoMatch",
+ // Note that this needs OpenSSL 1.0.2 because that is the first
+ // version that supports the -alpn flag.
+ command: []string{"openssl", "s_client", "-alpn", "proto2,proto1"},
+ config: &config,
+ validate: func(state ConnectionState) error {
+ // Rather than reject the connection, Go doesn't select
+ // a protocol when there is no overlap.
+ if state.NegotiatedProtocol != "" {
+ return fmt.Errorf("Got protocol %q, wanted ''", state.NegotiatedProtocol)
+ }
+ return nil
+ },
}
- config.MaxVersion = uint16(maxVersion)
+ runServerTestTLS12(t, test)
+}
- suites := strings.Split(*testCipherSuites, ",")
- config.CipherSuites = make([]uint16, len(suites))
- for i := range suites {
- suite, err := strconv.ParseUint(suites[i], 0, 64)
- if err != nil {
- panic(err)
- }
- config.CipherSuites[i] = uint16(suite)
+// TestHandshakeServerSNI involves a client sending an SNI extension of
+// "snitest.com", which happens to match the CN of testSNICertificate. The test
+// verifies that the server correctly selects that certificate.
+func TestHandshakeServerSNI(t *testing.T) {
+ test := &serverTest{
+ name: "SNI",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-servername", "snitest.com"},
}
+ runServerTestTLS12(t, test)
+}
- ecdsa := false
- for _, suite := range config.CipherSuites {
- switch suite {
- case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
- TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
- TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
- ecdsa = true
- }
+// TestHandshakeServerSNICertForName is similar to TestHandshakeServerSNI, but
+// tests the dynamic GetCertificate method
+func TestHandshakeServerSNIGetCertificate(t *testing.T) {
+ config := *testConfig
+
+ // Replace the NameToCertificate map with a GetCertificate function
+ nameToCert := config.NameToCertificate
+ config.NameToCertificate = nil
+ config.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) {
+ cert, _ := nameToCert[clientHello.ServerName]
+ return cert, nil
}
- if ecdsa {
- config.Certificates = nil
- if !*connect {
- config.Certificates = make([]Certificate, 1)
- config.Certificates[0].Certificate = [][]byte{testECDSACertificate}
- config.Certificates[0].PrivateKey = testECDSAPrivateKey
- }
- config.BuildNameToCertificate()
+ test := &serverTest{
+ name: "SNI",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-servername", "snitest.com"},
+ config: &config,
}
-
- config.ClientAuth = ClientAuthType(*testClientAuth)
- return &config
+ runServerTestTLS12(t, test)
}
-func TestRunServer(t *testing.T) {
- if !*serve {
- return
- }
-
- config := GetTestConfig()
+// TestHandshakeServerSNICertForNameNotFound is similar to
+// TestHandshakeServerSNICertForName, but tests to make sure that when the
+// GetCertificate method doesn't return a cert, we fall back to what's in
+// the NameToCertificate map.
+func TestHandshakeServerSNIGetCertificateNotFound(t *testing.T) {
+ config := *testConfig
- const addr = ":10443"
- l, err := net.Listen("tcp", addr)
- if err != nil {
- t.Fatal(err)
+ config.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) {
+ return nil, nil
}
- log.Printf("Now listening for connections on %s", addr)
-
- for {
- tcpConn, err := l.Accept()
- if err != nil {
- log.Printf("error accepting connection: %s", err)
- break
- }
-
- record := &recordingConn{
- Conn: tcpConn,
- }
-
- conn := Server(record, config)
- if err := conn.Handshake(); err != nil {
- log.Printf("error from TLS handshake: %s", err)
- break
- }
-
- _, err = conn.Write([]byte("hello, world\n"))
- if err != nil {
- log.Printf("error from Write: %s", err)
- continue
- }
-
- conn.Close()
-
- record.WriteTo(os.Stdout)
+ test := &serverTest{
+ name: "SNI",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-servername", "snitest.com"},
+ config: &config,
}
+ runServerTestTLS12(t, test)
}
-func bigFromString(s string) *big.Int {
- ret := new(big.Int)
- ret.SetString(s, 10)
- return ret
-}
+// TestHandshakeServerSNICertForNameError tests to make sure that errors in
+// GetCertificate result in a tls alert.
+func TestHandshakeServerSNIGetCertificateError(t *testing.T) {
+ config := *testConfig
-func fromHex(s string) []byte {
- b, _ := hex.DecodeString(s)
- return b
+ config.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) {
+ return nil, fmt.Errorf("Test error in GetCertificate")
+ }
+ test := &serverTest{
+ name: "SNI",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-servername", "snitest.com"},
+ config: &config,
+ expectAlert: true,
+ }
+ runServerTestTLS12(t, test)
}
-var testRSACertificate = fromHex("308202b030820219a00302010202090085b0bba48a7fb8ca300d06092a864886f70d01010505003045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3130303432343039303933385a170d3131303432343039303933385a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819f300d06092a864886f70d010101050003818d0030818902818100bb79d6f517b5e5bf4610d0dc69bee62b07435ad0032d8a7a4385b71452e7a5654c2c78b8238cb5b482e5de1f953b7e62a52ca533d6fe125c7a56fcf506bffa587b263fb5cd04d3d0c921964ac7f4549f5abfef427100fe1899077f7e887d7df10439c4a22edb51c97ce3c04c3b326601cfafb11db8719a1ddbdb896baeda2d790203010001a381a73081a4301d0603551d0e04160414b1ade2855acfcb28db69ce2369ded3268e18883930750603551d23046e306c8014b1ade2855acfcb28db69ce2369ded3268e188839a149a4473045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746482090085b0bba48a7fb8ca300c0603551d13040530030101ff300d06092a864886f70d010105050003818100086c4524c76bb159ab0c52ccf2b014d7879d7a6475b55a9566e4c52b8eae12661feb4f38b36e60d392fdf74108b52513b1187a24fb301dbaed98b917ece7d73159db95d31d78ea50565cd5825a2d5a5f33c4b6d8c97590968c0f5298b5cd981f89205ff2a01ca31b9694dda9fd57e970e8266d71999b266e3850296c90a7bdd9")
-
-var testECDSACertificate = fromHex("3082020030820162020900b8bf2d47a0d2ebf4300906072a8648ce3d04013045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3132313132323135303633325a170d3232313132303135303633325a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819b301006072a8648ce3d020106052b81040023038186000400c4a1edbe98f90b4873367ec316561122f23d53c33b4d213dcd6b75e6f6b0dc9adf26c1bcb287f072327cb3642f1c90bcea6823107efee325c0483a69e0286dd33700ef0462dd0da09c706283d881d36431aa9e9731bd96b068c09b23de76643f1a5c7fe9120e5858b65f70dd9bd8ead5d7f5d5ccb9b69f30665b669a20e227e5bffe3b300906072a8648ce3d040103818c0030818802420188a24febe245c5487d1bacf5ed989dae4770c05e1bb62fbdf1b64db76140d311a2ceee0b7e927eff769dc33b7ea53fcefa10e259ec472d7cacda4e970e15a06fd00242014dfcbe67139c2d050ebd3fa38c25c13313830d9406bbd4377af6ec7ac9862eddd711697f857c56defb31782be4c7780daecbbe9e4e3624317b6a0f399512078f2a")
-
-var testSNICertificate = fromHex("308201f23082015da003020102020100300b06092a864886f70d01010530283110300e060355040a130741636d6520436f311430120603550403130b736e69746573742e636f6d301e170d3132303431313137343033355a170d3133303431313137343533355a30283110300e060355040a130741636d6520436f311430120603550403130b736e69746573742e636f6d30819d300b06092a864886f70d01010103818d0030818902818100bb79d6f517b5e5bf4610d0dc69bee62b07435ad0032d8a7a4385b71452e7a5654c2c78b8238cb5b482e5de1f953b7e62a52ca533d6fe125c7a56fcf506bffa587b263fb5cd04d3d0c921964ac7f4549f5abfef427100fe1899077f7e887d7df10439c4a22edb51c97ce3c04c3b326601cfafb11db8719a1ddbdb896baeda2d790203010001a3323030300e0603551d0f0101ff0404030200a0300d0603551d0e0406040401020304300f0603551d2304083006800401020304300b06092a864886f70d0101050381810089c6455f1c1f5ef8eb1ab174ee2439059f5c4259bb1a8d86cdb1d056f56a717da40e95ab90f59e8deaf627c157995094db0802266eb34fc6842dea8a4b68d9c1389103ab84fb9e1f85d9b5d23ff2312c8670fbb540148245a4ebafe264d90c8a4cf4f85b0fac12ac2fc4a3154bad52462868af96c62c6525d652b6e31845bdcc")
+// TestCipherSuiteCertPreferance ensures that we select an RSA ciphersuite with
+// an RSA certificate and an ECDSA ciphersuite with an ECDSA certificate.
+func TestCipherSuiteCertPreferenceECDSA(t *testing.T) {
+ config := *testConfig
+ config.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA}
+ config.PreferServerCipherSuites = true
-var testRSAPrivateKey = &rsa.PrivateKey{
- PublicKey: rsa.PublicKey{
- N: bigFromString("131650079503776001033793877885499001334664249354723305978524647182322416328664556247316495448366990052837680518067798333412266673813370895702118944398081598789828837447552603077848001020611640547221687072142537202428102790818451901395596882588063427854225330436740647715202971973145151161964464812406232198521"),
- E: 65537,
- },
- D: bigFromString("29354450337804273969007277378287027274721892607543397931919078829901848876371746653677097639302788129485893852488285045793268732234230875671682624082413996177431586734171663258657462237320300610850244186316880055243099640544518318093544057213190320837094958164973959123058337475052510833916491060913053867729"),
- Primes: []*big.Int{
- bigFromString("11969277782311800166562047708379380720136961987713178380670422671426759650127150688426177829077494755200794297055316163155755835813760102405344560929062149"),
- bigFromString("10998999429884441391899182616418192492905073053684657075974935218461686523870125521822756579792315215543092255516093840728890783887287417039645833477273829"),
- },
-}
+ test := &serverTest{
+ name: "CipherSuiteCertPreferenceRSA",
+ config: &config,
+ }
+ runServerTestTLS12(t, test)
-var testECDSAPrivateKey = &ecdsa.PrivateKey{
- PublicKey: ecdsa.PublicKey{
- Curve: &elliptic.CurveParams{
- P: bigFromString("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151"),
- N: bigFromString("6864797660130609714981900799081393217269435300143305409394463459185543183397655394245057746333217197532963996371363321113864768612440380340372808892707005449"),
- B: bigFromString("1093849038073734274511112390766805569936207598951683748994586394495953116150735016013708737573759623248592132296706313309438452531591012912142327488478985984"),
- Gx: bigFromString("2661740802050217063228768716723360960729859168756973147706671368418802944996427808491545080627771902352094241225065558662157113545570916814161637315895999846"),
- Gy: bigFromString("3757180025770020463545507224491183603594455134769762486694567779615544477440556316691234405012945539562144444537289428522585666729196580810124344277578376784"),
- BitSize: 521,
+ config = *testConfig
+ config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA}
+ config.Certificates = []Certificate{
+ {
+ Certificate: [][]byte{testECDSACertificate},
+ PrivateKey: testECDSAPrivateKey,
},
- X: bigFromString("2636411247892461147287360222306590634450676461695221912739908880441342231985950069527906976759812296359387337367668045707086543273113073382714101597903639351"),
- Y: bigFromString("3204695818431246682253994090650952614555094516658732116404513121125038617915183037601737180082382202488628239201196033284060130040574800684774115478859677243"),
- },
- D: bigFromString("5477294338614160138026852784385529180817726002953041720191098180813046231640184669647735805135001309477695746518160084669446643325196003346204701381388769751"),
-}
-
-func loadPEMCert(in string) *x509.Certificate {
- block, _ := pem.Decode([]byte(in))
- if block.Type == "CERTIFICATE" && len(block.Headers) == 0 {
- cert, err := x509.ParseCertificate(block.Bytes)
- if err == nil {
- return cert
- }
- panic("error parsing cert")
}
- panic("error parsing PEM")
-}
+ config.BuildNameToCertificate()
+ config.PreferServerCipherSuites = true
-// Script of interaction with gnutls implementation.
-// The values for this test are obtained by building and running in server mode:
-// % go test -test.run "TestRunServer" -serve
-// The recorded bytes are written to stdout.
-var rsaRC4ServerScript = [][]byte{
- {
- 0x16, 0x03, 0x01, 0x00, 0x54, 0x01, 0x00, 0x00,
- 0x50, 0x03, 0x01, 0x50, 0x77, 0x3d, 0xbd, 0x32,
- 0x13, 0xd7, 0xea, 0x33, 0x65, 0x02, 0xb8, 0x70,
- 0xb7, 0x84, 0xc4, 0x05, 0x1f, 0xa4, 0x24, 0xc4,
- 0x91, 0x69, 0x04, 0x32, 0x96, 0xfe, 0x5b, 0x49,
- 0x71, 0x60, 0x9a, 0x00, 0x00, 0x28, 0x00, 0x39,
- 0x00, 0x38, 0x00, 0x35, 0x00, 0x16, 0x00, 0x13,
- 0x00, 0x0a, 0x00, 0x33, 0x00, 0x32, 0x00, 0x2f,
- 0x00, 0x05, 0x00, 0x04, 0x00, 0x15, 0x00, 0x12,
- 0x00, 0x09, 0x00, 0x14, 0x00, 0x11, 0x00, 0x08,
- 0x00, 0x06, 0x00, 0x03, 0x00, 0xff, 0x02, 0x01,
- 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00,
- 0x26, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x16,
- 0x03, 0x01, 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba,
- 0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82,
- 0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03,
- 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0,
- 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d,
- 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d,
- 0x31, 0x30, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39,
- 0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31,
- 0x31, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30,
- 0x39, 0x33, 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b,
- 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
- 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06,
- 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f,
- 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
- 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04,
- 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72,
- 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67,
- 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20,
- 0x4c, 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d,
- 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d,
- 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00,
- 0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf,
- 0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b,
- 0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a,
- 0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65,
- 0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4,
- 0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62,
- 0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c,
- 0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58,
- 0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0,
- 0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f,
- 0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18,
- 0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1,
- 0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9,
- 0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01,
- 0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d,
- 0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79,
- 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7,
- 0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55,
- 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad,
- 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69,
- 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18,
- 0x88, 0x39, 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d,
- 0x23, 0x04, 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1,
- 0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb,
- 0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e,
- 0x18, 0x88, 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30,
- 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
- 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
- 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
- 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
- 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
- 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e,
- 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
- 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
- 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09,
- 0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8,
- 0xca, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13,
- 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
- 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81,
- 0x81, 0x00, 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b,
- 0xb1, 0x59, 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0,
- 0x14, 0xd7, 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5,
- 0x5a, 0x95, 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae,
- 0x12, 0x66, 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e,
- 0x60, 0xd3, 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5,
- 0x25, 0x13, 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30,
- 0x1d, 0xba, 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7,
- 0xd7, 0x31, 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78,
- 0xea, 0x50, 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d,
- 0x5a, 0x5f, 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75,
- 0x90, 0x96, 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd,
- 0x98, 0x1f, 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c,
- 0xa3, 0x1b, 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57,
- 0xe9, 0x70, 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b,
- 0x26, 0x6e, 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7,
- 0xbd, 0xd9, 0x16, 0x03, 0x01, 0x00, 0x04, 0x0e,
- 0x00, 0x00, 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00,
- 0x82, 0x00, 0x80, 0x2d, 0x09, 0x7c, 0x7f, 0xfc,
- 0x84, 0xce, 0xb3, 0x30, 0x9b, 0xf9, 0xb7, 0xc8,
- 0xc3, 0xff, 0xee, 0x6f, 0x20, 0x8a, 0xf4, 0xfb,
- 0x86, 0x55, 0x1f, 0x6a, 0xb4, 0x81, 0x50, 0x3a,
- 0x46, 0x1b, 0xd3, 0xca, 0x4b, 0x11, 0xff, 0xef,
- 0x02, 0xbc, 0x18, 0xb8, 0x4a, 0x7d, 0x43, 0x23,
- 0x96, 0x92, 0x27, 0x7c, 0xca, 0xcf, 0xe6, 0x91,
- 0xe8, 0x14, 0x97, 0x68, 0xb4, 0xe5, 0xc0, 0xc9,
- 0x23, 0xdd, 0x54, 0x07, 0xa6, 0x2e, 0x8c, 0x98,
- 0xfc, 0xc6, 0x8c, 0x04, 0x6b, 0x1b, 0x5f, 0xd5,
- 0x3d, 0x8b, 0x6c, 0x55, 0x4f, 0x7a, 0xe6, 0x6c,
- 0x74, 0x2c, 0x1e, 0x34, 0xdb, 0xfb, 0x00, 0xb1,
- 0x4e, 0x10, 0x21, 0x16, 0xe0, 0x3e, 0xc5, 0x64,
- 0x84, 0x28, 0x2b, 0x2b, 0x29, 0x47, 0x51, 0x34,
- 0x76, 0x15, 0x20, 0x71, 0x0b, 0x30, 0xa1, 0x85,
- 0xd5, 0x15, 0x18, 0x14, 0x64, 0x4b, 0x40, 0x7c,
- 0x4f, 0xb3, 0x7b, 0x14, 0x03, 0x01, 0x00, 0x01,
- 0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0xab, 0xee,
- 0xf5, 0x97, 0x5f, 0xc6, 0x78, 0xf3, 0xc6, 0x83,
- 0x5b, 0x55, 0x4f, 0xcb, 0x45, 0x3f, 0xfa, 0xf7,
- 0x05, 0x02, 0xc2, 0x63, 0x87, 0x18, 0xb5, 0x9a,
- 0x62, 0xe2, 0x3f, 0x88, 0x5a, 0x60, 0x61, 0x72,
- 0xfa, 0x9c,
- },
- {
- 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
- 0x01, 0x00, 0x24, 0x72, 0xa4, 0xe4, 0xaa, 0xd2,
- 0xc4, 0x39, 0x7e, 0x2a, 0xc1, 0x6f, 0x34, 0x42,
- 0x28, 0xcb, 0x9d, 0x7a, 0x09, 0xca, 0x96, 0xad,
- 0x0e, 0x11, 0x51, 0x8a, 0x06, 0xb0, 0xe9, 0xca,
- 0xeb, 0xce, 0xe2, 0xd5, 0x2e, 0xc1, 0x8d, 0x17,
- 0x03, 0x01, 0x00, 0x21, 0x2e, 0x61, 0x86, 0x17,
- 0xdb, 0xa6, 0x30, 0xe2, 0x62, 0x06, 0x2a, 0x8b,
- 0x75, 0x2c, 0x2d, 0xcf, 0xf5, 0x01, 0x11, 0x52,
- 0x81, 0x38, 0xcf, 0xd5, 0xf7, 0xdc, 0x52, 0x31,
- 0x1f, 0x97, 0x43, 0xc2, 0x71, 0x15, 0x03, 0x01,
- 0x00, 0x16, 0xe0, 0x21, 0xfe, 0x36, 0x2e, 0x68,
- 0x2c, 0xf1, 0xbe, 0x04, 0xec, 0xd4, 0xc6, 0xdd,
- 0xac, 0x6f, 0x4c, 0x85, 0x32, 0x3f, 0x87, 0x1b,
- },
+ test = &serverTest{
+ name: "CipherSuiteCertPreferenceECDSA",
+ config: &config,
+ }
+ runServerTestTLS12(t, test)
}
-var rsaDES3ServerScript = [][]byte{
- {
- 0x16, 0x03, 0x00, 0x00, 0xc5, 0x01, 0x00, 0x00,
- 0xc1, 0x03, 0x03, 0x50, 0xae, 0x5d, 0x38, 0xec,
- 0xaa, 0x2f, 0x41, 0xf9, 0xd2, 0x7b, 0xa1, 0xfd,
- 0x0f, 0xff, 0x4e, 0x54, 0x0e, 0x15, 0x57, 0xaf,
- 0x2c, 0x91, 0xb5, 0x35, 0x5b, 0x2e, 0xb0, 0xec,
- 0x20, 0xe5, 0xd2, 0x00, 0x00, 0x50, 0xc0, 0x09,
- 0xc0, 0x23, 0xc0, 0x2b, 0xc0, 0x0a, 0xc0, 0x24,
- 0xc0, 0x2c, 0xc0, 0x08, 0xc0, 0x13, 0xc0, 0x27,
- 0xc0, 0x2f, 0xc0, 0x14, 0xc0, 0x30, 0xc0, 0x12,
- 0x00, 0x33, 0x00, 0x67, 0x00, 0x45, 0x00, 0x9e,
- 0x00, 0x39, 0x00, 0x6b, 0x00, 0x88, 0x00, 0x16,
- 0x00, 0x32, 0x00, 0x40, 0x00, 0x44, 0x00, 0xa2,
- 0x00, 0x38, 0x00, 0x6a, 0x00, 0x87, 0x00, 0x13,
- 0x00, 0x66, 0x00, 0x2f, 0x00, 0x3c, 0x00, 0x41,
- 0x00, 0x9c, 0x00, 0x35, 0x00, 0x3d, 0x00, 0x84,
- 0x00, 0x0a, 0x00, 0x05, 0x00, 0x04, 0x01, 0x00,
- 0x00, 0x48, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x01, 0x00,
- 0x00, 0x23, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0c,
- 0x00, 0x0a, 0x00, 0x13, 0x00, 0x15, 0x00, 0x17,
- 0x00, 0x18, 0x00, 0x19, 0x00, 0x0b, 0x00, 0x02,
- 0x01, 0x00, 0x00, 0x0d, 0x00, 0x1c, 0x00, 0x1a,
- 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x05, 0x01,
- 0x05, 0x03, 0x06, 0x01, 0x06, 0x03, 0x03, 0x01,
- 0x03, 0x02, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02,
- 0x02, 0x03,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x30, 0x02, 0x00, 0x00,
- 0x2c, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00,
- 0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x01,
- 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, 0x00, 0x02,
- 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, 0x02, 0xb0,
- 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, 0x02, 0x01,
- 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4,
- 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30,
- 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
- 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
- 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d,
- 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
- 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
- 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
- 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
- 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
- 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30,
- 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39,
- 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30,
- 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, 0x33,
- 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
- 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
- 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
- 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
- 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
- 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
- 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
- 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
- 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
- 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
- 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0x79,
- 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, 0x46, 0x10,
- 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, 0x07, 0x43,
- 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, 0x43, 0x85,
- 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, 0x4c, 0x2c,
- 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, 0x82, 0xe5,
- 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, 0xa5, 0x2c,
- 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, 0x7a, 0x56,
- 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, 0x7b, 0x26,
- 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, 0xc9, 0x21,
- 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, 0x5a, 0xbf,
- 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, 0x99, 0x07,
- 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, 0x04, 0x39,
- 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, 0x7c, 0xe3,
- 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, 0xcf, 0xaf,
- 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, 0xdb, 0xdb,
- 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, 0x02, 0x03,
- 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
- 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
- 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, 0xe2, 0x85,
- 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23,
- 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39,
- 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
- 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, 0xad, 0xe2,
- 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce,
- 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88,
- 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0x85,
- 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30,
- 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
- 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00,
- 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, 0xb1, 0x59,
- 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, 0x14, 0xd7,
- 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, 0x5a, 0x95,
- 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, 0x12, 0x66,
- 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, 0x60, 0xd3,
- 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, 0x25, 0x13,
- 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, 0x1d, 0xba,
- 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, 0xd7, 0x31,
- 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, 0xea, 0x50,
- 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, 0x5a, 0x5f,
- 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, 0x90, 0x96,
- 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, 0x98, 0x1f,
- 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, 0xa3, 0x1b,
- 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, 0xe9, 0x70,
- 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, 0x26, 0x6e,
- 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, 0xbd, 0xd9,
- 0x16, 0x03, 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00,
- 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00,
- 0x82, 0x00, 0x80, 0x51, 0x04, 0xf1, 0x7a, 0xbf,
- 0xe8, 0xa5, 0x86, 0x09, 0xa7, 0xf3, 0xcc, 0x93,
- 0x00, 0x10, 0x5b, 0xb8, 0xc1, 0x51, 0x0d, 0x5b,
- 0xcd, 0xed, 0x26, 0x01, 0x69, 0x73, 0xf4, 0x05,
- 0x8a, 0x6a, 0xc3, 0xb1, 0x9e, 0x84, 0x4e, 0x39,
- 0xcf, 0x5e, 0x55, 0xa9, 0x70, 0x19, 0x96, 0x91,
- 0xcd, 0x2c, 0x78, 0x3c, 0xa2, 0x6d, 0xb0, 0x49,
- 0x86, 0xf6, 0xd1, 0x3a, 0xde, 0x00, 0x4b, 0xa6,
- 0x25, 0xbf, 0x85, 0x39, 0xce, 0xb1, 0xcf, 0xbc,
- 0x16, 0xc7, 0x66, 0xac, 0xf8, 0xd2, 0x3b, 0xd1,
- 0xcc, 0x16, 0xac, 0x63, 0x3c, 0xbe, 0xd9, 0xb6,
- 0x6a, 0xe4, 0x13, 0x8a, 0xf4, 0x56, 0x2f, 0x92,
- 0x54, 0xd8, 0xf0, 0x84, 0x01, 0x32, 0x1a, 0xa9,
- 0x2d, 0xaf, 0x82, 0x0e, 0x00, 0xfa, 0x07, 0x88,
- 0xd9, 0x87, 0xe7, 0xdc, 0x9e, 0xe9, 0x72, 0x49,
- 0xb8, 0xfa, 0x8c, 0x7b, 0x07, 0x0b, 0x03, 0x7c,
- 0x10, 0x8c, 0x8a, 0x14, 0x03, 0x01, 0x00, 0x01,
- 0x01, 0x16, 0x03, 0x01, 0x00, 0xa8, 0x61, 0xa4,
- 0xf4, 0x5f, 0x8a, 0x1f, 0x5c, 0x92, 0x3f, 0x8c,
- 0xdb, 0xd6, 0x10, 0xcd, 0x9e, 0xe7, 0xf0, 0xc4,
- 0x3c, 0xb6, 0x1c, 0x9a, 0x56, 0x73, 0x7f, 0xa6,
- 0x14, 0x24, 0xcb, 0x96, 0x1f, 0xe0, 0xaf, 0xcd,
- 0x3c, 0x66, 0x43, 0xb7, 0x37, 0x65, 0x34, 0x47,
- 0xf8, 0x43, 0xf1, 0xcc, 0x15, 0xb8, 0xdc, 0x35,
- 0xe0, 0xa4, 0x2d, 0x78, 0x94, 0xe0, 0x02, 0xf3,
- 0x76, 0x46, 0xf7, 0x9b, 0x8d, 0x0d, 0x5d, 0x0b,
- 0xd3, 0xdd, 0x9a, 0x9e, 0x62, 0x2e, 0xc5, 0x98,
- 0x75, 0x63, 0x0c, 0xbf, 0x8e, 0x49, 0x33, 0x23,
- 0x7c, 0x00, 0xcf, 0xfb, 0xcf, 0xba, 0x0f, 0x41,
- 0x39, 0x89, 0xb9, 0xcc, 0x59, 0xd0, 0x2b, 0xb6,
- 0xec, 0x04, 0xe2, 0xc0, 0x52, 0xc7, 0xcf, 0x71,
- 0x47, 0xff, 0x70, 0x7e, 0xa9, 0xbd, 0x1c, 0xdd,
- 0x17, 0xa5, 0x6c, 0xb7, 0x10, 0x4f, 0x42, 0x18,
- 0x37, 0x69, 0xa9, 0xd2, 0xb3, 0x18, 0x84, 0x92,
- 0xa7, 0x47, 0x21, 0xf6, 0x95, 0x63, 0x29, 0xd6,
- 0xa5, 0xb6, 0xda, 0x65, 0x67, 0x69, 0xc4, 0x26,
- 0xac, 0x8b, 0x08, 0x58, 0xdd, 0x3c, 0x31, 0x20,
- 0xd5, 0x0c, 0x88, 0x72, 0x18, 0x16, 0x88, 0x1e,
- 0x4a, 0x0f, 0xe1, 0xcf, 0x95, 0x24,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x72, 0x04, 0x00, 0x00,
- 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
- 0xe8, 0x4b, 0xde, 0xef, 0xba, 0x3e, 0x18, 0x1c,
- 0x1e, 0x5e, 0xbc, 0x87, 0xf1, 0x87, 0x8d, 0x72,
- 0xe3, 0xbe, 0x0f, 0xdf, 0xfd, 0xd0, 0xb2, 0x89,
- 0xf8, 0x05, 0x9a, 0x52, 0x47, 0x77, 0x9e, 0xe8,
- 0xb1, 0x1d, 0x18, 0xed, 0x6a, 0x4b, 0x63, 0x1d,
- 0xf1, 0x62, 0xd2, 0x65, 0x21, 0x26, 0x73, 0xd4,
- 0x35, 0x5b, 0x95, 0x89, 0x12, 0x59, 0x23, 0x8c,
- 0xc3, 0xfc, 0xf9, 0x4d, 0x21, 0x79, 0xa0, 0xbd,
- 0xff, 0x33, 0xa2, 0x3d, 0x0b, 0x6f, 0x89, 0xc9,
- 0x23, 0xe4, 0xe7, 0x9f, 0x1d, 0x98, 0xf6, 0xed,
- 0x02, 0x8d, 0xac, 0x1a, 0xf9, 0xcb, 0xa5, 0x14,
- 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01,
- 0x00, 0x28, 0x91, 0x56, 0x80, 0xe2, 0x6d, 0x51,
- 0x88, 0x03, 0xf8, 0x49, 0xe6, 0x6a, 0x5a, 0xfb,
- 0x2f, 0x0b, 0xb5, 0xa1, 0x0d, 0x63, 0x83, 0xae,
- 0xb9, 0xbc, 0x05, 0xf0, 0x81, 0x00, 0x61, 0x83,
- 0x38, 0xda, 0x14, 0xf6, 0xea, 0xd8, 0x78, 0x65,
- 0xc7, 0x26, 0x17, 0x03, 0x01, 0x00, 0x18, 0x81,
- 0x30, 0x8b, 0x22, 0x5a, 0xd3, 0x7f, 0xc8, 0xf2,
- 0x8a, 0x6b, 0xa3, 0xba, 0x4d, 0xe7, 0x6e, 0xd2,
- 0xfd, 0xbf, 0xf2, 0xc5, 0x28, 0xa0, 0x62, 0x17,
- 0x03, 0x01, 0x00, 0x28, 0x17, 0x83, 0x3c, 0x78,
- 0x18, 0xfa, 0x8d, 0x58, 0x5c, 0xaa, 0x05, 0x7d,
- 0x67, 0x96, 0x11, 0x60, 0x11, 0xc0, 0x1e, 0x0d,
- 0x6a, 0x6e, 0x5f, 0x1d, 0x98, 0x4b, 0xff, 0x82,
- 0xee, 0x21, 0x06, 0x29, 0xd3, 0x8b, 0x80, 0x78,
- 0x39, 0x05, 0x34, 0x9b, 0x15, 0x03, 0x01, 0x00,
- 0x18, 0xa9, 0x38, 0x18, 0x4f, 0x9d, 0x84, 0x75,
- 0x88, 0x53, 0xd6, 0x85, 0xc2, 0x15, 0x4b, 0xe3,
- 0xe3, 0x35, 0x9a, 0x74, 0xc9, 0x3e, 0x13, 0xc1,
- 0x8c,
- },
-}
+func TestResumption(t *testing.T) {
+ sessionFilePath := tempFile("")
+ defer os.Remove(sessionFilePath)
-var rsaAESServerScript = [][]byte{
- {
- 0x16, 0x03, 0x00, 0x00, 0xc5, 0x01, 0x00, 0x00,
- 0xc1, 0x03, 0x03, 0x50, 0xae, 0x5c, 0xe9, 0x5e,
- 0x31, 0x93, 0x82, 0xa5, 0x6f, 0x51, 0x82, 0xc8,
- 0x55, 0x4f, 0x1f, 0x2e, 0x90, 0x98, 0x81, 0x13,
- 0x27, 0x80, 0x68, 0xb4, 0x2d, 0xba, 0x3a, 0x76,
- 0xd8, 0xd7, 0x2c, 0x00, 0x00, 0x50, 0xc0, 0x09,
- 0xc0, 0x23, 0xc0, 0x2b, 0xc0, 0x0a, 0xc0, 0x24,
- 0xc0, 0x2c, 0xc0, 0x08, 0xc0, 0x13, 0xc0, 0x27,
- 0xc0, 0x2f, 0xc0, 0x14, 0xc0, 0x30, 0xc0, 0x12,
- 0x00, 0x33, 0x00, 0x67, 0x00, 0x45, 0x00, 0x9e,
- 0x00, 0x39, 0x00, 0x6b, 0x00, 0x88, 0x00, 0x16,
- 0x00, 0x32, 0x00, 0x40, 0x00, 0x44, 0x00, 0xa2,
- 0x00, 0x38, 0x00, 0x6a, 0x00, 0x87, 0x00, 0x13,
- 0x00, 0x66, 0x00, 0x2f, 0x00, 0x3c, 0x00, 0x41,
- 0x00, 0x9c, 0x00, 0x35, 0x00, 0x3d, 0x00, 0x84,
- 0x00, 0x0a, 0x00, 0x05, 0x00, 0x04, 0x01, 0x00,
- 0x00, 0x48, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x01, 0x00,
- 0x00, 0x23, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0c,
- 0x00, 0x0a, 0x00, 0x13, 0x00, 0x15, 0x00, 0x17,
- 0x00, 0x18, 0x00, 0x19, 0x00, 0x0b, 0x00, 0x02,
- 0x01, 0x00, 0x00, 0x0d, 0x00, 0x1c, 0x00, 0x1a,
- 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x05, 0x01,
- 0x05, 0x03, 0x06, 0x01, 0x06, 0x03, 0x03, 0x01,
- 0x03, 0x02, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02,
- 0x02, 0x03,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x30, 0x02, 0x00, 0x00,
- 0x2c, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00,
- 0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x01,
- 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, 0x00, 0x02,
- 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, 0x02, 0xb0,
- 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, 0x02, 0x01,
- 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4,
- 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30,
- 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
- 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
- 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d,
- 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
- 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
- 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
- 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
- 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
- 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30,
- 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39,
- 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30,
- 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, 0x33,
- 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
- 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
- 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
- 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
- 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
- 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
- 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
- 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
- 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
- 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
- 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0x79,
- 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, 0x46, 0x10,
- 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, 0x07, 0x43,
- 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, 0x43, 0x85,
- 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, 0x4c, 0x2c,
- 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, 0x82, 0xe5,
- 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, 0xa5, 0x2c,
- 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, 0x7a, 0x56,
- 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, 0x7b, 0x26,
- 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, 0xc9, 0x21,
- 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, 0x5a, 0xbf,
- 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, 0x99, 0x07,
- 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, 0x04, 0x39,
- 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, 0x7c, 0xe3,
- 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, 0xcf, 0xaf,
- 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, 0xdb, 0xdb,
- 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, 0x02, 0x03,
- 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
- 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
- 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, 0xe2, 0x85,
- 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23,
- 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39,
- 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
- 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, 0xad, 0xe2,
- 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce,
- 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88,
- 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0x85,
- 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30,
- 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
- 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00,
- 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, 0xb1, 0x59,
- 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, 0x14, 0xd7,
- 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, 0x5a, 0x95,
- 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, 0x12, 0x66,
- 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, 0x60, 0xd3,
- 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, 0x25, 0x13,
- 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, 0x1d, 0xba,
- 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, 0xd7, 0x31,
- 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, 0xea, 0x50,
- 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, 0x5a, 0x5f,
- 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, 0x90, 0x96,
- 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, 0x98, 0x1f,
- 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, 0xa3, 0x1b,
- 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, 0xe9, 0x70,
- 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, 0x26, 0x6e,
- 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, 0xbd, 0xd9,
- 0x16, 0x03, 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00,
- 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00,
- 0x82, 0x00, 0x80, 0x51, 0x2e, 0xec, 0x0d, 0x86,
- 0xf3, 0x9f, 0xf2, 0x77, 0x04, 0x27, 0x2b, 0x0e,
- 0x9c, 0xab, 0x35, 0x84, 0x65, 0xff, 0x36, 0xef,
- 0xc0, 0x08, 0xc9, 0x1d, 0x9f, 0x29, 0xae, 0x8d,
- 0xc5, 0x66, 0x81, 0x31, 0x92, 0x5e, 0x3d, 0xac,
- 0xaa, 0x37, 0x28, 0x2c, 0x06, 0x91, 0xa6, 0xc2,
- 0xd0, 0x83, 0x34, 0x24, 0x1c, 0x88, 0xfc, 0x0a,
- 0xcf, 0xbf, 0xc2, 0x94, 0xe2, 0xed, 0xa7, 0x6a,
- 0xa8, 0x8d, 0x3d, 0xf7, 0x06, 0x7d, 0x69, 0xf8,
- 0x0d, 0xb2, 0xf7, 0xe4, 0x45, 0xcb, 0x0a, 0x25,
- 0xcb, 0xb2, 0x2e, 0x38, 0x9a, 0x84, 0x75, 0xe8,
- 0xe1, 0x42, 0x39, 0xa2, 0x18, 0x0e, 0x48, 0xca,
- 0x33, 0x16, 0x4e, 0xf6, 0x2f, 0xec, 0x07, 0xe7,
- 0x57, 0xe1, 0x20, 0x40, 0x40, 0x6d, 0x4e, 0x29,
- 0x04, 0x1a, 0x8c, 0x99, 0xfb, 0x19, 0x3c, 0xaa,
- 0x75, 0x64, 0xd3, 0xa6, 0xe6, 0xed, 0x3f, 0x5a,
- 0xd2, 0xc9, 0x80, 0x14, 0x03, 0x01, 0x00, 0x01,
- 0x01, 0x16, 0x03, 0x01, 0x01, 0x10, 0xe9, 0x9e,
- 0x06, 0x92, 0x18, 0xbf, 0x5e, 0xaf, 0x33, 0xc1,
- 0xbf, 0x0e, 0x12, 0x07, 0x48, 0x4f, 0x6b, 0x6c,
- 0xf5, 0x23, 0x5e, 0x87, 0xa7, 0xd3, 0x50, 0x79,
- 0x38, 0xdc, 0xe0, 0x49, 0xd3, 0x81, 0x21, 0x12,
- 0xd0, 0x3d, 0x9a, 0xfb, 0x83, 0xc1, 0x8b, 0xfc,
- 0x14, 0xd5, 0xd5, 0xa7, 0xa3, 0x34, 0x14, 0x71,
- 0xbe, 0xea, 0x37, 0x18, 0x12, 0x7f, 0x41, 0xfb,
- 0xc5, 0x51, 0x17, 0x9d, 0x96, 0x58, 0x14, 0xfb,
- 0x4f, 0xd7, 0xd3, 0x15, 0x0f, 0xec, 0x5a, 0x0d,
- 0x35, 0xbb, 0x3c, 0x81, 0x5b, 0x3f, 0xdf, 0x52,
- 0xa4, 0x4c, 0xcd, 0x13, 0xe1, 0x10, 0x37, 0x34,
- 0xbf, 0xb4, 0x80, 0x1e, 0x8d, 0xe2, 0xc3, 0x7a,
- 0x0f, 0x7b, 0x7d, 0x23, 0xeb, 0xd0, 0x99, 0x69,
- 0xad, 0x0a, 0x2d, 0xb3, 0x6c, 0xd6, 0x80, 0x11,
- 0x7f, 0x6c, 0xed, 0x1b, 0xcd, 0x08, 0x22, 0x56,
- 0x90, 0x0e, 0xa4, 0xc3, 0x29, 0x33, 0x96, 0x30,
- 0x34, 0x94, 0xa1, 0xeb, 0x9c, 0x1b, 0x5a, 0xd1,
- 0x03, 0x61, 0xf9, 0xdd, 0xf3, 0x64, 0x8a, 0xfd,
- 0x5f, 0x44, 0xdb, 0x2e, 0xa7, 0xfd, 0xe1, 0x1a,
- 0x66, 0xc5, 0x01, 0x9c, 0xc7, 0xd1, 0xc4, 0xd3,
- 0xea, 0x14, 0x3c, 0xed, 0x74, 0xbb, 0x1b, 0x97,
- 0x8f, 0xf1, 0x29, 0x39, 0x33, 0x92, 0x93, 0x4e,
- 0xf5, 0x87, 0x91, 0x61, 0x65, 0x8d, 0x27, 0x8d,
- 0x76, 0xc1, 0xfa, 0x6a, 0x99, 0x80, 0xb1, 0x9b,
- 0x29, 0x53, 0xce, 0x3e, 0xb6, 0x9a, 0xce, 0x3c,
- 0x19, 0x5e, 0x48, 0x83, 0xaa, 0xa7, 0x66, 0x98,
- 0x59, 0xf4, 0xbb, 0xf2, 0xbc, 0xd9, 0xc5, 0x9a,
- 0xc8, 0x2c, 0x63, 0x58, 0xd5, 0xd4, 0xbc, 0x03,
- 0xa9, 0x06, 0xa9, 0x80, 0x0d, 0xb3, 0x46, 0x2d,
- 0xe3, 0xc6, 0xaf, 0x1a, 0x39, 0x18, 0x7e, 0x1e,
- 0x83, 0x80, 0x46, 0x11, 0xd2, 0x13, 0x9f, 0xda,
- 0xfc, 0x2d, 0x42, 0xaa, 0x5a, 0x1d, 0x4c, 0x31,
- 0xe5, 0x58, 0x78, 0x5e, 0xe2, 0x04, 0xd6, 0x23,
- 0x7f, 0x3f, 0x06, 0xc0, 0x54, 0xf8,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x72, 0x04, 0x00, 0x00,
- 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
- 0xe8, 0x4b, 0xfb, 0xef, 0xba, 0xed, 0xc5, 0x36,
- 0xc8, 0x5a, 0x41, 0x3f, 0x05, 0xfa, 0xfe, 0x48,
- 0xc3, 0x91, 0x12, 0x8b, 0xe8, 0x32, 0x6a, 0x9f,
- 0xdc, 0x97, 0xe2, 0x77, 0xb9, 0x96, 0x2d, 0xd4,
- 0xe5, 0xbd, 0xa1, 0xfd, 0x94, 0xbb, 0x74, 0x63,
- 0xb1, 0x0c, 0x38, 0xbc, 0x6f, 0x69, 0xaf, 0xa3,
- 0x46, 0x9c, 0x96, 0x41, 0xde, 0x59, 0x23, 0xff,
- 0x15, 0x6b, 0x3a, 0xef, 0x91, 0x6d, 0x92, 0x44,
- 0xdc, 0x72, 0x1f, 0x40, 0x3d, 0xb5, 0x34, 0x8f,
- 0x2a, 0xac, 0x21, 0x69, 0x05, 0x6f, 0xb2, 0x60,
- 0x32, 0x5d, 0x3d, 0x97, 0xb4, 0x24, 0x99, 0x14,
- 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01,
- 0x00, 0x30, 0x68, 0x27, 0x97, 0xca, 0x63, 0x09,
- 0x22, 0xed, 0x0e, 0x61, 0x7c, 0x76, 0x31, 0x9c,
- 0xbe, 0x27, 0xc9, 0xe6, 0x09, 0xc3, 0xc3, 0xc2,
- 0xf4, 0xa2, 0x32, 0xba, 0x7c, 0xf2, 0x0f, 0xb8,
- 0x3d, 0xcb, 0xe2, 0x4c, 0xc0, 0x7d, 0x8e, 0x5b,
- 0x5a, 0xed, 0x05, 0x5c, 0x15, 0x96, 0x69, 0xc2,
- 0x6f, 0x5f, 0x17, 0x03, 0x01, 0x00, 0x20, 0x5a,
- 0xfe, 0x0b, 0xe1, 0x6f, 0xa8, 0x54, 0x19, 0x78,
- 0xca, 0xba, 0x2e, 0x1e, 0x2e, 0xe1, 0x5d, 0x17,
- 0xe5, 0x97, 0x05, 0x2c, 0x08, 0x0c, 0xff, 0xa8,
- 0x59, 0xa9, 0xde, 0x5e, 0x21, 0x34, 0x04, 0x17,
- 0x03, 0x01, 0x00, 0x30, 0x86, 0xb1, 0x3f, 0x88,
- 0x43, 0xf0, 0x07, 0xee, 0xa8, 0xf4, 0xbc, 0xe7,
- 0x5f, 0xc6, 0x8c, 0x86, 0x4c, 0xca, 0x70, 0x88,
- 0xcc, 0x6a, 0xb4, 0x3d, 0x40, 0xe8, 0x54, 0x89,
- 0x19, 0x43, 0x1f, 0x76, 0xe2, 0xac, 0xb2, 0x5b,
- 0x92, 0xf8, 0x57, 0x39, 0x2a, 0xc3, 0x6d, 0x13,
- 0x45, 0xfa, 0x36, 0x9e, 0x15, 0x03, 0x01, 0x00,
- 0x20, 0x6d, 0xed, 0x7b, 0x59, 0x28, 0x2a, 0x27,
- 0x04, 0x15, 0x07, 0x4e, 0xeb, 0x13, 0x00, 0xe3,
- 0x3a, 0x3f, 0xf8, 0xaa, 0x2b, 0x3b, 0x1a, 0x8c,
- 0x12, 0xd6, 0x4c, 0xec, 0x2a, 0xaf, 0x33, 0x60,
- 0xaf,
- },
-}
+ test := &serverTest{
+ name: "IssueTicket",
+ command: []string{"openssl", "s_client", "-cipher", "RC4-SHA", "-sess_out", sessionFilePath},
+ }
+ runServerTestTLS12(t, test)
-// Generated using:
-// $ go test -test.run TestRunServer -serve -ciphersuites=0xc00a
-// $ openssl s_client -host 127.0.0.1 -port 10443 -cipher ECDHE-ECDSA-AES256-SHA
-var ecdheECDSAAESServerScript = [][]byte{
- {
- 0x16, 0x03, 0x01, 0x00, 0xa0, 0x01, 0x00, 0x00,
- 0x9c, 0x03, 0x03, 0x50, 0xd7, 0x18, 0x31, 0x49,
- 0xde, 0x19, 0x8d, 0x08, 0x5c, 0x4b, 0x60, 0x67,
- 0x0f, 0xfe, 0xd0, 0x62, 0xf9, 0x31, 0x48, 0x17,
- 0x9e, 0x50, 0xc1, 0xd8, 0x35, 0x24, 0x0e, 0xa6,
- 0x09, 0x06, 0x51, 0x00, 0x00, 0x04, 0xc0, 0x0a,
- 0x00, 0xff, 0x01, 0x00, 0x00, 0x6f, 0x00, 0x0b,
- 0x00, 0x04, 0x03, 0x00, 0x01, 0x02, 0x00, 0x0a,
- 0x00, 0x34, 0x00, 0x32, 0x00, 0x0e, 0x00, 0x0d,
- 0x00, 0x19, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x18,
- 0x00, 0x09, 0x00, 0x0a, 0x00, 0x16, 0x00, 0x17,
- 0x00, 0x08, 0x00, 0x06, 0x00, 0x07, 0x00, 0x14,
- 0x00, 0x15, 0x00, 0x04, 0x00, 0x05, 0x00, 0x12,
- 0x00, 0x13, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03,
- 0x00, 0x0f, 0x00, 0x10, 0x00, 0x11, 0x00, 0x23,
- 0x00, 0x00, 0x00, 0x0d, 0x00, 0x22, 0x00, 0x20,
- 0x06, 0x01, 0x06, 0x02, 0x06, 0x03, 0x05, 0x01,
- 0x05, 0x02, 0x05, 0x03, 0x04, 0x01, 0x04, 0x02,
- 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x03, 0x03,
- 0x02, 0x01, 0x02, 0x02, 0x02, 0x03, 0x01, 0x01,
- 0x00, 0x0f, 0x00, 0x01, 0x01,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x30, 0x02, 0x00, 0x00,
- 0x2c, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xc0, 0x0a, 0x00, 0x00,
- 0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x01,
- 0x02, 0x0e, 0x0b, 0x00, 0x02, 0x0a, 0x00, 0x02,
- 0x07, 0x00, 0x02, 0x04, 0x30, 0x82, 0x02, 0x00,
- 0x30, 0x82, 0x01, 0x62, 0x02, 0x09, 0x00, 0xb8,
- 0xbf, 0x2d, 0x47, 0xa0, 0xd2, 0xeb, 0xf4, 0x30,
- 0x09, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d,
- 0x04, 0x01, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
- 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
- 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
- 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
- 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
- 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
- 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
- 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
- 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
- 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x31,
- 0x31, 0x32, 0x32, 0x31, 0x35, 0x30, 0x36, 0x33,
- 0x32, 0x5a, 0x17, 0x0d, 0x32, 0x32, 0x31, 0x31,
- 0x32, 0x30, 0x31, 0x35, 0x30, 0x36, 0x33, 0x32,
- 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06,
- 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55,
- 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
- 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d,
- 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30,
- 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18,
- 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
- 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73,
- 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64,
- 0x30, 0x81, 0x9b, 0x30, 0x10, 0x06, 0x07, 0x2a,
- 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05,
- 0x2b, 0x81, 0x04, 0x00, 0x23, 0x03, 0x81, 0x86,
- 0x00, 0x04, 0x00, 0xc4, 0xa1, 0xed, 0xbe, 0x98,
- 0xf9, 0x0b, 0x48, 0x73, 0x36, 0x7e, 0xc3, 0x16,
- 0x56, 0x11, 0x22, 0xf2, 0x3d, 0x53, 0xc3, 0x3b,
- 0x4d, 0x21, 0x3d, 0xcd, 0x6b, 0x75, 0xe6, 0xf6,
- 0xb0, 0xdc, 0x9a, 0xdf, 0x26, 0xc1, 0xbc, 0xb2,
- 0x87, 0xf0, 0x72, 0x32, 0x7c, 0xb3, 0x64, 0x2f,
- 0x1c, 0x90, 0xbc, 0xea, 0x68, 0x23, 0x10, 0x7e,
- 0xfe, 0xe3, 0x25, 0xc0, 0x48, 0x3a, 0x69, 0xe0,
- 0x28, 0x6d, 0xd3, 0x37, 0x00, 0xef, 0x04, 0x62,
- 0xdd, 0x0d, 0xa0, 0x9c, 0x70, 0x62, 0x83, 0xd8,
- 0x81, 0xd3, 0x64, 0x31, 0xaa, 0x9e, 0x97, 0x31,
- 0xbd, 0x96, 0xb0, 0x68, 0xc0, 0x9b, 0x23, 0xde,
- 0x76, 0x64, 0x3f, 0x1a, 0x5c, 0x7f, 0xe9, 0x12,
- 0x0e, 0x58, 0x58, 0xb6, 0x5f, 0x70, 0xdd, 0x9b,
- 0xd8, 0xea, 0xd5, 0xd7, 0xf5, 0xd5, 0xcc, 0xb9,
- 0xb6, 0x9f, 0x30, 0x66, 0x5b, 0x66, 0x9a, 0x20,
- 0xe2, 0x27, 0xe5, 0xbf, 0xfe, 0x3b, 0x30, 0x09,
- 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04,
- 0x01, 0x03, 0x81, 0x8c, 0x00, 0x30, 0x81, 0x88,
- 0x02, 0x42, 0x01, 0x88, 0xa2, 0x4f, 0xeb, 0xe2,
- 0x45, 0xc5, 0x48, 0x7d, 0x1b, 0xac, 0xf5, 0xed,
- 0x98, 0x9d, 0xae, 0x47, 0x70, 0xc0, 0x5e, 0x1b,
- 0xb6, 0x2f, 0xbd, 0xf1, 0xb6, 0x4d, 0xb7, 0x61,
- 0x40, 0xd3, 0x11, 0xa2, 0xce, 0xee, 0x0b, 0x7e,
- 0x92, 0x7e, 0xff, 0x76, 0x9d, 0xc3, 0x3b, 0x7e,
- 0xa5, 0x3f, 0xce, 0xfa, 0x10, 0xe2, 0x59, 0xec,
- 0x47, 0x2d, 0x7c, 0xac, 0xda, 0x4e, 0x97, 0x0e,
- 0x15, 0xa0, 0x6f, 0xd0, 0x02, 0x42, 0x01, 0x4d,
- 0xfc, 0xbe, 0x67, 0x13, 0x9c, 0x2d, 0x05, 0x0e,
- 0xbd, 0x3f, 0xa3, 0x8c, 0x25, 0xc1, 0x33, 0x13,
- 0x83, 0x0d, 0x94, 0x06, 0xbb, 0xd4, 0x37, 0x7a,
- 0xf6, 0xec, 0x7a, 0xc9, 0x86, 0x2e, 0xdd, 0xd7,
- 0x11, 0x69, 0x7f, 0x85, 0x7c, 0x56, 0xde, 0xfb,
- 0x31, 0x78, 0x2b, 0xe4, 0xc7, 0x78, 0x0d, 0xae,
- 0xcb, 0xbe, 0x9e, 0x4e, 0x36, 0x24, 0x31, 0x7b,
- 0x6a, 0x0f, 0x39, 0x95, 0x12, 0x07, 0x8f, 0x2a,
- 0x16, 0x03, 0x01, 0x01, 0x1a, 0x0c, 0x00, 0x01,
- 0x16, 0x03, 0x00, 0x19, 0x85, 0x04, 0x01, 0x39,
- 0xdc, 0xee, 0x44, 0x17, 0x5e, 0xdb, 0xd7, 0x27,
- 0xaf, 0xb6, 0x56, 0xd9, 0xb4, 0x43, 0x5a, 0x99,
- 0xcf, 0xaa, 0x31, 0x37, 0x0c, 0x6f, 0x3a, 0xa0,
- 0xf8, 0x53, 0xc4, 0x74, 0xd1, 0x91, 0x0a, 0x46,
- 0xf5, 0x38, 0x3b, 0x5c, 0x09, 0xd8, 0x97, 0xdc,
- 0x4b, 0xaa, 0x70, 0x26, 0x48, 0xf2, 0xd6, 0x0b,
- 0x31, 0xc9, 0xf8, 0xd4, 0x98, 0x43, 0xe1, 0x6c,
- 0xd5, 0xc7, 0xb2, 0x8e, 0x0b, 0x01, 0xe6, 0xb6,
- 0x00, 0x28, 0x80, 0x7b, 0xfc, 0x96, 0x8f, 0x0d,
- 0xa2, 0x4f, 0xb0, 0x79, 0xaf, 0xdc, 0x61, 0x28,
- 0x63, 0x33, 0x78, 0xf6, 0x31, 0x39, 0xfd, 0x8a,
- 0xf4, 0x15, 0x18, 0x11, 0xfe, 0xdb, 0xd5, 0x07,
- 0xda, 0x2c, 0xed, 0x49, 0xa0, 0x23, 0xbf, 0xd0,
- 0x3a, 0x38, 0x1d, 0x54, 0xae, 0x1c, 0x7b, 0xea,
- 0x29, 0xee, 0xd0, 0x38, 0xc1, 0x76, 0xa7, 0x7f,
- 0x2a, 0xf4, 0xce, 0x1e, 0xac, 0xcc, 0x94, 0x79,
- 0x90, 0x33, 0x00, 0x8b, 0x30, 0x81, 0x88, 0x02,
- 0x42, 0x00, 0xc6, 0x85, 0x8e, 0x06, 0xb7, 0x04,
- 0x04, 0xe9, 0xcd, 0x9e, 0x3e, 0xcb, 0x66, 0x23,
- 0x95, 0xb4, 0x42, 0x9c, 0x64, 0x81, 0x39, 0x05,
- 0x3f, 0xb5, 0x21, 0xf8, 0x28, 0xaf, 0x60, 0x6b,
- 0x4d, 0x3d, 0xba, 0xa1, 0x4b, 0x5e, 0x77, 0xef,
- 0xe7, 0x59, 0x28, 0xfe, 0x1d, 0xc1, 0x27, 0xa2,
- 0xff, 0xa8, 0xde, 0x33, 0x48, 0xb3, 0xc1, 0x85,
- 0x6a, 0x42, 0x9b, 0xf9, 0x7e, 0x7e, 0x31, 0xc2,
- 0xe5, 0xbd, 0x66, 0x02, 0x42, 0x00, 0xad, 0x7d,
- 0x06, 0x35, 0xab, 0xec, 0x8d, 0xac, 0xd4, 0xba,
- 0x1b, 0x49, 0x5e, 0x05, 0x5f, 0xf0, 0x97, 0x93,
- 0x82, 0xb8, 0x2b, 0x8d, 0x91, 0x98, 0x63, 0x8e,
- 0xb4, 0x14, 0x62, 0xdb, 0x1e, 0xc9, 0x2b, 0x30,
- 0xf8, 0x41, 0x9b, 0xa6, 0xe6, 0xbc, 0xde, 0x0e,
- 0x68, 0x30, 0x22, 0x50, 0xe6, 0x98, 0x97, 0x7b,
- 0x69, 0xf7, 0x93, 0xed, 0xcd, 0x19, 0x2f, 0x44,
- 0x6c, 0x2e, 0xdf, 0x25, 0xee, 0xcc, 0x46, 0x16,
- 0x03, 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x8a, 0x10, 0x00, 0x00,
- 0x86, 0x85, 0x04, 0x00, 0x1c, 0xc5, 0xe8, 0xb3,
- 0x42, 0xb4, 0xad, 0xca, 0x45, 0xcd, 0x42, 0x7b,
- 0xfb, 0x0c, 0xea, 0x32, 0x26, 0xd4, 0x8a, 0xef,
- 0xdf, 0xc9, 0xff, 0xd2, 0xe0, 0x36, 0xea, 0x4e,
- 0xbb, 0x3e, 0xf4, 0x9c, 0x76, 0x4f, 0x44, 0xbd,
- 0x84, 0x72, 0xdd, 0xcb, 0xe5, 0x28, 0x8d, 0x31,
- 0x72, 0x3b, 0xd3, 0xf2, 0x9a, 0x13, 0xfb, 0x8a,
- 0xa7, 0x72, 0xca, 0x21, 0x6c, 0xea, 0xbf, 0xe9,
- 0x8c, 0x0a, 0xcc, 0x8f, 0xd6, 0x00, 0x20, 0x87,
- 0xf3, 0x7d, 0x18, 0xc5, 0xfd, 0x9e, 0xdd, 0x6b,
- 0x06, 0xdc, 0x52, 0xeb, 0x14, 0xc0, 0x67, 0x5a,
- 0x06, 0xd8, 0x98, 0x19, 0x14, 0xe7, 0xd4, 0x36,
- 0x32, 0xee, 0xb7, 0xfa, 0xe2, 0x85, 0x4a, 0x16,
- 0x42, 0x0c, 0xa6, 0x21, 0xcf, 0x1f, 0xae, 0x10,
- 0x8b, 0x28, 0x32, 0x19, 0xa4, 0x0a, 0xd7, 0xce,
- 0xe6, 0xe1, 0x93, 0xfb, 0x5f, 0x08, 0x8b, 0x42,
- 0xa2, 0x20, 0xed, 0x0d, 0x62, 0xca, 0xed, 0x14,
- 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01,
- 0x00, 0x30, 0x2e, 0x33, 0xc0, 0x57, 0x6c, 0xb4,
- 0x1b, 0xd2, 0x63, 0xe8, 0x67, 0x10, 0x2d, 0x87,
- 0x71, 0x6e, 0x19, 0x60, 0xf4, 0xa4, 0x10, 0x52,
- 0x73, 0x2d, 0x09, 0x5e, 0xdb, 0x6c, 0xdc, 0xcf,
- 0x2d, 0xff, 0x03, 0x11, 0x95, 0x76, 0x90, 0xd7,
- 0x87, 0x54, 0x43, 0xed, 0xc2, 0x36, 0x69, 0x14,
- 0x72, 0x4a,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x72, 0x04, 0x00, 0x00,
- 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
- 0xe8, 0x8b, 0xde, 0xef, 0xba, 0xc5, 0x7e, 0x04,
- 0xab, 0xfd, 0x79, 0x56, 0xf3, 0xe1, 0xa5, 0x3e,
- 0x02, 0xdf, 0x69, 0x6d, 0x1f, 0x41, 0x9f, 0xbc,
- 0x93, 0xe2, 0x6c, 0xf1, 0xb1, 0x38, 0xf5, 0x2b,
- 0x8c, 0x4c, 0xf4, 0x74, 0xe1, 0x79, 0x35, 0x34,
- 0x97, 0x9b, 0xd5, 0xba, 0xfd, 0xf7, 0x2f, 0x2d,
- 0x9e, 0x84, 0x54, 0xee, 0x77, 0x59, 0x23, 0x8f,
- 0xc8, 0x84, 0xb4, 0xd6, 0xea, 0x4c, 0x44, 0x8a,
- 0xc6, 0x9c, 0xf9, 0x9b, 0x27, 0xea, 0x4f, 0x28,
- 0x72, 0x33, 0x12, 0x20, 0x7c, 0xd7, 0x3f, 0x56,
- 0xa6, 0x76, 0xc7, 0x48, 0xe4, 0x2d, 0x6f, 0x14,
- 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01,
- 0x00, 0x30, 0x36, 0xe3, 0xd4, 0xf7, 0xb1, 0x69,
- 0x18, 0x8d, 0x09, 0xba, 0x52, 0x1e, 0xd5, 0x7d,
- 0x2c, 0x15, 0x3a, 0xd6, 0xe3, 0x99, 0x30, 0x2c,
- 0x99, 0x97, 0xbc, 0x19, 0x3c, 0x63, 0xa1, 0x25,
- 0x68, 0xbc, 0x8a, 0x16, 0x47, 0xec, 0xae, 0x13,
- 0xa4, 0x03, 0x96, 0x29, 0x11, 0x92, 0x90, 0x1a,
- 0xc8, 0xa4, 0x17, 0x03, 0x01, 0x00, 0x20, 0xc1,
- 0x10, 0x1d, 0xa6, 0xf1, 0xe2, 0x8a, 0xcc, 0x37,
- 0x7d, 0x8e, 0x05, 0x00, 0xfb, 0xd1, 0x9f, 0xc7,
- 0x11, 0xd2, 0x00, 0xb4, 0x27, 0x0a, 0x25, 0x14,
- 0xd9, 0x79, 0x1b, 0xcb, 0x4d, 0x81, 0x61, 0x17,
- 0x03, 0x01, 0x00, 0x30, 0x5c, 0x7c, 0x2d, 0xc0,
- 0x9e, 0xa6, 0xc4, 0x8e, 0xfd, 0xf4, 0xe2, 0xe5,
- 0xe4, 0xe6, 0x56, 0x9f, 0x7d, 0x4c, 0x4c, 0x2d,
- 0xb7, 0xa9, 0xac, 0xfa, 0x9f, 0x12, 0x7f, 0x2d,
- 0x30, 0x57, 0xe4, 0x8e, 0x30, 0x86, 0x65, 0x59,
- 0xcd, 0x24, 0xda, 0xe2, 0x8a, 0x7b, 0x0c, 0x5e,
- 0x86, 0x05, 0x06, 0x2a, 0x15, 0x03, 0x01, 0x00,
- 0x20, 0xd6, 0xb7, 0x70, 0xf8, 0x47, 0xbc, 0x0f,
- 0xf4, 0x66, 0x98, 0x1b, 0x1e, 0x8a, 0x8c, 0x0b,
- 0xa1, 0x4a, 0x04, 0x29, 0x60, 0x72, 0x8b, 0xc4,
- 0x73, 0xc1, 0xd6, 0x41, 0x72, 0xb7, 0x17, 0x39,
- 0xda,
- },
+ test = &serverTest{
+ name: "Resume",
+ command: []string{"openssl", "s_client", "-cipher", "RC4-SHA", "-sess_in", sessionFilePath},
+ }
+ runServerTestTLS12(t, test)
}
-var sslv3ServerScript = [][]byte{
- {
- 0x16, 0x03, 0x00, 0x00, 0x54, 0x01, 0x00, 0x00,
- 0x50, 0x03, 0x00, 0x50, 0x77, 0x3d, 0x42, 0xae,
- 0x84, 0xbd, 0xc5, 0x07, 0xa5, 0xc4, 0xd6, 0x16,
- 0x4e, 0xd5, 0xc5, 0xfa, 0x02, 0x7a, 0x0f, 0x1d,
- 0xc1, 0xe1, 0xaa, 0xe3, 0x3b, 0x4b, 0x6f, 0x11,
- 0xfa, 0x1a, 0xa4, 0x00, 0x00, 0x28, 0x00, 0x39,
- 0x00, 0x38, 0x00, 0x35, 0x00, 0x16, 0x00, 0x13,
- 0x00, 0x0a, 0x00, 0x33, 0x00, 0x32, 0x00, 0x2f,
- 0x00, 0x05, 0x00, 0x04, 0x00, 0x15, 0x00, 0x12,
- 0x00, 0x09, 0x00, 0x14, 0x00, 0x11, 0x00, 0x08,
- 0x00, 0x06, 0x00, 0x03, 0x00, 0xff, 0x02, 0x01,
- 0x00,
- },
- {
- 0x16, 0x03, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00,
- 0x26, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x16,
- 0x03, 0x00, 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba,
- 0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82,
- 0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03,
- 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0,
- 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d,
- 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d,
- 0x31, 0x30, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39,
- 0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31,
- 0x31, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30,
- 0x39, 0x33, 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b,
- 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
- 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06,
- 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f,
- 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
- 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04,
- 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72,
- 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67,
- 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20,
- 0x4c, 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d,
- 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d,
- 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00,
- 0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf,
- 0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b,
- 0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a,
- 0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65,
- 0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4,
- 0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62,
- 0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c,
- 0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58,
- 0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0,
- 0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f,
- 0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18,
- 0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1,
- 0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9,
- 0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01,
- 0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d,
- 0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79,
- 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7,
- 0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55,
- 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad,
- 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69,
- 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18,
- 0x88, 0x39, 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d,
- 0x23, 0x04, 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1,
- 0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb,
- 0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e,
- 0x18, 0x88, 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30,
- 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
- 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
- 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
- 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
- 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
- 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e,
- 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
- 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
- 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09,
- 0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8,
- 0xca, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13,
- 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
- 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81,
- 0x81, 0x00, 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b,
- 0xb1, 0x59, 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0,
- 0x14, 0xd7, 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5,
- 0x5a, 0x95, 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae,
- 0x12, 0x66, 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e,
- 0x60, 0xd3, 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5,
- 0x25, 0x13, 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30,
- 0x1d, 0xba, 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7,
- 0xd7, 0x31, 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78,
- 0xea, 0x50, 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d,
- 0x5a, 0x5f, 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75,
- 0x90, 0x96, 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd,
- 0x98, 0x1f, 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c,
- 0xa3, 0x1b, 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57,
- 0xe9, 0x70, 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b,
- 0x26, 0x6e, 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7,
- 0xbd, 0xd9, 0x16, 0x03, 0x00, 0x00, 0x04, 0x0e,
- 0x00, 0x00, 0x00,
- },
- {
- 0x16, 0x03, 0x00, 0x00, 0x84, 0x10, 0x00, 0x00,
- 0x80, 0x4a, 0x8d, 0xc4, 0x38, 0x7a, 0x9c, 0xd6,
- 0xe8, 0x72, 0x9e, 0xa3, 0xdf, 0x37, 0xb4, 0x6c,
- 0x58, 0x33, 0x59, 0xd9, 0xc9, 0x4b, 0x50, 0x33,
- 0x6c, 0xed, 0x73, 0x38, 0x2a, 0x46, 0x55, 0x31,
- 0xa9, 0x8e, 0x8e, 0xfc, 0x0b, 0x5d, 0x5f, 0x3c,
- 0x88, 0x28, 0x3f, 0x60, 0x51, 0x13, 0xf1, 0x59,
- 0x0c, 0xa3, 0x5e, 0xe0, 0xa3, 0x35, 0x06, 0xb1,
- 0x71, 0x59, 0x24, 0x4e, 0xed, 0x07, 0x15, 0x88,
- 0x50, 0xef, 0xc2, 0xb2, 0x2a, 0x52, 0x30, 0x6a,
- 0x7c, 0xbe, 0x2f, 0xc6, 0x8f, 0xa8, 0x83, 0xc5,
- 0x80, 0x14, 0x62, 0x74, 0x7f, 0x96, 0x9f, 0x41,
- 0x32, 0x74, 0xdd, 0x76, 0x2d, 0x7b, 0xeb, 0x7b,
- 0xea, 0xd0, 0x4f, 0x0c, 0xcf, 0x9a, 0x9c, 0xc5,
- 0x7a, 0xe4, 0xbc, 0xf8, 0xa6, 0xe1, 0x09, 0x8e,
- 0x7c, 0x53, 0x3a, 0xe3, 0x30, 0x8f, 0x76, 0xee,
- 0x58, 0xbb, 0xfd, 0x0b, 0x06, 0xb8, 0xdf, 0xb7,
- 0x31, 0x14, 0x03, 0x00, 0x00, 0x01, 0x01, 0x16,
- 0x03, 0x00, 0x00, 0x3c, 0x13, 0x91, 0xc6, 0x4a,
- 0x0c, 0x59, 0x25, 0xce, 0x54, 0xc0, 0x1d, 0xb9,
- 0x2a, 0xff, 0x4d, 0xca, 0x26, 0x0c, 0x8c, 0x04,
- 0x98, 0x7c, 0x7c, 0x38, 0xa3, 0xf5, 0xf9, 0x36,
- 0x1c, 0x04, 0x32, 0x47, 0x2d, 0x48, 0x0e, 0x96,
- 0xe8, 0x2b, 0x5e, 0x5a, 0xc6, 0x0a, 0x48, 0x41,
- 0x34, 0x5e, 0x62, 0xd5, 0x68, 0x4e, 0x44, 0x1d,
- 0xb2, 0xa1, 0x11, 0xad, 0x6e, 0x14, 0x85, 0x61,
- },
- {
- 0x14, 0x03, 0x00, 0x00, 0x01, 0x01, 0x16, 0x03,
- 0x00, 0x00, 0x3c, 0x88, 0xae, 0xa9, 0xd4, 0xa8,
- 0x10, 0x8d, 0x65, 0xa6, 0x3e, 0x1e, 0xed, 0xd2,
- 0xfc, 0xc4, 0x7c, 0xa8, 0x94, 0x4f, 0x11, 0xaf,
- 0xa6, 0x87, 0x09, 0x37, 0x54, 0xf7, 0x69, 0xd1,
- 0xb5, 0x25, 0x6b, 0xb5, 0xed, 0xcb, 0x25, 0x39,
- 0x73, 0xeb, 0x53, 0x6c, 0xc7, 0xb4, 0x29, 0x8f,
- 0xd6, 0x49, 0xd1, 0x95, 0x59, 0x80, 0x9a, 0x67,
- 0x5c, 0xb2, 0xe0, 0xbd, 0x1e, 0xff, 0xaa, 0x17,
- 0x03, 0x00, 0x00, 0x21, 0x65, 0x7b, 0x99, 0x09,
- 0x02, 0xc3, 0x9d, 0x54, 0xd6, 0xe7, 0x32, 0x62,
- 0xab, 0xc1, 0x09, 0x91, 0x30, 0x0a, 0xc9, 0xfa,
- 0x70, 0xec, 0x06, 0x7b, 0xa3, 0xe1, 0x5f, 0xb4,
- 0x63, 0xe6, 0x5c, 0xba, 0x1f, 0x15, 0x03, 0x00,
- 0x00, 0x16, 0x40, 0x70, 0xbe, 0xe6, 0xa6, 0xee,
- 0x8f, 0xd0, 0x87, 0xa0, 0x43, 0xa1, 0x92, 0xd7,
- 0xd0, 0x1a, 0x0c, 0x20, 0x7c, 0xbf, 0xa2, 0xb5,
- },
-}
+func TestResumptionDisabled(t *testing.T) {
+ sessionFilePath := tempFile("")
+ defer os.Remove(sessionFilePath)
-var selectCertificateBySNIScript = [][]byte{
- {
- 0x16, 0x03, 0x01, 0x00, 0x6a, 0x01, 0x00, 0x00,
- 0x66, 0x03, 0x01, 0x50, 0x77, 0x3d, 0xfe, 0xfb,
- 0x8d, 0xc2, 0x68, 0xeb, 0xf9, 0xfa, 0x54, 0x97,
- 0x86, 0x45, 0xa2, 0xa3, 0xed, 0xb1, 0x91, 0xb8,
- 0x28, 0xc0, 0x47, 0xaf, 0xfb, 0xcd, 0xdc, 0x0e,
- 0xb3, 0xea, 0xa5, 0x00, 0x00, 0x28, 0x00, 0x39,
- 0x00, 0x38, 0x00, 0x35, 0x00, 0x16, 0x00, 0x13,
- 0x00, 0x0a, 0x00, 0x33, 0x00, 0x32, 0x00, 0x2f,
- 0x00, 0x05, 0x00, 0x04, 0x00, 0x15, 0x00, 0x12,
- 0x00, 0x09, 0x00, 0x14, 0x00, 0x11, 0x00, 0x08,
- 0x00, 0x06, 0x00, 0x03, 0x00, 0xff, 0x02, 0x01,
- 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00,
- 0x0e, 0x00, 0x00, 0x0b, 0x73, 0x6e, 0x69, 0x74,
- 0x65, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00,
- 0x26, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x16,
- 0x03, 0x01, 0x02, 0x00, 0x0b, 0x00, 0x01, 0xfc,
- 0x00, 0x01, 0xf9, 0x00, 0x01, 0xf6, 0x30, 0x82,
- 0x01, 0xf2, 0x30, 0x82, 0x01, 0x5d, 0xa0, 0x03,
- 0x02, 0x01, 0x02, 0x02, 0x01, 0x00, 0x30, 0x0b,
- 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x01, 0x05, 0x30, 0x28, 0x31, 0x10, 0x30,
- 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x07,
- 0x41, 0x63, 0x6d, 0x65, 0x20, 0x43, 0x6f, 0x31,
- 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x03,
- 0x13, 0x0b, 0x73, 0x6e, 0x69, 0x74, 0x65, 0x73,
- 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17,
- 0x0d, 0x31, 0x32, 0x30, 0x34, 0x31, 0x31, 0x31,
- 0x37, 0x34, 0x30, 0x33, 0x35, 0x5a, 0x17, 0x0d,
- 0x31, 0x33, 0x30, 0x34, 0x31, 0x31, 0x31, 0x37,
- 0x34, 0x35, 0x33, 0x35, 0x5a, 0x30, 0x28, 0x31,
- 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a,
- 0x13, 0x07, 0x41, 0x63, 0x6d, 0x65, 0x20, 0x43,
- 0x6f, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55,
- 0x04, 0x03, 0x13, 0x0b, 0x73, 0x6e, 0x69, 0x74,
- 0x65, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30,
- 0x81, 0x9d, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x03,
- 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81,
- 0x81, 0x00, 0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5,
- 0xe5, 0xbf, 0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe,
- 0xe6, 0x2b, 0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d,
- 0x8a, 0x7a, 0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7,
- 0xa5, 0x65, 0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c,
- 0xb5, 0xb4, 0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b,
- 0x7e, 0x62, 0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe,
- 0x12, 0x5c, 0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf,
- 0xfa, 0x58, 0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04,
- 0xd3, 0xd0, 0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4,
- 0x54, 0x9f, 0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00,
- 0xfe, 0x18, 0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d,
- 0x7d, 0xf1, 0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb,
- 0x51, 0xc9, 0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32,
- 0x66, 0x01, 0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71,
- 0x9a, 0x1d, 0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda,
- 0x2d, 0x79, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3,
- 0x32, 0x30, 0x30, 0x30, 0x0e, 0x06, 0x03, 0x55,
- 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03,
- 0x02, 0x00, 0xa0, 0x30, 0x0d, 0x06, 0x03, 0x55,
- 0x1d, 0x0e, 0x04, 0x06, 0x04, 0x04, 0x01, 0x02,
- 0x03, 0x04, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d,
- 0x23, 0x04, 0x08, 0x30, 0x06, 0x80, 0x04, 0x01,
- 0x02, 0x03, 0x04, 0x30, 0x0b, 0x06, 0x09, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
- 0x03, 0x81, 0x81, 0x00, 0x89, 0xc6, 0x45, 0x5f,
- 0x1c, 0x1f, 0x5e, 0xf8, 0xeb, 0x1a, 0xb1, 0x74,
- 0xee, 0x24, 0x39, 0x05, 0x9f, 0x5c, 0x42, 0x59,
- 0xbb, 0x1a, 0x8d, 0x86, 0xcd, 0xb1, 0xd0, 0x56,
- 0xf5, 0x6a, 0x71, 0x7d, 0xa4, 0x0e, 0x95, 0xab,
- 0x90, 0xf5, 0x9e, 0x8d, 0xea, 0xf6, 0x27, 0xc1,
- 0x57, 0x99, 0x50, 0x94, 0xdb, 0x08, 0x02, 0x26,
- 0x6e, 0xb3, 0x4f, 0xc6, 0x84, 0x2d, 0xea, 0x8a,
- 0x4b, 0x68, 0xd9, 0xc1, 0x38, 0x91, 0x03, 0xab,
- 0x84, 0xfb, 0x9e, 0x1f, 0x85, 0xd9, 0xb5, 0xd2,
- 0x3f, 0xf2, 0x31, 0x2c, 0x86, 0x70, 0xfb, 0xb5,
- 0x40, 0x14, 0x82, 0x45, 0xa4, 0xeb, 0xaf, 0xe2,
- 0x64, 0xd9, 0x0c, 0x8a, 0x4c, 0xf4, 0xf8, 0x5b,
- 0x0f, 0xac, 0x12, 0xac, 0x2f, 0xc4, 0xa3, 0x15,
- 0x4b, 0xad, 0x52, 0x46, 0x28, 0x68, 0xaf, 0x96,
- 0xc6, 0x2c, 0x65, 0x25, 0xd6, 0x52, 0xb6, 0xe3,
- 0x18, 0x45, 0xbd, 0xcc, 0x16, 0x03, 0x01, 0x00,
- 0x04, 0x0e, 0x00, 0x00, 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00,
- 0x82, 0x00, 0x80, 0x69, 0xc3, 0xd4, 0x0e, 0xcc,
- 0xdc, 0xbc, 0x5e, 0xc2, 0x64, 0xa6, 0xde, 0x3c,
- 0x0c, 0x7e, 0x0c, 0x6b, 0x80, 0x0f, 0xd4, 0x8f,
- 0x02, 0x4b, 0xb2, 0xba, 0x8d, 0x01, 0xeb, 0x6b,
- 0xa1, 0x2e, 0x79, 0x37, 0xba, 0xae, 0x24, 0xc2,
- 0x26, 0x72, 0x51, 0xe1, 0x82, 0x8e, 0x51, 0x41,
- 0x1c, 0x54, 0xa4, 0x26, 0xbe, 0x13, 0xcd, 0x1b,
- 0xc6, 0xed, 0x3d, 0x1f, 0xfd, 0x72, 0x80, 0x90,
- 0xdb, 0xbf, 0xd6, 0x39, 0x94, 0x5f, 0x48, 0xfb,
- 0x25, 0x5a, 0xc9, 0x60, 0x9b, 0xd7, 0xc6, 0x20,
- 0xa8, 0x66, 0x64, 0x13, 0xf3, 0x65, 0xc8, 0xb1,
- 0xd5, 0x33, 0x21, 0x0e, 0x73, 0x41, 0xc0, 0x18,
- 0x1a, 0x37, 0xfe, 0xcf, 0x28, 0x2a, 0xcd, 0xe4,
- 0x0b, 0xac, 0xdd, 0x25, 0x5e, 0xcb, 0x17, 0x51,
- 0x69, 0xd5, 0x8c, 0xf4, 0xb6, 0x21, 0x98, 0xef,
- 0x20, 0xdb, 0x14, 0x67, 0xf3, 0x7c, 0x95, 0x6a,
- 0x48, 0x2a, 0x6a, 0x14, 0x03, 0x01, 0x00, 0x01,
- 0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0x36, 0x1b,
- 0x09, 0xe5, 0xb9, 0xb9, 0x4d, 0x7d, 0xae, 0x87,
- 0xb6, 0x0f, 0xaf, 0xec, 0x22, 0xba, 0x0d, 0xa5,
- 0x96, 0x5e, 0x64, 0x65, 0xe7, 0xfb, 0xe3, 0xf3,
- 0x6b, 0x72, 0xa8, 0xdb, 0xed, 0xd8, 0x69, 0x9c,
- 0x08, 0xd8,
- },
- {
- 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
- 0x01, 0x00, 0x24, 0x60, 0xf7, 0x09, 0x5f, 0xd1,
- 0xcb, 0xc9, 0xe1, 0x22, 0xb5, 0x2a, 0xcc, 0xde,
- 0x7c, 0xa7, 0xb8, 0x85, 0x00, 0xbc, 0xfd, 0x85,
- 0xe1, 0x91, 0x36, 0xbb, 0x07, 0x42, 0xad, 0x3d,
- 0x29, 0x62, 0x69, 0xc1, 0x45, 0x92, 0x6f, 0x17,
- 0x03, 0x01, 0x00, 0x21, 0x0d, 0xf9, 0xd5, 0x87,
- 0xb9, 0x57, 0x3c, 0x50, 0x19, 0xe4, 0x3a, 0x50,
- 0x45, 0xcc, 0x86, 0x89, 0xd4, 0x32, 0x79, 0x45,
- 0x7c, 0x9f, 0x96, 0xd4, 0x54, 0x56, 0x0c, 0x63,
- 0x72, 0x81, 0xc3, 0xd3, 0xe3, 0x15, 0x03, 0x01,
- 0x00, 0x16, 0x84, 0xec, 0x2e, 0xf6, 0xaf, 0x4f,
- 0xee, 0x48, 0x0f, 0xbe, 0xcd, 0x82, 0x5c, 0x56,
- 0x16, 0xe4, 0xfb, 0x89, 0xc5, 0x57, 0x3e, 0x91,
- },
-}
+ config := *testConfig
-var issueSessionTicketTest = [][]byte{
- {
- 0x16, 0x03, 0x01, 0x00, 0x5a, 0x01, 0x00, 0x00,
- 0x56, 0x03, 0x01, 0x50, 0x77, 0x3e, 0x49, 0x7a,
- 0xb7, 0x86, 0x5c, 0x27, 0xd2, 0x97, 0x61, 0xe3,
- 0x49, 0x41, 0x48, 0xe7, 0x0e, 0xaa, 0x7e, 0x4d,
- 0xb8, 0xdc, 0x01, 0x97, 0xfb, 0xab, 0x53, 0xb2,
- 0x5e, 0x36, 0xf6, 0x00, 0x00, 0x28, 0x00, 0x39,
- 0x00, 0x38, 0x00, 0x35, 0x00, 0x16, 0x00, 0x13,
- 0x00, 0x0a, 0x00, 0x33, 0x00, 0x32, 0x00, 0x2f,
- 0x00, 0x05, 0x00, 0x04, 0x00, 0x15, 0x00, 0x12,
- 0x00, 0x09, 0x00, 0x14, 0x00, 0x11, 0x00, 0x08,
- 0x00, 0x06, 0x00, 0x03, 0x00, 0xff, 0x02, 0x01,
- 0x00, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x30, 0x02, 0x00, 0x00,
- 0x2c, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
- 0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x01,
- 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, 0x00, 0x02,
- 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, 0x02, 0xb0,
- 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, 0x02, 0x01,
- 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4,
- 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30,
- 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
- 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
- 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d,
- 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
- 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
- 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
- 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
- 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
- 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30,
- 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39,
- 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30,
- 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, 0x33,
- 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
- 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
- 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
- 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
- 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
- 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
- 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
- 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
- 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
- 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
- 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0x79,
- 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, 0x46, 0x10,
- 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, 0x07, 0x43,
- 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, 0x43, 0x85,
- 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, 0x4c, 0x2c,
- 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, 0x82, 0xe5,
- 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, 0xa5, 0x2c,
- 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, 0x7a, 0x56,
- 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, 0x7b, 0x26,
- 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, 0xc9, 0x21,
- 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, 0x5a, 0xbf,
- 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, 0x99, 0x07,
- 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, 0x04, 0x39,
- 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, 0x7c, 0xe3,
- 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, 0xcf, 0xaf,
- 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, 0xdb, 0xdb,
- 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, 0x02, 0x03,
- 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
- 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
- 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, 0xe2, 0x85,
- 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23,
- 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39,
- 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
- 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, 0xad, 0xe2,
- 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce,
- 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88,
- 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0x85,
- 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30,
- 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
- 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00,
- 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, 0xb1, 0x59,
- 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, 0x14, 0xd7,
- 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, 0x5a, 0x95,
- 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, 0x12, 0x66,
- 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, 0x60, 0xd3,
- 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, 0x25, 0x13,
- 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, 0x1d, 0xba,
- 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, 0xd7, 0x31,
- 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, 0xea, 0x50,
- 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, 0x5a, 0x5f,
- 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, 0x90, 0x96,
- 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, 0x98, 0x1f,
- 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, 0xa3, 0x1b,
- 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, 0xe9, 0x70,
- 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, 0x26, 0x6e,
- 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, 0xbd, 0xd9,
- 0x16, 0x03, 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00,
- 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00,
- 0x82, 0x00, 0x80, 0x68, 0x10, 0xdc, 0x80, 0xbc,
- 0xb3, 0x5a, 0x10, 0x75, 0x89, 0xcc, 0xe5, 0x9f,
- 0xbf, 0xe2, 0xce, 0xa4, 0x9f, 0x7f, 0x60, 0xc4,
- 0xfe, 0x5c, 0xb5, 0x02, 0x2d, 0xa5, 0xa9, 0x1e,
- 0x2c, 0x10, 0x79, 0x15, 0x0f, 0xed, 0x96, 0xb3,
- 0xa8, 0x5e, 0x21, 0xbc, 0x5b, 0xdc, 0x58, 0x04,
- 0x7d, 0x37, 0xdb, 0xa0, 0x31, 0xe8, 0x4f, 0x04,
- 0xbc, 0x46, 0x7c, 0xdb, 0x2e, 0x93, 0x07, 0xaf,
- 0xa6, 0x36, 0xd3, 0x39, 0x8d, 0x1d, 0x95, 0xa8,
- 0x50, 0x4b, 0xc4, 0x2b, 0xde, 0xd7, 0x04, 0x6d,
- 0x77, 0x6c, 0x4d, 0x70, 0x51, 0x88, 0x16, 0x31,
- 0x40, 0xb5, 0xba, 0x90, 0x47, 0x64, 0x0c, 0x87,
- 0xa5, 0x19, 0xf9, 0x89, 0x24, 0x3c, 0x5e, 0x4b,
- 0xaa, 0xe0, 0x60, 0x47, 0x0f, 0x2e, 0xcc, 0xc2,
- 0xd5, 0x21, 0xed, 0x72, 0xd0, 0xa9, 0xdd, 0x2a,
- 0x2b, 0xef, 0x08, 0x3a, 0x65, 0xea, 0x8b, 0x52,
- 0x77, 0x2d, 0xcc, 0x14, 0x03, 0x01, 0x00, 0x01,
- 0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0xe2, 0x95,
- 0x62, 0x3c, 0x18, 0xe5, 0xc7, 0x2c, 0xda, 0x16,
- 0x9b, 0x28, 0x0d, 0xf7, 0x88, 0x7b, 0x5d, 0x33,
- 0x55, 0x3b, 0x01, 0x73, 0xf2, 0xc6, 0x4e, 0x96,
- 0x01, 0x01, 0x83, 0x65, 0xd4, 0xef, 0x12, 0x13,
- 0x1d, 0x42,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x72, 0x04, 0x00, 0x00,
- 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
- 0xe8, 0x4b, 0xd1, 0xef, 0xba, 0xfb, 0x41, 0x92,
- 0x6d, 0x37, 0x5f, 0xf8, 0x7d, 0x90, 0x0f, 0x01,
- 0xf8, 0x8c, 0xee, 0xbc, 0xd9, 0x0c, 0x97, 0x7e,
- 0x23, 0x46, 0xe2, 0x6b, 0x52, 0xc6, 0xc6, 0x97,
- 0x1d, 0xab, 0xde, 0xa0, 0x86, 0x94, 0xc8, 0x2e,
- 0x8b, 0x2e, 0x42, 0x5f, 0xc2, 0x70, 0x35, 0xc9,
- 0xee, 0x37, 0xeb, 0x70, 0xaa, 0x59, 0x23, 0x6c,
- 0xc8, 0xc1, 0x84, 0x89, 0x39, 0x87, 0x73, 0x0a,
- 0x7e, 0xba, 0xca, 0xed, 0x63, 0xba, 0x4e, 0x4f,
- 0xf3, 0x31, 0x4b, 0xf0, 0xee, 0x91, 0xa5, 0xb4,
- 0x62, 0x01, 0x9e, 0xbd, 0xbc, 0xb3, 0x35, 0x14,
- 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01,
- 0x00, 0x24, 0x3f, 0x66, 0xe4, 0x98, 0xc1, 0x3f,
- 0xc6, 0x2c, 0x81, 0xfb, 0xa9, 0x9f, 0x27, 0xe9,
- 0x63, 0x20, 0x1e, 0x0e, 0x4f, 0xfc, 0x5d, 0x12,
- 0xee, 0x77, 0x73, 0xc6, 0x96, 0x51, 0xf2, 0x26,
- 0x35, 0x3f, 0xce, 0x6a, 0xa9, 0xfd, 0x17, 0x03,
- 0x01, 0x00, 0x21, 0x8d, 0xd5, 0x67, 0x60, 0x5d,
- 0xa7, 0x93, 0xcc, 0x39, 0x78, 0x59, 0xab, 0xdb,
- 0x10, 0x96, 0xf2, 0xad, 0xa2, 0x85, 0xe2, 0x93,
- 0x43, 0x43, 0xcf, 0x82, 0xbd, 0x1f, 0xdc, 0x7a,
- 0x72, 0xd6, 0x83, 0x3b, 0x15, 0x03, 0x01, 0x00,
- 0x16, 0x89, 0x55, 0xf6, 0x42, 0x71, 0xa9, 0xe9,
- 0x05, 0x68, 0xe8, 0xce, 0x0d, 0x21, 0xe9, 0xec,
- 0xf2, 0x27, 0x67, 0xa7, 0x94, 0xf8, 0x34,
- },
-}
-var serverResumeTest = [][]byte{
- {
- 0x16, 0x03, 0x01, 0x00, 0xc2, 0x01, 0x00, 0x00,
- 0xbe, 0x03, 0x01, 0x50, 0x77, 0x3e, 0x4f, 0x1f,
- 0x6f, 0xa5, 0x81, 0xeb, 0xb8, 0x80, 0x55, 0xa4,
- 0x76, 0xc2, 0x7f, 0x27, 0xf2, 0xe7, 0xc9, 0x7a,
- 0x01, 0x3c, 0xd8, 0xc1, 0xde, 0x99, 0x1f, 0x7c,
- 0xab, 0x35, 0x98, 0x00, 0x00, 0x28, 0x00, 0x39,
- 0x00, 0x38, 0x00, 0x35, 0x00, 0x16, 0x00, 0x13,
- 0x00, 0x0a, 0x00, 0x33, 0x00, 0x32, 0x00, 0x2f,
- 0x00, 0x05, 0x00, 0x04, 0x00, 0x15, 0x00, 0x12,
- 0x00, 0x09, 0x00, 0x14, 0x00, 0x11, 0x00, 0x08,
- 0x00, 0x06, 0x00, 0x03, 0x00, 0xff, 0x02, 0x01,
- 0x00, 0x00, 0x6c, 0x00, 0x23, 0x00, 0x68, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
- 0xe8, 0x4b, 0xd1, 0xef, 0xba, 0xfb, 0x41, 0x92,
- 0x6d, 0x37, 0x5f, 0xf8, 0x7d, 0x90, 0x0f, 0x01,
- 0xf8, 0x8c, 0xee, 0xbc, 0xd9, 0x0c, 0x97, 0x7e,
- 0x23, 0x46, 0xe2, 0x6b, 0x52, 0xc6, 0xc6, 0x97,
- 0x1d, 0xab, 0xde, 0xa0, 0x86, 0x94, 0xc8, 0x2e,
- 0x8b, 0x2e, 0x42, 0x5f, 0xc2, 0x70, 0x35, 0xc9,
- 0xee, 0x37, 0xeb, 0x70, 0xaa, 0x59, 0x23, 0x6c,
- 0xc8, 0xc1, 0x84, 0x89, 0x39, 0x87, 0x73, 0x0a,
- 0x7e, 0xba, 0xca, 0xed, 0x63, 0xba, 0x4e, 0x4f,
- 0xf3, 0x31, 0x4b, 0xf0, 0xee, 0x91, 0xa5, 0xb4,
- 0x62, 0x01, 0x9e, 0xbd, 0xbc, 0xb3, 0x35,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00,
- 0x26, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x14,
- 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01,
- 0x00, 0x24, 0xc5, 0x35, 0x74, 0x19, 0x05, 0xc5,
- 0x85, 0x68, 0x48, 0xe8, 0xb5, 0xe9, 0xaf, 0x78,
- 0xbd, 0x35, 0x6f, 0xe9, 0x79, 0x34, 0x1b, 0xf0,
- 0x35, 0xd4, 0x4e, 0x55, 0x2e, 0x3c, 0xd5, 0xaf,
- 0xfc, 0xba, 0xf5, 0x1e, 0x83, 0x32,
- },
- {
- 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
- 0x01, 0x00, 0x24, 0x27, 0x28, 0x88, 0xe1, 0x7e,
- 0x0d, 0x9c, 0x12, 0x50, 0xf6, 0x7a, 0xa7, 0x32,
- 0x21, 0x68, 0xba, 0xd8, 0x0a, 0xdc, 0x39, 0xef,
- 0x68, 0x95, 0x82, 0xae, 0xbd, 0x12, 0x79, 0xa1,
- 0x99, 0xfd, 0xd0, 0x10, 0x8e, 0x4b, 0xd8,
- },
- {
- 0x17, 0x03, 0x01, 0x00, 0x21, 0xc5, 0x7e, 0x0a,
- 0x52, 0x6a, 0xb9, 0xaa, 0x1d, 0xae, 0x9e, 0x24,
- 0x9c, 0x34, 0x1e, 0xdb, 0x50, 0x95, 0xee, 0x76,
- 0xd7, 0x28, 0x88, 0x08, 0xe3, 0x2e, 0x58, 0xf7,
- 0xdb, 0x34, 0x75, 0xa5, 0x7f, 0x9d, 0x15, 0x03,
- 0x01, 0x00, 0x16, 0x2c, 0xc1, 0x29, 0x5f, 0x12,
- 0x1d, 0x19, 0xab, 0xb3, 0xf4, 0x35, 0x1c, 0x62,
- 0x6a, 0x80, 0x29, 0x0d, 0x0e, 0xef, 0x7d, 0x6e,
- 0x50,
- },
-}
+ test := &serverTest{
+ name: "IssueTicketPreDisable",
+ command: []string{"openssl", "s_client", "-cipher", "RC4-SHA", "-sess_out", sessionFilePath},
+ config: &config,
+ }
+ runServerTestTLS12(t, test)
-var clientauthRSATests = []clientauthTest{
- // Server asks for cert with empty CA list, client doesn't give it.
- // go test -run "TestRunServer" -serve -clientauth 1
- {"RequestClientCert, none given", RequestClientCert, nil, [][]byte{
- {
- 0x16, 0x03, 0x01, 0x01, 0x1e, 0x01, 0x00, 0x01,
- 0x1a, 0x03, 0x03, 0x51, 0xe5, 0x6c, 0xb5, 0x5a,
- 0xc2, 0xf5, 0xf0, 0x92, 0x94, 0x8a, 0x64, 0x18,
- 0xa4, 0x2b, 0x82, 0x07, 0xbc, 0xd9, 0xd9, 0xf9,
- 0x7b, 0xd2, 0xd0, 0xee, 0xa2, 0x70, 0x4e, 0x23,
- 0x88, 0x7c, 0x95, 0x00, 0x00, 0x82, 0xc0, 0x30,
- 0xc0, 0x2c, 0xc0, 0x28, 0xc0, 0x24, 0xc0, 0x14,
- 0xc0, 0x0a, 0x00, 0xa3, 0x00, 0x9f, 0x00, 0x6b,
- 0x00, 0x6a, 0x00, 0x39, 0x00, 0x38, 0xc0, 0x32,
- 0xc0, 0x2e, 0xc0, 0x2a, 0xc0, 0x26, 0xc0, 0x0f,
- 0xc0, 0x05, 0x00, 0x9d, 0x00, 0x3d, 0x00, 0x35,
- 0xc0, 0x12, 0xc0, 0x08, 0x00, 0x16, 0x00, 0x13,
- 0xc0, 0x0d, 0xc0, 0x03, 0x00, 0x0a, 0xc0, 0x2f,
- 0xc0, 0x2b, 0xc0, 0x27, 0xc0, 0x23, 0xc0, 0x13,
- 0xc0, 0x09, 0x00, 0xa2, 0x00, 0x9e, 0x00, 0x67,
- 0x00, 0x40, 0x00, 0x33, 0x00, 0x32, 0xc0, 0x31,
- 0xc0, 0x2d, 0xc0, 0x29, 0xc0, 0x25, 0xc0, 0x0e,
- 0xc0, 0x04, 0x00, 0x9c, 0x00, 0x3c, 0x00, 0x2f,
- 0x00, 0x07, 0xc0, 0x11, 0xc0, 0x07, 0xc0, 0x0c,
- 0xc0, 0x02, 0x00, 0x05, 0x00, 0x04, 0x00, 0x15,
- 0x00, 0x12, 0x00, 0x09, 0x00, 0x14, 0x00, 0x11,
- 0x00, 0x08, 0x00, 0x06, 0x00, 0x03, 0x00, 0xff,
- 0x01, 0x00, 0x00, 0x6f, 0x00, 0x0b, 0x00, 0x04,
- 0x03, 0x00, 0x01, 0x02, 0x00, 0x0a, 0x00, 0x34,
- 0x00, 0x32, 0x00, 0x0e, 0x00, 0x0d, 0x00, 0x19,
- 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x09,
- 0x00, 0x0a, 0x00, 0x16, 0x00, 0x17, 0x00, 0x08,
- 0x00, 0x06, 0x00, 0x07, 0x00, 0x14, 0x00, 0x15,
- 0x00, 0x04, 0x00, 0x05, 0x00, 0x12, 0x00, 0x13,
- 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x0f,
- 0x00, 0x10, 0x00, 0x11, 0x00, 0x23, 0x00, 0x00,
- 0x00, 0x0d, 0x00, 0x22, 0x00, 0x20, 0x06, 0x01,
- 0x06, 0x02, 0x06, 0x03, 0x05, 0x01, 0x05, 0x02,
- 0x05, 0x03, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03,
- 0x03, 0x01, 0x03, 0x02, 0x03, 0x03, 0x02, 0x01,
- 0x02, 0x02, 0x02, 0x03, 0x01, 0x01, 0x00, 0x0f,
- 0x00, 0x01, 0x01,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x30, 0x02, 0x00, 0x00,
- 0x2c, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
- 0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x01,
- 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, 0x00, 0x02,
- 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, 0x02, 0xb0,
- 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, 0x02, 0x01,
- 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4,
- 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30,
- 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
- 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
- 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d,
- 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
- 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
- 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
- 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
- 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
- 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30,
- 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39,
- 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30,
- 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, 0x33,
- 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
- 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
- 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
- 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
- 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
- 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
- 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
- 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
- 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
- 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
- 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0x79,
- 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, 0x46, 0x10,
- 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, 0x07, 0x43,
- 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, 0x43, 0x85,
- 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, 0x4c, 0x2c,
- 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, 0x82, 0xe5,
- 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, 0xa5, 0x2c,
- 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, 0x7a, 0x56,
- 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, 0x7b, 0x26,
- 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, 0xc9, 0x21,
- 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, 0x5a, 0xbf,
- 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, 0x99, 0x07,
- 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, 0x04, 0x39,
- 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, 0x7c, 0xe3,
- 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, 0xcf, 0xaf,
- 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, 0xdb, 0xdb,
- 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, 0x02, 0x03,
- 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
- 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
- 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, 0xe2, 0x85,
- 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23,
- 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39,
- 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
- 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, 0xad, 0xe2,
- 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce,
- 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88,
- 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0x85,
- 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30,
- 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
- 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00,
- 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, 0xb1, 0x59,
- 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, 0x14, 0xd7,
- 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, 0x5a, 0x95,
- 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, 0x12, 0x66,
- 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, 0x60, 0xd3,
- 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, 0x25, 0x13,
- 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, 0x1d, 0xba,
- 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, 0xd7, 0x31,
- 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, 0xea, 0x50,
- 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, 0x5a, 0x5f,
- 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, 0x90, 0x96,
- 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, 0x98, 0x1f,
- 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, 0xa3, 0x1b,
- 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, 0xe9, 0x70,
- 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, 0x26, 0x6e,
- 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, 0xbd, 0xd9,
- 0x16, 0x03, 0x01, 0x00, 0x09, 0x0d, 0x00, 0x00,
- 0x05, 0x02, 0x01, 0x40, 0x00, 0x00, 0x16, 0x03,
- 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x07, 0x0b, 0x00, 0x00,
- 0x03, 0x00, 0x00, 0x00, 0x16, 0x03, 0x01, 0x00,
- 0x86, 0x10, 0x00, 0x00, 0x82, 0x00, 0x80, 0x36,
- 0xfc, 0xd8, 0xc8, 0xa2, 0x67, 0xc8, 0xc6, 0xf4,
- 0x28, 0x70, 0xe1, 0x5a, 0x02, 0x8f, 0xef, 0x42,
- 0xe0, 0xd3, 0xb8, 0xd6, 0x6b, 0xe4, 0xee, 0x5c,
- 0xcf, 0x42, 0xc4, 0xfa, 0xcd, 0x0f, 0xfe, 0xf4,
- 0x76, 0x76, 0x47, 0x73, 0xa8, 0x72, 0x8f, 0xa2,
- 0x56, 0x81, 0x83, 0xb8, 0x84, 0x72, 0x67, 0xdd,
- 0xbe, 0x05, 0x4b, 0x84, 0xd9, 0xd2, 0xb6, 0xc2,
- 0xe7, 0x20, 0xac, 0x1f, 0x46, 0x9d, 0x05, 0x47,
- 0x8e, 0x89, 0xc0, 0x42, 0x57, 0x4a, 0xa2, 0x98,
- 0xe5, 0x39, 0x4f, 0xc4, 0x27, 0x6d, 0x43, 0xa8,
- 0x83, 0x76, 0xe6, 0xad, 0xe3, 0x17, 0x68, 0x31,
- 0xcb, 0x7e, 0xfc, 0xe7, 0x4b, 0x76, 0x3d, 0x3c,
- 0xfa, 0x77, 0x65, 0xc9, 0x4c, 0x5b, 0xce, 0x5e,
- 0xf7, 0x8b, 0xa8, 0xa6, 0xdd, 0xb2, 0xef, 0x0b,
- 0x46, 0x83, 0xdf, 0x0a, 0x8c, 0x22, 0x12, 0x6e,
- 0xe1, 0x45, 0x54, 0x88, 0xd1, 0xe8, 0xd2, 0x14,
- 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01,
- 0x00, 0x24, 0x30, 0x8c, 0x7d, 0x40, 0xfc, 0x5e,
- 0x80, 0x9c, 0xc4, 0x7c, 0x62, 0x01, 0xa1, 0x37,
- 0xcf, 0x1a, 0x75, 0x28, 0x8d, 0xeb, 0x63, 0xcc,
- 0x02, 0xa6, 0x66, 0xdf, 0x36, 0x01, 0xb3, 0x9d,
- 0x38, 0x42, 0x16, 0x91, 0xf0, 0x02,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x72, 0x04, 0x00, 0x00,
- 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
- 0xe8, 0x4b, 0xd1, 0xef, 0xba, 0x96, 0x9a, 0x2a,
- 0x6c, 0x8c, 0x7e, 0x38, 0x10, 0x46, 0x86, 0x1d,
- 0x19, 0x1d, 0x62, 0x29, 0x3f, 0x58, 0xfb, 0x6d,
- 0x89, 0xd2, 0x81, 0x9a, 0x1c, 0xb3, 0x58, 0xb3,
- 0x19, 0x39, 0x17, 0x47, 0x49, 0xc9, 0xfe, 0x4a,
- 0x7a, 0x32, 0xac, 0x2c, 0x43, 0xf9, 0xa9, 0xea,
- 0xec, 0x51, 0x46, 0xf1, 0xb8, 0x59, 0x23, 0x70,
- 0xce, 0x7c, 0xb9, 0x47, 0x70, 0xa3, 0xc9, 0xae,
- 0x47, 0x7b, 0x7e, 0xc7, 0xcf, 0x76, 0x12, 0x76,
- 0x18, 0x90, 0x12, 0xcd, 0xf3, 0xd4, 0x27, 0x81,
- 0xfc, 0x46, 0x03, 0x3e, 0x05, 0x87, 0x6f, 0x14,
- 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01,
- 0x00, 0x24, 0xc3, 0xa0, 0x29, 0xb1, 0x52, 0x82,
- 0xef, 0x85, 0xa1, 0x64, 0x0f, 0xe4, 0xa3, 0xfb,
- 0xa7, 0x1d, 0x22, 0x4c, 0xcb, 0xd6, 0x5b, 0x18,
- 0x61, 0xc7, 0x7c, 0xf2, 0x67, 0x4a, 0xc7, 0x11,
- 0x9d, 0x8e, 0x0e, 0x15, 0x22, 0xcf, 0x17, 0x03,
- 0x01, 0x00, 0x21, 0xfd, 0xbb, 0xf1, 0xa9, 0x7c,
- 0xbf, 0x92, 0xb3, 0xfa, 0x2c, 0x08, 0x6f, 0x22,
- 0x78, 0x80, 0xf2, 0x2e, 0x86, 0x26, 0x21, 0x36,
- 0x3f, 0x32, 0xdf, 0xb6, 0x47, 0xa5, 0xf8, 0x27,
- 0xc1, 0xe9, 0x53, 0x90, 0x15, 0x03, 0x01, 0x00,
- 0x16, 0xfe, 0xef, 0x2e, 0xa0, 0x5d, 0xe0, 0xce,
- 0x94, 0x20, 0x56, 0x61, 0x6e, 0xe5, 0x62, 0xce,
- 0x27, 0x57, 0x3e, 0x30, 0x32, 0x77, 0x53,
- },
- }},
+ config.SessionTicketsDisabled = true
- // Server asks for cert with empty CA list, client gives one
- // go test -run "TestRunServer" -serve -clientauth 1
- {"RequestClientCert, client gives it", RequestClientCert, []*x509.Certificate{clientCertificate}, [][]byte{
- {
- 0x16, 0x03, 0x01, 0x01, 0x1e, 0x01, 0x00, 0x01,
- 0x1a, 0x03, 0x03, 0x51, 0xe5, 0x74, 0x0e, 0x95,
- 0x6f, 0x4f, 0x4a, 0xbf, 0xb7, 0xc0, 0x6c, 0xac,
- 0xd9, 0xfe, 0x7d, 0xd0, 0x51, 0x19, 0x62, 0x62,
- 0x1c, 0x6e, 0x57, 0x77, 0xd2, 0x31, 0xaf, 0x88,
- 0xb9, 0xc0, 0x1d, 0x00, 0x00, 0x82, 0xc0, 0x30,
- 0xc0, 0x2c, 0xc0, 0x28, 0xc0, 0x24, 0xc0, 0x14,
- 0xc0, 0x0a, 0x00, 0xa3, 0x00, 0x9f, 0x00, 0x6b,
- 0x00, 0x6a, 0x00, 0x39, 0x00, 0x38, 0xc0, 0x32,
- 0xc0, 0x2e, 0xc0, 0x2a, 0xc0, 0x26, 0xc0, 0x0f,
- 0xc0, 0x05, 0x00, 0x9d, 0x00, 0x3d, 0x00, 0x35,
- 0xc0, 0x12, 0xc0, 0x08, 0x00, 0x16, 0x00, 0x13,
- 0xc0, 0x0d, 0xc0, 0x03, 0x00, 0x0a, 0xc0, 0x2f,
- 0xc0, 0x2b, 0xc0, 0x27, 0xc0, 0x23, 0xc0, 0x13,
- 0xc0, 0x09, 0x00, 0xa2, 0x00, 0x9e, 0x00, 0x67,
- 0x00, 0x40, 0x00, 0x33, 0x00, 0x32, 0xc0, 0x31,
- 0xc0, 0x2d, 0xc0, 0x29, 0xc0, 0x25, 0xc0, 0x0e,
- 0xc0, 0x04, 0x00, 0x9c, 0x00, 0x3c, 0x00, 0x2f,
- 0x00, 0x07, 0xc0, 0x11, 0xc0, 0x07, 0xc0, 0x0c,
- 0xc0, 0x02, 0x00, 0x05, 0x00, 0x04, 0x00, 0x15,
- 0x00, 0x12, 0x00, 0x09, 0x00, 0x14, 0x00, 0x11,
- 0x00, 0x08, 0x00, 0x06, 0x00, 0x03, 0x00, 0xff,
- 0x01, 0x00, 0x00, 0x6f, 0x00, 0x0b, 0x00, 0x04,
- 0x03, 0x00, 0x01, 0x02, 0x00, 0x0a, 0x00, 0x34,
- 0x00, 0x32, 0x00, 0x0e, 0x00, 0x0d, 0x00, 0x19,
- 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x09,
- 0x00, 0x0a, 0x00, 0x16, 0x00, 0x17, 0x00, 0x08,
- 0x00, 0x06, 0x00, 0x07, 0x00, 0x14, 0x00, 0x15,
- 0x00, 0x04, 0x00, 0x05, 0x00, 0x12, 0x00, 0x13,
- 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x0f,
- 0x00, 0x10, 0x00, 0x11, 0x00, 0x23, 0x00, 0x00,
- 0x00, 0x0d, 0x00, 0x22, 0x00, 0x20, 0x06, 0x01,
- 0x06, 0x02, 0x06, 0x03, 0x05, 0x01, 0x05, 0x02,
- 0x05, 0x03, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03,
- 0x03, 0x01, 0x03, 0x02, 0x03, 0x03, 0x02, 0x01,
- 0x02, 0x02, 0x02, 0x03, 0x01, 0x01, 0x00, 0x0f,
- 0x00, 0x01, 0x01,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x30, 0x02, 0x00, 0x00,
- 0x2c, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
- 0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x01,
- 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, 0x00, 0x02,
- 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, 0x02, 0xb0,
- 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, 0x02, 0x01,
- 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4,
- 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30,
- 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
- 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
- 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d,
- 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
- 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
- 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
- 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
- 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
- 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30,
- 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39,
- 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30,
- 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, 0x33,
- 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
- 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
- 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
- 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
- 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
- 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
- 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
- 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
- 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
- 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
- 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0x79,
- 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, 0x46, 0x10,
- 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, 0x07, 0x43,
- 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, 0x43, 0x85,
- 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, 0x4c, 0x2c,
- 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, 0x82, 0xe5,
- 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, 0xa5, 0x2c,
- 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, 0x7a, 0x56,
- 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, 0x7b, 0x26,
- 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, 0xc9, 0x21,
- 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, 0x5a, 0xbf,
- 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, 0x99, 0x07,
- 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, 0x04, 0x39,
- 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, 0x7c, 0xe3,
- 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, 0xcf, 0xaf,
- 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, 0xdb, 0xdb,
- 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, 0x02, 0x03,
- 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
- 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
- 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, 0xe2, 0x85,
- 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23,
- 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39,
- 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
- 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, 0xad, 0xe2,
- 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce,
- 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88,
- 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0x85,
- 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30,
- 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
- 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00,
- 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, 0xb1, 0x59,
- 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, 0x14, 0xd7,
- 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, 0x5a, 0x95,
- 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, 0x12, 0x66,
- 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, 0x60, 0xd3,
- 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, 0x25, 0x13,
- 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, 0x1d, 0xba,
- 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, 0xd7, 0x31,
- 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, 0xea, 0x50,
- 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, 0x5a, 0x5f,
- 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, 0x90, 0x96,
- 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, 0x98, 0x1f,
- 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, 0xa3, 0x1b,
- 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, 0xe9, 0x70,
- 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, 0x26, 0x6e,
- 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, 0xbd, 0xd9,
- 0x16, 0x03, 0x01, 0x00, 0x09, 0x0d, 0x00, 0x00,
- 0x05, 0x02, 0x01, 0x40, 0x00, 0x00, 0x16, 0x03,
- 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x01, 0xfb, 0x0b, 0x00, 0x01,
- 0xf7, 0x00, 0x01, 0xf4, 0x00, 0x01, 0xf1, 0x30,
- 0x82, 0x01, 0xed, 0x30, 0x82, 0x01, 0x58, 0xa0,
- 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x00, 0x30,
- 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x05, 0x30, 0x26, 0x31, 0x10,
- 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
- 0x07, 0x41, 0x63, 0x6d, 0x65, 0x20, 0x43, 0x6f,
- 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04,
- 0x03, 0x13, 0x09, 0x31, 0x32, 0x37, 0x2e, 0x30,
- 0x2e, 0x30, 0x2e, 0x31, 0x30, 0x1e, 0x17, 0x0d,
- 0x31, 0x31, 0x31, 0x32, 0x30, 0x38, 0x30, 0x37,
- 0x35, 0x35, 0x31, 0x32, 0x5a, 0x17, 0x0d, 0x31,
- 0x32, 0x31, 0x32, 0x30, 0x37, 0x30, 0x38, 0x30,
- 0x30, 0x31, 0x32, 0x5a, 0x30, 0x26, 0x31, 0x10,
- 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
- 0x07, 0x41, 0x63, 0x6d, 0x65, 0x20, 0x43, 0x6f,
- 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04,
- 0x03, 0x13, 0x09, 0x31, 0x32, 0x37, 0x2e, 0x30,
- 0x2e, 0x30, 0x2e, 0x31, 0x30, 0x81, 0x9c, 0x30,
- 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x01, 0x03, 0x81, 0x8c, 0x00,
- 0x30, 0x81, 0x88, 0x02, 0x81, 0x80, 0x4e, 0xd0,
- 0x7b, 0x31, 0xe3, 0x82, 0x64, 0xd9, 0x59, 0xc0,
- 0xc2, 0x87, 0xa4, 0x5e, 0x1e, 0x8b, 0x73, 0x33,
- 0xc7, 0x63, 0x53, 0xdf, 0x66, 0x92, 0x06, 0x84,
- 0xf6, 0x64, 0xd5, 0x8f, 0xe4, 0x36, 0xa7, 0x1d,
- 0x2b, 0xe8, 0xb3, 0x20, 0x36, 0x45, 0x23, 0xb5,
- 0xe3, 0x95, 0xae, 0xed, 0xe0, 0xf5, 0x20, 0x9c,
- 0x8d, 0x95, 0xdf, 0x7f, 0x5a, 0x12, 0xef, 0x87,
- 0xe4, 0x5b, 0x68, 0xe4, 0xe9, 0x0e, 0x74, 0xec,
- 0x04, 0x8a, 0x7f, 0xde, 0x93, 0x27, 0xc4, 0x01,
- 0x19, 0x7a, 0xbd, 0xf2, 0xdc, 0x3d, 0x14, 0xab,
- 0xd0, 0x54, 0xca, 0x21, 0x0c, 0xd0, 0x4d, 0x6e,
- 0x87, 0x2e, 0x5c, 0xc5, 0xd2, 0xbb, 0x4d, 0x4b,
- 0x4f, 0xce, 0xb6, 0x2c, 0xf7, 0x7e, 0x88, 0xec,
- 0x7c, 0xd7, 0x02, 0x91, 0x74, 0xa6, 0x1e, 0x0c,
- 0x1a, 0xda, 0xe3, 0x4a, 0x5a, 0x2e, 0xde, 0x13,
- 0x9c, 0x4c, 0x40, 0x88, 0x59, 0x93, 0x02, 0x03,
- 0x01, 0x00, 0x01, 0xa3, 0x32, 0x30, 0x30, 0x30,
- 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01,
- 0xff, 0x04, 0x04, 0x03, 0x02, 0x00, 0xa0, 0x30,
- 0x0d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x06,
- 0x04, 0x04, 0x01, 0x02, 0x03, 0x04, 0x30, 0x0f,
- 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x08, 0x30,
- 0x06, 0x80, 0x04, 0x01, 0x02, 0x03, 0x04, 0x30,
- 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x05, 0x03, 0x81, 0x81, 0x00,
- 0x36, 0x1f, 0xb3, 0x7a, 0x0c, 0x75, 0xc9, 0x6e,
- 0x37, 0x46, 0x61, 0x2b, 0xd5, 0xbd, 0xc0, 0xa7,
- 0x4b, 0xcc, 0x46, 0x9a, 0x81, 0x58, 0x7c, 0x85,
- 0x79, 0x29, 0xc8, 0xc8, 0xc6, 0x67, 0xdd, 0x32,
- 0x56, 0x45, 0x2b, 0x75, 0xb6, 0xe9, 0x24, 0xa9,
- 0x50, 0x9a, 0xbe, 0x1f, 0x5a, 0xfa, 0x1a, 0x15,
- 0xd9, 0xcc, 0x55, 0x95, 0x72, 0x16, 0x83, 0xb9,
- 0xc2, 0xb6, 0x8f, 0xfd, 0x88, 0x8c, 0x38, 0x84,
- 0x1d, 0xab, 0x5d, 0x92, 0x31, 0x13, 0x4f, 0xfd,
- 0x83, 0x3b, 0xc6, 0x9d, 0xf1, 0x11, 0x62, 0xb6,
- 0x8b, 0xec, 0xab, 0x67, 0xbe, 0xc8, 0x64, 0xb0,
- 0x11, 0x50, 0x46, 0x58, 0x17, 0x6b, 0x99, 0x1c,
- 0xd3, 0x1d, 0xfc, 0x06, 0xf1, 0x0e, 0xe5, 0x96,
- 0xa8, 0x0c, 0xf9, 0x78, 0x20, 0xb7, 0x44, 0x18,
- 0x51, 0x8d, 0x10, 0x7e, 0x4f, 0x94, 0x67, 0xdf,
- 0xa3, 0x4e, 0x70, 0x73, 0x8e, 0x90, 0x91, 0x85,
- 0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00,
- 0x82, 0x00, 0x80, 0x0a, 0x4e, 0x89, 0xdf, 0x3a,
- 0x3f, 0xf0, 0x4f, 0xef, 0x1a, 0x90, 0xd4, 0x3c,
- 0xaf, 0x10, 0x57, 0xb0, 0xa1, 0x5f, 0xcd, 0x62,
- 0x01, 0xe9, 0x0c, 0x36, 0x42, 0xfd, 0xaf, 0x23,
- 0xf9, 0x14, 0xa6, 0x72, 0x26, 0x4e, 0x01, 0xdb,
- 0xac, 0xb7, 0x4c, 0xe6, 0xa9, 0x52, 0xe2, 0xec,
- 0x26, 0x8c, 0x7a, 0x64, 0xf8, 0x0b, 0x4c, 0x2f,
- 0xa9, 0xcb, 0x75, 0xaf, 0x60, 0xd4, 0xb4, 0xe6,
- 0xe8, 0xdb, 0x78, 0x78, 0x85, 0xf6, 0x0c, 0x95,
- 0xcc, 0xb6, 0x55, 0xb9, 0xba, 0x9e, 0x91, 0xbc,
- 0x66, 0xdb, 0x1e, 0x28, 0xab, 0x73, 0xce, 0x8b,
- 0xd0, 0xd3, 0xe8, 0xbc, 0xd0, 0x21, 0x28, 0xbd,
- 0xfb, 0x74, 0x64, 0xde, 0x3b, 0x3b, 0xd3, 0x4c,
- 0x32, 0x40, 0x82, 0xba, 0x91, 0x1e, 0xe8, 0x47,
- 0xc2, 0x09, 0xb7, 0x16, 0xaa, 0x25, 0xa9, 0x3c,
- 0x6c, 0xa7, 0xf8, 0xc9, 0x54, 0x84, 0xc6, 0xf7,
- 0x56, 0x05, 0xa4, 0x16, 0x03, 0x01, 0x00, 0x86,
- 0x0f, 0x00, 0x00, 0x82, 0x00, 0x80, 0x4b, 0xab,
- 0xda, 0xac, 0x2a, 0xb3, 0xe6, 0x34, 0x55, 0xcd,
- 0xf2, 0x4b, 0x67, 0xe3, 0xd3, 0xff, 0xa3, 0xf4,
- 0x79, 0x82, 0x01, 0x47, 0x8a, 0xe3, 0x9f, 0x89,
- 0x70, 0xbe, 0x24, 0x24, 0xb7, 0x69, 0x60, 0xed,
- 0x55, 0xa0, 0xca, 0x72, 0xb6, 0x4a, 0xbc, 0x1d,
- 0xe2, 0x3f, 0xb5, 0x31, 0xda, 0x02, 0xf6, 0x37,
- 0x51, 0xf8, 0x4c, 0x88, 0x2e, 0xb3, 0x8a, 0xe8,
- 0x7b, 0x4a, 0x90, 0x36, 0xe4, 0xa6, 0x31, 0x95,
- 0x8b, 0xa0, 0xc6, 0x91, 0x12, 0xb9, 0x35, 0x4e,
- 0x72, 0xeb, 0x5c, 0xa2, 0xe8, 0x4c, 0x68, 0xf9,
- 0x69, 0xfa, 0x70, 0x60, 0x6c, 0x7f, 0x32, 0x99,
- 0xf1, 0xc3, 0x2d, 0xb4, 0x59, 0x58, 0x87, 0xaf,
- 0x67, 0x62, 0x90, 0xe7, 0x8d, 0xd0, 0xa3, 0x77,
- 0x33, 0xc2, 0x9b, 0xd5, 0x9c, 0xc7, 0xea, 0x25,
- 0x98, 0x76, 0x9c, 0xe0, 0x6a, 0x03, 0x3a, 0x10,
- 0xfd, 0x10, 0x3d, 0x55, 0x53, 0xa0, 0x14, 0x03,
- 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01, 0x00,
- 0x24, 0xd5, 0x12, 0xfc, 0xb9, 0x5a, 0xe3, 0x27,
- 0x01, 0xbe, 0xc3, 0x77, 0x17, 0x1a, 0xbb, 0x4f,
- 0xae, 0xd5, 0xa7, 0xee, 0x56, 0x61, 0x0d, 0x40,
- 0xf4, 0xa4, 0xb5, 0xcc, 0x76, 0xfd, 0xbd, 0x13,
- 0x04, 0xe1, 0xb8, 0xc7, 0x36,
- },
- {
- 0x16, 0x03, 0x01, 0x02, 0x67, 0x04, 0x00, 0x02,
- 0x63, 0x00, 0x00, 0x00, 0x00, 0x02, 0x5d, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
- 0xe8, 0x4b, 0xd1, 0xef, 0xba, 0x1f, 0xe2, 0x69,
- 0x07, 0x7f, 0x85, 0x2d, 0x4e, 0x2a, 0x2e, 0xbd,
- 0x05, 0xe9, 0xc1, 0x6c, 0x9e, 0xbf, 0x47, 0x18,
- 0x91, 0x77, 0xf7, 0xe8, 0xb6, 0x27, 0x37, 0xa6,
- 0x6b, 0x87, 0x29, 0xbb, 0x3b, 0xe5, 0x68, 0x62,
- 0x04, 0x3e, 0xad, 0x4d, 0xff, 0xad, 0xf1, 0x22,
- 0x87, 0x8d, 0xf6, 0x04, 0x3b, 0x59, 0x22, 0xf7,
- 0xfd, 0x88, 0x0e, 0xa4, 0x09, 0xc0, 0x0d, 0x10,
- 0x80, 0x10, 0x79, 0xee, 0x70, 0x96, 0xdb, 0x22,
- 0x8b, 0xb7, 0xac, 0xe0, 0x98, 0xad, 0xe9, 0xe3,
- 0xcb, 0xea, 0x9f, 0xe6, 0x83, 0x28, 0x7c, 0x7e,
- 0x4e, 0x9a, 0x8d, 0xd9, 0xf3, 0x86, 0xf4, 0x89,
- 0x8b, 0x79, 0x8f, 0xbb, 0xe9, 0x74, 0x02, 0x02,
- 0x14, 0x04, 0xea, 0xba, 0x16, 0x10, 0xa1, 0x85,
- 0xbe, 0x4e, 0x4e, 0x92, 0xc5, 0x83, 0xf6, 0x1e,
- 0x1f, 0xd4, 0x25, 0xc2, 0xc2, 0xb9, 0xce, 0x33,
- 0x63, 0x66, 0x79, 0x1f, 0x54, 0x35, 0xc1, 0xe8,
- 0x89, 0x34, 0x78, 0x94, 0x36, 0x14, 0xef, 0x01,
- 0x1f, 0xf1, 0xbd, 0x77, 0x2c, 0x4d, 0xac, 0x5c,
- 0x5c, 0x4a, 0xc6, 0xed, 0xd8, 0x0e, 0x72, 0x84,
- 0x83, 0xdc, 0x56, 0x84, 0xc8, 0xf3, 0x89, 0x56,
- 0xfd, 0x89, 0xc1, 0xc9, 0x9a, 0x29, 0x91, 0x7e,
- 0x19, 0xe9, 0x8b, 0x5b, 0x11, 0x15, 0x4e, 0x6c,
- 0xf4, 0x89, 0xe7, 0x6d, 0x68, 0x1e, 0xf9, 0x6c,
- 0x23, 0x72, 0x05, 0x68, 0x82, 0x60, 0x84, 0x1f,
- 0x83, 0x20, 0x09, 0x86, 0x10, 0x81, 0xec, 0xec,
- 0xdc, 0x25, 0x53, 0x20, 0xfa, 0xa9, 0x41, 0x64,
- 0xd6, 0x20, 0xf3, 0xf4, 0x52, 0xf2, 0x80, 0x62,
- 0x83, 0xc9, 0x23, 0x66, 0x44, 0x95, 0x5a, 0x99,
- 0x8a, 0xe1, 0x26, 0x63, 0xc1, 0x8b, 0x31, 0xf9,
- 0x21, 0x06, 0x77, 0x04, 0x27, 0xf2, 0x0c, 0x63,
- 0x83, 0x45, 0xa0, 0xa9, 0x7b, 0xcf, 0xdf, 0xd7,
- 0x56, 0x75, 0xbc, 0xdd, 0x95, 0x36, 0xb1, 0x75,
- 0x39, 0x05, 0x00, 0x3c, 0x8a, 0x79, 0xd6, 0xe9,
- 0xf0, 0x4b, 0xdc, 0x51, 0x6b, 0x01, 0x94, 0x16,
- 0x87, 0x12, 0x92, 0x6c, 0x07, 0xc1, 0xf5, 0x58,
- 0xb7, 0x2a, 0x81, 0xf5, 0xa0, 0x37, 0x8b, 0xa6,
- 0x22, 0xfe, 0x28, 0x0a, 0x7e, 0x68, 0xe2, 0xda,
- 0x6c, 0x53, 0xee, 0x0e, 0x8d, 0x2d, 0x8b, 0x0b,
- 0xda, 0xf8, 0x99, 0x3e, 0x0e, 0xed, 0x9f, 0xc1,
- 0x2b, 0xf6, 0xfe, 0xe9, 0x52, 0x38, 0x7b, 0x83,
- 0x9a, 0x50, 0xa6, 0xd7, 0x49, 0x83, 0x43, 0x7e,
- 0x82, 0xec, 0xc7, 0x09, 0x3d, 0x3d, 0xb1, 0xee,
- 0xe8, 0xc5, 0x6a, 0xc3, 0x3d, 0x4b, 0x4c, 0x6a,
- 0xbb, 0x0b, 0x2c, 0x24, 0x2e, 0xdb, 0x7d, 0x57,
- 0x87, 0xb4, 0x80, 0xa5, 0xae, 0xff, 0x54, 0xa8,
- 0xa5, 0x27, 0x69, 0x95, 0xc8, 0xe7, 0x79, 0xc7,
- 0x89, 0x2a, 0x73, 0x49, 0xcb, 0xf5, 0xc5, 0xbc,
- 0x4a, 0xe0, 0x73, 0xa9, 0xbc, 0x88, 0x64, 0x96,
- 0x98, 0xa5, 0x1e, 0xe3, 0x43, 0xc1, 0x7d, 0x78,
- 0xc7, 0x94, 0x72, 0xd4, 0x2c, 0x6e, 0x85, 0x39,
- 0x9a, 0xaf, 0xdb, 0xa1, 0xe9, 0xe2, 0xcb, 0x37,
- 0x04, 0xc6, 0x8c, 0x81, 0xd3, 0x2a, 0xb7, 0xbe,
- 0x6c, 0x07, 0x1f, 0x5e, 0xd9, 0x00, 0xd2, 0xf7,
- 0xe1, 0xa7, 0xbc, 0x0c, 0xb6, 0x6d, 0xfb, 0x3f,
- 0x3d, 0x24, 0xaa, 0xfb, 0x7e, 0xe1, 0xb5, 0x1b,
- 0xff, 0x38, 0xaa, 0x69, 0x59, 0x38, 0x52, 0x9a,
- 0x0e, 0x6d, 0xbc, 0xde, 0x4f, 0x13, 0x09, 0x17,
- 0xc4, 0xa9, 0x05, 0x84, 0xbc, 0x50, 0xef, 0x40,
- 0xb0, 0x4c, 0x24, 0x32, 0xed, 0x94, 0x2c, 0xdd,
- 0xda, 0x20, 0x24, 0x67, 0xe2, 0xea, 0x71, 0x3d,
- 0x4a, 0x04, 0x0d, 0x98, 0x29, 0x20, 0x4c, 0xeb,
- 0x70, 0xce, 0x45, 0x9e, 0x5a, 0xaf, 0xb6, 0xa3,
- 0x92, 0xc8, 0x28, 0xf2, 0xe3, 0xe8, 0x8a, 0x5d,
- 0x0a, 0x33, 0x79, 0x9b, 0x6a, 0xf3, 0x30, 0x01,
- 0x1d, 0x47, 0xbd, 0x01, 0xcc, 0x4d, 0x71, 0xc0,
- 0x56, 0xfa, 0xfd, 0x37, 0xed, 0x0f, 0x27, 0xc0,
- 0xbb, 0xa0, 0xee, 0xc3, 0x79, 0x8b, 0xe7, 0x41,
- 0x8f, 0xfa, 0x3a, 0xcb, 0x45, 0x3b, 0x85, 0x9f,
- 0x06, 0x90, 0xb2, 0x51, 0x7a, 0xc3, 0x11, 0x41,
- 0x4b, 0xe3, 0x26, 0x94, 0x3e, 0xa2, 0xfd, 0x0a,
- 0xda, 0x50, 0xf6, 0x50, 0x78, 0x19, 0x6c, 0x52,
- 0xd1, 0x12, 0x76, 0xc2, 0x50, 0x2f, 0x0b, 0xca,
- 0x33, 0xe5, 0x79, 0x93, 0x14, 0x03, 0x01, 0x00,
- 0x01, 0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0x2b,
- 0x51, 0x42, 0x95, 0x6b, 0xca, 0x9f, 0x42, 0x5d,
- 0xd2, 0xd9, 0x67, 0xf9, 0x49, 0x30, 0xfd, 0x2a,
- 0x46, 0xd3, 0x04, 0xf4, 0x86, 0xf9, 0x11, 0x34,
- 0x82, 0xac, 0xe2, 0xc2, 0x2d, 0xc4, 0xd0, 0xfe,
- 0xa9, 0xc9, 0x4b, 0x17, 0x03, 0x01, 0x00, 0x21,
- 0x65, 0x1c, 0xe9, 0x5c, 0xb6, 0xe2, 0x7c, 0x8e,
- 0x49, 0x12, 0x1b, 0xe6, 0x40, 0xd3, 0x97, 0x21,
- 0x76, 0x01, 0xe5, 0x80, 0x5e, 0xf3, 0x11, 0x47,
- 0x25, 0x02, 0x78, 0x8e, 0x6b, 0xae, 0xb3, 0xf3,
- 0x59, 0x15, 0x03, 0x01, 0x00, 0x16, 0x38, 0xc1,
- 0x99, 0x2e, 0xf8, 0x6f, 0x45, 0xa4, 0x10, 0x79,
- 0x5b, 0xc1, 0x47, 0x9a, 0xf6, 0x5c, 0x90, 0xeb,
- 0xa6, 0xe3, 0x1a, 0x24,
- },
- }},
-}
+ test = &serverTest{
+ name: "ResumeDisabled",
+ command: []string{"openssl", "s_client", "-cipher", "RC4-SHA", "-sess_in", sessionFilePath},
+ config: &config,
+ }
+ runServerTestTLS12(t, test)
-var tls11ECDHEAESServerScript = [][]byte{
- {
- 0x16, 0x03, 0x01, 0x01, 0x46, 0x01, 0x00, 0x01,
- 0x42, 0x03, 0x03, 0x51, 0x9f, 0xa3, 0xb0, 0xb7,
- 0x1d, 0x26, 0x93, 0x36, 0xc0, 0x8d, 0x7e, 0xf8,
- 0x4f, 0x6f, 0xc9, 0x3c, 0x31, 0x1e, 0x7f, 0xb1,
- 0xf0, 0xc1, 0x0f, 0xf9, 0x0c, 0xa2, 0xd5, 0xca,
- 0x48, 0xe5, 0x35, 0x00, 0x00, 0xd0, 0xc0, 0x30,
- 0xc0, 0x2c, 0xc0, 0x28, 0xc0, 0x24, 0xc0, 0x14,
- 0xc0, 0x0a, 0xc0, 0x22, 0xc0, 0x21, 0x00, 0xa5,
- 0x00, 0xa3, 0x00, 0xa1, 0x00, 0x9f, 0x00, 0x6b,
- 0x00, 0x6a, 0x00, 0x69, 0x00, 0x68, 0x00, 0x39,
- 0x00, 0x38, 0x00, 0x37, 0x00, 0x36, 0x00, 0x88,
- 0x00, 0x87, 0x00, 0x86, 0x00, 0x85, 0xc0, 0x32,
- 0xc0, 0x2e, 0xc0, 0x2a, 0xc0, 0x26, 0xc0, 0x0f,
- 0xc0, 0x05, 0x00, 0x9d, 0x00, 0x3d, 0x00, 0x35,
- 0x00, 0x84, 0xc0, 0x12, 0xc0, 0x08, 0xc0, 0x1c,
- 0xc0, 0x1b, 0x00, 0x16, 0x00, 0x13, 0x00, 0x10,
- 0x00, 0x0d, 0xc0, 0x0d, 0xc0, 0x03, 0x00, 0x0a,
- 0xc0, 0x2f, 0xc0, 0x2b, 0xc0, 0x27, 0xc0, 0x23,
- 0xc0, 0x13, 0xc0, 0x09, 0xc0, 0x1f, 0xc0, 0x1e,
- 0x00, 0xa4, 0x00, 0xa2, 0x00, 0xa0, 0x00, 0x9e,
- 0x00, 0x67, 0x00, 0x40, 0x00, 0x3f, 0x00, 0x3e,
- 0x00, 0x33, 0x00, 0x32, 0x00, 0x31, 0x00, 0x30,
- 0x00, 0x9a, 0x00, 0x99, 0x00, 0x98, 0x00, 0x97,
- 0x00, 0x45, 0x00, 0x44, 0x00, 0x43, 0x00, 0x42,
- 0xc0, 0x31, 0xc0, 0x2d, 0xc0, 0x29, 0xc0, 0x25,
- 0xc0, 0x0e, 0xc0, 0x04, 0x00, 0x9c, 0x00, 0x3c,
- 0x00, 0x2f, 0x00, 0x96, 0x00, 0x41, 0x00, 0x07,
- 0xc0, 0x11, 0xc0, 0x07, 0xc0, 0x0c, 0xc0, 0x02,
- 0x00, 0x05, 0x00, 0x04, 0x00, 0x15, 0x00, 0x12,
- 0x00, 0x0f, 0x00, 0x0c, 0x00, 0x09, 0x00, 0x14,
- 0x00, 0x11, 0x00, 0x0e, 0x00, 0x0b, 0x00, 0x08,
- 0x00, 0x06, 0x00, 0x03, 0x00, 0xff, 0x01, 0x00,
- 0x00, 0x49, 0x00, 0x0b, 0x00, 0x04, 0x03, 0x00,
- 0x01, 0x02, 0x00, 0x0a, 0x00, 0x34, 0x00, 0x32,
- 0x00, 0x0e, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x0b,
- 0x00, 0x0c, 0x00, 0x18, 0x00, 0x09, 0x00, 0x0a,
- 0x00, 0x16, 0x00, 0x17, 0x00, 0x08, 0x00, 0x06,
- 0x00, 0x07, 0x00, 0x14, 0x00, 0x15, 0x00, 0x04,
- 0x00, 0x05, 0x00, 0x12, 0x00, 0x13, 0x00, 0x01,
- 0x00, 0x02, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x10,
- 0x00, 0x11, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0f,
- 0x00, 0x01, 0x01,
- },
- {
- 0x16, 0x03, 0x02, 0x00, 0x30, 0x02, 0x00, 0x00,
- 0x2c, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xc0, 0x13, 0x00, 0x00,
- 0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x02,
- 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, 0x00, 0x02,
- 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, 0x02, 0xb0,
- 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, 0x02, 0x01,
- 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4,
- 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30,
- 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
- 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
- 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d,
- 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
- 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
- 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
- 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
- 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
- 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30,
- 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39,
- 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30,
- 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, 0x33,
- 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
- 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
- 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
- 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
- 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
- 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
- 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
- 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
- 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
- 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
- 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0x79,
- 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, 0x46, 0x10,
- 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, 0x07, 0x43,
- 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, 0x43, 0x85,
- 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, 0x4c, 0x2c,
- 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, 0x82, 0xe5,
- 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, 0xa5, 0x2c,
- 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, 0x7a, 0x56,
- 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, 0x7b, 0x26,
- 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, 0xc9, 0x21,
- 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, 0x5a, 0xbf,
- 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, 0x99, 0x07,
- 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, 0x04, 0x39,
- 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, 0x7c, 0xe3,
- 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, 0xcf, 0xaf,
- 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, 0xdb, 0xdb,
- 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, 0x02, 0x03,
- 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
- 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
- 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, 0xe2, 0x85,
- 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23,
- 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39,
- 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
- 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, 0xad, 0xe2,
- 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce,
- 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88,
- 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0x85,
- 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30,
- 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
- 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00,
- 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, 0xb1, 0x59,
- 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, 0x14, 0xd7,
- 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, 0x5a, 0x95,
- 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, 0x12, 0x66,
- 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, 0x60, 0xd3,
- 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, 0x25, 0x13,
- 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, 0x1d, 0xba,
- 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, 0xd7, 0x31,
- 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, 0xea, 0x50,
- 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, 0x5a, 0x5f,
- 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, 0x90, 0x96,
- 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, 0x98, 0x1f,
- 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, 0xa3, 0x1b,
- 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, 0xe9, 0x70,
- 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, 0x26, 0x6e,
- 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, 0xbd, 0xd9,
- 0x16, 0x03, 0x02, 0x01, 0x0f, 0x0c, 0x00, 0x01,
- 0x0b, 0x03, 0x00, 0x19, 0x85, 0x04, 0x01, 0x39,
- 0xdc, 0xee, 0x44, 0x17, 0x5e, 0xdb, 0xd7, 0x27,
- 0xaf, 0xb6, 0x56, 0xd9, 0xb4, 0x43, 0x5a, 0x99,
- 0xcf, 0xaa, 0x31, 0x37, 0x0c, 0x6f, 0x3a, 0xa0,
- 0xf8, 0x53, 0xc4, 0x74, 0xd1, 0x91, 0x0a, 0x46,
- 0xf5, 0x38, 0x3b, 0x5c, 0x09, 0xd8, 0x97, 0xdc,
- 0x4b, 0xaa, 0x70, 0x26, 0x48, 0xf2, 0xd6, 0x0b,
- 0x31, 0xc9, 0xf8, 0xd4, 0x98, 0x43, 0xe1, 0x6c,
- 0xd5, 0xc7, 0xb2, 0x8e, 0x0b, 0x01, 0xe6, 0xb6,
- 0x00, 0x28, 0x80, 0x7b, 0xfc, 0x96, 0x8f, 0x0d,
- 0xa2, 0x4f, 0xb0, 0x79, 0xaf, 0xdc, 0x61, 0x28,
- 0x63, 0x33, 0x78, 0xf6, 0x31, 0x39, 0xfd, 0x8a,
- 0xf4, 0x15, 0x18, 0x11, 0xfe, 0xdb, 0xd5, 0x07,
- 0xda, 0x2c, 0xed, 0x49, 0xa0, 0x23, 0xbf, 0xd0,
- 0x3a, 0x38, 0x1d, 0x54, 0xae, 0x1c, 0x7b, 0xea,
- 0x29, 0xee, 0xd0, 0x38, 0xc1, 0x76, 0xa7, 0x7f,
- 0x2a, 0xf4, 0xce, 0x1e, 0xac, 0xcc, 0x94, 0x79,
- 0x90, 0x33, 0x00, 0x80, 0x16, 0x83, 0x9b, 0xf9,
- 0x72, 0xdb, 0x9f, 0x55, 0x02, 0xe1, 0x04, 0xf7,
- 0xb5, 0x3f, 0x4c, 0x71, 0x13, 0x5a, 0x91, 0xe9,
- 0x1d, 0xeb, 0x9d, 0x9c, 0xfb, 0x88, 0xef, 0xca,
- 0xec, 0x7d, 0x9b, 0xdd, 0xd9, 0xee, 0x2b, 0x8e,
- 0xef, 0xf8, 0xb6, 0xc7, 0x7d, 0xfe, 0xda, 0x7f,
- 0x90, 0x2e, 0x53, 0xf1, 0x64, 0x95, 0xfc, 0x66,
- 0xfc, 0x87, 0x27, 0xb6, 0x9f, 0xc8, 0x3a, 0x95,
- 0x68, 0x17, 0xe1, 0x7d, 0xf1, 0x88, 0xe8, 0x17,
- 0x5f, 0x99, 0x90, 0x3f, 0x47, 0x47, 0x81, 0x06,
- 0xe2, 0x8e, 0x22, 0x56, 0x8f, 0xc2, 0x14, 0xe5,
- 0x62, 0xa7, 0x0d, 0x41, 0x3c, 0xc7, 0x4a, 0x0a,
- 0x74, 0x4b, 0xda, 0x00, 0x8e, 0x4f, 0x90, 0xe6,
- 0xd7, 0x68, 0xe5, 0x8b, 0xf2, 0x3f, 0x53, 0x1d,
- 0x7a, 0xe6, 0xb3, 0xe9, 0x8a, 0xc9, 0x4d, 0x19,
- 0xa6, 0xcf, 0xf9, 0xed, 0x5e, 0x26, 0xdc, 0x90,
- 0x1c, 0x41, 0xad, 0x7c, 0x16, 0x03, 0x02, 0x00,
- 0x04, 0x0e, 0x00, 0x00, 0x00,
- },
- {
- 0x16, 0x03, 0x02, 0x00, 0x8a, 0x10, 0x00, 0x00,
- 0x86, 0x85, 0x04, 0x01, 0x11, 0xf2, 0xa4, 0x2d,
- 0x1a, 0x75, 0x6c, 0xbc, 0x2d, 0x91, 0x95, 0x07,
- 0xbe, 0xd6, 0x41, 0x7a, 0xbb, 0xc2, 0x7b, 0xa6,
- 0x9b, 0xe3, 0xdc, 0x41, 0x7f, 0x1e, 0x2e, 0xcc,
- 0x6d, 0xa3, 0x85, 0x53, 0x98, 0x9f, 0x2d, 0xe6,
- 0x3c, 0xb9, 0x82, 0xa6, 0x80, 0x53, 0x9b, 0x71,
- 0xfd, 0x27, 0xe5, 0xe5, 0xdf, 0x13, 0xba, 0x56,
- 0x62, 0x30, 0x4a, 0x57, 0x27, 0xa7, 0xcc, 0x26,
- 0x54, 0xe8, 0x65, 0x6e, 0x4d, 0x00, 0xbf, 0x8a,
- 0xcc, 0x89, 0x6a, 0x6c, 0x88, 0xda, 0x79, 0x4f,
- 0xc5, 0xad, 0x6d, 0x1d, 0x7c, 0x53, 0x7b, 0x1a,
- 0x96, 0xf2, 0xf8, 0x30, 0x01, 0x0b, 0xc2, 0xf0,
- 0x78, 0x41, 0xf4, 0x0d, 0xe0, 0xbe, 0xb9, 0x36,
- 0xe0, 0xb7, 0xee, 0x16, 0xeb, 0x25, 0x67, 0x04,
- 0xc0, 0x2e, 0xd8, 0x34, 0x4a, 0x65, 0xa5, 0xf1,
- 0x95, 0x75, 0xc7, 0x39, 0xa9, 0x68, 0xa9, 0x53,
- 0x93, 0x5b, 0xca, 0x7b, 0x7f, 0xc0, 0x63, 0x14,
- 0x03, 0x02, 0x00, 0x01, 0x01, 0x16, 0x03, 0x02,
- 0x00, 0x40, 0x01, 0xb1, 0xae, 0x1b, 0x8a, 0x65,
- 0xf8, 0x37, 0x50, 0x39, 0x76, 0xef, 0xaa, 0xda,
- 0x84, 0xc9, 0x5f, 0x80, 0xdc, 0xfa, 0xe0, 0x46,
- 0x5a, 0xc7, 0x77, 0x9d, 0x76, 0x03, 0xa6, 0xd5,
- 0x0e, 0xbf, 0x25, 0x30, 0x5c, 0x99, 0x7d, 0xcd,
- 0x2b, 0xaa, 0x2e, 0x8c, 0xdd, 0xda, 0xaa, 0xd7,
- 0xf1, 0xf6, 0x33, 0x47, 0x51, 0x1e, 0x83, 0xa1,
- 0x83, 0x04, 0xd2, 0xb2, 0xc8, 0xbc, 0x11, 0xc5,
- 0x1a, 0x87,
- },
- {
- 0x16, 0x03, 0x02, 0x00, 0x72, 0x04, 0x00, 0x00,
- 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
- 0xeb, 0x8b, 0xc7, 0xef, 0xba, 0xe8, 0x0f, 0x69,
- 0xfe, 0xfb, 0xc3, 0x3d, 0x90, 0x5d, 0xd7, 0xb2,
- 0x51, 0x64, 0xac, 0xc3, 0xae, 0x33, 0x03, 0x42,
- 0x45, 0x2d, 0xa7, 0x57, 0xbd, 0xa3, 0x85, 0x64,
- 0xa6, 0xfe, 0x5c, 0x33, 0x04, 0x93, 0xf2, 0x7c,
- 0x06, 0x6d, 0xd7, 0xd7, 0xcf, 0x4a, 0xaf, 0xb2,
- 0xdd, 0x06, 0xdc, 0x28, 0x14, 0x59, 0x23, 0x02,
- 0xef, 0x97, 0x6a, 0xe8, 0xec, 0xca, 0x10, 0x44,
- 0xcd, 0xb8, 0x50, 0x16, 0x46, 0x5a, 0x05, 0xda,
- 0x04, 0xb3, 0x0e, 0xe9, 0xf0, 0x74, 0xc5, 0x23,
- 0xc2, 0x0e, 0xa1, 0x54, 0x66, 0x7b, 0xe8, 0x14,
- 0x03, 0x02, 0x00, 0x01, 0x01, 0x16, 0x03, 0x02,
- 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x6b, 0x43, 0x1c, 0x58, 0xbc, 0x85,
- 0xf7, 0xc1, 0x76, 0xbc, 0x72, 0x33, 0x41, 0x6b,
- 0xb8, 0xf8, 0xfd, 0x53, 0x21, 0xc2, 0x41, 0x1b,
- 0x72, 0x4f, 0xce, 0x97, 0xca, 0x14, 0x23, 0x4d,
- 0xbc, 0x44, 0xd6, 0xd7, 0xfc, 0xbc, 0xfd, 0xfd,
- 0x5d, 0x33, 0x42, 0x1b, 0x52, 0x40, 0x0a, 0x2b,
- 0x6c, 0x98, 0x17, 0x03, 0x02, 0x00, 0x40, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d,
- 0x31, 0xef, 0x03, 0x7d, 0xa5, 0x74, 0x92, 0x24,
- 0x34, 0xae, 0x4e, 0xc9, 0xfc, 0x59, 0xcb, 0x64,
- 0xf4, 0x45, 0xb1, 0xac, 0x02, 0xf2, 0x87, 0xe7,
- 0x2f, 0xfd, 0x01, 0xca, 0x78, 0x02, 0x2e, 0x3a,
- 0x38, 0xcd, 0xb1, 0xe0, 0xf2, 0x2e, 0xf6, 0x27,
- 0xa0, 0xac, 0x1f, 0x91, 0x43, 0xc2, 0x3d, 0x15,
- 0x03, 0x02, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x9f, 0x30, 0x24, 0x56,
- 0x2c, 0xde, 0xa0, 0xe6, 0x44, 0x35, 0x30, 0x51,
- 0xec, 0xd4, 0x69, 0x2d, 0x46, 0x64, 0x04, 0x21,
- 0xfe, 0x7c, 0x4d, 0xc5, 0xd0, 0x8c, 0xf9, 0xd2,
- 0x3f, 0x88, 0x69, 0xd5,
- },
+ // One needs to manually confirm that the handshake in the golden data
+ // file for ResumeDisabled does not include a resumption handshake.
}
-// $ go test -run TestRunServer -serve -clientauth 1 \
-// -ciphersuites=0xc011 -minversion=0x0303 -maxversion=0x0303
-var tls12ServerScript = [][]byte{
- {
- 0x16, 0x03, 0x01, 0x01, 0x1e, 0x01, 0x00, 0x01,
- 0x1a, 0x03, 0x03, 0x51, 0xe5, 0x76, 0x84, 0x0e,
- 0xb9, 0x17, 0xca, 0x08, 0x47, 0xd9, 0xbd, 0xd0,
- 0x94, 0xd1, 0x97, 0xca, 0x5b, 0xe7, 0x20, 0xac,
- 0x8e, 0xbb, 0xc7, 0x29, 0xe9, 0x26, 0xcf, 0x7d,
- 0xb3, 0xdc, 0x99, 0x00, 0x00, 0x82, 0xc0, 0x30,
- 0xc0, 0x2c, 0xc0, 0x28, 0xc0, 0x24, 0xc0, 0x14,
- 0xc0, 0x0a, 0x00, 0xa3, 0x00, 0x9f, 0x00, 0x6b,
- 0x00, 0x6a, 0x00, 0x39, 0x00, 0x38, 0xc0, 0x32,
- 0xc0, 0x2e, 0xc0, 0x2a, 0xc0, 0x26, 0xc0, 0x0f,
- 0xc0, 0x05, 0x00, 0x9d, 0x00, 0x3d, 0x00, 0x35,
- 0xc0, 0x12, 0xc0, 0x08, 0x00, 0x16, 0x00, 0x13,
- 0xc0, 0x0d, 0xc0, 0x03, 0x00, 0x0a, 0xc0, 0x2f,
- 0xc0, 0x2b, 0xc0, 0x27, 0xc0, 0x23, 0xc0, 0x13,
- 0xc0, 0x09, 0x00, 0xa2, 0x00, 0x9e, 0x00, 0x67,
- 0x00, 0x40, 0x00, 0x33, 0x00, 0x32, 0xc0, 0x31,
- 0xc0, 0x2d, 0xc0, 0x29, 0xc0, 0x25, 0xc0, 0x0e,
- 0xc0, 0x04, 0x00, 0x9c, 0x00, 0x3c, 0x00, 0x2f,
- 0x00, 0x07, 0xc0, 0x11, 0xc0, 0x07, 0xc0, 0x0c,
- 0xc0, 0x02, 0x00, 0x05, 0x00, 0x04, 0x00, 0x15,
- 0x00, 0x12, 0x00, 0x09, 0x00, 0x14, 0x00, 0x11,
- 0x00, 0x08, 0x00, 0x06, 0x00, 0x03, 0x00, 0xff,
- 0x01, 0x00, 0x00, 0x6f, 0x00, 0x0b, 0x00, 0x04,
- 0x03, 0x00, 0x01, 0x02, 0x00, 0x0a, 0x00, 0x34,
- 0x00, 0x32, 0x00, 0x0e, 0x00, 0x0d, 0x00, 0x19,
- 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x09,
- 0x00, 0x0a, 0x00, 0x16, 0x00, 0x17, 0x00, 0x08,
- 0x00, 0x06, 0x00, 0x07, 0x00, 0x14, 0x00, 0x15,
- 0x00, 0x04, 0x00, 0x05, 0x00, 0x12, 0x00, 0x13,
- 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x0f,
- 0x00, 0x10, 0x00, 0x11, 0x00, 0x23, 0x00, 0x00,
- 0x00, 0x0d, 0x00, 0x22, 0x00, 0x20, 0x06, 0x01,
- 0x06, 0x02, 0x06, 0x03, 0x05, 0x01, 0x05, 0x02,
- 0x05, 0x03, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03,
- 0x03, 0x01, 0x03, 0x02, 0x03, 0x03, 0x02, 0x01,
- 0x02, 0x02, 0x02, 0x03, 0x01, 0x01, 0x00, 0x0f,
- 0x00, 0x01, 0x01,
- },
- {
- 0x16, 0x03, 0x03, 0x00, 0x30, 0x02, 0x00, 0x00,
- 0x2c, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xc0, 0x11, 0x00, 0x00,
- 0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x03,
- 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, 0x00, 0x02,
- 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, 0x02, 0xb0,
- 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, 0x02, 0x01,
- 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4,
- 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30,
- 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
- 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
- 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d,
- 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
- 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
- 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
- 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
- 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
- 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30,
- 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39,
- 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30,
- 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, 0x33,
- 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
- 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
- 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
- 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
- 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
- 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
- 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
- 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
- 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
- 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
- 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0x79,
- 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, 0x46, 0x10,
- 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, 0x07, 0x43,
- 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, 0x43, 0x85,
- 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, 0x4c, 0x2c,
- 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, 0x82, 0xe5,
- 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, 0xa5, 0x2c,
- 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, 0x7a, 0x56,
- 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, 0x7b, 0x26,
- 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, 0xc9, 0x21,
- 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, 0x5a, 0xbf,
- 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, 0x99, 0x07,
- 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, 0x04, 0x39,
- 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, 0x7c, 0xe3,
- 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, 0xcf, 0xaf,
- 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, 0xdb, 0xdb,
- 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, 0x02, 0x03,
- 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
- 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
- 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, 0xe2, 0x85,
- 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23,
- 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39,
- 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
- 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, 0xad, 0xe2,
- 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce,
- 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88,
- 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0x85,
- 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30,
- 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
- 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00,
- 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, 0xb1, 0x59,
- 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, 0x14, 0xd7,
- 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, 0x5a, 0x95,
- 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, 0x12, 0x66,
- 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, 0x60, 0xd3,
- 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, 0x25, 0x13,
- 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, 0x1d, 0xba,
- 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, 0xd7, 0x31,
- 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, 0xea, 0x50,
- 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, 0x5a, 0x5f,
- 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, 0x90, 0x96,
- 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, 0x98, 0x1f,
- 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, 0xa3, 0x1b,
- 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, 0xe9, 0x70,
- 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, 0x26, 0x6e,
- 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, 0xbd, 0xd9,
- 0x16, 0x03, 0x03, 0x01, 0x11, 0x0c, 0x00, 0x01,
- 0x0d, 0x03, 0x00, 0x19, 0x85, 0x04, 0x01, 0x39,
- 0xdc, 0xee, 0x44, 0x17, 0x5e, 0xdb, 0xd7, 0x27,
- 0xaf, 0xb6, 0x56, 0xd9, 0xb4, 0x43, 0x5a, 0x99,
- 0xcf, 0xaa, 0x31, 0x37, 0x0c, 0x6f, 0x3a, 0xa0,
- 0xf8, 0x53, 0xc4, 0x74, 0xd1, 0x91, 0x0a, 0x46,
- 0xf5, 0x38, 0x3b, 0x5c, 0x09, 0xd8, 0x97, 0xdc,
- 0x4b, 0xaa, 0x70, 0x26, 0x48, 0xf2, 0xd6, 0x0b,
- 0x31, 0xc9, 0xf8, 0xd4, 0x98, 0x43, 0xe1, 0x6c,
- 0xd5, 0xc7, 0xb2, 0x8e, 0x0b, 0x01, 0xe6, 0xb6,
- 0x00, 0x28, 0x80, 0x7b, 0xfc, 0x96, 0x8f, 0x0d,
- 0xa2, 0x4f, 0xb0, 0x79, 0xaf, 0xdc, 0x61, 0x28,
- 0x63, 0x33, 0x78, 0xf6, 0x31, 0x39, 0xfd, 0x8a,
- 0xf4, 0x15, 0x18, 0x11, 0xfe, 0xdb, 0xd5, 0x07,
- 0xda, 0x2c, 0xed, 0x49, 0xa0, 0x23, 0xbf, 0xd0,
- 0x3a, 0x38, 0x1d, 0x54, 0xae, 0x1c, 0x7b, 0xea,
- 0x29, 0xee, 0xd0, 0x38, 0xc1, 0x76, 0xa7, 0x7f,
- 0x2a, 0xf4, 0xce, 0x1e, 0xac, 0xcc, 0x94, 0x79,
- 0x90, 0x33, 0x04, 0x01, 0x00, 0x80, 0x4a, 0xf9,
- 0xf5, 0x0a, 0x61, 0x37, 0x7e, 0x4e, 0x92, 0xb5,
- 0x1c, 0x91, 0x21, 0xb2, 0xb5, 0x17, 0x00, 0xbf,
- 0x01, 0x5f, 0x30, 0xec, 0x62, 0x08, 0xd6, 0x9d,
- 0x1a, 0x08, 0x05, 0x72, 0x8b, 0xf4, 0x49, 0x85,
- 0xa7, 0xbf, 0x3f, 0x75, 0x58, 0x3e, 0x26, 0x82,
- 0xc3, 0x28, 0x07, 0xf9, 0x41, 0x7d, 0x03, 0x14,
- 0x3b, 0xc3, 0x05, 0x64, 0xff, 0x52, 0xf4, 0x75,
- 0x6a, 0x87, 0xcd, 0xdf, 0x93, 0x31, 0x0a, 0x71,
- 0x60, 0x17, 0xc6, 0x33, 0xf0, 0x79, 0xb6, 0x7b,
- 0xd0, 0x9c, 0xa0, 0x5f, 0x74, 0x14, 0x2c, 0x5a,
- 0xb4, 0x3f, 0x39, 0xf5, 0xe4, 0x9f, 0xbe, 0x6d,
- 0x21, 0xd2, 0xa9, 0x42, 0xf7, 0xdc, 0xa6, 0x65,
- 0xb7, 0x6a, 0x7e, 0x2e, 0x14, 0xd3, 0xf6, 0xf3,
- 0x4b, 0x4c, 0x5b, 0x1a, 0x70, 0x7a, 0xbc, 0xb0,
- 0x12, 0xf3, 0x6e, 0x0c, 0xcf, 0x43, 0x22, 0xae,
- 0x5b, 0xba, 0x00, 0xf8, 0xfd, 0xaf, 0x16, 0x03,
- 0x03, 0x00, 0x0f, 0x0d, 0x00, 0x00, 0x0b, 0x02,
- 0x01, 0x40, 0x00, 0x04, 0x04, 0x01, 0x04, 0x03,
- 0x00, 0x00, 0x16, 0x03, 0x03, 0x00, 0x04, 0x0e,
- 0x00, 0x00, 0x00,
- },
- {
- 0x16, 0x03, 0x03, 0x01, 0xfb, 0x0b, 0x00, 0x01,
- 0xf7, 0x00, 0x01, 0xf4, 0x00, 0x01, 0xf1, 0x30,
- 0x82, 0x01, 0xed, 0x30, 0x82, 0x01, 0x58, 0xa0,
- 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x00, 0x30,
- 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x05, 0x30, 0x26, 0x31, 0x10,
- 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
- 0x07, 0x41, 0x63, 0x6d, 0x65, 0x20, 0x43, 0x6f,
- 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04,
- 0x03, 0x13, 0x09, 0x31, 0x32, 0x37, 0x2e, 0x30,
- 0x2e, 0x30, 0x2e, 0x31, 0x30, 0x1e, 0x17, 0x0d,
- 0x31, 0x31, 0x31, 0x32, 0x30, 0x38, 0x30, 0x37,
- 0x35, 0x35, 0x31, 0x32, 0x5a, 0x17, 0x0d, 0x31,
- 0x32, 0x31, 0x32, 0x30, 0x37, 0x30, 0x38, 0x30,
- 0x30, 0x31, 0x32, 0x5a, 0x30, 0x26, 0x31, 0x10,
- 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
- 0x07, 0x41, 0x63, 0x6d, 0x65, 0x20, 0x43, 0x6f,
- 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04,
- 0x03, 0x13, 0x09, 0x31, 0x32, 0x37, 0x2e, 0x30,
- 0x2e, 0x30, 0x2e, 0x31, 0x30, 0x81, 0x9c, 0x30,
- 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x01, 0x03, 0x81, 0x8c, 0x00,
- 0x30, 0x81, 0x88, 0x02, 0x81, 0x80, 0x4e, 0xd0,
- 0x7b, 0x31, 0xe3, 0x82, 0x64, 0xd9, 0x59, 0xc0,
- 0xc2, 0x87, 0xa4, 0x5e, 0x1e, 0x8b, 0x73, 0x33,
- 0xc7, 0x63, 0x53, 0xdf, 0x66, 0x92, 0x06, 0x84,
- 0xf6, 0x64, 0xd5, 0x8f, 0xe4, 0x36, 0xa7, 0x1d,
- 0x2b, 0xe8, 0xb3, 0x20, 0x36, 0x45, 0x23, 0xb5,
- 0xe3, 0x95, 0xae, 0xed, 0xe0, 0xf5, 0x20, 0x9c,
- 0x8d, 0x95, 0xdf, 0x7f, 0x5a, 0x12, 0xef, 0x87,
- 0xe4, 0x5b, 0x68, 0xe4, 0xe9, 0x0e, 0x74, 0xec,
- 0x04, 0x8a, 0x7f, 0xde, 0x93, 0x27, 0xc4, 0x01,
- 0x19, 0x7a, 0xbd, 0xf2, 0xdc, 0x3d, 0x14, 0xab,
- 0xd0, 0x54, 0xca, 0x21, 0x0c, 0xd0, 0x4d, 0x6e,
- 0x87, 0x2e, 0x5c, 0xc5, 0xd2, 0xbb, 0x4d, 0x4b,
- 0x4f, 0xce, 0xb6, 0x2c, 0xf7, 0x7e, 0x88, 0xec,
- 0x7c, 0xd7, 0x02, 0x91, 0x74, 0xa6, 0x1e, 0x0c,
- 0x1a, 0xda, 0xe3, 0x4a, 0x5a, 0x2e, 0xde, 0x13,
- 0x9c, 0x4c, 0x40, 0x88, 0x59, 0x93, 0x02, 0x03,
- 0x01, 0x00, 0x01, 0xa3, 0x32, 0x30, 0x30, 0x30,
- 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01,
- 0xff, 0x04, 0x04, 0x03, 0x02, 0x00, 0xa0, 0x30,
- 0x0d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x06,
- 0x04, 0x04, 0x01, 0x02, 0x03, 0x04, 0x30, 0x0f,
- 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x08, 0x30,
- 0x06, 0x80, 0x04, 0x01, 0x02, 0x03, 0x04, 0x30,
- 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x05, 0x03, 0x81, 0x81, 0x00,
- 0x36, 0x1f, 0xb3, 0x7a, 0x0c, 0x75, 0xc9, 0x6e,
- 0x37, 0x46, 0x61, 0x2b, 0xd5, 0xbd, 0xc0, 0xa7,
- 0x4b, 0xcc, 0x46, 0x9a, 0x81, 0x58, 0x7c, 0x85,
- 0x79, 0x29, 0xc8, 0xc8, 0xc6, 0x67, 0xdd, 0x32,
- 0x56, 0x45, 0x2b, 0x75, 0xb6, 0xe9, 0x24, 0xa9,
- 0x50, 0x9a, 0xbe, 0x1f, 0x5a, 0xfa, 0x1a, 0x15,
- 0xd9, 0xcc, 0x55, 0x95, 0x72, 0x16, 0x83, 0xb9,
- 0xc2, 0xb6, 0x8f, 0xfd, 0x88, 0x8c, 0x38, 0x84,
- 0x1d, 0xab, 0x5d, 0x92, 0x31, 0x13, 0x4f, 0xfd,
- 0x83, 0x3b, 0xc6, 0x9d, 0xf1, 0x11, 0x62, 0xb6,
- 0x8b, 0xec, 0xab, 0x67, 0xbe, 0xc8, 0x64, 0xb0,
- 0x11, 0x50, 0x46, 0x58, 0x17, 0x6b, 0x99, 0x1c,
- 0xd3, 0x1d, 0xfc, 0x06, 0xf1, 0x0e, 0xe5, 0x96,
- 0xa8, 0x0c, 0xf9, 0x78, 0x20, 0xb7, 0x44, 0x18,
- 0x51, 0x8d, 0x10, 0x7e, 0x4f, 0x94, 0x67, 0xdf,
- 0xa3, 0x4e, 0x70, 0x73, 0x8e, 0x90, 0x91, 0x85,
- 0x16, 0x03, 0x03, 0x00, 0x8a, 0x10, 0x00, 0x00,
- 0x86, 0x85, 0x04, 0x01, 0x5d, 0x3a, 0x92, 0x59,
- 0x7f, 0x9a, 0x22, 0x36, 0x0e, 0x1b, 0x1d, 0x2a,
- 0x05, 0xb7, 0xa4, 0xb6, 0x5d, 0xfc, 0x51, 0x6e,
- 0x15, 0xe5, 0x89, 0x7c, 0xe2, 0xfa, 0x87, 0x38,
- 0x05, 0x79, 0x15, 0x92, 0xb4, 0x8f, 0x88, 0x8f,
- 0x9d, 0x5d, 0xa0, 0xaf, 0xf8, 0xce, 0xf9, 0x6f,
- 0x83, 0xf4, 0x08, 0x69, 0xe4, 0x91, 0xc5, 0xed,
- 0xb9, 0xc5, 0xa8, 0x1f, 0x4b, 0xec, 0xef, 0x91,
- 0xc1, 0xa3, 0x34, 0x24, 0x18, 0x00, 0x2d, 0xcd,
- 0xe6, 0x44, 0xef, 0x5a, 0x3e, 0x52, 0x63, 0x5b,
- 0x36, 0x1f, 0x7e, 0xce, 0x9e, 0xaa, 0xda, 0x8d,
- 0xb5, 0xc9, 0xea, 0xd8, 0x1b, 0xd1, 0x1c, 0x7c,
- 0x07, 0xfc, 0x3c, 0x2d, 0x70, 0x1f, 0xf9, 0x4d,
- 0xcb, 0xaa, 0xad, 0x07, 0xd5, 0x6d, 0xbd, 0xa6,
- 0x61, 0xf3, 0x2f, 0xa3, 0x9c, 0x45, 0x02, 0x4a,
- 0xac, 0x6c, 0xb6, 0x37, 0x95, 0xb1, 0x4a, 0xb5,
- 0x0a, 0x4e, 0x60, 0x67, 0xd7, 0xe0, 0x04, 0x16,
- 0x03, 0x03, 0x00, 0x88, 0x0f, 0x00, 0x00, 0x84,
- 0x04, 0x01, 0x00, 0x80, 0x08, 0x83, 0x53, 0xf0,
- 0xf8, 0x14, 0xf5, 0xc2, 0xd1, 0x8b, 0xf0, 0xa5,
- 0xc1, 0xd8, 0x1a, 0x36, 0x4b, 0x75, 0x77, 0x02,
- 0x19, 0xd8, 0x11, 0x3f, 0x5a, 0x36, 0xfc, 0xe9,
- 0x2b, 0x4b, 0xf9, 0xfe, 0xda, 0x8a, 0x0f, 0x6e,
- 0x3d, 0xd3, 0x52, 0x87, 0xf7, 0x9c, 0x78, 0x39,
- 0xa8, 0xf1, 0xd7, 0xf7, 0x4e, 0x35, 0x33, 0xf9,
- 0xc5, 0x76, 0xa8, 0x12, 0xc4, 0x91, 0x33, 0x1d,
- 0x93, 0x8c, 0xbf, 0xb1, 0x83, 0x00, 0x90, 0xc5,
- 0x52, 0x3e, 0xe0, 0x0a, 0xe8, 0x92, 0x75, 0xdf,
- 0x54, 0x5f, 0x9f, 0x95, 0x76, 0x62, 0xb5, 0x85,
- 0x69, 0xa4, 0x86, 0x85, 0x6c, 0xf3, 0x6b, 0x2a,
- 0x72, 0x7b, 0x4d, 0x42, 0x33, 0x67, 0x4a, 0xce,
- 0xb5, 0xdb, 0x9b, 0xae, 0xc0, 0xb0, 0x10, 0xeb,
- 0x3b, 0xf4, 0xc2, 0x9a, 0x64, 0x47, 0x4c, 0x1e,
- 0xa5, 0x91, 0x7f, 0x6d, 0xd1, 0x03, 0xf5, 0x4a,
- 0x90, 0x69, 0x18, 0xb1, 0x14, 0x03, 0x03, 0x00,
- 0x01, 0x01, 0x16, 0x03, 0x03, 0x00, 0x24, 0x59,
- 0xfc, 0x7e, 0xae, 0xb3, 0xbf, 0xab, 0x4d, 0xdb,
- 0x4e, 0xab, 0xa9, 0x6d, 0x6b, 0x4c, 0x60, 0xb6,
- 0x16, 0xe0, 0xab, 0x7f, 0x52, 0x2d, 0xa1, 0xfc,
- 0xe1, 0x80, 0xd2, 0x8a, 0xa1, 0xe5, 0x8f, 0xa1,
- 0x70, 0x93, 0x23,
- },
- {
- 0x16, 0x03, 0x03, 0x02, 0x67, 0x04, 0x00, 0x02,
- 0x63, 0x00, 0x00, 0x00, 0x00, 0x02, 0x5d, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
- 0xea, 0x8b, 0xc5, 0xef, 0xba, 0x64, 0xb7, 0x23,
- 0x08, 0x86, 0x4f, 0x37, 0xe0, 0x8f, 0xbd, 0x75,
- 0x71, 0x2b, 0xcb, 0x20, 0x75, 0x11, 0x3b, 0xa2,
- 0x9e, 0x39, 0x3c, 0x03, 0xef, 0x6e, 0x41, 0xd7,
- 0xcf, 0x1a, 0x2c, 0xf2, 0xfe, 0xc2, 0xd3, 0x65,
- 0x59, 0x00, 0x9d, 0x03, 0xb4, 0xf2, 0x20, 0xe4,
- 0x33, 0x80, 0xcd, 0xf6, 0xe4, 0x59, 0x22, 0xf7,
- 0xfd, 0x88, 0x0e, 0xa4, 0x09, 0xc0, 0x0d, 0x10,
- 0x80, 0x10, 0x79, 0xee, 0x70, 0x96, 0xdb, 0x22,
- 0x8b, 0xb7, 0xac, 0xe0, 0x98, 0xad, 0xe9, 0xe3,
- 0xcb, 0xea, 0x9f, 0xe6, 0x83, 0x28, 0x7c, 0x7e,
- 0x4e, 0x9a, 0x8d, 0xd9, 0xf3, 0x86, 0xf4, 0x89,
- 0x8b, 0x79, 0x8f, 0xbb, 0xe9, 0x74, 0x02, 0x02,
- 0x14, 0x04, 0xea, 0xba, 0x16, 0x10, 0xa1, 0x85,
- 0xbe, 0x4e, 0x4e, 0x92, 0xc5, 0x83, 0xf6, 0x1e,
- 0x1f, 0xd4, 0x25, 0xc2, 0xc2, 0xb9, 0xce, 0x33,
- 0x63, 0x66, 0x79, 0x1f, 0x54, 0x35, 0xc1, 0xe8,
- 0x89, 0x34, 0x78, 0x94, 0x36, 0x14, 0xef, 0x01,
- 0x1f, 0xf1, 0xbd, 0x77, 0x2c, 0x4d, 0xac, 0x5c,
- 0x5c, 0x4a, 0xc6, 0xed, 0xd8, 0x0e, 0x72, 0x84,
- 0x83, 0xdc, 0x56, 0x84, 0xc8, 0xf3, 0x89, 0x56,
- 0xfd, 0x89, 0xc1, 0xc9, 0x9a, 0x29, 0x91, 0x7e,
- 0x19, 0xe9, 0x8b, 0x5b, 0x11, 0x15, 0x4e, 0x6c,
- 0xf4, 0x89, 0xe7, 0x6d, 0x68, 0x1e, 0xf9, 0x6c,
- 0x23, 0x72, 0x05, 0x68, 0x82, 0x60, 0x84, 0x1f,
- 0x83, 0x20, 0x09, 0x86, 0x10, 0x81, 0xec, 0xec,
- 0xdc, 0x25, 0x53, 0x20, 0xfa, 0xa9, 0x41, 0x64,
- 0xd6, 0x20, 0xf3, 0xf4, 0x52, 0xf2, 0x80, 0x62,
- 0x83, 0xc9, 0x23, 0x66, 0x44, 0x95, 0x5a, 0x99,
- 0x8a, 0xe1, 0x26, 0x63, 0xc1, 0x8b, 0x31, 0xf9,
- 0x21, 0x06, 0x77, 0x04, 0x27, 0xf2, 0x0c, 0x63,
- 0x83, 0x45, 0xa0, 0xa9, 0x7b, 0xcf, 0xdf, 0xd7,
- 0x56, 0x75, 0xbc, 0xdd, 0x95, 0x36, 0xb1, 0x75,
- 0x39, 0x05, 0x00, 0x3c, 0x8a, 0x79, 0xd6, 0xe9,
- 0xf0, 0x4b, 0xdc, 0x51, 0x6b, 0x01, 0x94, 0x16,
- 0x87, 0x12, 0x92, 0x6c, 0x07, 0xc1, 0xf5, 0x58,
- 0xb7, 0x2a, 0x81, 0xf5, 0xa0, 0x37, 0x8b, 0xa6,
- 0x22, 0xfe, 0x28, 0x0a, 0x7e, 0x68, 0xe2, 0xda,
- 0x6c, 0x53, 0xee, 0x0e, 0x8d, 0x2d, 0x8b, 0x0b,
- 0xda, 0xf8, 0x99, 0x3e, 0x0e, 0xed, 0x9f, 0xc1,
- 0x2b, 0xf6, 0xfe, 0xe9, 0x52, 0x38, 0x7b, 0x83,
- 0x9a, 0x50, 0xa6, 0xd7, 0x49, 0x83, 0x43, 0x7e,
- 0x82, 0xec, 0xc7, 0x09, 0x3d, 0x3d, 0xb1, 0xee,
- 0xe8, 0xc5, 0x6a, 0xc3, 0x3d, 0x4b, 0x4c, 0x6a,
- 0xbb, 0x0b, 0x2c, 0x24, 0x2e, 0xdb, 0x7d, 0x57,
- 0x87, 0xb4, 0x80, 0xa5, 0xae, 0xff, 0x54, 0xa8,
- 0xa5, 0x27, 0x69, 0x95, 0xc8, 0xe7, 0x79, 0xc7,
- 0x89, 0x2a, 0x73, 0x49, 0xcb, 0xf5, 0xc5, 0xbc,
- 0x4a, 0xe0, 0x73, 0xa9, 0xbc, 0x88, 0x64, 0x96,
- 0x98, 0xa5, 0x1e, 0xe3, 0x43, 0xc1, 0x7d, 0x78,
- 0xc7, 0x94, 0x72, 0xd4, 0x2c, 0x6e, 0x85, 0x39,
- 0x9a, 0xaf, 0xdb, 0xa1, 0xe9, 0xe2, 0xcb, 0x37,
- 0x04, 0xc6, 0x8c, 0x81, 0xd3, 0x2a, 0xb7, 0xbe,
- 0x6c, 0x07, 0x1f, 0x5e, 0xd9, 0x00, 0xd2, 0xf7,
- 0xe1, 0xa7, 0xbc, 0x0c, 0xb6, 0x6d, 0xfb, 0x3f,
- 0x3d, 0x24, 0xaa, 0xfb, 0x7e, 0xe1, 0xb5, 0x1b,
- 0xff, 0x38, 0xaa, 0x69, 0x59, 0x38, 0x52, 0x9a,
- 0x0e, 0x6d, 0xbc, 0xde, 0x4f, 0x13, 0x09, 0x17,
- 0xc4, 0xa9, 0x05, 0x84, 0xbc, 0x50, 0xef, 0x40,
- 0xb0, 0x4c, 0x24, 0x32, 0xed, 0x94, 0x2c, 0xdd,
- 0xda, 0x20, 0x24, 0x67, 0xe2, 0xea, 0x71, 0x3d,
- 0x4a, 0x04, 0x0d, 0x98, 0x29, 0x20, 0x4c, 0xeb,
- 0x70, 0xce, 0x45, 0x9e, 0x5a, 0xaf, 0xb6, 0xa3,
- 0x92, 0xc8, 0x28, 0xf2, 0xe3, 0xe8, 0x8a, 0x5d,
- 0x0a, 0x33, 0x79, 0x9b, 0x6a, 0xf3, 0x30, 0x01,
- 0x1d, 0x47, 0xbd, 0x01, 0xcc, 0x4d, 0x71, 0xc0,
- 0x56, 0xfa, 0xfd, 0x37, 0xed, 0x0f, 0x27, 0xc0,
- 0xbb, 0xa0, 0xee, 0xc3, 0x79, 0x8b, 0xe7, 0x41,
- 0x8f, 0xfa, 0x3a, 0xcb, 0x45, 0x3b, 0x85, 0x9f,
- 0x06, 0x90, 0xb2, 0x51, 0xc0, 0x48, 0x10, 0xac,
- 0x2a, 0xec, 0xec, 0x48, 0x7a, 0x19, 0x47, 0xc4,
- 0x2a, 0xeb, 0xb3, 0xa2, 0x07, 0x22, 0x32, 0x78,
- 0xf4, 0x73, 0x5e, 0x92, 0x42, 0x15, 0xa1, 0x90,
- 0x91, 0xd0, 0xeb, 0x12, 0x14, 0x03, 0x03, 0x00,
- 0x01, 0x01, 0x16, 0x03, 0x03, 0x00, 0x24, 0x45,
- 0x4b, 0x80, 0x42, 0x46, 0xde, 0xbb, 0xe7, 0x76,
- 0xd1, 0x33, 0x92, 0xfc, 0x46, 0x17, 0x6d, 0x21,
- 0xf6, 0x0e, 0x16, 0xca, 0x9b, 0x9b, 0x04, 0x65,
- 0x16, 0x40, 0x44, 0x64, 0xbc, 0x58, 0xfa, 0x2a,
- 0x49, 0xe9, 0xed, 0x17, 0x03, 0x03, 0x00, 0x21,
- 0x89, 0x71, 0xcd, 0x56, 0x54, 0xbf, 0x73, 0xde,
- 0xfb, 0x4b, 0x4e, 0xf1, 0x7f, 0xc6, 0x75, 0xa6,
- 0xbd, 0x6b, 0x6c, 0xd9, 0xdc, 0x0c, 0x71, 0xb4,
- 0xb9, 0xbb, 0x6e, 0xfa, 0x9e, 0xc7, 0xc7, 0x4c,
- 0x24, 0x15, 0x03, 0x03, 0x00, 0x16, 0x62, 0xea,
- 0x65, 0x69, 0x68, 0x4a, 0xce, 0xa7, 0x9e, 0xce,
- 0xc0, 0xf1, 0x5c, 0x96, 0xd9, 0x1f, 0x49, 0xac,
- 0x2d, 0x05, 0x89, 0x94,
- },
+func TestFallbackSCSV(t *testing.T) {
+ test := &serverTest{
+ name: "FallbackSCSV",
+ // OpenSSL 1.0.1j is needed for the -fallback_scsv option.
+ command: []string{"openssl", "s_client", "-fallback_scsv"},
+ expectHandshakeErrorIncluding: "inppropriate protocol fallback",
+ }
+ runServerTestTLS11(t, test)
}
// cert.pem and key.pem were generated with generate_cert.go
// Thus, they have no ExtKeyUsage fields and trigger an error
// when verification is turned on.
-var clientCertificate = loadPEMCert(`
+const clientCertificatePEM = `
-----BEGIN CERTIFICATE-----
MIIB7TCCAVigAwIBAgIBADALBgkqhkiG9w0BAQUwJjEQMA4GA1UEChMHQWNtZSBD
bzESMBAGA1UEAxMJMTI3LjAuMC4xMB4XDTExMTIwODA3NTUxMloXDTEyMTIwNzA4
@@ -3147,10 +742,9 @@ DwYDVR0jBAgwBoAEAQIDBDALBgkqhkiG9w0BAQUDgYEANh+zegx1yW43RmEr1b3A
p0vMRpqBWHyFeSnIyMZn3TJWRSt1tukkqVCavh9a+hoV2cxVlXIWg7nCto/9iIw4
hB2rXZIxE0/9gzvGnfERYraL7KtnvshksBFQRlgXa5kc0x38BvEO5ZaoDPl4ILdE
GFGNEH5PlGffo05wc46QkYU=
------END CERTIFICATE-----
-`)
+-----END CERTIFICATE-----`
-/* corresponding key.pem for cert.pem is:
+const clientKeyPEM = `
-----BEGIN RSA PRIVATE KEY-----
MIICWgIBAAKBgE7QezHjgmTZWcDCh6ReHotzM8djU99mkgaE9mTVj+Q2px0r6LMg
NkUjteOVru3g9SCcjZXff1oS74fkW2jk6Q507ASKf96TJ8QBGXq98tw9FKvQVMoh
@@ -3165,10 +759,9 @@ saG9sF+UEhRt9AxUfW/U/tIQ9V0ZHHcSg1XaCM5Nvp934brdKdvTOKnJAkBD5h/3
Rybatlvg/fzBEaJFyq09zhngkxlZOUtBVTqzl17RVvY2orgH02U4HbCHy4phxOn7
qTdQRYlHRftgnWK1AkANibn9PRYJ7mJyJ9Dyj2QeNcSkSTzrt0tPvUMf4+meJymN
1Ntu5+S1DLLzfxlaljWG6ylW6DNxujCyuXIV2rvA
------END RSA PRIVATE KEY-----
-*/
+-----END RSA PRIVATE KEY-----`
-var clientECDSACertificate = loadPEMCert(`
+const clientECDSACertificatePEM = `
-----BEGIN CERTIFICATE-----
MIIB/DCCAV4CCQCaMIRsJjXZFzAJBgcqhkjOPQQBMEUxCzAJBgNVBAYTAkFVMRMw
EQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0
@@ -3181,10 +774,9 @@ ixgnTy5w/hOWusPTQBbNZU6sER7m8TAJBgcqhkjOPQQBA4GMADCBiAJCAOAUxGBg
C3JosDJdYUoCdFzCgbkWqD8pyDbHgf9stlvZcPE4O1BIKJTLCRpS8V3ujfK58PDa
2RU6+b0DeoeiIzXsAkIBo9SKeDUcSpoj0gq+KxAxnZxfvuiRs9oa9V2jI/Umi0Vw
jWVim34BmT0Y9hCaOGGbLlfk+syxis7iI6CH8OFnUes=
------END CERTIFICATE-----
-`)
+-----END CERTIFICATE-----`
-/* corresponding key for cert is:
+const clientECDSAKeyPEM = `
-----BEGIN EC PARAMETERS-----
BgUrgQQAIw==
-----END EC PARAMETERS-----
@@ -3194,603 +786,83 @@ k+wLWoqizS3NpQyMtrU8JFdWfj+C57UNkOugBwYFK4EEACOhgYkDgYYABACVjJF1
FMBexFe01MNvja5oHt1vzobhfm6ySD6B5U7ixohLZNz1MLvT/2XMW/TdtWo+PtAd
3kfDdq0Z9kUsjLzYHQFMH3CQRnZIi4+DzEpcj0B22uCJ7B0rxE4wdihBsmKo+1vx
+U56jb0JuK7qixgnTy5w/hOWusPTQBbNZU6sER7m8Q==
------END EC PRIVATE KEY-----
-*/
-var clientauthECDSATests = []clientauthTest{
- // Server asks for cert with empty CA list, client gives one
- // go test -run "TestRunServer" -serve \
- // -clientauth 1 -ciphersuites=0xc00a
- // openssl s_client -host 127.0.0.1 -port 10443 \
- // -cipher ECDHE-ECDSA-AES256-SHA -key client.key -cert client.crt
- {"RequestClientCert, client gives it", RequestClientCert, []*x509.Certificate{clientECDSACertificate}, [][]byte{
- {
- 0x16, 0x03, 0x01, 0x00, 0xa0, 0x01, 0x00, 0x00,
- 0x9c, 0x03, 0x03, 0x51, 0xe5, 0x73, 0xc5, 0xae,
- 0x51, 0x94, 0xb4, 0xf2, 0xe8, 0xf6, 0x03, 0x0e,
- 0x3b, 0x34, 0xaf, 0xf0, 0xdc, 0x1b, 0xcc, 0xd8,
- 0x0c, 0x45, 0x82, 0xd4, 0xd6, 0x76, 0x04, 0x6e,
- 0x4f, 0x7a, 0x24, 0x00, 0x00, 0x04, 0xc0, 0x0a,
- 0x00, 0xff, 0x01, 0x00, 0x00, 0x6f, 0x00, 0x0b,
- 0x00, 0x04, 0x03, 0x00, 0x01, 0x02, 0x00, 0x0a,
- 0x00, 0x34, 0x00, 0x32, 0x00, 0x0e, 0x00, 0x0d,
- 0x00, 0x19, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x18,
- 0x00, 0x09, 0x00, 0x0a, 0x00, 0x16, 0x00, 0x17,
- 0x00, 0x08, 0x00, 0x06, 0x00, 0x07, 0x00, 0x14,
- 0x00, 0x15, 0x00, 0x04, 0x00, 0x05, 0x00, 0x12,
- 0x00, 0x13, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03,
- 0x00, 0x0f, 0x00, 0x10, 0x00, 0x11, 0x00, 0x23,
- 0x00, 0x00, 0x00, 0x0d, 0x00, 0x22, 0x00, 0x20,
- 0x06, 0x01, 0x06, 0x02, 0x06, 0x03, 0x05, 0x01,
- 0x05, 0x02, 0x05, 0x03, 0x04, 0x01, 0x04, 0x02,
- 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x03, 0x03,
- 0x02, 0x01, 0x02, 0x02, 0x02, 0x03, 0x01, 0x01,
- 0x00, 0x0f, 0x00, 0x01, 0x01,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x30, 0x02, 0x00, 0x00,
- 0x2c, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xc0, 0x0a, 0x00, 0x00,
- 0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x01,
- 0x02, 0x0e, 0x0b, 0x00, 0x02, 0x0a, 0x00, 0x02,
- 0x07, 0x00, 0x02, 0x04, 0x30, 0x82, 0x02, 0x00,
- 0x30, 0x82, 0x01, 0x62, 0x02, 0x09, 0x00, 0xb8,
- 0xbf, 0x2d, 0x47, 0xa0, 0xd2, 0xeb, 0xf4, 0x30,
- 0x09, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d,
- 0x04, 0x01, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
- 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
- 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
- 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
- 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
- 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
- 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
- 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
- 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
- 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x31,
- 0x31, 0x32, 0x32, 0x31, 0x35, 0x30, 0x36, 0x33,
- 0x32, 0x5a, 0x17, 0x0d, 0x32, 0x32, 0x31, 0x31,
- 0x32, 0x30, 0x31, 0x35, 0x30, 0x36, 0x33, 0x32,
- 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06,
- 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55,
- 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
- 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d,
- 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30,
- 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18,
- 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
- 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73,
- 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64,
- 0x30, 0x81, 0x9b, 0x30, 0x10, 0x06, 0x07, 0x2a,
- 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05,
- 0x2b, 0x81, 0x04, 0x00, 0x23, 0x03, 0x81, 0x86,
- 0x00, 0x04, 0x00, 0xc4, 0xa1, 0xed, 0xbe, 0x98,
- 0xf9, 0x0b, 0x48, 0x73, 0x36, 0x7e, 0xc3, 0x16,
- 0x56, 0x11, 0x22, 0xf2, 0x3d, 0x53, 0xc3, 0x3b,
- 0x4d, 0x21, 0x3d, 0xcd, 0x6b, 0x75, 0xe6, 0xf6,
- 0xb0, 0xdc, 0x9a, 0xdf, 0x26, 0xc1, 0xbc, 0xb2,
- 0x87, 0xf0, 0x72, 0x32, 0x7c, 0xb3, 0x64, 0x2f,
- 0x1c, 0x90, 0xbc, 0xea, 0x68, 0x23, 0x10, 0x7e,
- 0xfe, 0xe3, 0x25, 0xc0, 0x48, 0x3a, 0x69, 0xe0,
- 0x28, 0x6d, 0xd3, 0x37, 0x00, 0xef, 0x04, 0x62,
- 0xdd, 0x0d, 0xa0, 0x9c, 0x70, 0x62, 0x83, 0xd8,
- 0x81, 0xd3, 0x64, 0x31, 0xaa, 0x9e, 0x97, 0x31,
- 0xbd, 0x96, 0xb0, 0x68, 0xc0, 0x9b, 0x23, 0xde,
- 0x76, 0x64, 0x3f, 0x1a, 0x5c, 0x7f, 0xe9, 0x12,
- 0x0e, 0x58, 0x58, 0xb6, 0x5f, 0x70, 0xdd, 0x9b,
- 0xd8, 0xea, 0xd5, 0xd7, 0xf5, 0xd5, 0xcc, 0xb9,
- 0xb6, 0x9f, 0x30, 0x66, 0x5b, 0x66, 0x9a, 0x20,
- 0xe2, 0x27, 0xe5, 0xbf, 0xfe, 0x3b, 0x30, 0x09,
- 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04,
- 0x01, 0x03, 0x81, 0x8c, 0x00, 0x30, 0x81, 0x88,
- 0x02, 0x42, 0x01, 0x88, 0xa2, 0x4f, 0xeb, 0xe2,
- 0x45, 0xc5, 0x48, 0x7d, 0x1b, 0xac, 0xf5, 0xed,
- 0x98, 0x9d, 0xae, 0x47, 0x70, 0xc0, 0x5e, 0x1b,
- 0xb6, 0x2f, 0xbd, 0xf1, 0xb6, 0x4d, 0xb7, 0x61,
- 0x40, 0xd3, 0x11, 0xa2, 0xce, 0xee, 0x0b, 0x7e,
- 0x92, 0x7e, 0xff, 0x76, 0x9d, 0xc3, 0x3b, 0x7e,
- 0xa5, 0x3f, 0xce, 0xfa, 0x10, 0xe2, 0x59, 0xec,
- 0x47, 0x2d, 0x7c, 0xac, 0xda, 0x4e, 0x97, 0x0e,
- 0x15, 0xa0, 0x6f, 0xd0, 0x02, 0x42, 0x01, 0x4d,
- 0xfc, 0xbe, 0x67, 0x13, 0x9c, 0x2d, 0x05, 0x0e,
- 0xbd, 0x3f, 0xa3, 0x8c, 0x25, 0xc1, 0x33, 0x13,
- 0x83, 0x0d, 0x94, 0x06, 0xbb, 0xd4, 0x37, 0x7a,
- 0xf6, 0xec, 0x7a, 0xc9, 0x86, 0x2e, 0xdd, 0xd7,
- 0x11, 0x69, 0x7f, 0x85, 0x7c, 0x56, 0xde, 0xfb,
- 0x31, 0x78, 0x2b, 0xe4, 0xc7, 0x78, 0x0d, 0xae,
- 0xcb, 0xbe, 0x9e, 0x4e, 0x36, 0x24, 0x31, 0x7b,
- 0x6a, 0x0f, 0x39, 0x95, 0x12, 0x07, 0x8f, 0x2a,
- 0x16, 0x03, 0x01, 0x01, 0x1a, 0x0c, 0x00, 0x01,
- 0x16, 0x03, 0x00, 0x19, 0x85, 0x04, 0x01, 0x39,
- 0xdc, 0xee, 0x44, 0x17, 0x5e, 0xdb, 0xd7, 0x27,
- 0xaf, 0xb6, 0x56, 0xd9, 0xb4, 0x43, 0x5a, 0x99,
- 0xcf, 0xaa, 0x31, 0x37, 0x0c, 0x6f, 0x3a, 0xa0,
- 0xf8, 0x53, 0xc4, 0x74, 0xd1, 0x91, 0x0a, 0x46,
- 0xf5, 0x38, 0x3b, 0x5c, 0x09, 0xd8, 0x97, 0xdc,
- 0x4b, 0xaa, 0x70, 0x26, 0x48, 0xf2, 0xd6, 0x0b,
- 0x31, 0xc9, 0xf8, 0xd4, 0x98, 0x43, 0xe1, 0x6c,
- 0xd5, 0xc7, 0xb2, 0x8e, 0x0b, 0x01, 0xe6, 0xb6,
- 0x00, 0x28, 0x80, 0x7b, 0xfc, 0x96, 0x8f, 0x0d,
- 0xa2, 0x4f, 0xb0, 0x79, 0xaf, 0xdc, 0x61, 0x28,
- 0x63, 0x33, 0x78, 0xf6, 0x31, 0x39, 0xfd, 0x8a,
- 0xf4, 0x15, 0x18, 0x11, 0xfe, 0xdb, 0xd5, 0x07,
- 0xda, 0x2c, 0xed, 0x49, 0xa0, 0x23, 0xbf, 0xd0,
- 0x3a, 0x38, 0x1d, 0x54, 0xae, 0x1c, 0x7b, 0xea,
- 0x29, 0xee, 0xd0, 0x38, 0xc1, 0x76, 0xa7, 0x7f,
- 0x2a, 0xf4, 0xce, 0x1e, 0xac, 0xcc, 0x94, 0x79,
- 0x90, 0x33, 0x00, 0x8b, 0x30, 0x81, 0x88, 0x02,
- 0x42, 0x00, 0xc6, 0x85, 0x8e, 0x06, 0xb7, 0x04,
- 0x04, 0xe9, 0xcd, 0x9e, 0x3e, 0xcb, 0x66, 0x23,
- 0x95, 0xb4, 0x42, 0x9c, 0x64, 0x81, 0x39, 0x05,
- 0x3f, 0xb5, 0x21, 0xf8, 0x28, 0xaf, 0x60, 0x6b,
- 0x4d, 0x3d, 0xba, 0xa1, 0x4b, 0x5e, 0x77, 0xef,
- 0xe7, 0x59, 0x28, 0xfe, 0x1d, 0xc1, 0x27, 0xa2,
- 0xff, 0xa8, 0xde, 0x33, 0x48, 0xb3, 0xc1, 0x85,
- 0x6a, 0x42, 0x9b, 0xf9, 0x7e, 0x7e, 0x31, 0xc2,
- 0xe5, 0xbd, 0x66, 0x02, 0x42, 0x00, 0xad, 0x7d,
- 0x06, 0x35, 0xab, 0xec, 0x8d, 0xac, 0xd4, 0xba,
- 0x1b, 0x49, 0x5e, 0x05, 0x5f, 0xf0, 0x97, 0x93,
- 0x82, 0xb8, 0x2b, 0x8d, 0x91, 0x98, 0x63, 0x8e,
- 0xb4, 0x14, 0x62, 0xdb, 0x1e, 0xc9, 0x2b, 0x30,
- 0xf8, 0x41, 0x9b, 0xa6, 0xe6, 0xbc, 0xde, 0x0e,
- 0x68, 0x30, 0x21, 0xf4, 0xa8, 0xa9, 0x1b, 0xec,
- 0x44, 0x4f, 0x5d, 0x02, 0x2f, 0x60, 0x45, 0x60,
- 0xba, 0xe0, 0x4e, 0xc0, 0xd4, 0x3b, 0x01, 0x16,
- 0x03, 0x01, 0x00, 0x09, 0x0d, 0x00, 0x00, 0x05,
- 0x02, 0x01, 0x40, 0x00, 0x00, 0x16, 0x03, 0x01,
- 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x02, 0x0a, 0x0b, 0x00, 0x02,
- 0x06, 0x00, 0x02, 0x03, 0x00, 0x02, 0x00, 0x30,
- 0x82, 0x01, 0xfc, 0x30, 0x82, 0x01, 0x5e, 0x02,
- 0x09, 0x00, 0x9a, 0x30, 0x84, 0x6c, 0x26, 0x35,
- 0xd9, 0x17, 0x30, 0x09, 0x06, 0x07, 0x2a, 0x86,
- 0x48, 0xce, 0x3d, 0x04, 0x01, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d,
- 0x31, 0x32, 0x31, 0x31, 0x31, 0x34, 0x31, 0x33,
- 0x32, 0x35, 0x35, 0x33, 0x5a, 0x17, 0x0d, 0x32,
- 0x32, 0x31, 0x31, 0x31, 0x32, 0x31, 0x33, 0x32,
- 0x35, 0x35, 0x33, 0x5a, 0x30, 0x41, 0x31, 0x0b,
- 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
- 0x02, 0x41, 0x55, 0x31, 0x0c, 0x30, 0x0a, 0x06,
- 0x03, 0x55, 0x04, 0x08, 0x13, 0x03, 0x4e, 0x53,
- 0x57, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55,
- 0x04, 0x07, 0x13, 0x07, 0x50, 0x79, 0x72, 0x6d,
- 0x6f, 0x6e, 0x74, 0x31, 0x12, 0x30, 0x10, 0x06,
- 0x03, 0x55, 0x04, 0x03, 0x13, 0x09, 0x4a, 0x6f,
- 0x65, 0x6c, 0x20, 0x53, 0x69, 0x6e, 0x67, 0x30,
- 0x81, 0x9b, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86,
- 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b,
- 0x81, 0x04, 0x00, 0x23, 0x03, 0x81, 0x86, 0x00,
- 0x04, 0x00, 0x95, 0x8c, 0x91, 0x75, 0x14, 0xc0,
- 0x5e, 0xc4, 0x57, 0xb4, 0xd4, 0xc3, 0x6f, 0x8d,
- 0xae, 0x68, 0x1e, 0xdd, 0x6f, 0xce, 0x86, 0xe1,
- 0x7e, 0x6e, 0xb2, 0x48, 0x3e, 0x81, 0xe5, 0x4e,
- 0xe2, 0xc6, 0x88, 0x4b, 0x64, 0xdc, 0xf5, 0x30,
- 0xbb, 0xd3, 0xff, 0x65, 0xcc, 0x5b, 0xf4, 0xdd,
- 0xb5, 0x6a, 0x3e, 0x3e, 0xd0, 0x1d, 0xde, 0x47,
- 0xc3, 0x76, 0xad, 0x19, 0xf6, 0x45, 0x2c, 0x8c,
- 0xbc, 0xd8, 0x1d, 0x01, 0x4c, 0x1f, 0x70, 0x90,
- 0x46, 0x76, 0x48, 0x8b, 0x8f, 0x83, 0xcc, 0x4a,
- 0x5c, 0x8f, 0x40, 0x76, 0xda, 0xe0, 0x89, 0xec,
- 0x1d, 0x2b, 0xc4, 0x4e, 0x30, 0x76, 0x28, 0x41,
- 0xb2, 0x62, 0xa8, 0xfb, 0x5b, 0xf1, 0xf9, 0x4e,
- 0x7a, 0x8d, 0xbd, 0x09, 0xb8, 0xae, 0xea, 0x8b,
- 0x18, 0x27, 0x4f, 0x2e, 0x70, 0xfe, 0x13, 0x96,
- 0xba, 0xc3, 0xd3, 0x40, 0x16, 0xcd, 0x65, 0x4e,
- 0xac, 0x11, 0x1e, 0xe6, 0xf1, 0x30, 0x09, 0x06,
- 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01,
- 0x03, 0x81, 0x8c, 0x00, 0x30, 0x81, 0x88, 0x02,
- 0x42, 0x00, 0xe0, 0x14, 0xc4, 0x60, 0x60, 0x0b,
- 0x72, 0x68, 0xb0, 0x32, 0x5d, 0x61, 0x4a, 0x02,
- 0x74, 0x5c, 0xc2, 0x81, 0xb9, 0x16, 0xa8, 0x3f,
- 0x29, 0xc8, 0x36, 0xc7, 0x81, 0xff, 0x6c, 0xb6,
- 0x5b, 0xd9, 0x70, 0xf1, 0x38, 0x3b, 0x50, 0x48,
- 0x28, 0x94, 0xcb, 0x09, 0x1a, 0x52, 0xf1, 0x5d,
- 0xee, 0x8d, 0xf2, 0xb9, 0xf0, 0xf0, 0xda, 0xd9,
- 0x15, 0x3a, 0xf9, 0xbd, 0x03, 0x7a, 0x87, 0xa2,
- 0x23, 0x35, 0xec, 0x02, 0x42, 0x01, 0xa3, 0xd4,
- 0x8a, 0x78, 0x35, 0x1c, 0x4a, 0x9a, 0x23, 0xd2,
- 0x0a, 0xbe, 0x2b, 0x10, 0x31, 0x9d, 0x9c, 0x5f,
- 0xbe, 0xe8, 0x91, 0xb3, 0xda, 0x1a, 0xf5, 0x5d,
- 0xa3, 0x23, 0xf5, 0x26, 0x8b, 0x45, 0x70, 0x8d,
- 0x65, 0x62, 0x9b, 0x7e, 0x01, 0x99, 0x3d, 0x18,
- 0xf6, 0x10, 0x9a, 0x38, 0x61, 0x9b, 0x2e, 0x57,
- 0xe4, 0xfa, 0xcc, 0xb1, 0x8a, 0xce, 0xe2, 0x23,
- 0xa0, 0x87, 0xf0, 0xe1, 0x67, 0x51, 0xeb, 0x16,
- 0x03, 0x01, 0x00, 0x8a, 0x10, 0x00, 0x00, 0x86,
- 0x85, 0x04, 0x00, 0xcd, 0x1c, 0xe8, 0x66, 0x5b,
- 0xa8, 0x9d, 0x83, 0x2f, 0x7e, 0x1d, 0x0b, 0x59,
- 0x23, 0xbc, 0x30, 0xcf, 0xa3, 0xaf, 0x21, 0xdc,
- 0xf2, 0x57, 0x49, 0x56, 0x30, 0x25, 0x7c, 0x84,
- 0x5d, 0xad, 0xaa, 0x9c, 0x7b, 0x2a, 0x95, 0x58,
- 0x3d, 0x30, 0x87, 0x01, 0x3b, 0xb7, 0xea, 0xcb,
- 0xc4, 0xa3, 0xeb, 0x22, 0xbf, 0x2d, 0x61, 0x17,
- 0x8c, 0x9b, 0xe8, 0x1b, 0xb2, 0x87, 0x16, 0x78,
- 0xd5, 0xfd, 0x8b, 0xdd, 0x00, 0x0f, 0xda, 0x8e,
- 0xfd, 0x28, 0x36, 0xeb, 0xe4, 0xc5, 0x42, 0x14,
- 0xc7, 0xbd, 0x29, 0x5e, 0x9a, 0xed, 0x5e, 0xc1,
- 0xf7, 0xf4, 0xbd, 0xbd, 0x15, 0x9c, 0xe8, 0x44,
- 0x71, 0xa7, 0xb6, 0xe9, 0xfa, 0x7e, 0x97, 0xcb,
- 0x96, 0x3e, 0x53, 0x76, 0xfb, 0x11, 0x1f, 0x36,
- 0x8f, 0x30, 0xfb, 0x71, 0x3a, 0x75, 0x3a, 0x25,
- 0x7b, 0xa2, 0xc1, 0xf9, 0x3e, 0x58, 0x5f, 0x07,
- 0x16, 0xed, 0xe1, 0xf7, 0xc1, 0xb1, 0x16, 0x03,
- 0x01, 0x00, 0x90, 0x0f, 0x00, 0x00, 0x8c, 0x00,
- 0x8a, 0x30, 0x81, 0x87, 0x02, 0x42, 0x00, 0xb2,
- 0xd3, 0x91, 0xe6, 0xd5, 0x9b, 0xb2, 0xb8, 0x03,
- 0xf4, 0x85, 0x4d, 0x43, 0x79, 0x1f, 0xb6, 0x6f,
- 0x0c, 0xcd, 0x67, 0x5f, 0x5e, 0xca, 0xee, 0xb3,
- 0xe4, 0xab, 0x1e, 0x58, 0xc3, 0x04, 0xa9, 0x8a,
- 0xa7, 0xcf, 0xaa, 0x33, 0x88, 0xd5, 0x35, 0xd2,
- 0x80, 0x8f, 0xfa, 0x1b, 0x3c, 0x3d, 0xf7, 0x80,
- 0x50, 0xde, 0x80, 0x30, 0x64, 0xee, 0xc0, 0xb3,
- 0x91, 0x6e, 0x5d, 0x1e, 0xc0, 0xdc, 0x3a, 0x93,
- 0x02, 0x41, 0x4e, 0xca, 0x98, 0x41, 0x8c, 0x36,
- 0xf2, 0x12, 0xbf, 0x8e, 0x0f, 0x69, 0x8e, 0xf8,
- 0x7b, 0x9d, 0xba, 0x9c, 0x5c, 0x48, 0x79, 0xf4,
- 0xba, 0x3d, 0x06, 0xa5, 0xab, 0x47, 0xe0, 0x1a,
- 0x45, 0x28, 0x3a, 0x8f, 0xbf, 0x14, 0x24, 0x36,
- 0xd1, 0x1d, 0x29, 0xdc, 0xde, 0x72, 0x5b, 0x76,
- 0x41, 0x67, 0xe8, 0xe5, 0x71, 0x4a, 0x77, 0xe9,
- 0xed, 0x02, 0x19, 0xdd, 0xe4, 0xaa, 0xe9, 0x2d,
- 0xe7, 0x47, 0x32, 0x14, 0x03, 0x01, 0x00, 0x01,
- 0x01, 0x16, 0x03, 0x01, 0x00, 0x30, 0xfa, 0xc3,
- 0xf2, 0x35, 0xd0, 0x6d, 0x32, 0x78, 0x6a, 0xd6,
- 0xe6, 0x70, 0x5e, 0x00, 0x4c, 0x35, 0xf1, 0xe0,
- 0x21, 0xcf, 0xc3, 0x78, 0xcd, 0xe0, 0x2b, 0x0b,
- 0xf4, 0xeb, 0xf9, 0xc0, 0x38, 0xf2, 0x9a, 0x31,
- 0x55, 0x07, 0x2b, 0x8d, 0x68, 0x40, 0x31, 0x08,
- 0xaa, 0xe3, 0x16, 0xcf, 0x4b, 0xd4,
- },
- {
- 0x16, 0x03, 0x01, 0x02, 0x76, 0x04, 0x00, 0x02,
- 0x72, 0x00, 0x00, 0x00, 0x00, 0x02, 0x6c, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
- 0xe8, 0x8b, 0xde, 0xef, 0xba, 0xf9, 0xdb, 0x95,
- 0x24, 0xa5, 0x49, 0xb3, 0x23, 0xd8, 0x73, 0x88,
- 0x50, 0x42, 0xed, 0xeb, 0xa3, 0xd8, 0xab, 0x31,
- 0x9c, 0xd0, 0x00, 0x01, 0xef, 0xc0, 0xbf, 0xab,
- 0x59, 0x55, 0xb5, 0xb9, 0xef, 0xa5, 0xa6, 0xec,
- 0x69, 0xed, 0x00, 0x2f, 0x47, 0xdb, 0x75, 0x52,
- 0x0c, 0xe5, 0x86, 0xb7, 0x02, 0x59, 0x22, 0xf7,
- 0xfd, 0x8b, 0xff, 0xa4, 0x09, 0xc0, 0x1c, 0x10,
- 0x80, 0x10, 0x7f, 0x4c, 0x7a, 0x94, 0x40, 0x10,
- 0x0d, 0xda, 0x8a, 0xe5, 0x4a, 0xbc, 0xd0, 0xc0,
- 0x4b, 0xa5, 0x33, 0x97, 0xc6, 0xe7, 0x40, 0x7f,
- 0x7f, 0x8c, 0xf9, 0xf8, 0xc8, 0xb8, 0xfb, 0x8c,
- 0xdd, 0x28, 0x81, 0xae, 0xfd, 0x37, 0x20, 0x3a,
- 0x40, 0x37, 0x99, 0xc4, 0x21, 0x01, 0xc4, 0x91,
- 0xb0, 0x5e, 0x11, 0xc5, 0xa9, 0xfd, 0x9a, 0x02,
- 0x7e, 0x97, 0x6a, 0x86, 0x89, 0xb8, 0xc1, 0x32,
- 0x4c, 0x7e, 0x6d, 0x47, 0x61, 0x0e, 0xe3, 0xc2,
- 0xf0, 0x62, 0x3c, 0xc6, 0x71, 0x4f, 0xbb, 0x47,
- 0x65, 0xb1, 0xd9, 0x22, 0x79, 0x15, 0xea, 0x1f,
- 0x4b, 0x2a, 0x8a, 0xa4, 0xc8, 0x73, 0x34, 0xba,
- 0x83, 0xe4, 0x70, 0x99, 0xc9, 0xcf, 0xbe, 0x64,
- 0x99, 0xb9, 0xfa, 0xe9, 0xaf, 0x5d, 0xc7, 0x20,
- 0x26, 0xde, 0xc5, 0x06, 0x12, 0x36, 0x4f, 0x4d,
- 0xc0, 0xbb, 0x81, 0x5b, 0x5e, 0x38, 0xc3, 0x07,
- 0x21, 0x04, 0x1a, 0x53, 0x9c, 0x59, 0xac, 0x2d,
- 0xe6, 0xa5, 0x93, 0xa5, 0x19, 0xc6, 0xb0, 0xf7,
- 0x56, 0x5d, 0xdf, 0xd1, 0xf4, 0xfd, 0x44, 0x6d,
- 0xc6, 0xa2, 0x31, 0xa7, 0x35, 0x42, 0x18, 0x50,
- 0x0c, 0x4f, 0x6e, 0xe3, 0x3b, 0xa3, 0xaa, 0x1c,
- 0xbe, 0x41, 0x0d, 0xce, 0x6c, 0x62, 0xe1, 0x96,
- 0x2d, 0xbd, 0x14, 0x31, 0xe3, 0xc4, 0x5b, 0xbf,
- 0xf6, 0xde, 0xec, 0x42, 0xe8, 0xc7, 0x2a, 0x0b,
- 0xdb, 0x2d, 0x7c, 0xf0, 0x3f, 0x45, 0x32, 0x45,
- 0x09, 0x47, 0x09, 0x0f, 0x21, 0x22, 0x45, 0x06,
- 0x11, 0xb8, 0xf9, 0xe6, 0x67, 0x90, 0x4b, 0x4a,
- 0xde, 0x81, 0xfb, 0xeb, 0xe7, 0x9a, 0x08, 0x30,
- 0xcf, 0x51, 0xe1, 0xd9, 0xfa, 0x79, 0xa3, 0xcc,
- 0x65, 0x1a, 0x83, 0x86, 0xc9, 0x7a, 0x41, 0xf5,
- 0xdf, 0xa0, 0x7c, 0x44, 0x23, 0x17, 0xf3, 0x62,
- 0xe8, 0xa9, 0x31, 0x1e, 0x6b, 0x05, 0x4b, 0x4f,
- 0x9d, 0x91, 0x46, 0x92, 0xa6, 0x25, 0x32, 0xca,
- 0xa1, 0x75, 0xda, 0xe6, 0x80, 0x3e, 0x7f, 0xd1,
- 0x26, 0x57, 0x07, 0x42, 0xe4, 0x91, 0xff, 0xbd,
- 0x44, 0xae, 0x98, 0x5c, 0x1d, 0xdf, 0x11, 0xe3,
- 0xae, 0x87, 0x5e, 0xb7, 0x69, 0xad, 0x34, 0x7f,
- 0x3a, 0x07, 0x7c, 0xdf, 0xfc, 0x76, 0x17, 0x8b,
- 0x62, 0xc8, 0xe1, 0x78, 0x2a, 0xc8, 0xb9, 0x8a,
- 0xbb, 0x5c, 0xfb, 0x38, 0x74, 0x91, 0x6e, 0x12,
- 0x0c, 0x1f, 0x8e, 0xe1, 0xc2, 0x01, 0xd8, 0x9d,
- 0x23, 0x0f, 0xc4, 0x67, 0x5d, 0xe5, 0x67, 0x4b,
- 0x94, 0x6e, 0x69, 0x72, 0x90, 0x2d, 0x52, 0x78,
- 0x8e, 0x61, 0xba, 0xdf, 0x4e, 0xf5, 0xdc, 0xfb,
- 0x73, 0xbe, 0x03, 0x70, 0xd9, 0x01, 0x30, 0xf3,
- 0xa1, 0xbb, 0x9a, 0x5f, 0xec, 0x9e, 0xed, 0x8d,
- 0xdd, 0x53, 0xfd, 0x60, 0xc3, 0x2b, 0x7a, 0x00,
- 0x2c, 0xf9, 0x0a, 0x57, 0x47, 0x45, 0x43, 0xb3,
- 0x23, 0x01, 0x9c, 0xee, 0x54, 0x4d, 0x58, 0xd3,
- 0x71, 0x1c, 0xc9, 0xd3, 0x30, 0x9e, 0x14, 0xa5,
- 0xf3, 0xbf, 0x4d, 0x9b, 0xb7, 0x13, 0x21, 0xae,
- 0xd2, 0x8d, 0x6e, 0x6f, 0x1c, 0xcc, 0xb2, 0x41,
- 0xb2, 0x64, 0x56, 0x83, 0xce, 0xd1, 0x0c, 0x79,
- 0x32, 0x78, 0xef, 0xc5, 0x21, 0xb1, 0xe8, 0xc4,
- 0x42, 0xa7, 0x8d, 0xc1, 0xfa, 0xa1, 0x9c, 0x3c,
- 0x21, 0xd8, 0xe9, 0x90, 0xe2, 0x7c, 0x14, 0x26,
- 0xfe, 0x61, 0x3e, 0xf9, 0x71, 0x1d, 0x5d, 0x49,
- 0x3b, 0xb1, 0xb8, 0x42, 0xa1, 0xb8, 0x1c, 0x75,
- 0x7d, 0xee, 0xed, 0xfc, 0xe6, 0x20, 0x2b, 0x9e,
- 0x10, 0x52, 0xda, 0x56, 0x4d, 0x64, 0x6c, 0x41,
- 0xc1, 0xf7, 0x60, 0x0c, 0x10, 0x65, 0x6f, 0xd4,
- 0xe9, 0x9b, 0x0d, 0x83, 0x13, 0xc8, 0x5a, 0xa3,
- 0x56, 0x2a, 0x42, 0xc6, 0x1c, 0xfe, 0xdb, 0xba,
- 0x3d, 0x04, 0x12, 0xfd, 0x28, 0xeb, 0x78, 0xdd,
- 0xbc, 0xc8, 0x0d, 0xa1, 0xce, 0xd4, 0x54, 0xbf,
- 0xaf, 0xe1, 0x60, 0x0c, 0xa3, 0xc3, 0xc3, 0x62,
- 0x58, 0xc1, 0x79, 0xa7, 0x95, 0x41, 0x09, 0x24,
- 0xc6, 0x9a, 0x50, 0x14, 0x03, 0x01, 0x00, 0x01,
- 0x01, 0x16, 0x03, 0x01, 0x00, 0x30, 0x4d, 0x7b,
- 0x5f, 0x28, 0x5e, 0x68, 0x6c, 0xa3, 0x65, 0xc7,
- 0x7e, 0x49, 0x6c, 0xb3, 0x67, 0xbb, 0xd0, 0x75,
- 0xa2, 0x9e, 0x8c, 0x92, 0x4f, 0x8c, 0x33, 0x14,
- 0x7c, 0x6c, 0xf1, 0x74, 0x97, 0xc3, 0xe0, 0x10,
- 0xe9, 0x0d, 0xc2, 0x30, 0x5c, 0x23, 0xee, 0x1d,
- 0x16, 0x2e, 0xb9, 0x96, 0x2b, 0x2d, 0x17, 0x03,
- 0x01, 0x00, 0x20, 0xf2, 0xc8, 0xa7, 0x1b, 0x60,
- 0x46, 0xee, 0xe5, 0x7e, 0xc9, 0x35, 0xb3, 0xf1,
- 0x7c, 0x32, 0x0c, 0x85, 0x94, 0x59, 0x57, 0x27,
- 0xb0, 0xbd, 0x52, 0x86, 0x90, 0xf1, 0xb7, 0x4d,
- 0x1e, 0xc1, 0x16, 0x17, 0x03, 0x01, 0x00, 0x30,
- 0xff, 0x85, 0x50, 0xdf, 0x3f, 0xfc, 0xa2, 0x61,
- 0x1a, 0x12, 0xc0, 0x1e, 0x10, 0x32, 0x88, 0x50,
- 0xa0, 0x2c, 0x80, 0xda, 0x77, 0xea, 0x09, 0x47,
- 0xe0, 0x85, 0x07, 0x29, 0x45, 0x65, 0x19, 0xa3,
- 0x8d, 0x99, 0xb8, 0xbf, 0xb6, 0xbc, 0x76, 0xe2,
- 0x50, 0x24, 0x82, 0x0a, 0xfd, 0xdd, 0x35, 0x09,
- 0x15, 0x03, 0x01, 0x00, 0x20, 0xe7, 0x36, 0xf6,
- 0x61, 0xd2, 0x95, 0x3c, 0xb6, 0x65, 0x7b, 0xb2,
- 0xb8, 0xdf, 0x03, 0x53, 0xeb, 0xf7, 0x16, 0xe0,
- 0xe0, 0x15, 0x22, 0x71, 0x70, 0x62, 0x73, 0xad,
- 0xb5, 0x1a, 0x77, 0x44, 0x57,
- },
- }},
+-----END EC PRIVATE KEY-----`
+
+func TestClientAuth(t *testing.T) {
+ var certPath, keyPath, ecdsaCertPath, ecdsaKeyPath string
+
+ if *update {
+ certPath = tempFile(clientCertificatePEM)
+ defer os.Remove(certPath)
+ keyPath = tempFile(clientKeyPEM)
+ defer os.Remove(keyPath)
+ ecdsaCertPath = tempFile(clientECDSACertificatePEM)
+ defer os.Remove(ecdsaCertPath)
+ ecdsaKeyPath = tempFile(clientECDSAKeyPEM)
+ defer os.Remove(ecdsaKeyPath)
+ }
+
+ config := *testConfig
+ config.ClientAuth = RequestClientCert
+
+ test := &serverTest{
+ name: "ClientAuthRequestedNotGiven",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "RC4-SHA"},
+ config: &config,
+ }
+ runServerTestTLS12(t, test)
+
+ test = &serverTest{
+ name: "ClientAuthRequestedAndGiven",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "RC4-SHA", "-cert", certPath, "-key", keyPath},
+ config: &config,
+ expectedPeerCerts: []string{clientCertificatePEM},
+ }
+ runServerTestTLS12(t, test)
+
+ test = &serverTest{
+ name: "ClientAuthRequestedAndECDSAGiven",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "RC4-SHA", "-cert", ecdsaCertPath, "-key", ecdsaKeyPath},
+ config: &config,
+ expectedPeerCerts: []string{clientECDSACertificatePEM},
+ }
+ runServerTestTLS12(t, test)
}
-var aesGCMServerScript = [][]byte{
- {
- 0x16, 0x03, 0x01, 0x01, 0x1c, 0x01, 0x00, 0x01,
- 0x18, 0x03, 0x03, 0x52, 0x1e, 0x74, 0xf0, 0xb0,
- 0xc1, 0x8b, 0x16, 0xf9, 0x74, 0xfc, 0x16, 0xc4,
- 0x11, 0x18, 0x96, 0x08, 0x25, 0x38, 0x4f, 0x98,
- 0x98, 0xbe, 0xb5, 0x61, 0xdf, 0x94, 0x15, 0xcc,
- 0x9b, 0x61, 0xef, 0x00, 0x00, 0x80, 0xc0, 0x30,
- 0xc0, 0x2c, 0xc0, 0x28, 0xc0, 0x24, 0xc0, 0x14,
- 0xc0, 0x0a, 0x00, 0xa3, 0x00, 0x9f, 0x00, 0x6b,
- 0x00, 0x6a, 0x00, 0x39, 0x00, 0x38, 0xc0, 0x32,
- 0xc0, 0x2e, 0xc0, 0x2a, 0xc0, 0x26, 0xc0, 0x0f,
- 0xc0, 0x05, 0x00, 0x9d, 0x00, 0x3d, 0x00, 0x35,
- 0xc0, 0x12, 0xc0, 0x08, 0x00, 0x16, 0x00, 0x13,
- 0xc0, 0x0d, 0xc0, 0x03, 0x00, 0x0a, 0xc0, 0x2f,
- 0xc0, 0x2b, 0xc0, 0x27, 0xc0, 0x23, 0xc0, 0x13,
- 0xc0, 0x09, 0x00, 0xa2, 0x00, 0x9e, 0x00, 0x67,
- 0x00, 0x40, 0x00, 0x33, 0x00, 0x32, 0xc0, 0x31,
- 0xc0, 0x2d, 0xc0, 0x29, 0xc0, 0x25, 0xc0, 0x0e,
- 0xc0, 0x04, 0x00, 0x9c, 0x00, 0x3c, 0x00, 0x2f,
- 0xc0, 0x11, 0xc0, 0x07, 0xc0, 0x0c, 0xc0, 0x02,
- 0x00, 0x05, 0x00, 0x04, 0x00, 0x15, 0x00, 0x12,
- 0x00, 0x09, 0x00, 0x14, 0x00, 0x11, 0x00, 0x08,
- 0x00, 0x06, 0x00, 0x03, 0x00, 0xff, 0x01, 0x00,
- 0x00, 0x6f, 0x00, 0x0b, 0x00, 0x04, 0x03, 0x00,
- 0x01, 0x02, 0x00, 0x0a, 0x00, 0x34, 0x00, 0x32,
- 0x00, 0x0e, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x0b,
- 0x00, 0x0c, 0x00, 0x18, 0x00, 0x09, 0x00, 0x0a,
- 0x00, 0x16, 0x00, 0x17, 0x00, 0x08, 0x00, 0x06,
- 0x00, 0x07, 0x00, 0x14, 0x00, 0x15, 0x00, 0x04,
- 0x00, 0x05, 0x00, 0x12, 0x00, 0x13, 0x00, 0x01,
- 0x00, 0x02, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x10,
- 0x00, 0x11, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0d,
- 0x00, 0x22, 0x00, 0x20, 0x06, 0x01, 0x06, 0x02,
- 0x06, 0x03, 0x05, 0x01, 0x05, 0x02, 0x05, 0x03,
- 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x03, 0x01,
- 0x03, 0x02, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02,
- 0x02, 0x03, 0x01, 0x01, 0x00, 0x0f, 0x00, 0x01,
- 0x01,
- },
- {
- 0x16, 0x03, 0x03, 0x00, 0x30, 0x02, 0x00, 0x00,
- 0x2c, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xc0, 0x2f, 0x00, 0x00,
- 0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x03,
- 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, 0x00, 0x02,
- 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, 0x02, 0xb0,
- 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, 0x02, 0x01,
- 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4,
- 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30,
- 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
- 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
- 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d,
- 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
- 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
- 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
- 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
- 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
- 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30,
- 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39,
- 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30,
- 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, 0x33,
- 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
- 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
- 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
- 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
- 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
- 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
- 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
- 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
- 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
- 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
- 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0x79,
- 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, 0x46, 0x10,
- 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, 0x07, 0x43,
- 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, 0x43, 0x85,
- 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, 0x4c, 0x2c,
- 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, 0x82, 0xe5,
- 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, 0xa5, 0x2c,
- 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, 0x7a, 0x56,
- 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, 0x7b, 0x26,
- 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, 0xc9, 0x21,
- 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, 0x5a, 0xbf,
- 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, 0x99, 0x07,
- 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, 0x04, 0x39,
- 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, 0x7c, 0xe3,
- 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, 0xcf, 0xaf,
- 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, 0xdb, 0xdb,
- 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, 0x02, 0x03,
- 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
- 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
- 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, 0xe2, 0x85,
- 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23,
- 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39,
- 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
- 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, 0xad, 0xe2,
- 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce,
- 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88,
- 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0x85,
- 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30,
- 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
- 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00,
- 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, 0xb1, 0x59,
- 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, 0x14, 0xd7,
- 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, 0x5a, 0x95,
- 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, 0x12, 0x66,
- 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, 0x60, 0xd3,
- 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, 0x25, 0x13,
- 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, 0x1d, 0xba,
- 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, 0xd7, 0x31,
- 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, 0xea, 0x50,
- 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, 0x5a, 0x5f,
- 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, 0x90, 0x96,
- 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, 0x98, 0x1f,
- 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, 0xa3, 0x1b,
- 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, 0xe9, 0x70,
- 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, 0x26, 0x6e,
- 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, 0xbd, 0xd9,
- 0x16, 0x03, 0x03, 0x01, 0x11, 0x0c, 0x00, 0x01,
- 0x0d, 0x03, 0x00, 0x19, 0x85, 0x04, 0x01, 0x39,
- 0xdc, 0xee, 0x44, 0x17, 0x5e, 0xdb, 0xd7, 0x27,
- 0xaf, 0xb6, 0x56, 0xd9, 0xb4, 0x43, 0x5a, 0x99,
- 0xcf, 0xaa, 0x31, 0x37, 0x0c, 0x6f, 0x3a, 0xa0,
- 0xf8, 0x53, 0xc4, 0x74, 0xd1, 0x91, 0x0a, 0x46,
- 0xf5, 0x38, 0x3b, 0x5c, 0x09, 0xd8, 0x97, 0xdc,
- 0x4b, 0xaa, 0x70, 0x26, 0x48, 0xf2, 0xd6, 0x0b,
- 0x31, 0xc9, 0xf8, 0xd4, 0x98, 0x43, 0xe1, 0x6c,
- 0xd5, 0xc7, 0xb2, 0x8e, 0x0b, 0x01, 0xe6, 0xb6,
- 0x00, 0x28, 0x80, 0x7b, 0xfc, 0x96, 0x8f, 0x0d,
- 0xa2, 0x4f, 0xb0, 0x79, 0xaf, 0xdc, 0x61, 0x28,
- 0x63, 0x33, 0x78, 0xf6, 0x31, 0x39, 0xfd, 0x8a,
- 0xf4, 0x15, 0x18, 0x11, 0xfe, 0xdb, 0xd5, 0x07,
- 0xda, 0x2c, 0xed, 0x49, 0xa0, 0x23, 0xbf, 0xd0,
- 0x3a, 0x38, 0x1d, 0x54, 0xae, 0x1c, 0x7b, 0xea,
- 0x29, 0xee, 0xd0, 0x38, 0xc1, 0x76, 0xa7, 0x7f,
- 0x2a, 0xf4, 0xce, 0x1e, 0xac, 0xcc, 0x94, 0x79,
- 0x90, 0x33, 0x04, 0x01, 0x00, 0x80, 0x0d, 0x8e,
- 0x79, 0xe6, 0x86, 0xf6, 0xb6, 0xfb, 0x6b, 0x6a,
- 0xcc, 0x55, 0xe4, 0x80, 0x4d, 0xc5, 0x0c, 0xc6,
- 0xa3, 0x9f, 0x1d, 0x39, 0xd2, 0x98, 0x57, 0x31,
- 0xa2, 0x90, 0x73, 0xe8, 0xd2, 0xcd, 0xb0, 0x93,
- 0x1a, 0x60, 0x0f, 0x38, 0x02, 0x3b, 0x1b, 0x25,
- 0x56, 0xec, 0x44, 0xab, 0xbe, 0x2e, 0x0c, 0xc0,
- 0x6e, 0x54, 0x91, 0x50, 0xd6, 0xb1, 0xa2, 0x98,
- 0x14, 0xa8, 0x35, 0x62, 0x9d, 0xca, 0xfb, 0x0f,
- 0x64, 0x2b, 0x05, 0xa0, 0xa0, 0x57, 0xef, 0xcd,
- 0x95, 0x45, 0x13, 0x5a, 0x9b, 0x3d, 0xdb, 0x42,
- 0x54, 0x7f, 0xb9, 0x17, 0x08, 0x7f, 0xb2, 0xf0,
- 0xb1, 0xc3, 0xdf, 0x67, 0x95, 0xe2, 0x73, 0xf2,
- 0x76, 0xa3, 0x97, 0xfd, 0x9c, 0x92, 0x4a, 0xdb,
- 0x95, 0x1e, 0x91, 0x95, 0xae, 0x3d, 0xae, 0x58,
- 0xb5, 0x03, 0x6f, 0x5c, 0x3a, 0x19, 0xab, 0x92,
- 0xa5, 0x09, 0x6b, 0x40, 0x61, 0xb0, 0x16, 0x03,
- 0x03, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00,
+func bigFromString(s string) *big.Int {
+ ret := new(big.Int)
+ ret.SetString(s, 10)
+ return ret
+}
+
+func fromHex(s string) []byte {
+ b, _ := hex.DecodeString(s)
+ return b
+}
+
+var testRSACertificate = fromHex("308202b030820219a00302010202090085b0bba48a7fb8ca300d06092a864886f70d01010505003045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3130303432343039303933385a170d3131303432343039303933385a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819f300d06092a864886f70d010101050003818d0030818902818100bb79d6f517b5e5bf4610d0dc69bee62b07435ad0032d8a7a4385b71452e7a5654c2c78b8238cb5b482e5de1f953b7e62a52ca533d6fe125c7a56fcf506bffa587b263fb5cd04d3d0c921964ac7f4549f5abfef427100fe1899077f7e887d7df10439c4a22edb51c97ce3c04c3b326601cfafb11db8719a1ddbdb896baeda2d790203010001a381a73081a4301d0603551d0e04160414b1ade2855acfcb28db69ce2369ded3268e18883930750603551d23046e306c8014b1ade2855acfcb28db69ce2369ded3268e188839a149a4473045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746482090085b0bba48a7fb8ca300c0603551d13040530030101ff300d06092a864886f70d010105050003818100086c4524c76bb159ab0c52ccf2b014d7879d7a6475b55a9566e4c52b8eae12661feb4f38b36e60d392fdf74108b52513b1187a24fb301dbaed98b917ece7d73159db95d31d78ea50565cd5825a2d5a5f33c4b6d8c97590968c0f5298b5cd981f89205ff2a01ca31b9694dda9fd57e970e8266d71999b266e3850296c90a7bdd9")
+
+var testECDSACertificate = fromHex("3082020030820162020900b8bf2d47a0d2ebf4300906072a8648ce3d04013045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3132313132323135303633325a170d3232313132303135303633325a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819b301006072a8648ce3d020106052b81040023038186000400c4a1edbe98f90b4873367ec316561122f23d53c33b4d213dcd6b75e6f6b0dc9adf26c1bcb287f072327cb3642f1c90bcea6823107efee325c0483a69e0286dd33700ef0462dd0da09c706283d881d36431aa9e9731bd96b068c09b23de76643f1a5c7fe9120e5858b65f70dd9bd8ead5d7f5d5ccb9b69f30665b669a20e227e5bffe3b300906072a8648ce3d040103818c0030818802420188a24febe245c5487d1bacf5ed989dae4770c05e1bb62fbdf1b64db76140d311a2ceee0b7e927eff769dc33b7ea53fcefa10e259ec472d7cacda4e970e15a06fd00242014dfcbe67139c2d050ebd3fa38c25c13313830d9406bbd4377af6ec7ac9862eddd711697f857c56defb31782be4c7780daecbbe9e4e3624317b6a0f399512078f2a")
+
+var testSNICertificate = fromHex("308201f23082015da003020102020100300b06092a864886f70d01010530283110300e060355040a130741636d6520436f311430120603550403130b736e69746573742e636f6d301e170d3132303431313137343033355a170d3133303431313137343533355a30283110300e060355040a130741636d6520436f311430120603550403130b736e69746573742e636f6d30819d300b06092a864886f70d01010103818d0030818902818100bb79d6f517b5e5bf4610d0dc69bee62b07435ad0032d8a7a4385b71452e7a5654c2c78b8238cb5b482e5de1f953b7e62a52ca533d6fe125c7a56fcf506bffa587b263fb5cd04d3d0c921964ac7f4549f5abfef427100fe1899077f7e887d7df10439c4a22edb51c97ce3c04c3b326601cfafb11db8719a1ddbdb896baeda2d790203010001a3323030300e0603551d0f0101ff0404030200a0300d0603551d0e0406040401020304300f0603551d2304083006800401020304300b06092a864886f70d0101050381810089c6455f1c1f5ef8eb1ab174ee2439059f5c4259bb1a8d86cdb1d056f56a717da40e95ab90f59e8deaf627c157995094db0802266eb34fc6842dea8a4b68d9c1389103ab84fb9e1f85d9b5d23ff2312c8670fbb540148245a4ebafe264d90c8a4cf4f85b0fac12ac2fc4a3154bad52462868af96c62c6525d652b6e31845bdcc")
+
+var testRSAPrivateKey = &rsa.PrivateKey{
+ PublicKey: rsa.PublicKey{
+ N: bigFromString("131650079503776001033793877885499001334664249354723305978524647182322416328664556247316495448366990052837680518067798333412266673813370895702118944398081598789828837447552603077848001020611640547221687072142537202428102790818451901395596882588063427854225330436740647715202971973145151161964464812406232198521"),
+ E: 65537,
},
- {
- 0x16, 0x03, 0x03, 0x00, 0x8a, 0x10, 0x00, 0x00,
- 0x86, 0x85, 0x04, 0x01, 0xba, 0xb8, 0xad, 0x69,
- 0x20, 0x5e, 0xc1, 0x61, 0xc3, 0x0f, 0xb4, 0x30,
- 0x64, 0x66, 0x70, 0x96, 0x33, 0x3c, 0x8e, 0x12,
- 0x56, 0xbf, 0x6d, 0xb8, 0x6d, 0xc6, 0xba, 0xea,
- 0xfc, 0x38, 0xc0, 0x8b, 0x87, 0xa8, 0xf3, 0x87,
- 0xa1, 0xd5, 0xb6, 0xb0, 0x72, 0xc7, 0xd4, 0x19,
- 0x56, 0xa0, 0x91, 0xe1, 0x45, 0xc7, 0xf1, 0x7d,
- 0xb0, 0x1d, 0x78, 0x18, 0xf6, 0x3d, 0xbf, 0x1a,
- 0x23, 0x93, 0x0b, 0x19, 0xb1, 0x00, 0x56, 0xc9,
- 0x5e, 0x89, 0xd4, 0x9d, 0xd9, 0x5b, 0xe0, 0xb8,
- 0xff, 0x2f, 0x7d, 0x93, 0xae, 0x5b, 0xa5, 0x1f,
- 0x1f, 0x2b, 0x09, 0xe5, 0xf6, 0x07, 0x26, 0xa3,
- 0xed, 0xcb, 0x6a, 0x1a, 0xd6, 0x14, 0x83, 0x9b,
- 0xd3, 0x9d, 0x47, 0x1b, 0xf3, 0x72, 0x5f, 0x69,
- 0x21, 0x8f, 0xfa, 0x09, 0x38, 0x1a, 0x6b, 0x91,
- 0xcf, 0x19, 0x32, 0x54, 0x58, 0x8e, 0xee, 0xaf,
- 0xeb, 0x06, 0x9b, 0x3a, 0x34, 0x16, 0x66, 0x14,
- 0x03, 0x03, 0x00, 0x01, 0x01, 0x16, 0x03, 0x03,
- 0x00, 0x28, 0xc6, 0x96, 0x67, 0x62, 0xcc, 0x47,
- 0x01, 0xb5, 0xbd, 0xb7, 0x24, 0xd3, 0xb6, 0xfd,
- 0xb8, 0x46, 0xce, 0x82, 0x6d, 0x31, 0x1f, 0x15,
- 0x11, 0x8f, 0xed, 0x62, 0x71, 0x5f, 0xae, 0xb6,
- 0xa9, 0x0c, 0x24, 0x1d, 0xe8, 0x26, 0x51, 0xca,
- 0x7c, 0x42,
+ D: bigFromString("29354450337804273969007277378287027274721892607543397931919078829901848876371746653677097639302788129485893852488285045793268732234230875671682624082413996177431586734171663258657462237320300610850244186316880055243099640544518318093544057213190320837094958164973959123058337475052510833916491060913053867729"),
+ Primes: []*big.Int{
+ bigFromString("11969277782311800166562047708379380720136961987713178380670422671426759650127150688426177829077494755200794297055316163155755835813760102405344560929062149"),
+ bigFromString("10998999429884441391899182616418192492905073053684657075974935218461686523870125521822756579792315215543092255516093840728890783887287417039645833477273829"),
},
- {
- 0x16, 0x03, 0x03, 0x00, 0x72, 0x04, 0x00, 0x00,
- 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
- 0xea, 0x8b, 0xfb, 0xef, 0xba, 0xc8, 0x88, 0x94,
- 0x44, 0x99, 0x5f, 0x02, 0x68, 0x3a, 0x12, 0x67,
- 0x7f, 0xb9, 0x39, 0x71, 0x84, 0xe0, 0x30, 0xe6,
- 0x90, 0x6c, 0xcf, 0x32, 0x29, 0x29, 0x5c, 0x5a,
- 0x8b, 0x7d, 0xaa, 0x11, 0x28, 0x26, 0xb5, 0xce,
- 0xd2, 0x88, 0xd5, 0xb0, 0x5f, 0x94, 0x37, 0xa2,
- 0x48, 0xd9, 0x53, 0xb2, 0xab, 0x59, 0x23, 0x3d,
- 0x81, 0x6e, 0x64, 0x89, 0xca, 0x1a, 0x84, 0x16,
- 0xdf, 0x31, 0x10, 0xde, 0x52, 0x7f, 0x50, 0xf3,
- 0xd9, 0x27, 0xa0, 0xe8, 0x34, 0x15, 0x9e, 0x11,
- 0xdd, 0xba, 0xce, 0x40, 0x17, 0xf3, 0x67, 0x14,
- 0x03, 0x03, 0x00, 0x01, 0x01, 0x16, 0x03, 0x03,
- 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x35, 0xcb, 0x17, 0x66, 0xee, 0xfd,
- 0x27, 0xdb, 0xb8, 0xa8, 0x8a, 0xf1, 0x56, 0x67,
- 0x89, 0x0d, 0x13, 0xac, 0xe2, 0x31, 0xb9, 0xa2,
- 0x26, 0xbb, 0x1c, 0xcf, 0xd1, 0xb2, 0x48, 0x1d,
- 0x0d, 0xb1, 0x17, 0x03, 0x03, 0x00, 0x25, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0,
- 0x89, 0x7c, 0x58, 0x6a, 0x9b, 0x00, 0x05, 0x8c,
- 0x7f, 0x28, 0x54, 0x61, 0x44, 0x10, 0xee, 0x85,
- 0x26, 0xa8, 0x04, 0xcd, 0xca, 0x85, 0x60, 0xf2,
- 0xeb, 0x22, 0xbd, 0x9e, 0x15, 0x03, 0x03, 0x00,
- 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x02, 0x10, 0xe4, 0xe5, 0xf9, 0x85, 0xe3, 0xb0,
- 0xec, 0x84, 0x29, 0x91, 0x05, 0x7d, 0x86, 0xe3,
- 0x97, 0xeb, 0xb2,
+}
+
+var testECDSAPrivateKey = &ecdsa.PrivateKey{
+ PublicKey: ecdsa.PublicKey{
+ Curve: elliptic.P521(),
+ X: bigFromString("2636411247892461147287360222306590634450676461695221912739908880441342231985950069527906976759812296359387337367668045707086543273113073382714101597903639351"),
+ Y: bigFromString("3204695818431246682253994090650952614555094516658732116404513121125038617915183037601737180082382202488628239201196033284060130040574800684774115478859677243"),
},
+ D: bigFromString("5477294338614160138026852784385529180817726002953041720191098180813046231640184669647735805135001309477695746518160084669446643325196003346204701381388769751"),
}
diff --git a/libgo/go/crypto/tls/handshake_test.go b/libgo/go/crypto/tls/handshake_test.go
new file mode 100644
index 0000000000..f95f274ab4
--- /dev/null
+++ b/libgo/go/crypto/tls/handshake_test.go
@@ -0,0 +1,167 @@
+// 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 tls
+
+import (
+ "bufio"
+ "encoding/hex"
+ "errors"
+ "flag"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net"
+ "strconv"
+ "strings"
+ "sync"
+)
+
+// TLS reference tests run a connection against a reference implementation
+// (OpenSSL) of TLS and record the bytes of the resulting connection. The Go
+// code, during a test, is configured with deterministic randomness and so the
+// reference test can be reproduced exactly in the future.
+//
+// In order to save everyone who wishes to run the tests from needing the
+// reference implementation installed, the reference connections are saved in
+// files in the testdata directory. Thus running the tests involves nothing
+// external, but creating and updating them requires the reference
+// implementation.
+//
+// Tests can be updated by running them with the -update flag. This will cause
+// the test files. Generally one should combine the -update flag with -test.run
+// to updated a specific test. Since the reference implementation will always
+// generate fresh random numbers, large parts of the reference connection will
+// always change.
+
+var update = flag.Bool("update", false, "update golden files on disk")
+
+// recordingConn is a net.Conn that records the traffic that passes through it.
+// WriteTo can be used to produce output that can be later be loaded with
+// ParseTestData.
+type recordingConn struct {
+ net.Conn
+ sync.Mutex
+ flows [][]byte
+ reading bool
+}
+
+func (r *recordingConn) Read(b []byte) (n int, err error) {
+ if n, err = r.Conn.Read(b); n == 0 {
+ return
+ }
+ b = b[:n]
+
+ r.Lock()
+ defer r.Unlock()
+
+ if l := len(r.flows); l == 0 || !r.reading {
+ buf := make([]byte, len(b))
+ copy(buf, b)
+ r.flows = append(r.flows, buf)
+ } else {
+ r.flows[l-1] = append(r.flows[l-1], b[:n]...)
+ }
+ r.reading = true
+ return
+}
+
+func (r *recordingConn) Write(b []byte) (n int, err error) {
+ if n, err = r.Conn.Write(b); n == 0 {
+ return
+ }
+ b = b[:n]
+
+ r.Lock()
+ defer r.Unlock()
+
+ if l := len(r.flows); l == 0 || r.reading {
+ buf := make([]byte, len(b))
+ copy(buf, b)
+ r.flows = append(r.flows, buf)
+ } else {
+ r.flows[l-1] = append(r.flows[l-1], b[:n]...)
+ }
+ r.reading = false
+ return
+}
+
+// WriteTo writes Go source code to w that contains the recorded traffic.
+func (r *recordingConn) WriteTo(w io.Writer) {
+ // TLS always starts with a client to server flow.
+ clientToServer := true
+
+ for i, flow := range r.flows {
+ source, dest := "client", "server"
+ if !clientToServer {
+ source, dest = dest, source
+ }
+ fmt.Fprintf(w, ">>> Flow %d (%s to %s)\n", i+1, source, dest)
+ dumper := hex.Dumper(w)
+ dumper.Write(flow)
+ dumper.Close()
+ clientToServer = !clientToServer
+ }
+}
+
+func parseTestData(r io.Reader) (flows [][]byte, err error) {
+ var currentFlow []byte
+
+ scanner := bufio.NewScanner(r)
+ for scanner.Scan() {
+ line := scanner.Text()
+ // If the line starts with ">>> " then it marks the beginning
+ // of a new flow.
+ if strings.HasPrefix(line, ">>> ") {
+ if len(currentFlow) > 0 || len(flows) > 0 {
+ flows = append(flows, currentFlow)
+ currentFlow = nil
+ }
+ continue
+ }
+
+ // Otherwise the line is a line of hex dump that looks like:
+ // 00000170 fc f5 06 bf (...) |.....X{&?......!|
+ // (Some bytes have been omitted from the middle section.)
+
+ if i := strings.IndexByte(line, ' '); i >= 0 {
+ line = line[i:]
+ } else {
+ return nil, errors.New("invalid test data")
+ }
+
+ if i := strings.IndexByte(line, '|'); i >= 0 {
+ line = line[:i]
+ } else {
+ return nil, errors.New("invalid test data")
+ }
+
+ hexBytes := strings.Fields(line)
+ for _, hexByte := range hexBytes {
+ val, err := strconv.ParseUint(hexByte, 16, 8)
+ if err != nil {
+ return nil, errors.New("invalid hex byte in test data: " + err.Error())
+ }
+ currentFlow = append(currentFlow, byte(val))
+ }
+ }
+
+ if len(currentFlow) > 0 {
+ flows = append(flows, currentFlow)
+ }
+
+ return flows, nil
+}
+
+// tempFile creates a temp file containing contents and returns its path.
+func tempFile(contents string) string {
+ file, err := ioutil.TempFile("", "go-tls-test")
+ if err != nil {
+ panic("failed to create temp file: " + err.Error())
+ }
+ path := file.Name()
+ file.WriteString(contents)
+ file.Close()
+ return path
+}
diff --git a/libgo/go/crypto/tls/key_agreement.go b/libgo/go/crypto/tls/key_agreement.go
index 7e820c1e7e..0974fc6e0f 100644
--- a/libgo/go/crypto/tls/key_agreement.go
+++ b/libgo/go/crypto/tls/key_agreement.go
@@ -19,6 +19,9 @@ import (
"math/big"
)
+var errClientKeyExchange = errors.New("tls: invalid ClientKeyExchange message")
+var errServerKeyExchange = errors.New("tls: invalid ServerKeyExchange message")
+
// rsaKeyAgreement implements the standard TLS key agreement where the client
// encrypts the pre-master secret to the server's public key.
type rsaKeyAgreement struct{}
@@ -35,14 +38,14 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certifi
}
if len(ckx.ciphertext) < 2 {
- return nil, errors.New("bad ClientKeyExchange")
+ return nil, errClientKeyExchange
}
ciphertext := ckx.ciphertext
if version != VersionSSL30 {
ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1])
if ciphertextLen != len(ckx.ciphertext)-2 {
- return nil, errors.New("bad ClientKeyExchange")
+ return nil, errClientKeyExchange
}
ciphertext = ckx.ciphertext[2:]
}
@@ -61,7 +64,7 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certifi
}
func (ka rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
- return errors.New("unexpected ServerKeyExchange")
+ return errors.New("tls: unexpected ServerKeyExchange")
}
func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
@@ -138,7 +141,7 @@ 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
-// advertized list of supported signature and hash combinations.
+// advertised list of supported signature and hash combinations.
func pickTLS12HashForSignature(sigType uint8, clientSignatureAndHashes []signatureAndHash) (uint8, error) {
if len(clientSignatureAndHashes) == 0 {
// If the client didn't specify any signature_algorithms
@@ -160,6 +163,20 @@ func pickTLS12HashForSignature(sigType uint8, clientSignatureAndHashes []signatu
return 0, errors.New("tls: client doesn't support any common hash functions")
}
+func curveForCurveID(id CurveID) (elliptic.Curve, bool) {
+ switch id {
+ case CurveP256:
+ return elliptic.P256(), true
+ case CurveP384:
+ return elliptic.P384(), true
+ case CurveP521:
+ return elliptic.P521(), true
+ default:
+ return nil, false
+ }
+
+}
+
// ecdheRSAKeyAgreement implements a TLS key agreement where the server
// generates a ephemeral EC public/private key pair and signs it. The
// pre-master secret is then calculated using ECDH. The signature may
@@ -173,23 +190,16 @@ type ecdheKeyAgreement struct {
}
func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
- var curveid uint16
-
-Curve:
- for _, c := range clientHello.supportedCurves {
- switch c {
- case curveP256:
- ka.curve = elliptic.P256()
- curveid = c
- break Curve
- case curveP384:
- ka.curve = elliptic.P384()
- curveid = c
- break Curve
- case curveP521:
- ka.curve = elliptic.P521()
- curveid = c
- break Curve
+ var curveid CurveID
+ preferredCurves := config.curvePreferences()
+
+NextCandidate:
+ for _, candidate := range preferredCurves {
+ for _, c := range clientHello.supportedCurves {
+ if candidate == c {
+ curveid = c
+ break NextCandidate
+ }
}
}
@@ -197,6 +207,11 @@ Curve:
return nil, errors.New("tls: no supported elliptic curves offered")
}
+ var ok bool
+ if ka.curve, ok = curveForCurveID(curveid); !ok {
+ return nil, errors.New("tls: preferredCurves includes unsupported curve")
+ }
+
var x, y *big.Int
var err error
ka.privateKey, x, y, err = elliptic.GenerateKey(ka.curve, config.rand())
@@ -271,11 +286,14 @@ Curve:
func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 {
- return nil, errors.New("bad ClientKeyExchange")
+ return nil, errClientKeyExchange
}
x, y := elliptic.Unmarshal(ka.curve, ckx.ciphertext[1:])
if x == nil {
- return nil, errors.New("bad ClientKeyExchange")
+ return nil, errClientKeyExchange
+ }
+ if !ka.curve.IsOnCurve(x, y) {
+ return nil, errClientKeyExchange
}
x, _ = ka.curve.ScalarMult(x, y, ka.privateKey)
preMasterSecret := make([]byte, (ka.curve.Params().BitSize+7)>>3)
@@ -285,26 +303,18 @@ func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Cert
return preMasterSecret, nil
}
-var errServerKeyExchange = errors.New("invalid ServerKeyExchange")
-
func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
if len(skx.key) < 4 {
return errServerKeyExchange
}
if skx.key[0] != 3 { // named curve
- return errors.New("server selected unsupported curve")
+ return errors.New("tls: server selected unsupported curve")
}
- curveid := uint16(skx.key[1])<<8 | uint16(skx.key[2])
+ curveid := CurveID(skx.key[1])<<8 | CurveID(skx.key[2])
- switch curveid {
- case curveP256:
- ka.curve = elliptic.P256()
- case curveP384:
- ka.curve = elliptic.P384()
- case curveP521:
- ka.curve = elliptic.P521()
- default:
- return errors.New("server selected unsupported curve")
+ var ok bool
+ if ka.curve, ok = curveForCurveID(curveid); !ok {
+ return errors.New("tls: server selected unsupported curve")
}
publicLen := int(skx.key[3])
@@ -315,6 +325,9 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell
if ka.x == nil {
return errServerKeyExchange
}
+ if !ka.curve.IsOnCurve(ka.x, ka.y) {
+ return errServerKeyExchange
+ }
serverECDHParams := skx.key[:4+publicLen]
sig := skx.key[4+publicLen:]
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA
new file mode 100644
index 0000000000..00722cba94
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA
@@ -0,0 +1,129 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+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 |..........|
+>>> 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+.....|
+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....|
+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 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 |.......@......|
+>>> 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|
+00000020 d9 17 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 |..0...*.H.=..0E1|
+00000030 0b 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 |.0...U....AU1.0.|
+00000040 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 |..U....Some-Stat|
+00000050 65 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 |e1!0...U....Inte|
+00000060 72 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 |rnet Widgits Pty|
+00000070 20 4c 74 64 30 1e 17 0d 31 32 31 31 31 34 31 33 | Ltd0...12111413|
+00000080 32 35 35 33 5a 17 0d 32 32 31 31 31 32 31 33 32 |2553Z..221112132|
+00000090 35 35 33 5a 30 41 31 0b 30 09 06 03 55 04 06 13 |553Z0A1.0...U...|
+000000a0 02 41 55 31 0c 30 0a 06 03 55 04 08 13 03 4e 53 |.AU1.0...U....NS|
+000000b0 57 31 10 30 0e 06 03 55 04 07 13 07 50 79 72 6d |W1.0...U....Pyrm|
+000000c0 6f 6e 74 31 12 30 10 06 03 55 04 03 13 09 4a 6f |ont1.0...U....Jo|
+000000d0 65 6c 20 53 69 6e 67 30 81 9b 30 10 06 07 2a 86 |el Sing0..0...*.|
+000000e0 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 86 00 |H.=....+...#....|
+000000f0 04 00 95 8c 91 75 14 c0 5e c4 57 b4 d4 c3 6f 8d |.....u..^.W...o.|
+00000100 ae 68 1e dd 6f ce 86 e1 7e 6e b2 48 3e 81 e5 4e |.h..o...~n.H>..N|
+00000110 e2 c6 88 4b 64 dc f5 30 bb d3 ff 65 cc 5b f4 dd |...Kd..0...e.[..|
+00000120 b5 6a 3e 3e d0 1d de 47 c3 76 ad 19 f6 45 2c 8c |.j>>...G.v...E,.|
+00000130 bc d8 1d 01 4c 1f 70 90 46 76 48 8b 8f 83 cc 4a |....L.p.FvH....J|
+00000140 5c 8f 40 76 da e0 89 ec 1d 2b c4 4e 30 76 28 41 |\.@v.....+.N0v(A|
+00000150 b2 62 a8 fb 5b f1 f9 4e 7a 8d bd 09 b8 ae ea 8b |.b..[..Nz.......|
+00000160 18 27 4f 2e 70 fe 13 96 ba c3 d3 40 16 cd 65 4e |.'O.p......@..eN|
+00000170 ac 11 1e e6 f1 30 09 06 07 2a 86 48 ce 3d 04 01 |.....0...*.H.=..|
+00000180 03 81 8c 00 30 81 88 02 42 00 e0 14 c4 60 60 0b |....0...B....``.|
+00000190 72 68 b0 32 5d 61 4a 02 74 5c c2 81 b9 16 a8 3f |rh.2]aJ.t\.....?|
+000001a0 29 c8 36 c7 81 ff 6c b6 5b d9 70 f1 38 3b 50 48 |).6...l.[.p.8;PH|
+000001b0 28 94 cb 09 1a 52 f1 5d ee 8d f2 b9 f0 f0 da d9 |(....R.]........|
+000001c0 15 3a f9 bd 03 7a 87 a2 23 35 ec 02 42 01 a3 d4 |.:...z..#5..B...|
+000001d0 8a 78 35 1c 4a 9a 23 d2 0a be 2b 10 31 9d 9c 5f |.x5.J.#...+.1.._|
+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 01 00 46 10 00 00 42 41 04 1e 18 37 ef 0d 19 |...F...BA...7...|
+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....A<RB|
+000002e0 10 44 73 88 3e 44 24 bb 2e 77 01 77 6f a8 ac 14 |.Ds.>D$..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|
+>>> 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...|
+>>> 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....*......|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA
new file mode 100644
index 0000000000..c0be82491e
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA
@@ -0,0 +1,125 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+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 |..........|
+>>> 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.........|
+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..|
+00000080 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.|
+00000090 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+000000a0 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+000000b0 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+000000c0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+000000d0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090|
+000000e0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909|
+000000f0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....|
+00000100 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+00000110 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000120 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+00000130 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..|
+00000140 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+00000150 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F|
+00000160 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC|
+00000170 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....|
+00000180 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z|
+00000190 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......|
+000001a0 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....|
+000001b0 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.||
+000001c0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...|
+000001d0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0|
+000001e0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........|
+000001f0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...|
+00000200 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....|
+00000210 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..|
+00000220 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.|
+00000230 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
+00000240 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
+00000250 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
+00000260 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...|
+00000270 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...|
+00000280 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...|
+00000290 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.|
+000002a0 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z|
+000002b0 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`|
+000002c0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.|
+000002d0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.|
+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 01 00 0e 0d 00 |n8P)l...........|
+00000320 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|
+00000020 d9 17 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 |..0...*.H.=..0E1|
+00000030 0b 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 |.0...U....AU1.0.|
+00000040 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 |..U....Some-Stat|
+00000050 65 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 |e1!0...U....Inte|
+00000060 72 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 |rnet Widgits Pty|
+00000070 20 4c 74 64 30 1e 17 0d 31 32 31 31 31 34 31 33 | Ltd0...12111413|
+00000080 32 35 35 33 5a 17 0d 32 32 31 31 31 32 31 33 32 |2553Z..221112132|
+00000090 35 35 33 5a 30 41 31 0b 30 09 06 03 55 04 06 13 |553Z0A1.0...U...|
+000000a0 02 41 55 31 0c 30 0a 06 03 55 04 08 13 03 4e 53 |.AU1.0...U....NS|
+000000b0 57 31 10 30 0e 06 03 55 04 07 13 07 50 79 72 6d |W1.0...U....Pyrm|
+000000c0 6f 6e 74 31 12 30 10 06 03 55 04 03 13 09 4a 6f |ont1.0...U....Jo|
+000000d0 65 6c 20 53 69 6e 67 30 81 9b 30 10 06 07 2a 86 |el Sing0..0...*.|
+000000e0 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 86 00 |H.=....+...#....|
+000000f0 04 00 95 8c 91 75 14 c0 5e c4 57 b4 d4 c3 6f 8d |.....u..^.W...o.|
+00000100 ae 68 1e dd 6f ce 86 e1 7e 6e b2 48 3e 81 e5 4e |.h..o...~n.H>..N|
+00000110 e2 c6 88 4b 64 dc f5 30 bb d3 ff 65 cc 5b f4 dd |...Kd..0...e.[..|
+00000120 b5 6a 3e 3e d0 1d de 47 c3 76 ad 19 f6 45 2c 8c |.j>>...G.v...E,.|
+00000130 bc d8 1d 01 4c 1f 70 90 46 76 48 8b 8f 83 cc 4a |....L.p.FvH....J|
+00000140 5c 8f 40 76 da e0 89 ec 1d 2b c4 4e 30 76 28 41 |\.@v.....+.N0v(A|
+00000150 b2 62 a8 fb 5b f1 f9 4e 7a 8d bd 09 b8 ae ea 8b |.b..[..Nz.......|
+00000160 18 27 4f 2e 70 fe 13 96 ba c3 d3 40 16 cd 65 4e |.'O.p......@..eN|
+00000170 ac 11 1e e6 f1 30 09 06 07 2a 86 48 ce 3d 04 01 |.....0...*.H.=..|
+00000180 03 81 8c 00 30 81 88 02 42 00 e0 14 c4 60 60 0b |....0...B....``.|
+00000190 72 68 b0 32 5d 61 4a 02 74 5c c2 81 b9 16 a8 3f |rh.2]aJ.t\.....?|
+000001a0 29 c8 36 c7 81 ff 6c b6 5b d9 70 f1 38 3b 50 48 |).6...l.[.p.8;PH|
+000001b0 28 94 cb 09 1a 52 f1 5d ee 8d f2 b9 f0 f0 da d9 |(....R.]........|
+000001c0 15 3a f9 bd 03 7a 87 a2 23 35 ec 02 42 01 a3 d4 |.:...z..#5..B...|
+000001d0 8a 78 35 1c 4a 9a 23 d2 0a be 2b 10 31 9d 9c 5f |.x5.J.#...+.1.._|
+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 01 00 86 10 00 00 82 00 80 6d 51 f3 7f f9 3e |..........mQ...>|
+00000220 fb 75 82 41 36 83 e8 6a ee 2a 2e 25 90 67 4c 8e |.u.A6..j.*.%.gL.|
+00000230 62 2f 30 81 17 e0 85 09 0c 2b b7 23 d7 b0 e2 1d |b/0......+.#....|
+00000240 f7 3b d7 f5 a1 27 b6 ee 24 b6 1b cc 5b ea 66 0d |.;...'..$...[.f.|
+00000250 6a f4 e5 85 f9 da 43 b4 0e 86 85 e1 f5 aa be c8 |j.....C.........|
+00000260 ce 39 4c 9c 86 00 08 c2 4b e2 c6 ec 2f f7 ce e6 |.9L.....K.../...|
+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 01 00 90 0f |..C.0oUN.p......|
+000002a0 00 00 8c 00 8a 30 81 87 02 42 00 c6 85 8e 06 b7 |.....0...B......|
+000002b0 04 04 e9 cd 9e 3e cb 66 23 95 b4 42 9c 64 81 39 |.....>.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|.....|
+>>> 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.|
+>>> 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|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA
new file mode 100644
index 0000000000..3e6dbc271a
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA
@@ -0,0 +1,128 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+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 |..........|
+>>> 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....-......|
+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....|
+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 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 |........@......|
+>>> 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|
+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 01 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 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 |.|
+>>> 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|
+>>> 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.....|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA
new file mode 100644
index 0000000000..94e686004f
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA
@@ -0,0 +1,124 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+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 |..........|
+>>> 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......|
+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..|
+00000080 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.|
+00000090 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+000000a0 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+000000b0 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+000000c0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+000000d0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090|
+000000e0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909|
+000000f0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....|
+00000100 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+00000110 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000120 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+00000130 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..|
+00000140 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+00000150 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F|
+00000160 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC|
+00000170 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....|
+00000180 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z|
+00000190 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......|
+000001a0 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....|
+000001b0 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.||
+000001c0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...|
+000001d0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0|
+000001e0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........|
+000001f0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...|
+00000200 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....|
+00000210 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..|
+00000220 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.|
+00000230 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
+00000240 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
+00000250 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
+00000260 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...|
+00000270 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...|
+00000280 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...|
+00000290 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.|
+000002a0 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z|
+000002b0 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`|
+000002c0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.|
+000002d0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.|
+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 01 00 0e 0d 00 |n8P)l...........|
+00000320 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|
+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 01 00 86 10 00 00 82 00 80 6d 51 f3 7f f9 |...........mQ...|
+00000210 3e fb 75 82 41 36 83 e8 6a ee 2a 2e 25 90 67 4c |>.u.A6..j.*.%.gL|
+00000220 8e 62 2f 30 81 17 e0 85 09 0c 2b b7 23 d7 b0 e2 |.b/0......+.#...|
+00000230 1d f7 3b d7 f5 a1 27 b6 ee 24 b6 1b cc 5b ea 66 |..;...'..$...[.f|
+00000240 0d 6a f4 e5 85 f9 da 43 b4 0e 86 85 e1 f5 aa be |.j.....C........|
+00000250 c8 ce 39 4c 9c 86 00 08 c2 4b e2 c6 ec 2f f7 ce |..9L.....K.../..|
+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.$.|
+>>> 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..|
+>>> 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..[&.|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES b/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES
new file mode 100644
index 0000000000..30c4c6b831
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES
@@ -0,0 +1,87 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+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 |..........|
+>>> 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=.\..........|
+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....|
+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 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......|
+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..|
+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 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...+.|
+>>> 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..|
+>>> 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|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES b/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES
new file mode 100644
index 0000000000..868f0ceb0e
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES
@@ -0,0 +1,97 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+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 |..........|
+>>> 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 )>.......|
+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..............|
+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 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.........|
+>>> 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>|
+>>> 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......@./.|
+>>> 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..|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-RSA-RC4 b/libgo/go/crypto/tls/testdata/Client-TLSv10-RSA-RC4
new file mode 100644
index 0000000000..395d53bbab
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-RSA-RC4
@@ -0,0 +1,83 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+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 |..........|
+>>> 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.....|
+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..|
+00000080 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.|
+00000090 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+000000a0 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+000000b0 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+000000c0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+000000d0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090|
+000000e0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909|
+000000f0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....|
+00000100 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+00000110 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000120 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+00000130 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..|
+00000140 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+00000150 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F|
+00000160 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC|
+00000170 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....|
+00000180 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z|
+00000190 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......|
+000001a0 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....|
+000001b0 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.||
+000001c0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...|
+000001d0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0|
+000001e0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........|
+000001f0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...|
+00000200 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....|
+00000210 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..|
+00000220 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.|
+00000230 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
+00000240 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
+00000250 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
+00000260 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...|
+00000270 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...|
+00000280 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...|
+00000290 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.|
+000002a0 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z|
+000002b0 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`|
+000002c0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.|
+000002d0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.|
+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 01 00 04 0e 00 |n8P)l...........|
+00000320 00 00 |..|
+>>> Flow 3 (client to server)
+00000000 16 03 01 00 86 10 00 00 82 00 80 6d 51 f3 7f f9 |...........mQ...|
+00000010 3e fb 75 82 41 36 83 e8 6a ee 2a 2e 25 90 67 4c |>.u.A6..j.*.%.gL|
+00000020 8e 62 2f 30 81 17 e0 85 09 0c 2b b7 23 d7 b0 e2 |.b/0......+.#...|
+00000030 1d f7 3b d7 f5 a1 27 b6 ee 24 b6 1b cc 5b ea 66 |..;...'..$...[.f|
+00000040 0d 6a f4 e5 85 f9 da 43 b4 0e 86 85 e1 f5 aa be |.j.....C........|
+00000050 c8 ce 39 4c 9c 86 00 08 c2 4b e2 c6 ec 2f f7 ce |..9L.....K.../..|
+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.|
+>>> Flow 4 (server to client)
+00000000 14 03 01 00 01 01 16 03 01 00 24 ea 77 6f 3c 42 |..........$.wo<B|
+00000010 12 16 51 de e8 b6 f9 85 06 d9 6d 05 75 50 2b 27 |..Q.......m.uP+'|
+00000020 93 b7 6b 65 e9 14 99 48 53 3e be e4 be 03 5d |..ke...HS>....]|
+>>> 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.|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES b/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES
new file mode 100644
index 0000000000..9f941f8ef1
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES
@@ -0,0 +1,89 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+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 |..........|
+>>> 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....|
+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....|
+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 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 |...|
+>>> 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.|
+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 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..|
+>>> 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 |....:......|
+>>> 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.........|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES b/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES
new file mode 100644
index 0000000000..fc723396a4
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES
@@ -0,0 +1,99 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+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 |..........|
+>>> 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.... ..!.....|
+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..............|
+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 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 |..........|
+>>> 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.|
+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 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..|
+>>> 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|
+>>> 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.......|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv11-RSA-RC4 b/libgo/go/crypto/tls/testdata/Client-TLSv11-RSA-RC4
new file mode 100644
index 0000000000..f7be3f7e93
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv11-RSA-RC4
@@ -0,0 +1,83 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+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 |..........|
+>>> 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.........|
+00000050 05 ff 01 00 01 00 16 03 02 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..|
+00000080 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.|
+00000090 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+000000a0 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+000000b0 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+000000c0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+000000d0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090|
+000000e0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909|
+000000f0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....|
+00000100 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+00000110 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000120 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+00000130 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..|
+00000140 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+00000150 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F|
+00000160 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC|
+00000170 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....|
+00000180 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z|
+00000190 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......|
+000001a0 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....|
+000001b0 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.||
+000001c0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...|
+000001d0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0|
+000001e0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........|
+000001f0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...|
+00000200 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....|
+00000210 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..|
+00000220 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.|
+00000230 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
+00000240 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
+00000250 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
+00000260 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...|
+00000270 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...|
+00000280 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...|
+00000290 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.|
+000002a0 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z|
+000002b0 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`|
+000002c0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.|
+000002d0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.|
+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 02 00 04 0e 00 |n8P)l...........|
+00000320 00 00 |..|
+>>> Flow 3 (client to server)
+00000000 16 03 02 00 86 10 00 00 82 00 80 6d 51 f3 7f f9 |...........mQ...|
+00000010 3e fb 75 82 41 36 83 e8 6a ee 2a 2e 25 90 67 4c |>.u.A6..j.*.%.gL|
+00000020 8e 62 2f 30 81 17 e0 85 09 0c 2b b7 23 d7 b0 e2 |.b/0......+.#...|
+00000030 1d f7 3b d7 f5 a1 27 b6 ee 24 b6 1b cc 5b ea 66 |..;...'..$...[.f|
+00000040 0d 6a f4 e5 85 f9 da 43 b4 0e 86 85 e1 f5 aa be |.j.....C........|
+00000050 c8 ce 39 4c 9c 86 00 08 c2 4b e2 c6 ec 2f f7 ce |..9L.....K.../..|
+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 02 00 01 |5..C.0oUN.p.....|
+00000090 01 16 03 02 00 24 07 9f dc df 2d c3 a6 88 06 28 |.....$....-....(|
+000000a0 21 e0 e0 d3 31 99 fc 89 b8 82 6e 95 f4 4b 9e e2 |!...1.....n..K..|
+000000b0 d9 36 5c 14 ce d7 db e2 78 4e |.6\.....xN|
+>>> 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|
+>>> Flow 5 (client to server)
+00000000 17 03 02 00 1a b2 91 39 63 c0 38 3c 4d 25 fd 14 |.......9c.8<M%..|
+00000010 b9 b6 e1 23 21 b4 8d 17 9e 1f d8 33 92 69 c2 15 |...#!......3.i..|
+00000020 03 02 00 16 4b 10 25 4d 9d 09 c2 11 96 be f7 5b |....K.%M.......[|
+00000030 c2 9b 99 fd 1f 8e af 0f 2c 51 |........,Q|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ALPN b/libgo/go/crypto/tls/testdata/Client-TLSv12-ALPN
new file mode 100644
index 0000000000..f09a4f106c
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ALPN
@@ -0,0 +1,97 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 8d 01 00 00 89 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|
+>>> 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.../..|
+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.|
+00000080 02 19 a0 03 02 01 02 02 09 00 85 b0 bb a4 8a 7f |................|
+00000090 b8 ca 30 0d 06 09 2a 86 48 86 f7 0d 01 01 05 05 |..0...*.H.......|
+000000a0 00 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 55 |.0E1.0...U....AU|
+000000b0 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 2d |1.0...U....Some-|
+000000c0 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 18 |State1!0...U....|
+000000d0 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 73 |Internet Widgits|
+000000e0 20 50 74 79 20 4c 74 64 30 1e 17 0d 31 30 30 34 | Pty Ltd0...1004|
+000000f0 32 34 30 39 30 39 33 38 5a 17 0d 31 31 30 34 32 |24090938Z..11042|
+00000100 34 30 39 30 39 33 38 5a 30 45 31 0b 30 09 06 03 |4090938Z0E1.0...|
+00000110 55 04 06 13 02 41 55 31 13 30 11 06 03 55 04 08 |U....AU1.0...U..|
+00000120 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f |..Some-State1!0.|
+00000130 06 03 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 |..U....Internet |
+00000140 57 69 64 67 69 74 73 20 50 74 79 20 4c 74 64 30 |Widgits Pty Ltd0|
+00000150 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 |..0...*.H.......|
+00000160 00 03 81 8d 00 30 81 89 02 81 81 00 bb 79 d6 f5 |.....0.......y..|
+00000170 17 b5 e5 bf 46 10 d0 dc 69 be e6 2b 07 43 5a d0 |....F...i..+.CZ.|
+00000180 03 2d 8a 7a 43 85 b7 14 52 e7 a5 65 4c 2c 78 b8 |.-.zC...R..eL,x.|
+00000190 23 8c b5 b4 82 e5 de 1f 95 3b 7e 62 a5 2c a5 33 |#........;~b.,.3|
+000001a0 d6 fe 12 5c 7a 56 fc f5 06 bf fa 58 7b 26 3f b5 |...\zV.....X{&?.|
+000001b0 cd 04 d3 d0 c9 21 96 4a c7 f4 54 9f 5a bf ef 42 |.....!.J..T.Z..B|
+000001c0 71 00 fe 18 99 07 7f 7e 88 7d 7d f1 04 39 c4 a2 |q......~.}}..9..|
+000001d0 2e db 51 c9 7c e3 c0 4c 3b 32 66 01 cf af b1 1d |..Q.|..L;2f.....|
+000001e0 b8 71 9a 1d db db 89 6b ae da 2d 79 02 03 01 00 |.q.....k..-y....|
+000001f0 01 a3 81 a7 30 81 a4 30 1d 06 03 55 1d 0e 04 16 |....0..0...U....|
+00000200 04 14 b1 ad e2 85 5a cf cb 28 db 69 ce 23 69 de |......Z..(.i.#i.|
+00000210 d3 26 8e 18 88 39 30 75 06 03 55 1d 23 04 6e 30 |.&...90u..U.#.n0|
+00000220 6c 80 14 b1 ad e2 85 5a cf cb 28 db 69 ce 23 69 |l......Z..(.i.#i|
+00000230 de d3 26 8e 18 88 39 a1 49 a4 47 30 45 31 0b 30 |..&...9.I.G0E1.0|
+00000240 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...|
+00000250 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1|
+00000260 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern|
+00000270 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L|
+00000280 74 64 82 09 00 85 b0 bb a4 8a 7f b8 ca 30 0c 06 |td...........0..|
+00000290 03 55 1d 13 04 05 30 03 01 01 ff 30 0d 06 09 2a |.U....0....0...*|
+000002a0 86 48 86 f7 0d 01 01 05 05 00 03 81 81 00 08 6c |.H.............l|
+000002b0 45 24 c7 6b b1 59 ab 0c 52 cc f2 b0 14 d7 87 9d |E$.k.Y..R.......|
+000002c0 7a 64 75 b5 5a 95 66 e4 c5 2b 8e ae 12 66 1f eb |zdu.Z.f..+...f..|
+000002d0 4f 38 b3 6e 60 d3 92 fd f7 41 08 b5 25 13 b1 18 |O8.n`....A..%...|
+000002e0 7a 24 fb 30 1d ba ed 98 b9 17 ec e7 d7 31 59 db |z$.0.........1Y.|
+000002f0 95 d3 1d 78 ea 50 56 5c d5 82 5a 2d 5a 5f 33 c4 |...x.PV\..Z-Z_3.|
+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<w........p9|
+000003a0 c7 a3 1e 0f 7b 6c 78 2e c1 86 d2 67 36 d8 25 e0 |....{lx....g6.%.|
+000003b0 e8 e5 cc 35 a2 96 a1 b4 b7 06 68 1e aa c7 06 97 |...5......h.....|
+000003c0 b7 c2 83 ce c0 17 dd 4f 9e 6f 7a bd cd c7 6e 7f |.......O.oz...n.|
+000003d0 cb 80 d1 7d 06 2d f9 f1 fb 5f cc bb d8 62 5b f0 |...}.-..._...b[.|
+000003e0 27 12 57 d5 9b 55 aa 55 4b 9a 5a f6 a5 aa c1 82 |'.W..U.UK.Z.....|
+000003f0 39 11 6b dc 83 7f a8 47 28 5a 0f 3d 3f 0f c2 22 |9.k....G(Z.=?.."|
+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..|
+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 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.|
+>>> 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 |...|
+>>> 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.|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch b/libgo/go/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch
new file mode 100644
index 0000000000..f24a70cc82
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch
@@ -0,0 +1,95 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 86 01 00 00 82 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|
+>>> 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..../..|
+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 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 |..+.........|
+>>> 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|
+>>> 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|
+>>> 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 |..|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA
new file mode 100644
index 0000000000..2073270364
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA
@@ -0,0 +1,134 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+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 |..........|
+>>> 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.....|
+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 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...(...@. ....|
+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 |..|
+>>> 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|
+00000020 d9 17 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 |..0...*.H.=..0E1|
+00000030 0b 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 |.0...U....AU1.0.|
+00000040 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 |..U....Some-Stat|
+00000050 65 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 |e1!0...U....Inte|
+00000060 72 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 |rnet Widgits Pty|
+00000070 20 4c 74 64 30 1e 17 0d 31 32 31 31 31 34 31 33 | Ltd0...12111413|
+00000080 32 35 35 33 5a 17 0d 32 32 31 31 31 32 31 33 32 |2553Z..221112132|
+00000090 35 35 33 5a 30 41 31 0b 30 09 06 03 55 04 06 13 |553Z0A1.0...U...|
+000000a0 02 41 55 31 0c 30 0a 06 03 55 04 08 13 03 4e 53 |.AU1.0...U....NS|
+000000b0 57 31 10 30 0e 06 03 55 04 07 13 07 50 79 72 6d |W1.0...U....Pyrm|
+000000c0 6f 6e 74 31 12 30 10 06 03 55 04 03 13 09 4a 6f |ont1.0...U....Jo|
+000000d0 65 6c 20 53 69 6e 67 30 81 9b 30 10 06 07 2a 86 |el Sing0..0...*.|
+000000e0 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 86 00 |H.=....+...#....|
+000000f0 04 00 95 8c 91 75 14 c0 5e c4 57 b4 d4 c3 6f 8d |.....u..^.W...o.|
+00000100 ae 68 1e dd 6f ce 86 e1 7e 6e b2 48 3e 81 e5 4e |.h..o...~n.H>..N|
+00000110 e2 c6 88 4b 64 dc f5 30 bb d3 ff 65 cc 5b f4 dd |...Kd..0...e.[..|
+00000120 b5 6a 3e 3e d0 1d de 47 c3 76 ad 19 f6 45 2c 8c |.j>>...G.v...E,.|
+00000130 bc d8 1d 01 4c 1f 70 90 46 76 48 8b 8f 83 cc 4a |....L.p.FvH....J|
+00000140 5c 8f 40 76 da e0 89 ec 1d 2b c4 4e 30 76 28 41 |\.@v.....+.N0v(A|
+00000150 b2 62 a8 fb 5b f1 f9 4e 7a 8d bd 09 b8 ae ea 8b |.b..[..Nz.......|
+00000160 18 27 4f 2e 70 fe 13 96 ba c3 d3 40 16 cd 65 4e |.'O.p......@..eN|
+00000170 ac 11 1e e6 f1 30 09 06 07 2a 86 48 ce 3d 04 01 |.....0...*.H.=..|
+00000180 03 81 8c 00 30 81 88 02 42 00 e0 14 c4 60 60 0b |....0...B....``.|
+00000190 72 68 b0 32 5d 61 4a 02 74 5c c2 81 b9 16 a8 3f |rh.2]aJ.t\.....?|
+000001a0 29 c8 36 c7 81 ff 6c b6 5b d9 70 f1 38 3b 50 48 |).6...l.[.p.8;PH|
+000001b0 28 94 cb 09 1a 52 f1 5d ee 8d f2 b9 f0 f0 da d9 |(....R.]........|
+000001c0 15 3a f9 bd 03 7a 87 a2 23 35 ec 02 42 01 a3 d4 |.:...z..#5..B...|
+000001d0 8a 78 35 1c 4a 9a 23 d2 0a be 2b 10 31 9d 9c 5f |.x5.J.#...+.1.._|
+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 46 10 00 00 42 41 04 1e 18 37 ef 0d 19 |...F...BA...7...|
+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 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.`|
+>>> 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|
+>>> 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|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA
new file mode 100644
index 0000000000..c3b753a7b4
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA
@@ -0,0 +1,127 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+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 |..........|
+>>> 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 |.....+&.._-.....|
+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..|
+00000080 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.|
+00000090 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+000000a0 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+000000b0 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+000000c0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+000000d0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090|
+000000e0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909|
+000000f0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....|
+00000100 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+00000110 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000120 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+00000130 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..|
+00000140 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+00000150 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F|
+00000160 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC|
+00000170 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....|
+00000180 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z|
+00000190 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......|
+000001a0 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....|
+000001b0 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.||
+000001c0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...|
+000001d0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0|
+000001e0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........|
+000001f0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...|
+00000200 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....|
+00000210 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..|
+00000220 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.|
+00000230 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
+00000240 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
+00000250 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
+00000260 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...|
+00000270 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...|
+00000280 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...|
+00000290 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.|
+000002a0 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z|
+000002b0 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`|
+000002c0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.|
+000002d0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.|
+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 |.(...@. ........|
+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 |..............|
+>>> 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|
+00000020 d9 17 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 |..0...*.H.=..0E1|
+00000030 0b 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 |.0...U....AU1.0.|
+00000040 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 |..U....Some-Stat|
+00000050 65 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 |e1!0...U....Inte|
+00000060 72 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 |rnet Widgits Pty|
+00000070 20 4c 74 64 30 1e 17 0d 31 32 31 31 31 34 31 33 | Ltd0...12111413|
+00000080 32 35 35 33 5a 17 0d 32 32 31 31 31 32 31 33 32 |2553Z..221112132|
+00000090 35 35 33 5a 30 41 31 0b 30 09 06 03 55 04 06 13 |553Z0A1.0...U...|
+000000a0 02 41 55 31 0c 30 0a 06 03 55 04 08 13 03 4e 53 |.AU1.0...U....NS|
+000000b0 57 31 10 30 0e 06 03 55 04 07 13 07 50 79 72 6d |W1.0...U....Pyrm|
+000000c0 6f 6e 74 31 12 30 10 06 03 55 04 03 13 09 4a 6f |ont1.0...U....Jo|
+000000d0 65 6c 20 53 69 6e 67 30 81 9b 30 10 06 07 2a 86 |el Sing0..0...*.|
+000000e0 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 86 00 |H.=....+...#....|
+000000f0 04 00 95 8c 91 75 14 c0 5e c4 57 b4 d4 c3 6f 8d |.....u..^.W...o.|
+00000100 ae 68 1e dd 6f ce 86 e1 7e 6e b2 48 3e 81 e5 4e |.h..o...~n.H>..N|
+00000110 e2 c6 88 4b 64 dc f5 30 bb d3 ff 65 cc 5b f4 dd |...Kd..0...e.[..|
+00000120 b5 6a 3e 3e d0 1d de 47 c3 76 ad 19 f6 45 2c 8c |.j>>...G.v...E,.|
+00000130 bc d8 1d 01 4c 1f 70 90 46 76 48 8b 8f 83 cc 4a |....L.p.FvH....J|
+00000140 5c 8f 40 76 da e0 89 ec 1d 2b c4 4e 30 76 28 41 |\.@v.....+.N0v(A|
+00000150 b2 62 a8 fb 5b f1 f9 4e 7a 8d bd 09 b8 ae ea 8b |.b..[..Nz.......|
+00000160 18 27 4f 2e 70 fe 13 96 ba c3 d3 40 16 cd 65 4e |.'O.p......@..eN|
+00000170 ac 11 1e e6 f1 30 09 06 07 2a 86 48 ce 3d 04 01 |.....0...*.H.=..|
+00000180 03 81 8c 00 30 81 88 02 42 00 e0 14 c4 60 60 0b |....0...B....``.|
+00000190 72 68 b0 32 5d 61 4a 02 74 5c c2 81 b9 16 a8 3f |rh.2]aJ.t\.....?|
+000001a0 29 c8 36 c7 81 ff 6c b6 5b d9 70 f1 38 3b 50 48 |).6...l.[.p.8;PH|
+000001b0 28 94 cb 09 1a 52 f1 5d ee 8d f2 b9 f0 f0 da d9 |(....R.]........|
+000001c0 15 3a f9 bd 03 7a 87 a2 23 35 ec 02 42 01 a3 d4 |.:...z..#5..B...|
+000001d0 8a 78 35 1c 4a 9a 23 d2 0a be 2b 10 31 9d 9c 5f |.x5.J.#...+.1.._|
+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 6d 51 f3 7f f9 3e |..........mQ...>|
+00000220 fb 75 82 41 36 83 e8 6a ee 2a 2e 25 90 67 4c 8e |.u.A6..j.*.%.gL.|
+00000230 62 2f 30 81 17 e0 85 09 0c 2b b7 23 d7 b0 e2 1d |b/0......+.#....|
+00000240 f7 3b d7 f5 a1 27 b6 ee 24 b6 1b cc 5b ea 66 0d |.;...'..$...[.f.|
+00000250 6a f4 e5 85 f9 da 43 b4 0e 86 85 e1 f5 aa be c8 |j.....C.........|
+00000260 ce 39 4c 9c 86 00 08 c2 4b e2 c6 ec 2f f7 ce e6 |.9L.....K.../...|
+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!.......|
+>>> 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>.....+...|
+>>> 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%.|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA
new file mode 100644
index 0000000000..0037af61a0
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA
@@ -0,0 +1,133 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+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 |..........|
+>>> 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 |..!/@...........|
+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 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 |...|
+>>> 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 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 |.<Fa.x{..2..l.kv|
+00000280 67 a7 9e c8 7a 4c e8 79 0d 22 27 ad e7 98 6a 98 |g...zL.y."'...j.|
+00000290 89 88 8b a9 69 5b 6f c6 00 48 9a 21 77 a9 7c 15 |....i[o..H.!w.|.|
+000002a0 ba 47 16 74 8d 6c 67 dc 6d f1 98 b6 61 e8 bc 08 |.G.t.lg.m...a...|
+000002b0 18 53 a6 93 bf fc 27 5e b7 4d d2 eb 68 e9 23 ee |.S....'^.M..h.#.|
+000002c0 d2 70 d2 55 2c c7 99 7d c0 66 b5 1c ea 38 71 5c |.p.U,..}.f...8q\|
+000002d0 a6 57 1f 52 e4 8e e8 51 14 03 03 00 01 01 16 03 |.W.R...Q........|
+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 | `.|
+>>> 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......|
+>>> 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..|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA
new file mode 100644
index 0000000000..df3eaa4406
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA
@@ -0,0 +1,126 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+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 |..........|
+>>> 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.....|
+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..|
+00000080 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.|
+00000090 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+000000a0 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+000000b0 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+000000c0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+000000d0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090|
+000000e0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909|
+000000f0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....|
+00000100 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+00000110 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000120 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+00000130 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..|
+00000140 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+00000150 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F|
+00000160 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC|
+00000170 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....|
+00000180 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z|
+00000190 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......|
+000001a0 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....|
+000001b0 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.||
+000001c0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...|
+000001d0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0|
+000001e0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........|
+000001f0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...|
+00000200 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....|
+00000210 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..|
+00000220 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.|
+00000230 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
+00000240 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
+00000250 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
+00000260 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...|
+00000270 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...|
+00000280 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...|
+00000290 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.|
+000002a0 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z|
+000002b0 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`|
+000002c0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.|
+000002d0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.|
+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 |.(...@. ........|
+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 |..............|
+>>> 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 86 10 00 00 82 00 80 6d 51 f3 7f f9 |...........mQ...|
+00000210 3e fb 75 82 41 36 83 e8 6a ee 2a 2e 25 90 67 4c |>.u.A6..j.*.%.gL|
+00000220 8e 62 2f 30 81 17 e0 85 09 0c 2b b7 23 d7 b0 e2 |.b/0......+.#...|
+00000230 1d f7 3b d7 f5 a1 27 b6 ee 24 b6 1b cc 5b ea 66 |..;...'..$...[.f|
+00000240 0d 6a f4 e5 85 f9 da 43 b4 0e 86 85 e1 f5 aa be |.j.....C........|
+00000250 c8 ce 39 4c 9c 86 00 08 c2 4b e2 c6 ec 2f f7 ce |..9L.....K.../..|
+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.|
+>>> 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|
+>>> 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.).......|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES
new file mode 100644
index 0000000000..76445903ba
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES
@@ -0,0 +1,89 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+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 |..........|
+>>> 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.. ....|
+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 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 |......|
+>>> 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 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|
+>>> 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 |.......^)..|
+>>> 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 |^^........|
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
new file mode 100644
index 0000000000..fb5af17f0c
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM
@@ -0,0 +1,84 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+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 |..........|
+>>> 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{..-..+..|
+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 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..<d.i.|
+000002d0 4d b2 9b 55 12 60 33 94 cf f3 83 40 2b 7b 1b af |M..U.`3....@+{..|
+000002e0 5c f4 cd 02 66 fb 83 04 35 fd ab 74 98 1a 7d f6 |\...f...5..t..}.|
+000002f0 9e 50 98 c3 98 e8 56 9c f2 2a b0 30 9d 05 14 58 |.P....V..*.0...X|
+00000300 68 6a 88 04 49 07 78 bf 3a 02 42 01 be b2 05 9e |hj..I.x.:.B.....|
+00000310 67 da 1e e9 5a 36 98 52 21 9f 43 75 43 ba bb 9a |g...Z6.R!.CuC...|
+00000320 e6 e2 65 f4 e0 44 45 08 5a 1e 54 06 dd 5f 60 2e |..e..DE.Z.T.._`.|
+00000330 7d e7 55 08 d3 7b 4e 0a c7 da d4 27 34 d4 bd b0 |}.U..{N....'4...|
+00000340 12 2f 41 7a ed 71 32 ef ee 12 74 66 00 16 03 03 |./Az.q2...tf....|
+00000350 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 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#...|
+>>> 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.|
+>>> 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 |..|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES
new file mode 100644
index 0000000000..5336bbbad8
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES
@@ -0,0 +1,99 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+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 |..........|
+>>> 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........|
+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 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 |;...........|
+>>> 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 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..|
+>>> 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|
+>>> 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).,..|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-RSA-RC4 b/libgo/go/crypto/tls/testdata/Client-TLSv12-RSA-RC4
new file mode 100644
index 0000000000..0377f052ae
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-RSA-RC4
@@ -0,0 +1,83 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+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 |..........|
+>>> 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...........|
+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..|
+00000080 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.|
+00000090 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+000000a0 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+000000b0 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+000000c0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+000000d0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090|
+000000e0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909|
+000000f0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....|
+00000100 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+00000110 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000120 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+00000130 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..|
+00000140 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+00000150 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F|
+00000160 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC|
+00000170 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....|
+00000180 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z|
+00000190 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......|
+000001a0 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....|
+000001b0 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.||
+000001c0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...|
+000001d0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0|
+000001e0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........|
+000001f0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...|
+00000200 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....|
+00000210 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..|
+00000220 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.|
+00000230 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
+00000240 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
+00000250 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
+00000260 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...|
+00000270 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...|
+00000280 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...|
+00000290 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.|
+000002a0 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z|
+000002b0 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`|
+000002c0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.|
+000002d0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.|
+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 04 0e 00 |n8P)l...........|
+00000320 00 00 |..|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 86 10 00 00 82 00 80 6d 51 f3 7f f9 |...........mQ...|
+00000010 3e fb 75 82 41 36 83 e8 6a ee 2a 2e 25 90 67 4c |>.u.A6..j.*.%.gL|
+00000020 8e 62 2f 30 81 17 e0 85 09 0c 2b b7 23 d7 b0 e2 |.b/0......+.#...|
+00000030 1d f7 3b d7 f5 a1 27 b6 ee 24 b6 1b cc 5b ea 66 |..;...'..$...[.f|
+00000040 0d 6a f4 e5 85 f9 da 43 b4 0e 86 85 e1 f5 aa be |.j.....C........|
+00000050 c8 ce 39 4c 9c 86 00 08 c2 4b e2 c6 ec 2f f7 ce |..9L.....K.../..|
+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.\<|
+>>> 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.|
+>>> 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.|
diff --git a/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-3DES b/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-3DES
new file mode 100644
index 0000000000..a6c7a4196c
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-3DES
@@ -0,0 +1,83 @@
+>>> 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.........|
+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 |..|
+>>> 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 |....|
+>>> 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|
diff --git a/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-AES b/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-AES
new file mode 100644
index 0000000000..4885b267da
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-AES
@@ -0,0 +1,84 @@
+>>> 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.'..../|
+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 |..|
+>>> 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...|
+>>> 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|
diff --git a/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-RC4 b/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-RC4
new file mode 100644
index 0000000000..1314b659bf
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-RC4
@@ -0,0 +1,79 @@
+>>> 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_.......|
+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 |..|
+>>> 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 |...<x~...8......|
+000000a0 6a c5 3a 0f 85 e7 37 a6 3c 8d 1e 4b da 02 94 bf |j.:...7.<..K....|
+000000b0 ae 2c 50 3b 4e 1c 0c 3c 4f cc d5 1c da 33 13 43 |.,P;N..<O....3.C|
+000000c0 37 64 44 ac 26 43 28 0b d0 c2 04 09 b5 0f 23 1d |7dD.&C(.......#.|
+>>> 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....|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES b/libgo/go/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES
new file mode 100644
index 0000000000..9b8cb4d9b6
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES
@@ -0,0 +1,84 @@
+>>> 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 |...........|
+>>> 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 c0 0a 00 00 |................|
+00000030 05 ff 01 00 01 00 16 03 01 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 01 00 d6 0c 00 |{j.9....*.......|
+00000250 00 d2 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 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.:..........|
+>>> 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 |......|
+>>> 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....|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-3DES b/libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-3DES
new file mode 100644
index 0000000000..c0e6241c07
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-3DES
@@ -0,0 +1,79 @@
+>>> 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......|
+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 |..|
+>>> 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|
+>>> 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|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-AES b/libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-AES
new file mode 100644
index 0000000000..1670997b0d
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-AES
@@ -0,0 +1,82 @@
+>>> 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..../|
+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 |..|
+>>> 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 |.-....<Q.n.p..Y.|
+00000070 39 04 9f ae f3 5f fb a7 2b d3 5a c0 96 d9 4d 2a |9...._..+.Z...M*|
+00000080 2a 6c 6d 39 ee fc ce 76 1a 92 1b 14 03 01 00 01 |*lm9...v........|
+00000090 01 16 03 01 00 30 10 20 90 7b 0e e6 c2 05 81 c3 |.....0. .{......|
+000000a0 bc da 84 67 dd 5f 97 e2 74 c4 35 4e bf d2 1b 90 |...g._..t.5N....|
+000000b0 2f e0 af dd 6b f5 52 db 36 cd 3e e1 e6 bd 99 30 |/...k.R.6.>....0|
+000000c0 ed c6 bc c2 38 b6 |....8.|
+>>> 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~|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-RC4 b/libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-RC4
new file mode 100644
index 0000000000..d653561f9d
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-RC4
@@ -0,0 +1,76 @@
+>>> 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.._.........|
+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 |..|
+>>> 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_.....|
+>>> 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|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv11-FallbackSCSV b/libgo/go/crypto/tls/testdata/Server-TLSv11-FallbackSCSV
new file mode 100644
index 0000000000..2d8dfbc3b4
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv11-FallbackSCSV
@@ -0,0 +1,17 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 d4 01 00 00 d0 03 02 74 2d da 6d 98 |...........t-.m.|
+00000010 ad 3e a5 ec 90 ea d1 5b f0 e0 a7 45 33 d9 5e 8d |.>.....[...E3.^.|
+00000020 0f 1d 01 16 6d 00 31 65 ed 50 88 00 00 5e c0 14 |....m.1e.P...^..|
+00000030 c0 0a 00 39 00 38 00 88 00 87 c0 0f c0 05 00 35 |...9.8.........5|
+00000040 00 84 c0 13 c0 09 00 33 00 32 00 9a 00 99 00 45 |.......3.2.....E|
+00000050 00 44 c0 0e c0 04 00 2f 00 96 00 41 00 07 c0 11 |.D...../...A....|
+00000060 c0 07 c0 0c c0 02 00 05 00 04 c0 12 c0 08 00 16 |................|
+00000070 00 13 c0 0d c0 03 00 0a 00 15 00 12 00 09 00 14 |................|
+00000080 00 11 00 08 00 06 00 03 00 ff 56 00 01 00 00 49 |..........V....I|
+00000090 00 0b 00 04 03 00 01 02 00 0a 00 34 00 32 00 0e |...........4.2..|
+000000a0 00 0d 00 19 00 0b 00 0c 00 18 00 09 00 0a 00 16 |................|
+000000b0 00 17 00 08 00 06 00 07 00 14 00 15 00 04 00 05 |................|
+000000c0 00 12 00 13 00 01 00 02 00 03 00 0f 00 10 00 11 |................|
+000000d0 00 23 00 00 00 0f 00 01 01 |.#.......|
+>>> Flow 2 (server to client)
+00000000 15 03 02 00 02 02 56 |......V|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv11-RSA-RC4 b/libgo/go/crypto/tls/testdata/Server-TLSv11-RSA-RC4
new file mode 100644
index 0000000000..9237db0786
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv11-RSA-RC4
@@ -0,0 +1,76 @@
+>>> 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.......|
+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 |..|
+>>> 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.'|
+>>> 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@.,.|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN b/libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN
new file mode 100644
index 0000000000..106244d5a2
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN
@@ -0,0 +1,122 @@
+>>> 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|
+>>> 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 |................|
+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 |.....|
+>>> 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|
+>>> 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.|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch b/libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch
new file mode 100644
index 0000000000..db5881b768
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch
@@ -0,0 +1,121 @@
+>>> 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|
+>>> 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 |........|
+>>> 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`..|
+>>> 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<N.w..|
+000000c0 0f 1f 17 03 03 00 40 00 00 00 00 00 00 00 00 00 |......@.........|
+000000d0 00 00 00 00 00 00 00 0b 87 12 62 3e e5 3e 7d 74 |..........b>.>}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.|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA b/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA
new file mode 100644
index 0000000000..0ab8b8d74c
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA
@@ -0,0 +1,91 @@
+>>> 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 |...............|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 2a 02 00 00 26 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 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 |........|
+>>> 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..|
+>>> 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.;......@|
+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|
+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|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA b/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA
new file mode 100644
index 0000000000..88abb15a7e
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA
@@ -0,0 +1,101 @@
+>>> 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 |...............|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 2a 02 00 00 26 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 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 |:...>3<A .?\...#|
+00000380 12 48 ff d2 c4 30 7c 8a 51 3f 9f 19 6e 34 d7 60 |.H...0|.Q?..n4.`|
+00000390 7d 12 8a aa 90 0f 50 d9 0b 9a b2 d7 66 b1 c6 84 |}.....P.....f...|
+000003a0 af 5c e2 5e 16 3e 36 61 73 84 64 89 b3 c1 6d 50 |.\.^.>6as.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 |.............|
+>>> 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|
+>>> 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$....@|
+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....>|
+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|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven b/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven
new file mode 100644
index 0000000000..547f79834d
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven
@@ -0,0 +1,122 @@
+>>> 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 |.....+...". ....|
+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 |.|
+>>> 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 |......|
+>>> 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|
+00000020 d9 17 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 |..0...*.H.=..0E1|
+00000030 0b 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 |.0...U....AU1.0.|
+00000040 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 |..U....Some-Stat|
+00000050 65 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 |e1!0...U....Inte|
+00000060 72 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 |rnet Widgits Pty|
+00000070 20 4c 74 64 30 1e 17 0d 31 32 31 31 31 34 31 33 | Ltd0...12111413|
+00000080 32 35 35 33 5a 17 0d 32 32 31 31 31 32 31 33 32 |2553Z..221112132|
+00000090 35 35 33 5a 30 41 31 0b 30 09 06 03 55 04 06 13 |553Z0A1.0...U...|
+000000a0 02 41 55 31 0c 30 0a 06 03 55 04 08 13 03 4e 53 |.AU1.0...U....NS|
+000000b0 57 31 10 30 0e 06 03 55 04 07 13 07 50 79 72 6d |W1.0...U....Pyrm|
+000000c0 6f 6e 74 31 12 30 10 06 03 55 04 03 13 09 4a 6f |ont1.0...U....Jo|
+000000d0 65 6c 20 53 69 6e 67 30 81 9b 30 10 06 07 2a 86 |el Sing0..0...*.|
+000000e0 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 86 00 |H.=....+...#....|
+000000f0 04 00 95 8c 91 75 14 c0 5e c4 57 b4 d4 c3 6f 8d |.....u..^.W...o.|
+00000100 ae 68 1e dd 6f ce 86 e1 7e 6e b2 48 3e 81 e5 4e |.h..o...~n.H>..N|
+00000110 e2 c6 88 4b 64 dc f5 30 bb d3 ff 65 cc 5b f4 dd |...Kd..0...e.[..|
+00000120 b5 6a 3e 3e d0 1d de 47 c3 76 ad 19 f6 45 2c 8c |.j>>...G.v...E,.|
+00000130 bc d8 1d 01 4c 1f 70 90 46 76 48 8b 8f 83 cc 4a |....L.p.FvH....J|
+00000140 5c 8f 40 76 da e0 89 ec 1d 2b c4 4e 30 76 28 41 |\.@v.....+.N0v(A|
+00000150 b2 62 a8 fb 5b f1 f9 4e 7a 8d bd 09 b8 ae ea 8b |.b..[..Nz.......|
+00000160 18 27 4f 2e 70 fe 13 96 ba c3 d3 40 16 cd 65 4e |.'O.p......@..eN|
+00000170 ac 11 1e e6 f1 30 09 06 07 2a 86 48 ce 3d 04 01 |.....0...*.H.=..|
+00000180 03 81 8c 00 30 81 88 02 42 00 e0 14 c4 60 60 0b |....0...B....``.|
+00000190 72 68 b0 32 5d 61 4a 02 74 5c c2 81 b9 16 a8 3f |rh.2]aJ.t\.....?|
+000001a0 29 c8 36 c7 81 ff 6c b6 5b d9 70 f1 38 3b 50 48 |).6...l.[.p.8;PH|
+000001b0 28 94 cb 09 1a 52 f1 5d ee 8d f2 b9 f0 f0 da d9 |(....R.]........|
+000001c0 15 3a f9 bd 03 7a 87 a2 23 35 ec 02 42 01 a3 d4 |.:...z..#5..B...|
+000001d0 8a 78 35 1c 4a 9a 23 d2 0a be 2b 10 31 9d 9c 5f |.x5.J.#...+.1.._|
+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...|
+>>> 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<D.X..|
+00000030 03 03 00 21 51 0a 41 8c fd 50 e3 54 8b 6a 1f 83 |...!Q.A..P.T.j..|
+00000040 a5 37 98 e1 5b 1e ec 03 1d c7 0e 28 6d 79 3f 34 |.7..[......(my?4|
+00000050 de 1c 38 6d 7e 15 03 03 00 16 06 fc b1 7d ad 70 |..8m~........}.p|
+00000060 1a de d4 b7 b5 e7 a2 6d 1b 9a b0 31 0c cc 7b 70 |.......m...1..{p|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven b/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven
new file mode 100644
index 0000000000..04a5b117cd
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven
@@ -0,0 +1,121 @@
+>>> 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 |.....+...". ....|
+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 |.|
+>>> 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 |......|
+>>> 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 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 |......?|
+>>> 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.......|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven b/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven
new file mode 100644
index 0000000000..562fe1aaa0
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven
@@ -0,0 +1,81 @@
+>>> 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 |.....+...". ....|
+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 |.|
+>>> 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 |......|
+>>> 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|
+>>> 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|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES b/libgo/go/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES
new file mode 100644
index 0000000000..aacbb86705
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES
@@ -0,0 +1,89 @@
+>>> 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 |.|
+>>> 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 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 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...........|
+>>> 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.|
+>>> 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[...". ..)....@|
+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 ......+.!$.|
+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|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-IssueTicket b/libgo/go/crypto/tls/testdata/Server-TLSv12-IssueTicket
new file mode 100644
index 0000000000..e3e62f2242
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-IssueTicket
@@ -0,0 +1,87 @@
+>>> 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 |...../.#.....". |
+00000040 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 02 |................|
+00000050 04 03 03 01 03 02 03 03 02 01 02 02 02 03 01 01 |................|
+00000060 00 0f 00 01 01 |.....|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 35 02 00 00 31 03 03 00 00 00 00 00 |....5...1.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
+00000030 09 00 23 00 00 ff 01 00 01 00 16 03 03 02 be 0b |..#.............|
+00000040 00 02 ba 00 02 b7 00 02 b4 30 82 02 b0 30 82 02 |.........0...0..|
+00000050 19 a0 03 02 01 02 02 09 00 85 b0 bb a4 8a 7f b8 |................|
+00000060 ca 30 0d 06 09 2a 86 48 86 f7 0d 01 01 05 05 00 |.0...*.H........|
+00000070 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 55 31 |0E1.0...U....AU1|
+00000080 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 |.0...U....Some-S|
+00000090 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 18 49 |tate1!0...U....I|
+000000a0 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 73 20 |nternet Widgits |
+000000b0 50 74 79 20 4c 74 64 30 1e 17 0d 31 30 30 34 32 |Pty Ltd0...10042|
+000000c0 34 30 39 30 39 33 38 5a 17 0d 31 31 30 34 32 34 |4090938Z..110424|
+000000d0 30 39 30 39 33 38 5a 30 45 31 0b 30 09 06 03 55 |090938Z0E1.0...U|
+000000e0 04 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 |....AU1.0...U...|
+000000f0 0a 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 |.Some-State1!0..|
+00000100 03 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 |.U....Internet W|
+00000110 69 64 67 69 74 73 20 50 74 79 20 4c 74 64 30 81 |idgits Pty Ltd0.|
+00000120 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 |.0...*.H........|
+00000130 03 81 8d 00 30 81 89 02 81 81 00 bb 79 d6 f5 17 |....0.......y...|
+00000140 b5 e5 bf 46 10 d0 dc 69 be e6 2b 07 43 5a d0 03 |...F...i..+.CZ..|
+00000150 2d 8a 7a 43 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 |-.zC...R..eL,x.#|
+00000160 8c b5 b4 82 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 |........;~b.,.3.|
+00000170 fe 12 5c 7a 56 fc f5 06 bf fa 58 7b 26 3f b5 cd |..\zV.....X{&?..|
+00000180 04 d3 d0 c9 21 96 4a c7 f4 54 9f 5a bf ef 42 71 |....!.J..T.Z..Bq|
+00000190 00 fe 18 99 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e |......~.}}..9...|
+000001a0 db 51 c9 7c e3 c0 4c 3b 32 66 01 cf af b1 1d b8 |.Q.|..L;2f......|
+000001b0 71 9a 1d db db 89 6b ae da 2d 79 02 03 01 00 01 |q.....k..-y.....|
+000001c0 a3 81 a7 30 81 a4 30 1d 06 03 55 1d 0e 04 16 04 |...0..0...U.....|
+000001d0 14 b1 ad e2 85 5a cf cb 28 db 69 ce 23 69 de d3 |.....Z..(.i.#i..|
+000001e0 26 8e 18 88 39 30 75 06 03 55 1d 23 04 6e 30 6c |&...90u..U.#.n0l|
+000001f0 80 14 b1 ad e2 85 5a cf cb 28 db 69 ce 23 69 de |......Z..(.i.#i.|
+00000200 d3 26 8e 18 88 39 a1 49 a4 47 30 45 31 0b 30 09 |.&...9.I.G0E1.0.|
+00000210 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 55 |..U....AU1.0...U|
+00000220 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 21 |....Some-State1!|
+00000230 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e 65 |0...U....Interne|
+00000240 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c 74 |t Widgits Pty Lt|
+00000250 64 82 09 00 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 |d...........0...|
+00000260 55 1d 13 04 05 30 03 01 01 ff 30 0d 06 09 2a 86 |U....0....0...*.|
+00000270 48 86 f7 0d 01 01 05 05 00 03 81 81 00 08 6c 45 |H.............lE|
+00000280 24 c7 6b b1 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a |$.k.Y..R.......z|
+00000290 64 75 b5 5a 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f |du.Z.f..+...f..O|
+000002a0 38 b3 6e 60 d3 92 fd f7 41 08 b5 25 13 b1 18 7a |8.n`....A..%...z|
+000002b0 24 fb 30 1d ba ed 98 b9 17 ec e7 d7 31 59 db 95 |$.0.........1Y..|
+000002c0 d3 1d 78 ea 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 |..x.PV\..Z-Z_3..|
+000002d0 d8 c9 75 90 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f |..u....R...... _|
+000002e0 f2 a0 1c a3 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d |..........W.p.&m|
+000002f0 71 99 9b 26 6e 38 50 29 6c 90 a7 bd d9 16 03 03 |q..&n8P)l.......|
+00000300 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 86 10 00 00 82 00 80 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.....|
+>>> 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....|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable b/libgo/go/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable
new file mode 100644
index 0000000000..30f0026815
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable
@@ -0,0 +1,87 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 60 01 00 00 5c 03 03 54 23 54 02 17 |....`...\..T#T..|
+00000010 f3 53 13 3d 48 88 c3 19 b9 d1 3d 33 7f f5 99 56 |.S.=H.....=3...V|
+00000020 04 71 1b d9 d5 64 8a 0d 4a 54 00 00 00 04 00 05 |.q...d..JT......|
+00000030 00 ff 01 00 00 2f 00 23 00 00 00 0d 00 22 00 20 |...../.#.....". |
+00000040 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 02 |................|
+00000050 04 03 03 01 03 02 03 03 02 01 02 02 02 03 01 01 |................|
+00000060 00 0f 00 01 01 |.....|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 35 02 00 00 31 03 03 00 00 00 00 00 |....5...1.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
+00000030 09 00 23 00 00 ff 01 00 01 00 16 03 03 02 be 0b |..#.............|
+00000040 00 02 ba 00 02 b7 00 02 b4 30 82 02 b0 30 82 02 |.........0...0..|
+00000050 19 a0 03 02 01 02 02 09 00 85 b0 bb a4 8a 7f b8 |................|
+00000060 ca 30 0d 06 09 2a 86 48 86 f7 0d 01 01 05 05 00 |.0...*.H........|
+00000070 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 55 31 |0E1.0...U....AU1|
+00000080 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 |.0...U....Some-S|
+00000090 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 18 49 |tate1!0...U....I|
+000000a0 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 73 20 |nternet Widgits |
+000000b0 50 74 79 20 4c 74 64 30 1e 17 0d 31 30 30 34 32 |Pty Ltd0...10042|
+000000c0 34 30 39 30 39 33 38 5a 17 0d 31 31 30 34 32 34 |4090938Z..110424|
+000000d0 30 39 30 39 33 38 5a 30 45 31 0b 30 09 06 03 55 |090938Z0E1.0...U|
+000000e0 04 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 |....AU1.0...U...|
+000000f0 0a 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 |.Some-State1!0..|
+00000100 03 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 |.U....Internet W|
+00000110 69 64 67 69 74 73 20 50 74 79 20 4c 74 64 30 81 |idgits Pty Ltd0.|
+00000120 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 |.0...*.H........|
+00000130 03 81 8d 00 30 81 89 02 81 81 00 bb 79 d6 f5 17 |....0.......y...|
+00000140 b5 e5 bf 46 10 d0 dc 69 be e6 2b 07 43 5a d0 03 |...F...i..+.CZ..|
+00000150 2d 8a 7a 43 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 |-.zC...R..eL,x.#|
+00000160 8c b5 b4 82 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 |........;~b.,.3.|
+00000170 fe 12 5c 7a 56 fc f5 06 bf fa 58 7b 26 3f b5 cd |..\zV.....X{&?..|
+00000180 04 d3 d0 c9 21 96 4a c7 f4 54 9f 5a bf ef 42 71 |....!.J..T.Z..Bq|
+00000190 00 fe 18 99 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e |......~.}}..9...|
+000001a0 db 51 c9 7c e3 c0 4c 3b 32 66 01 cf af b1 1d b8 |.Q.|..L;2f......|
+000001b0 71 9a 1d db db 89 6b ae da 2d 79 02 03 01 00 01 |q.....k..-y.....|
+000001c0 a3 81 a7 30 81 a4 30 1d 06 03 55 1d 0e 04 16 04 |...0..0...U.....|
+000001d0 14 b1 ad e2 85 5a cf cb 28 db 69 ce 23 69 de d3 |.....Z..(.i.#i..|
+000001e0 26 8e 18 88 39 30 75 06 03 55 1d 23 04 6e 30 6c |&...90u..U.#.n0l|
+000001f0 80 14 b1 ad e2 85 5a cf cb 28 db 69 ce 23 69 de |......Z..(.i.#i.|
+00000200 d3 26 8e 18 88 39 a1 49 a4 47 30 45 31 0b 30 09 |.&...9.I.G0E1.0.|
+00000210 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 55 |..U....AU1.0...U|
+00000220 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 21 |....Some-State1!|
+00000230 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e 65 |0...U....Interne|
+00000240 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c 74 |t Widgits Pty Lt|
+00000250 64 82 09 00 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 |d...........0...|
+00000260 55 1d 13 04 05 30 03 01 01 ff 30 0d 06 09 2a 86 |U....0....0...*.|
+00000270 48 86 f7 0d 01 01 05 05 00 03 81 81 00 08 6c 45 |H.............lE|
+00000280 24 c7 6b b1 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a |$.k.Y..R.......z|
+00000290 64 75 b5 5a 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f |du.Z.f..+...f..O|
+000002a0 38 b3 6e 60 d3 92 fd f7 41 08 b5 25 13 b1 18 7a |8.n`....A..%...z|
+000002b0 24 fb 30 1d ba ed 98 b9 17 ec e7 d7 31 59 db 95 |$.0.........1Y..|
+000002c0 d3 1d 78 ea 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 |..x.PV\..Z-Z_3..|
+000002d0 d8 c9 75 90 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f |..u....R...... _|
+000002e0 f2 a0 1c a3 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d |..........W.p.&m|
+000002f0 71 99 9b 26 6e 38 50 29 6c 90 a7 bd d9 16 03 03 |q..&n8P)l.......|
+00000300 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 86 10 00 00 82 00 80 27 e9 a4 f7 e7 |...........'....|
+00000010 df 25 de 84 8c 1f d6 e6 c3 11 28 55 9a c1 91 37 |.%........(U...7|
+00000020 84 f5 ba f8 80 0d ca 50 cb 1e 72 f7 97 6f c2 b2 |.......P..r..o..|
+00000030 04 4d 13 7c e0 6e a0 1f 91 e1 38 1b a2 c0 55 16 |.M.|.n....8...U.|
+00000040 7f 29 fc ed 1c 1a cf 72 14 c3 00 c1 dd 36 36 af |.).....r.....66.|
+00000050 a6 e4 a8 be ba ec 13 d0 1e d0 1d fd e1 5b 27 fd |.............['.|
+00000060 9a da 2e 12 c8 b0 b9 c2 b9 76 ec 7f 3c 98 b6 63 |.........v..<..c|
+00000070 bc da f0 07 7a 3d e7 61 f4 2f 12 80 3b f9 3b cc |....z=.a./..;.;.|
+00000080 05 c8 2f 7e 28 b2 73 bf 97 61 29 14 03 03 00 01 |../~(.s..a).....|
+00000090 01 16 03 03 00 24 17 59 a9 45 53 46 33 96 50 dd |.....$.Y.ESF3.P.|
+000000a0 3e 23 aa 91 38 f8 56 4a 2f 1a f2 b1 44 9b ce 17 |>#..8.VJ/...D...|
+000000b0 6b 8a 89 76 bc 67 b8 8b ba 90 |k..v.g....|
+>>> Flow 4 (server to client)
+00000000 16 03 03 00 72 04 00 00 6e 00 00 00 00 00 68 00 |....r...n.....h.|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 65 |...............e|
+00000020 ea 4b d1 ef ba 2d db 0c ba 9a d4 20 76 57 c8 ec |.K...-..... vW..|
+00000030 dc 2d 77 fb fb 3b 93 5f 53 e0 14 4f 90 fb d6 55 |.-w..;._S..O...U|
+00000040 57 8c 8d 0d 25 ea 5d 0d f2 91 e5 12 22 12 ec 7b |W...%.]....."..{|
+00000050 5f b6 6e fd 07 59 23 24 fc b1 97 ca ea 56 a5 c2 |_.n..Y#$.....V..|
+00000060 a0 e4 9e 99 64 f2 64 d0 75 7a 46 63 e3 dc 21 ed |....d.d.uzFc..!.|
+00000070 78 56 e9 e1 ab 66 80 14 03 03 00 01 01 16 03 03 |xV...f..........|
+00000080 00 24 fc 14 68 07 17 1f df b7 84 cb fd c1 e0 e4 |.$..h...........|
+00000090 f2 1a ea 34 b5 00 7f 70 be c8 1c 0a d6 55 e3 57 |...4...p.....U.W|
+000000a0 50 4e 6d 7d 8a 5d 17 03 03 00 21 24 27 50 40 c1 |PNm}.]....!$'P@.|
+000000b0 c5 bd c7 9f 95 d9 ba 2e 7b 0e db ea a7 31 81 05 |........{....1..|
+000000c0 75 43 b1 63 cf b8 55 92 ef 76 98 a9 15 03 03 00 |uC.c..U..v......|
+000000d0 16 d7 ea 3c 79 e7 a6 2f 61 39 ec 4e 95 86 48 5e |...<y../a9.N..H^|
+000000e0 75 a0 9e 41 42 89 67 |u..AB.g|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-3DES b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-3DES
new file mode 100644
index 0000000000..5995b3314c
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-3DES
@@ -0,0 +1,83 @@
+>>> 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 |.....+...". ....|
+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 |.|
+>>> 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 |..|
+>>> 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..|
+>>> 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 |.....|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES
new file mode 100644
index 0000000000..a152a96a84
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES
@@ -0,0 +1,87 @@
+>>> 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 |.....+...". ....|
+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 |.|
+>>> 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 |..|
+>>> 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 |%.....|
+>>> 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.....@|
+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|
+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..<.|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM
new file mode 100644
index 0000000000..0ddfe022f2
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM
@@ -0,0 +1,93 @@
+>>> 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..........|
+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 |.|
+>>> 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 |....|
+>>> 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..|
+>>> 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......|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-RC4 b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-RC4
new file mode 100644
index 0000000000..b703a8f766
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-RC4
@@ -0,0 +1,79 @@
+>>> 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 |.....+...". ....|
+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 |.|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
+00000030 05 ff 01 00 01 00 16 03 03 02 be 0b 00 02 ba 00 |................|
+00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......|
+00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.|
+00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090|
+000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909|
+000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....|
+000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..|
+00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F|
+00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC|
+00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....|
+00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z|
+00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......|
+00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....|
+00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.||
+000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...|
+000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0|
+000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........|
+000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...|
+000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....|
+000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..|
+00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.|
+00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
+00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
+00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
+00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...|
+00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...|
+00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...|
+00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.|
+00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z|
+00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`|
+000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.|
+000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.|
+000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.|
+000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....|
+000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&|
+000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 03 00 04 0e 00 |n8P)l...........|
+00000300 00 00 |..|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 86 10 00 00 82 00 80 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.<H./|
+00000030 66 69 11 33 39 37 7a 36 a3 1c ef b0 81 71 7d 25 |fi.397z6.....q}%|
+00000040 35 da 2c 42 e2 ab d3 b7 07 8b 4a 0d 6d 77 bd ae |5.,B......J.mw..|
+00000050 02 51 7c a5 0d a6 03 4c 3c d0 ce 89 2c 83 6c de |.Q|....L<...,.l.|
+00000060 40 15 cc 72 c7 95 c8 6d ee 05 86 da 3e c6 7c d4 |@..r...m....>.|.|
+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..|
+>>> 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..|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-Resume b/libgo/go/crypto/tls/testdata/Server-TLSv12-Resume
new file mode 100644
index 0000000000..c495d4adc6
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-Resume
@@ -0,0 +1,36 @@
+>>> 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 |.............|
+>>> 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.......|
+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|
+>>> 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.|
+>>> 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 |.|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-ResumeDisabled b/libgo/go/crypto/tls/testdata/Server-TLSv12-ResumeDisabled
new file mode 100644
index 0000000000..db833f6555
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-ResumeDisabled
@@ -0,0 +1,87 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 e8 01 00 00 e4 03 03 54 23 54 02 a5 |...........T#T..|
+00000010 10 11 0f 6d e5 2d 2f e8 bb 52 b1 38 3f 65 01 43 |...m.-/..R.8?e.C|
+00000020 36 cc 48 f6 09 22 a1 85 20 28 3c 20 35 8b fe 7a |6.H..".. (< 5..z|
+00000030 41 3b 59 3a 5d b9 b3 21 f0 62 e9 0d 7b af f5 5d |A;Y:]..!.b..{..]|
+00000040 fa 65 1a 40 c8 ca cd 74 8c ef d2 fb 00 04 00 05 |.e.@...t........|
+00000050 00 ff 01 00 00 97 00 23 00 68 00 00 00 00 00 00 |.......#.h......|
+00000060 00 00 00 00 00 00 00 00 00 00 65 ea 4b d1 ef ba |..........e.K...|
+00000070 2d db 0c ba 9a d4 20 76 57 c8 ec dc 2d 77 fb fb |-..... vW...-w..|
+00000080 3b 93 5f 53 e0 14 4f 90 fb d6 55 57 8c 8d 0d 25 |;._S..O...UW...%|
+00000090 ea 5d 0d f2 91 e5 12 22 12 ec 7b 5f b6 6e fd 07 |.]....."..{_.n..|
+000000a0 59 23 24 fc b1 97 ca ea 56 a5 c2 a0 e4 9e 99 64 |Y#$.....V......d|
+000000b0 f2 64 d0 75 7a 46 63 e3 dc 21 ed 78 56 e9 e1 ab |.d.uzFc..!.xV...|
+000000c0 66 80 00 0d 00 22 00 20 06 01 06 02 06 03 05 01 |f....". ........|
+000000d0 05 02 05 03 04 01 04 02 04 03 03 01 03 02 03 03 |................|
+000000e0 02 01 02 02 02 03 01 01 00 0f 00 01 01 |.............|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
+00000030 05 ff 01 00 01 00 16 03 03 02 be 0b 00 02 ba 00 |................|
+00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......|
+00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.|
+00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090|
+000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909|
+000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....|
+000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..|
+00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F|
+00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC|
+00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....|
+00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z|
+00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......|
+00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....|
+00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.||
+000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...|
+000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0|
+000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........|
+000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...|
+000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....|
+000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..|
+00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.|
+00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
+00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
+00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
+00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...|
+00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...|
+00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...|
+00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.|
+00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z|
+00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`|
+000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.|
+000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.|
+000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.|
+000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....|
+000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&|
+000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 03 00 04 0e 00 |n8P)l...........|
+00000300 00 00 |..|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 86 10 00 00 82 00 80 ae 02 dd 1f 1a |................|
+00000010 86 83 f5 2f 82 46 4b 29 58 aa a1 b3 56 8b 4e 40 |.../.FK)X...V.N@|
+00000020 ef 23 65 67 ad 48 e5 e1 fd ae dd bf 68 fd bd a6 |.#eg.H......h...|
+00000030 13 a0 7e 05 ab f7 20 e1 6a 4e d1 37 93 08 1d c9 |..~... .jN.7....|
+00000040 37 e0 b5 34 28 bf 20 45 45 da 0f 7e 51 a7 c6 ae |7..4(. EE..~Q...|
+00000050 61 6c 07 1b 73 ef da 6e 25 c4 ed be e3 3f da ae |al..s..n%....?..|
+00000060 cd 3c 17 9c 2e ee fb 47 9d b3 a1 b2 c3 5d e0 83 |.<.....G.....]..|
+00000070 74 20 37 2d 72 d6 d0 4d 58 0e 26 1c 50 22 95 08 |t 7-r..MX.&.P"..|
+00000080 7d e0 5f 86 99 9e 2c 2e a7 a0 7f 14 03 03 00 01 |}._...,.........|
+00000090 01 16 03 03 00 24 a2 ab 41 25 a5 cf 04 18 1d 98 |.....$..A%......|
+000000a0 88 6c 59 21 86 33 54 f4 35 b4 21 6e a5 29 d5 6e |.lY!.3T.5.!n.).n|
+000000b0 3d 08 72 b0 af 46 b5 8f 6b 86 |=.r..F..k.|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 24 59 20 4d c2 17 |..........$Y M..|
+00000010 8b 3c 9b 33 d9 f9 ef fb 80 18 1f 67 a7 58 12 89 |.<.3.......g.X..|
+00000020 4e 73 0f 2d 7b e6 c4 a6 79 73 01 da 22 e8 54 17 |Ns.-{...ys..".T.|
+00000030 03 03 00 21 36 ca 64 0f 4a 12 a5 50 3d 97 bb 39 |...!6.d.J..P=..9|
+00000040 02 fc ed d1 82 6a 9a 2e 21 79 f6 e1 b3 cc 32 db |.....j..!y....2.|
+00000050 0f 5d b3 fb a5 15 03 03 00 16 51 f4 be 57 7a df |.]........Q..Wz.|
+00000060 f1 f2 bd b5 51 5e 45 80 be 0b 9a 0c d1 19 3c 79 |....Q^E.......<y|
diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-SNI b/libgo/go/crypto/tls/testdata/Server-TLSv12-SNI
new file mode 100644
index 0000000000..61b17a11da
--- /dev/null
+++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-SNI
@@ -0,0 +1,76 @@
+>>> 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...". |
+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 |.....|
+>>> 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 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.|
+>>> 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 |.....|
diff --git a/libgo/go/crypto/tls/ticket.go b/libgo/go/crypto/tls/ticket.go
index 4cfc5a53ff..0923027c70 100644
--- a/libgo/go/crypto/tls/ticket.go
+++ b/libgo/go/crypto/tls/ticket.go
@@ -153,7 +153,8 @@ func (c *Conn) encryptTicket(state *sessionState) ([]byte, error) {
}
func (c *Conn) decryptTicket(encrypted []byte) (*sessionState, bool) {
- if len(encrypted) < aes.BlockSize+sha256.Size {
+ if c.config.SessionTicketsDisabled ||
+ len(encrypted) < aes.BlockSize+sha256.Size {
return nil, false
}
diff --git a/libgo/go/crypto/tls/tls.go b/libgo/go/crypto/tls/tls.go
index 6c67506fc3..d50e120292 100644
--- a/libgo/go/crypto/tls/tls.go
+++ b/libgo/go/crypto/tls/tls.go
@@ -15,6 +15,7 @@ import (
"io/ioutil"
"net"
"strings"
+ "time"
)
// Server returns a new TLS server side connection
@@ -27,9 +28,8 @@ func Server(conn net.Conn, config *Config) *Conn {
// Client returns a new TLS client side connection
// using conn as the underlying transport.
-// Client interprets a nil configuration as equivalent to
-// the zero configuration; see the documentation of Config
-// for the defaults.
+// The config cannot be nil: users must set either ServerName or
+// InsecureSkipVerify in the config.
func Client(conn net.Conn, config *Config) *Conn {
return &Conn{conn: conn, config: config, isClient: true}
}
@@ -77,24 +77,51 @@ func Listen(network, laddr string, config *Config) (net.Listener, error) {
return NewListener(l, config), nil
}
-// Dial connects to the given network address using net.Dial
-// and then initiates a TLS handshake, returning the resulting
-// TLS connection.
-// Dial interprets a nil configuration as equivalent to
-// the zero configuration; see the documentation of Config
-// for the defaults.
-func Dial(network, addr string, config *Config) (*Conn, error) {
- raddr := addr
- c, err := net.Dial(network, raddr)
+type timeoutError struct{}
+
+func (timeoutError) Error() string { return "tls: DialWithDialer timed out" }
+func (timeoutError) Timeout() bool { return true }
+func (timeoutError) Temporary() bool { return true }
+
+// DialWithDialer connects to the given network address using dialer.Dial and
+// then initiates a TLS handshake, returning the resulting TLS connection. Any
+// timeout or deadline given in the dialer apply to connection and TLS
+// handshake as a whole.
+//
+// DialWithDialer interprets a nil configuration as equivalent to the zero
+// configuration; see the documentation of Config for the defaults.
+func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*Conn, error) {
+ // We want the Timeout and Deadline values from dialer to cover the
+ // whole process: TCP connection and TLS handshake. This means that we
+ // also need to start our own timers now.
+ timeout := dialer.Timeout
+
+ if !dialer.Deadline.IsZero() {
+ deadlineTimeout := dialer.Deadline.Sub(time.Now())
+ if timeout == 0 || deadlineTimeout < timeout {
+ timeout = deadlineTimeout
+ }
+ }
+
+ var errChannel chan error
+
+ if timeout != 0 {
+ errChannel = make(chan error, 2)
+ time.AfterFunc(timeout, func() {
+ errChannel <- timeoutError{}
+ })
+ }
+
+ rawConn, err := dialer.Dial(network, addr)
if err != nil {
return nil, err
}
- colonPos := strings.LastIndex(raddr, ":")
+ colonPos := strings.LastIndex(addr, ":")
if colonPos == -1 {
- colonPos = len(raddr)
+ colonPos = len(addr)
}
- hostname := raddr[:colonPos]
+ hostname := addr[:colonPos]
if config == nil {
config = defaultConfig()
@@ -107,14 +134,37 @@ func Dial(network, addr string, config *Config) (*Conn, error) {
c.ServerName = hostname
config = &c
}
- conn := Client(c, config)
- if err = conn.Handshake(); err != nil {
- c.Close()
+
+ conn := Client(rawConn, config)
+
+ if timeout == 0 {
+ err = conn.Handshake()
+ } else {
+ go func() {
+ errChannel <- conn.Handshake()
+ }()
+
+ err = <-errChannel
+ }
+
+ if err != nil {
+ rawConn.Close()
return nil, err
}
+
return conn, nil
}
+// Dial connects to the given network address using net.Dial
+// and then initiates a TLS handshake, returning the resulting
+// TLS connection.
+// Dial interprets a nil configuration as equivalent to
+// the zero configuration; see the documentation of Config
+// for the defaults.
+func Dial(network, addr string, config *Config) (*Conn, error) {
+ return DialWithDialer(new(net.Dialer), network, addr, config)
+}
+
// 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) {
diff --git a/libgo/go/crypto/tls/tls_test.go b/libgo/go/crypto/tls/tls_test.go
index 38229014cd..e82579eee9 100644
--- a/libgo/go/crypto/tls/tls_test.go
+++ b/libgo/go/crypto/tls/tls_test.go
@@ -5,7 +5,13 @@
package tls
import (
+ "bytes"
+ "fmt"
+ "io"
+ "net"
+ "strings"
"testing"
+ "time"
)
var rsaCertPEM = `-----BEGIN CERTIFICATE-----
@@ -105,3 +111,172 @@ func TestX509MixedKeyPair(t *testing.T) {
t.Error("Load of ECDSA certificate succeeded with RSA private key")
}
}
+
+func newLocalListener(t *testing.T) net.Listener {
+ ln, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ ln, err = net.Listen("tcp6", "[::1]:0")
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+ return ln
+}
+
+func TestDialTimeout(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping in short mode")
+ }
+ listener := newLocalListener(t)
+
+ addr := listener.Addr().String()
+ defer listener.Close()
+
+ complete := make(chan bool)
+ defer close(complete)
+
+ go func() {
+ conn, err := listener.Accept()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ <-complete
+ conn.Close()
+ }()
+
+ dialer := &net.Dialer{
+ Timeout: 10 * time.Millisecond,
+ }
+
+ var err error
+ if _, err = DialWithDialer(dialer, "tcp", addr, nil); err == nil {
+ t.Fatal("DialWithTimeout completed successfully")
+ }
+
+ if !strings.Contains(err.Error(), "timed out") {
+ t.Errorf("resulting error not a timeout: %s", err)
+ }
+}
+
+// tests that Conn.Read returns (non-zero, io.EOF) instead of
+// (non-zero, nil) when a Close (alertCloseNotify) is sitting right
+// behind the application data in the buffer.
+func TestConnReadNonzeroAndEOF(t *testing.T) {
+ // This test is racy: it assumes that after a write to a
+ // localhost TCP connection, the peer TCP connection can
+ // immediately read it. Because it's racy, we skip this test
+ // in short mode, and then retry it several times with an
+ // increasing sleep in between our final write (via srv.Close
+ // below) and the following read.
+ if testing.Short() {
+ t.Skip("skipping in short mode")
+ }
+ var err error
+ for delay := time.Millisecond; delay <= 64*time.Millisecond; delay *= 2 {
+ if err = testConnReadNonzeroAndEOF(t, delay); err == nil {
+ return
+ }
+ }
+ t.Error(err)
+}
+
+func testConnReadNonzeroAndEOF(t *testing.T, delay time.Duration) error {
+ ln := newLocalListener(t)
+ defer ln.Close()
+
+ srvCh := make(chan *Conn, 1)
+ var serr error
+ go func() {
+ sconn, err := ln.Accept()
+ if err != nil {
+ serr = err
+ srvCh <- nil
+ return
+ }
+ serverConfig := *testConfig
+ srv := Server(sconn, &serverConfig)
+ if err := srv.Handshake(); err != nil {
+ serr = fmt.Errorf("handshake: %v", err)
+ srvCh <- nil
+ return
+ }
+ srvCh <- srv
+ }()
+
+ clientConfig := *testConfig
+ conn, err := Dial("tcp", ln.Addr().String(), &clientConfig)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer conn.Close()
+
+ srv := <-srvCh
+ if srv == nil {
+ return serr
+ }
+
+ buf := make([]byte, 6)
+
+ srv.Write([]byte("foobar"))
+ n, err := conn.Read(buf)
+ if n != 6 || err != nil || string(buf) != "foobar" {
+ return fmt.Errorf("Read = %d, %v, data %q; want 6, nil, foobar", n, err, buf)
+ }
+
+ srv.Write([]byte("abcdef"))
+ srv.Close()
+ time.Sleep(delay)
+ n, err = conn.Read(buf)
+ if n != 6 || string(buf) != "abcdef" {
+ return fmt.Errorf("Read = %d, buf= %q; want 6, abcdef", n, buf)
+ }
+ if err != io.EOF {
+ return fmt.Errorf("Second Read error = %v; want io.EOF", err)
+ }
+ return nil
+}
+
+func TestTLSUniqueMatches(t *testing.T) {
+ ln := newLocalListener(t)
+ defer ln.Close()
+
+ serverTLSUniques := make(chan []byte)
+ go func() {
+ for i := 0; i < 2; i++ {
+ sconn, err := ln.Accept()
+ if err != nil {
+ t.Fatal(err)
+ }
+ serverConfig := *testConfig
+ srv := Server(sconn, &serverConfig)
+ if err := srv.Handshake(); err != nil {
+ t.Fatal(err)
+ }
+ serverTLSUniques <- srv.ConnectionState().TLSUnique
+ }
+ }()
+
+ clientConfig := *testConfig
+ clientConfig.ClientSessionCache = NewLRUClientSessionCache(1)
+ conn, err := Dial("tcp", ln.Addr().String(), &clientConfig)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(conn.ConnectionState().TLSUnique, <-serverTLSUniques) {
+ t.Error("client and server channel bindings differ")
+ }
+ conn.Close()
+
+ conn, err = Dial("tcp", ln.Addr().String(), &clientConfig)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer conn.Close()
+ if !conn.ConnectionState().DidResume {
+ t.Error("second session did not use resumption")
+ }
+ if !bytes.Equal(conn.ConnectionState().TLSUnique, <-serverTLSUniques) {
+ t.Error("client and server channel bindings differ when session resumption is used")
+ }
+}
diff --git a/libgo/go/crypto/x509/pem_decrypt_test.go b/libgo/go/crypto/x509/pem_decrypt_test.go
index 59ba6f9001..13e4700bdd 100644
--- a/libgo/go/crypto/x509/pem_decrypt_test.go
+++ b/libgo/go/crypto/x509/pem_decrypt_test.go
@@ -14,7 +14,7 @@ import (
func TestDecrypt(t *testing.T) {
for i, data := range testData {
- t.Logf("test %d. %s", i, data.kind)
+ t.Logf("test %v. %v", i, data.kind)
block, rest := pem.Decode(data.pemData)
if len(rest) > 0 {
t.Error("extra data")
@@ -39,7 +39,7 @@ func TestDecrypt(t *testing.T) {
func TestEncrypt(t *testing.T) {
for i, data := range testData {
- t.Logf("test %d. %s", i, data.kind)
+ t.Logf("test %v. %v", i, data.kind)
plainDER, err := base64.StdEncoding.DecodeString(data.plainDER)
if err != nil {
t.Fatal("cannot decode test DER data: ", err)
diff --git a/libgo/go/crypto/x509/pkix/pkix.go b/libgo/go/crypto/x509/pkix/pkix.go
index 5034946f71..8768b78590 100644
--- a/libgo/go/crypto/x509/pkix/pkix.go
+++ b/libgo/go/crypto/x509/pkix/pkix.go
@@ -30,6 +30,13 @@ type AttributeTypeAndValue struct {
Value interface{}
}
+// AttributeTypeAndValueSET represents a set of ASN.1 sequences of
+// AttributeTypeAndValue sequences from RFC 2986 (PKCS #10).
+type AttributeTypeAndValueSET struct {
+ Type asn1.ObjectIdentifier
+ Value [][]AttributeTypeAndValue `asn1:"set"`
+}
+
// Extension represents the ASN.1 structure of the same name. See RFC
// 5280, section 4.2.
type Extension struct {
@@ -157,7 +164,7 @@ type TBSCertificateList struct {
Signature AlgorithmIdentifier
Issuer RDNSequence
ThisUpdate time.Time
- NextUpdate time.Time
+ NextUpdate time.Time `asn1:"optional"`
RevokedCertificates []RevokedCertificate `asn1:"optional"`
Extensions []Extension `asn1:"tag:0,optional,explicit"`
}
diff --git a/libgo/go/crypto/x509/root_cgo_darwin.go b/libgo/go/crypto/x509/root_cgo_darwin.go
new file mode 100644
index 0000000000..bdcc2c1708
--- /dev/null
+++ b/libgo/go/crypto/x509/root_cgo_darwin.go
@@ -0,0 +1,79 @@
+// 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 cgo
+
+package x509
+
+/*
+#cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1060
+#cgo LDFLAGS: -framework CoreFoundation -framework Security
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <Security/Security.h>
+
+// FetchPEMRoots fetches the system's list of trusted X.509 root certificates.
+//
+// On success it returns 0 and fills pemRoots with a CFDataRef that contains the extracted root
+// certificates of the system. On failure, the function returns -1.
+//
+// Note: The CFDataRef returned in pemRoots must be released (using CFRelease) after
+// we've consumed its content.
+int FetchPEMRoots(CFDataRef *pemRoots) {
+ if (pemRoots == NULL) {
+ return -1;
+ }
+
+ CFArrayRef certs = NULL;
+ OSStatus err = SecTrustCopyAnchorCertificates(&certs);
+ if (err != noErr) {
+ return -1;
+ }
+
+ CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
+ int i, ncerts = CFArrayGetCount(certs);
+ for (i = 0; i < ncerts; i++) {
+ CFDataRef data = NULL;
+ SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, i);
+ if (cert == NULL) {
+ continue;
+ }
+
+ // Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport.
+ // Once we support weak imports via cgo we should prefer that, and fall back to this
+ // for older systems.
+ err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
+ if (err != noErr) {
+ continue;
+ }
+
+ if (data != NULL) {
+ CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data));
+ CFRelease(data);
+ }
+ }
+
+ CFRelease(certs);
+
+ *pemRoots = combinedData;
+ return 0;
+}
+*/
+import "C"
+import "unsafe"
+
+func initSystemRoots() {
+ roots := NewCertPool()
+
+ var data C.CFDataRef = nil
+ err := C.FetchPEMRoots(&data)
+ if err == -1 {
+ return
+ }
+
+ defer C.CFRelease(C.CFTypeRef(data))
+ buf := C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(data)), C.int(C.CFDataGetLength(data)))
+ roots.AppendCertsFromPEM(buf)
+ systemRoots = roots
+}
diff --git a/libgo/go/crypto/x509/root_darwin.go b/libgo/go/crypto/x509/root_darwin.go
index ad3bfb4b43..2a61d36eae 100644
--- a/libgo/go/crypto/x509/root_darwin.go
+++ b/libgo/go/crypto/x509/root_darwin.go
@@ -1,81 +1,23 @@
-// Copyright 2011 The Go Authors. All rights reserved.
+// 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 x509
-/*
-#cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1060
-#cgo LDFLAGS: -framework CoreFoundation -framework Security
-
-#include <CoreFoundation/CoreFoundation.h>
-#include <Security/Security.h>
-
-// FetchPEMRoots fetches the system's list of trusted X.509 root certificates.
-//
-// On success it returns 0 and fills pemRoots with a CFDataRef that contains the extracted root
-// certificates of the system. On failure, the function returns -1.
-//
-// Note: The CFDataRef returned in pemRoots must be released (using CFRelease) after
-// we've consumed its content.
-int FetchPEMRoots(CFDataRef *pemRoots) {
- if (pemRoots == NULL) {
- return -1;
- }
-
- CFArrayRef certs = NULL;
- OSStatus err = SecTrustCopyAnchorCertificates(&certs);
- if (err != noErr) {
- return -1;
- }
-
- CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
- int i, ncerts = CFArrayGetCount(certs);
- for (i = 0; i < ncerts; i++) {
- CFDataRef data = NULL;
- SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, i);
- if (cert == NULL) {
- continue;
- }
-
- // Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport.
- // Once we support weak imports via cgo we should prefer that, and fall back to this
- // for older systems.
- err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
- if (err != noErr) {
- continue;
- }
-
- if (data != NULL) {
- CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data));
- CFRelease(data);
- }
- }
-
- CFRelease(certs);
-
- *pemRoots = combinedData;
- return 0;
-}
-*/
-import "C"
-import "unsafe"
+import "os/exec"
func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
return nil, nil
}
-func initSystemRoots() {
- roots := NewCertPool()
-
- var data C.CFDataRef = nil
- err := C.FetchPEMRoots(&data)
- if err == -1 {
- return
+func execSecurityRoots() (*CertPool, 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
}
- defer C.CFRelease(C.CFTypeRef(data))
- buf := C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(data)), C.int(C.CFDataGetLength(data)))
- roots.AppendCertsFromPEM(buf)
- systemRoots = roots
+ roots := NewCertPool()
+ roots.AppendCertsFromPEM(data)
+ return roots, nil
}
diff --git a/libgo/go/crypto/x509/root_nocgo_darwin.go b/libgo/go/crypto/x509/root_nocgo_darwin.go
new file mode 100644
index 0000000000..d00e257662
--- /dev/null
+++ b/libgo/go/crypto/x509/root_nocgo_darwin.go
@@ -0,0 +1,11 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !cgo
+
+package x509
+
+func initSystemRoots() {
+ systemRoots, _ = execSecurityRoots()
+}
diff --git a/libgo/go/crypto/x509/root_stub.go b/libgo/go/crypto/x509/root_stub.go
deleted file mode 100644
index 4c742ccc37..0000000000
--- a/libgo/go/crypto/x509/root_stub.go
+++ /dev/null
@@ -1,14 +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,!cgo
-
-package x509
-
-func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
- return nil, nil
-}
-
-func initSystemRoots() {
-}
diff --git a/libgo/go/crypto/x509/root_unix.go b/libgo/go/crypto/x509/root_unix.go
index 324f855b13..f77d6c0c57 100644
--- a/libgo/go/crypto/x509/root_unix.go
+++ b/libgo/go/crypto/x509/root_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 dragonfly freebsd linux openbsd netbsd
+// +build dragonfly freebsd linux nacl netbsd openbsd solaris
package x509
@@ -15,6 +15,15 @@ var certFiles = []string{
"/etc/ssl/ca-bundle.pem", // OpenSUSE
"/etc/ssl/cert.pem", // OpenBSD
"/usr/local/share/certs/ca-root-nss.crt", // FreeBSD/DragonFly
+ "/etc/pki/tls/cacert.pem", // OpenELEC
+ "/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) {
@@ -32,6 +41,24 @@ func initSystemRoots() {
}
}
+ for _, directory := range certDirectories {
+ fis, err := ioutil.ReadDir(directory)
+ if err != nil {
+ continue
+ }
+ rootsAdded := false
+ for _, fi := range fis {
+ data, err := ioutil.ReadFile(directory + "/" + fi.Name())
+ if err == nil && roots.AppendCertsFromPEM(data) {
+ rootsAdded = true
+ }
+ }
+ if rootsAdded {
+ systemRoots = roots
+ return
+ }
+ }
+
// All of the files failed to load. systemRoots will be nil which will
// trigger a specific error at verification time.
}
diff --git a/libgo/go/crypto/x509/verify.go b/libgo/go/crypto/x509/verify.go
index 8327463ca8..ec1981423d 100644
--- a/libgo/go/crypto/x509/verify.go
+++ b/libgo/go/crypto/x509/verify.go
@@ -116,10 +116,9 @@ func (e UnknownAuthorityError) Error() string {
}
// SystemRootsError results when we fail to load the system root certificates.
-type SystemRootsError struct {
-}
+type SystemRootsError struct{}
-func (e SystemRootsError) Error() string {
+func (SystemRootsError) Error() string {
return "x509: failed to load system roots and no roots provided"
}
@@ -206,6 +205,9 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
// needed. If successful, it returns one or more chains where the first
// element of the chain is c and the last element is from opts.Roots.
//
+// If opts.Roots is nil and system roots are unavailable the returned error
+// will be of type SystemRootsError.
+//
// WARNING: this doesn't do any revocation checking.
func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
// Use Windows's own verification and chain building.
@@ -425,6 +427,7 @@ func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool {
// by each certificate. If we cross out all the usages, then the chain
// is unacceptable.
+NextCert:
for i := len(chain) - 1; i >= 0; i-- {
cert := chain[i]
if len(cert.ExtKeyUsage) == 0 && len(cert.UnknownExtKeyUsage) == 0 {
@@ -435,7 +438,7 @@ func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool {
for _, usage := range cert.ExtKeyUsage {
if usage == ExtKeyUsageAny {
// The certificate is explicitly good for any usage.
- continue
+ continue NextCert
}
}
diff --git a/libgo/go/crypto/x509/verify_test.go b/libgo/go/crypto/x509/verify_test.go
index ba6c13d451..96b9d9b420 100644
--- a/libgo/go/crypto/x509/verify_test.go
+++ b/libgo/go/crypto/x509/verify_test.go
@@ -31,8 +31,8 @@ type verifyTest struct {
var verifyTests = []verifyTest{
{
leaf: googleLeaf,
- intermediates: []string{thawteIntermediate},
- currentTime: 1302726541,
+ intermediates: []string{giag2Intermediate},
+ currentTime: 1395785200,
dnsName: "www.google.com",
testSystemRootsError: true,
@@ -42,39 +42,39 @@ var verifyTests = []verifyTest{
},
{
leaf: googleLeaf,
- intermediates: []string{thawteIntermediate},
- roots: []string{verisignRoot},
- currentTime: 1302726541,
+ intermediates: []string{giag2Intermediate},
+ roots: []string{geoTrustRoot},
+ currentTime: 1395785200,
dnsName: "www.google.com",
expectedChains: [][]string{
- {"Google", "Thawte", "VeriSign"},
+ {"Google", "Google Internet Authority", "GeoTrust"},
},
},
{
leaf: googleLeaf,
- intermediates: []string{thawteIntermediate},
- roots: []string{verisignRoot},
- currentTime: 1302726541,
+ intermediates: []string{giag2Intermediate},
+ roots: []string{geoTrustRoot},
+ currentTime: 1395785200,
dnsName: "WwW.GooGLE.coM",
expectedChains: [][]string{
- {"Google", "Thawte", "VeriSign"},
+ {"Google", "Google Internet Authority", "GeoTrust"},
},
},
{
leaf: googleLeaf,
- intermediates: []string{thawteIntermediate},
- roots: []string{verisignRoot},
- currentTime: 1302726541,
+ intermediates: []string{giag2Intermediate},
+ roots: []string{geoTrustRoot},
+ currentTime: 1395785200,
dnsName: "www.example.com",
errorCallback: expectHostnameError,
},
{
leaf: googleLeaf,
- intermediates: []string{thawteIntermediate},
- roots: []string{verisignRoot},
+ intermediates: []string{giag2Intermediate},
+ roots: []string{geoTrustRoot},
currentTime: 1,
dnsName: "www.example.com",
@@ -82,8 +82,8 @@ var verifyTests = []verifyTest{
},
{
leaf: googleLeaf,
- roots: []string{verisignRoot},
- currentTime: 1302726541,
+ roots: []string{geoTrustRoot},
+ currentTime: 1395785200,
dnsName: "www.google.com",
// Skip when using systemVerify, since Windows
@@ -93,14 +93,22 @@ var verifyTests = []verifyTest{
},
{
leaf: googleLeaf,
- intermediates: []string{verisignRoot, thawteIntermediate},
- roots: []string{verisignRoot},
- currentTime: 1302726541,
+ intermediates: []string{geoTrustRoot, giag2Intermediate},
+ roots: []string{geoTrustRoot},
+ currentTime: 1395785200,
dnsName: "www.google.com",
expectedChains: [][]string{
- {"Google", "Thawte", "VeriSign"},
+ {"Google", "Google Internet Authority", "GeoTrust"},
+ // TODO(agl): this is ok, but it would be nice if the
+ // chain building didn't visit the same SPKI
+ // twice.
+ {"Google", "Google Internet Authority", "GeoTrust", "GeoTrust"},
},
+ // CAPI doesn't build the chain with the duplicated GeoTrust
+ // entry so the results don't match. Thus we skip this test
+ // until that's fixed.
+ systemSkip: true,
},
{
leaf: dnssecExpLeaf,
@@ -128,9 +136,9 @@ var verifyTests = []verifyTest{
},
{
leaf: googleLeafWithInvalidHash,
- intermediates: []string{thawteIntermediate},
- roots: []string{verisignRoot},
- currentTime: 1302726541,
+ intermediates: []string{giag2Intermediate},
+ roots: []string{geoTrustRoot},
+ currentTime: 1395785200,
dnsName: "www.google.com",
// The specific error message may not occur when using system
@@ -201,6 +209,24 @@ var verifyTests = []verifyTest{
},
},
},
+ {
+ // Check that SHA-384 intermediates (which are popping up)
+ // work.
+ leaf: moipLeafCert,
+ intermediates: []string{comodoIntermediateSHA384, comodoRSAAuthority},
+ roots: []string{addTrustRoot},
+ currentTime: 1397502195,
+ dnsName: "api.moip.com.br",
+
+ expectedChains: [][]string{
+ {
+ "api.moip.com.br",
+ "COMODO RSA Extended Validation Secure Server CA",
+ "COMODO RSA Certification Authority",
+ "AddTrust External CA Root",
+ },
+ },
+ },
}
func expectHostnameError(t *testing.T, i int, err error) (ok bool) {
@@ -385,84 +411,111 @@ func nameToKey(name *pkix.Name) string {
return strings.Join(name.Country, ",") + "/" + strings.Join(name.Organization, ",") + "/" + strings.Join(name.OrganizationalUnit, ",") + "/" + name.CommonName
}
-const verisignRoot = `-----BEGIN CERTIFICATE-----
-MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG
-A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
-cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2
-MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV
-BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt
-YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN
-ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE
-BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is
-I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G
-CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do
-lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc
-AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k
+const geoTrustRoot = `-----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-----
`
-const thawteIntermediate = `-----BEGIN CERTIFICATE-----
-MIIDIzCCAoygAwIBAgIEMAAAAjANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJV
-UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDMgUHVi
-bGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNTEzMDAw
-MDAwWhcNMTQwNTEyMjM1OTU5WjBMMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhh
-d3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBD
-QTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1NNn0I0Vf67NMf59HZGhPwtx
-PKzMyGT7Y/wySweUvW+Aui/hBJPAM/wJMyPpC3QrccQDxtLN4i/1CWPN/0ilAL/g
-5/OIty0y3pg25gqtAHvEZEo7hHUD8nCSfQ5i9SGraTaEMXWQ+L/HbIgbBpV8yeWo
-3nWhLHpo39XKHIdYYBkCAwEAAaOB/jCB+zASBgNVHRMBAf8ECDAGAQH/AgEAMAsG
-A1UdDwQEAwIBBjARBglghkgBhvhCAQEEBAMCAQYwKAYDVR0RBCEwH6QdMBsxGTAX
-BgNVBAMTEFByaXZhdGVMYWJlbDMtMTUwMQYDVR0fBCowKDAmoCSgIoYgaHR0cDov
-L2NybC52ZXJpc2lnbi5jb20vcGNhMy5jcmwwMgYIKwYBBQUHAQEEJjAkMCIGCCsG
-AQUFBzABhhZodHRwOi8vb2NzcC50aGF3dGUuY29tMDQGA1UdJQQtMCsGCCsGAQUF
-BwMBBggrBgEFBQcDAgYJYIZIAYb4QgQBBgpghkgBhvhFAQgBMA0GCSqGSIb3DQEB
-BQUAA4GBAFWsY+reod3SkF+fC852vhNRj5PZBSvIG3dLrWlQoe7e3P3bB+noOZTc
-q3J5Lwa/q4FwxKjt6lM07e8eU9kGx1Yr0Vz00YqOtCuxN5BICEIlxT6Ky3/rbwTR
-bcV0oveifHtgPHfNDs5IAn8BL7abN+AqKjbc1YXWrOU/VG+WHgWv
+const giag2Intermediate = `-----BEGIN CERTIFICATE-----
+MIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
+MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
+YWwgQ0EwHhcNMTMwNDA1MTUxNTU1WhcNMTUwNDA0MTUxNTU1WjBJMQswCQYDVQQG
+EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy
+bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP
+VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv
+h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE
+ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ
+EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC
+DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB+zCB+DAfBgNVHSMEGDAWgBTAephojYn7
+qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wEgYD
+VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMwMTAvoC2g
+K4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwPQYI
+KwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vZ3RnbG9iYWwtb2NzcC5n
+ZW90cnVzdC5jb20wFwYDVR0gBBAwDjAMBgorBgEEAdZ5AgUBMA0GCSqGSIb3DQEB
+BQUAA4IBAQA21waAESetKhSbOHezI6B1WLuxfoNCunLaHtiONgaX4PCVOzf9G0JY
+/iLIa704XtE7JW4S615ndkZAkNoUyHgN7ZVm2o6Gb4ChulYylYbc3GrKBIxbf/a/
+zG+FA1jDaFETzf3I93k9mTXwVqO94FntT0QJo544evZG0R0SnU++0ED8Vf4GXjza
+HFa9llF7b1cq26KqltyMdMKVvvBulRP/F/A8rLIQjcxz++iPAsbw+zOzlTvjwsto
+WHPbqCRiOwY1nQ2pM714A5AuTHhdUDqB1O6gyHA43LL5Z/qHQF1hwFGPa4NrzQU6
+yuGnBXj8ytqU0CwIPX4WecigUCAkVDNx
-----END CERTIFICATE-----
`
const googleLeaf = `-----BEGIN CERTIFICATE-----
-MIIDITCCAoqgAwIBAgIQL9+89q6RUm0PmqPfQDQ+mjANBgkqhkiG9w0BAQUFADBM
-MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg
-THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0wOTEyMTgwMDAwMDBaFw0x
-MTEyMTgyMzU5NTlaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh
-MRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRcw
-FQYDVQQDFA53d3cuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC
-gYEA6PmGD5D6htffvXImttdEAoN4c9kCKO+IRTn7EOh8rqk41XXGOOsKFQebg+jN
-gtXj9xVoRaELGYW84u+E593y17iYwqG7tcFR39SDAqc9BkJb4SLD3muFXxzW2k6L
-05vuuWciKh0R73mkszeK9P4Y/bz5RiNQl/Os/CRGK1w7t0UCAwEAAaOB5zCB5DAM
-BgNVHRMBAf8EAjAAMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwudGhhd3Rl
-LmNvbS9UaGF3dGVTR0NDQS5jcmwwKAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUF
-BwMCBglghkgBhvhCBAEwcgYIKwYBBQUHAQEEZjBkMCIGCCsGAQUFBzABhhZodHRw
-Oi8vb2NzcC50aGF3dGUuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vd3d3LnRoYXd0
-ZS5jb20vcmVwb3NpdG9yeS9UaGF3dGVfU0dDX0NBLmNydDANBgkqhkiG9w0BAQUF
-AAOBgQCfQ89bxFApsb/isJr/aiEdLRLDLE5a+RLizrmCUi3nHX4adpaQedEkUjh5
-u2ONgJd8IyAPkU0Wueru9G2Jysa9zCRo1kNbzipYvzwY4OA8Ys+WAi0oR1A04Se6
-z5nRUP8pJcA2NhUzUnC+MY+f6H/nEQyNv4SgQhqAibAxWEEHXw==
------END CERTIFICATE-----`
+MIIEdjCCA16gAwIBAgIIcR5k4dkoe04wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE
+BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl
+cm5ldCBBdXRob3JpdHkgRzIwHhcNMTQwMzEyMDkzODMwWhcNMTQwNjEwMDAwMDAw
+WjBoMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN
+TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEXMBUGA1UEAwwOd3d3
+Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4zYCe
+m0oUBhwE0EwBr65eBOcgcQO2PaSIAB2dEP/c1EMX2tOy0ov8rk83ePhJ+MWdT1z6
+jge9X4zQQI8ZyA9qIiwrKBZOi8DNUvrqNZC7fJAVRrb9aX/99uYOJCypIbpmWG1q
+fhbHjJewhwf8xYPj71eU4rLG80a+DapWmphtfq3h52lDQIBzLVf1yYbyrTaELaz4
+NXF7HXb5YkId/gxIsSzM0aFUVu2o8sJcLYAsJqwfFKBKOMxUcn545nlspf0mTcWZ
+0APlbwsKznNs4/xCDwIxxWjjqgHrYAFl6y07i1gzbAOqdNEyR24p+3JWI8WZBlBI
+dk2KGj0W1fIfsvyxAgMBAAGjggFBMIIBPTAdBgNVHSUEFjAUBggrBgEFBQcDAQYI
+KwYBBQUHAwIwGQYDVR0RBBIwEIIOd3d3Lmdvb2dsZS5jb20waAYIKwYBBQUHAQEE
+XDBaMCsGCCsGAQUFBzAChh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lBRzIuY3J0
+MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50czEuZ29vZ2xlLmNvbS9vY3NwMB0G
+A1UdDgQWBBTXD5Bx6iqT+dmEhbFL4OUoHyZn8zAMBgNVHRMBAf8EAjAAMB8GA1Ud
+IwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEvMBcGA1UdIAQQMA4wDAYKKwYBBAHW
+eQIFATAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lB
+RzIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCR3RJtHzgDh33b/MI1ugiki+nl8Ikj
+5larbJRE/rcA5oite+QJyAr6SU1gJJ/rRrK3ItVEHr9L621BCM7GSdoNMjB9MMcf
+tJAW0kYGJ+wqKm53wG/JaOADTnnq2Mt/j6F2uvjgN/ouns1nRHufIvd370N0LeH+
+orKqTuAPzXK7imQk6+OycYABbqCtC/9qmwRd8wwn7sF97DtYfK8WuNHtFalCAwyi
+8LxJJYJCLWoMhZ+V8GZm+FOex5qkQAjnZrtNlbQJ8ro4r+rpKXtmMFFhfa+7L+PA
+Kom08eUK8skxAzfDDijZPh10VtJ66uBoiDPdT+uCBehcBIcmSTrKjFGX
+-----END CERTIFICATE-----
+`
// googleLeafWithInvalidHash is the same as googleLeaf, but the signature
// algorithm in the certificate contains a nonsense OID.
const googleLeafWithInvalidHash = `-----BEGIN CERTIFICATE-----
-MIIDITCCAoqgAwIBAgIQL9+89q6RUm0PmqPfQDQ+mjANBgkqhkiG9w0BATIFADBM
-MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg
-THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0wOTEyMTgwMDAwMDBaFw0x
-MTEyMTgyMzU5NTlaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh
-MRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRcw
-FQYDVQQDFA53d3cuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC
-gYEA6PmGD5D6htffvXImttdEAoN4c9kCKO+IRTn7EOh8rqk41XXGOOsKFQebg+jN
-gtXj9xVoRaELGYW84u+E593y17iYwqG7tcFR39SDAqc9BkJb4SLD3muFXxzW2k6L
-05vuuWciKh0R73mkszeK9P4Y/bz5RiNQl/Os/CRGK1w7t0UCAwEAAaOB5zCB5DAM
-BgNVHRMBAf8EAjAAMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwudGhhd3Rl
-LmNvbS9UaGF3dGVTR0NDQS5jcmwwKAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUF
-BwMCBglghkgBhvhCBAEwcgYIKwYBBQUHAQEEZjBkMCIGCCsGAQUFBzABhhZodHRw
-Oi8vb2NzcC50aGF3dGUuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vd3d3LnRoYXd0
-ZS5jb20vcmVwb3NpdG9yeS9UaGF3dGVfU0dDX0NBLmNydDANBgkqhkiG9w0BAVAF
-AAOBgQCfQ89bxFApsb/isJr/aiEdLRLDLE5a+RLizrmCUi3nHX4adpaQedEkUjh5
-u2ONgJd8IyAPkU0Wueru9G2Jysa9zCRo1kNbzipYvzwY4OA8Ys+WAi0oR1A04Se6
-z5nRUP8pJcA2NhUzUnC+MY+f6H/nEQyNv4SgQhqAibAxWEEHXw==
------END CERTIFICATE-----`
+MIIEdjCCA16gAwIBAgIIcR5k4dkoe04wDQYJKoZIhvcNAWAFBQAwSTELMAkGA1UE
+BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl
+cm5ldCBBdXRob3JpdHkgRzIwHhcNMTQwMzEyMDkzODMwWhcNMTQwNjEwMDAwMDAw
+WjBoMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN
+TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEXMBUGA1UEAwwOd3d3
+Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4zYCe
+m0oUBhwE0EwBr65eBOcgcQO2PaSIAB2dEP/c1EMX2tOy0ov8rk83ePhJ+MWdT1z6
+jge9X4zQQI8ZyA9qIiwrKBZOi8DNUvrqNZC7fJAVRrb9aX/99uYOJCypIbpmWG1q
+fhbHjJewhwf8xYPj71eU4rLG80a+DapWmphtfq3h52lDQIBzLVf1yYbyrTaELaz4
+NXF7HXb5YkId/gxIsSzM0aFUVu2o8sJcLYAsJqwfFKBKOMxUcn545nlspf0mTcWZ
+0APlbwsKznNs4/xCDwIxxWjjqgHrYAFl6y07i1gzbAOqdNEyR24p+3JWI8WZBlBI
+dk2KGj0W1fIfsvyxAgMBAAGjggFBMIIBPTAdBgNVHSUEFjAUBggrBgEFBQcDAQYI
+KwYBBQUHAwIwGQYDVR0RBBIwEIIOd3d3Lmdvb2dsZS5jb20waAYIKwYBBQUHAQEE
+XDBaMCsGCCsGAQUFBzAChh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lBRzIuY3J0
+MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50czEuZ29vZ2xlLmNvbS9vY3NwMB0G
+A1UdDgQWBBTXD5Bx6iqT+dmEhbFL4OUoHyZn8zAMBgNVHRMBAf8EAjAAMB8GA1Ud
+IwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEvMBcGA1UdIAQQMA4wDAYKKwYBBAHW
+eQIFATAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lB
+RzIuY3JsMA0GCSqGSIb3DQFgBQUAA4IBAQCR3RJtHzgDh33b/MI1ugiki+nl8Ikj
+5larbJRE/rcA5oite+QJyAr6SU1gJJ/rRrK3ItVEHr9L621BCM7GSdoNMjB9MMcf
+tJAW0kYGJ+wqKm53wG/JaOADTnnq2Mt/j6F2uvjgN/ouns1nRHufIvd370N0LeH+
+orKqTuAPzXK7imQk6+OycYABbqCtC/9qmwRd8wwn7sF97DtYfK8WuNHtFalCAwyi
+8LxJJYJCLWoMhZ+V8GZm+FOex5qkQAjnZrtNlbQJ8ro4r+rpKXtmMFFhfa+7L+PA
+Kom08eUK8skxAzfDDijZPh10VtJ66uBoiDPdT+uCBehcBIcmSTrKjFGX
+-----END CERTIFICATE-----
+`
const dnssecExpLeaf = `-----BEGIN CERTIFICATE-----
MIIGzTCCBbWgAwIBAgIDAdD6MA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ
@@ -936,3 +989,135 @@ AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad
DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
-----END CERTIFICATE-----`
+
+var moipLeafCert = `-----BEGIN CERTIFICATE-----
+MIIGQDCCBSigAwIBAgIRAPe/cwh7CUWizo8mYSDavLIwDQYJKoZIhvcNAQELBQAw
+gZIxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
+BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMTgwNgYD
+VQQDEy9DT01PRE8gUlNBIEV4dGVuZGVkIFZhbGlkYXRpb24gU2VjdXJlIFNlcnZl
+ciBDQTAeFw0xMzA4MTUwMDAwMDBaFw0xNDA4MTUyMzU5NTlaMIIBQjEXMBUGA1UE
+BRMOMDg3MTg0MzEwMDAxMDgxEzARBgsrBgEEAYI3PAIBAxMCQlIxGjAYBgsrBgEE
+AYI3PAIBAhMJU2FvIFBhdWxvMR0wGwYDVQQPExRQcml2YXRlIE9yZ2FuaXphdGlv
+bjELMAkGA1UEBhMCQlIxETAPBgNVBBETCDAxNDUyMDAwMRIwEAYDVQQIEwlTYW8g
+UGF1bG8xEjAQBgNVBAcTCVNhbyBQYXVsbzEtMCsGA1UECRMkQXZlbmlkYSBCcmln
+YWRlaXJvIEZhcmlhIExpbWEgLCAyOTI3MR0wGwYDVQQKExRNb2lwIFBhZ2FtZW50
+b3MgUy5BLjENMAsGA1UECxMETU9JUDEYMBYGA1UECxMPU1NMIEJsaW5kYWRvIEVW
+MRgwFgYDVQQDEw9hcGkubW9pcC5jb20uYnIwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQDN0b9x6TrXXA9hPCF8/NjqGJ++2D4LO4ZiMFTjs0VwpXy2Y1Oe
+s74/HuiLGnAHxTmAtV7IpZMibiOcTxcnDYp9oEWkf+gR+hZvwFZwyOBC7wyb3SR3
+UvV0N1ZbEVRYpN9kuX/3vjDghjDmzzBwu8a/T+y5JTym5uiJlngVAWyh/RjtIvYi
++NVkQMbyVlPGkoCe6c30pH8DKYuUCZU6DHjUsPTX3jAskqbhDSAnclX9iX0p2bmw
+KVBc+5Vh/2geyzDuquF0w+mNIYdU5h7uXvlmJnf3d2Cext5dxdL8/jezD3U0dAqI
+pYSKERbyxSkJWxdvRlhdpM9YXMJcpc88xNp1AgMBAAGjggHcMIIB2DAfBgNVHSME
+GDAWgBQ52v/KKBSKqHQTCLnkDqnS+n6daTAdBgNVHQ4EFgQU/lXuOa7DMExzZjRj
+LQWcMWGZY7swDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYw
+FAYIKwYBBQUHAwEGCCsGAQUFBwMCMEYGA1UdIAQ/MD0wOwYMKwYBBAGyMQECAQUB
+MCswKQYIKwYBBQUHAgEWHWh0dHBzOi8vc2VjdXJlLmNvbW9kby5jb20vQ1BTMFYG
+A1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0NPTU9ET1JT
+QUV4dGVuZGVkVmFsaWRhdGlvblNlY3VyZVNlcnZlckNBLmNybDCBhwYIKwYBBQUH
+AQEEezB5MFEGCCsGAQUFBzAChkVodHRwOi8vY3J0LmNvbW9kb2NhLmNvbS9DT01P
+RE9SU0FFeHRlbmRlZFZhbGlkYXRpb25TZWN1cmVTZXJ2ZXJDQS5jcnQwJAYIKwYB
+BQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTAvBgNVHREEKDAmgg9hcGku
+bW9pcC5jb20uYnKCE3d3dy5hcGkubW9pcC5jb20uYnIwDQYJKoZIhvcNAQELBQAD
+ggEBAFoTmPlaDcf+nudhjXHwud8g7/LRyA8ucb+3/vfmgbn7FUc1eprF5sJS1mA+
+pbiTyXw4IxcJq2KUj0Nw3IPOe9k84mzh+XMmdCKH+QK3NWkE9Udz+VpBOBc0dlqC
+1RH5umStYDmuZg/8/r652eeQ5kUDcJyADfpKWBgDPYaGtwzKVT4h3Aok9SLXRHx6
+z/gOaMjEDMarMCMw4VUIG1pvNraZrG5oTaALPaIXXpd8VqbQYPudYJ6fR5eY3FeW
+H/ofbYFdRcuD26MfBFWE9VGGral9Fgo8sEHffho+UWhgApuQV4/l5fMzxB5YBXyQ
+jhuy8PqqZS9OuLilTeLu4a8z2JI=
+-----END CERTIFICATE-----`
+
+var comodoIntermediateSHA384 = `-----BEGIN CERTIFICATE-----
+MIIGDjCCA/agAwIBAgIQBqdDgNTr/tQ1taP34Wq92DANBgkqhkiG9w0BAQwFADCB
+hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
+A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV
+BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTIwMjEy
+MDAwMDAwWhcNMjcwMjExMjM1OTU5WjCBkjELMAkGA1UEBhMCR0IxGzAZBgNVBAgT
+EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR
+Q09NT0RPIENBIExpbWl0ZWQxODA2BgNVBAMTL0NPTU9ETyBSU0EgRXh0ZW5kZWQg
+VmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAlVbeVLTf1QJJe9FbXKKyHo+cK2JMK40SKPMalaPGEP0p3uGf
+CzhAk9HvbpUQ/OGQF3cs7nU+e2PsYZJuTzurgElr3wDqAwB/L3XVKC/sVmePgIOj
+vdwDmZOLlJFWW6G4ajo/Br0OksxgnP214J9mMF/b5pTwlWqvyIqvgNnmiDkBfBzA
+xSr3e5Wg8narbZtyOTDr0VdVAZ1YEZ18bYSPSeidCfw8/QpKdhQhXBZzQCMZdMO6
+WAqmli7eNuWf0MLw4eDBYuPCGEUZUaoXHugjddTI0JYT/8ck0YwLJ66eetw6YWNg
+iJctXQUL5Tvrrs46R3N2qPos3cCHF+msMJn4HwIDAQABo4IBaTCCAWUwHwYDVR0j
+BBgwFoAUu69+Aj36pvE8hI6t7jiY7NkyMtQwHQYDVR0OBBYEFDna/8ooFIqodBMI
+ueQOqdL6fp1pMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMD4G
+A1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwczovL3NlY3VyZS5j
+b21vZG8uY29tL0NQUzBMBgNVHR8ERTBDMEGgP6A9hjtodHRwOi8vY3JsLmNvbW9k
+b2NhLmNvbS9DT01PRE9SU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggr
+BgEFBQcBAQRlMGMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9jcnQuY29tb2RvY2EuY29t
+L0NPTU9ET1JTQUFkZFRydXN0Q0EuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz
+cC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQEMBQADggIBAERCnUFRK0iIXZebeV4R
+AUpSGXtBLMeJPNBy3IX6WK/VJeQT+FhlZ58N/1eLqYVeyqZLsKeyLeCMIs37/3mk
+jCuN/gI9JN6pXV/kD0fQ22YlPodHDK4ixVAihNftSlka9pOlk7DgG4HyVsTIEFPk
+1Hax0VtpS3ey4E/EhOfUoFDuPPpE/NBXueEoU/1Tzdy5H3pAvTA/2GzS8+cHnx8i
+teoiccsq8FZ8/qyo0QYPFBRSTP5kKwxpKrgNUG4+BAe/eiCL+O5lCeHHSQgyPQ0o
+fkkdt0rvAucNgBfIXOBhYsvss2B5JdoaZXOcOBCgJjqwyBZ9kzEi7nQLiMBciUEA
+KKlHMd99SUWa9eanRRrSjhMQ34Ovmw2tfn6dNVA0BM7pINae253UqNpktNEvWS5e
+ojZh1CSggjMziqHRbO9haKPl0latxf1eYusVqHQSTC8xjOnB3xBLAer2VBvNfzu9
+XJ/B288ByvK6YBIhMe2pZLiySVgXbVrXzYxtvp5/4gJYp9vDLVj2dAZqmvZh+fYA
+tmnYOosxWd2R5nwnI4fdAw+PKowegwFOAWEMUnNt/AiiuSpm5HZNMaBWm9lTjaK2
+jwLI5jqmBNFI+8NKAnb9L9K8E7bobTQk+p0pisehKxTxlgBzuRPpwLk6R1YCcYAn
+pLwltum95OmYdBbxN4SBB7SC
+-----END CERTIFICATE-----`
+
+const comodoRSAAuthority = `-----BEGIN CERTIFICATE-----
+MIIFdDCCBFygAwIBAgIQJ2buVutJ846r13Ci/ITeIjANBgkqhkiG9w0BAQwFADBv
+MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk
+ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF
+eHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFow
+gYUxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
+BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMSswKQYD
+VQQDEyJDT01PRE8gUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkq
+hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAkehUktIKVrGsDSTdxc9EZ3SZKzejfSNw
+AHG8U9/E+ioSj0t/EFa9n3Byt2F/yUsPF6c947AEYe7/EZfH9IY+Cvo+XPmT5jR6
+2RRr55yzhaCCenavcZDX7P0N+pxs+t+wgvQUfvm+xKYvT3+Zf7X8Z0NyvQwA1onr
+ayzT7Y+YHBSrfuXjbvzYqOSSJNpDa2K4Vf3qwbxstovzDo2a5JtsaZn4eEgwRdWt
+4Q08RWD8MpZRJ7xnw8outmvqRsfHIKCxH2XeSAi6pE6p8oNGN4Tr6MyBSENnTnIq
+m1y9TBsoilwie7SrmNnu4FGDwwlGTm0+mfqVF9p8M1dBPI1R7Qu2XK8sYxrfV8g/
+vOldxJuvRZnio1oktLqpVj3Pb6r/SVi+8Kj/9Lit6Tf7urj0Czr56ENCHonYhMsT
+8dm74YlguIwoVqwUHZwK53Hrzw7dPamWoUi9PPevtQ0iTMARgexWO/bTouJbt7IE
+IlKVgJNp6I5MZfGRAy1wdALqi2cVKWlSArvX31BqVUa/oKMoYX9w0MOiqiwhqkfO
+KJwGRXa/ghgntNWutMtQ5mv0TIZxMOmm3xaG4Nj/QN370EKIf6MzOi5cHkERgWPO
+GHFrK+ymircxXDpqR+DDeVnWIBqv8mqYqnK8V0rSS527EPywTEHl7R09XiidnMy/
+s1Hap0flhFMCAwEAAaOB9DCB8TAfBgNVHSMEGDAWgBStvZh6NLQm9/rEJlTvA73g
+JMtUGjAdBgNVHQ4EFgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQD
+AgGGMA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0gBAowCDAGBgRVHSAAMEQGA1UdHwQ9
+MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9BZGRUcnVzdEV4dGVy
+bmFsQ0FSb290LmNybDA1BggrBgEFBQcBAQQpMCcwJQYIKwYBBQUHMAGGGWh0dHA6
+Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggEBAGS/g/FfmoXQ
+zbihKVcN6Fr30ek+8nYEbvFScLsePP9NDXRqzIGCJdPDoCpdTPW6i6FtxFQJdcfj
+Jw5dhHk3QBN39bSsHNA7qxcS1u80GH4r6XnTq1dFDK8o+tDb5VCViLvfhVdpfZLY
+Uspzgb8c8+a4bmYRBbMelC1/kZWSWfFMzqORcUx8Rww7Cxn2obFshj5cqsQugsv5
+B5a6SE2Q8pTIqXOi6wZ7I53eovNNVZ96YUWYGGjHXkBrI/V5eu+MtWuLt29G9Hvx
+PUsE2JOAWVrgQSQdso8VYFhH2+9uRv0V9dlfmrPb2LjkQLPNlzmuhbsdjrzch5vR
+pu/xO28QOG8=
+-----END CERTIFICATE-----`
+
+const addTrustRoot = `-----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-----`
diff --git a/libgo/go/crypto/x509/x509.go b/libgo/go/crypto/x509/x509.go
index 57f68ba7ed..7a37b98e31 100644
--- a/libgo/go/crypto/x509/x509.go
+++ b/libgo/go/crypto/x509/x509.go
@@ -13,6 +13,8 @@ import (
"crypto/elliptic"
"crypto/rsa"
"crypto/sha1"
+ _ "crypto/sha256"
+ _ "crypto/sha512"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/pem"
@@ -241,32 +243,31 @@ var (
oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4}
)
+var signatureAlgorithmDetails = []struct {
+ algo SignatureAlgorithm
+ oid asn1.ObjectIdentifier
+ pubKeyAlgo PublicKeyAlgorithm
+ hash crypto.Hash
+}{
+ {MD2WithRSA, oidSignatureMD2WithRSA, RSA, crypto.Hash(0) /* no value for MD2 */},
+ {MD5WithRSA, oidSignatureMD5WithRSA, RSA, crypto.MD5},
+ {SHA1WithRSA, oidSignatureSHA1WithRSA, RSA, crypto.SHA1},
+ {SHA256WithRSA, oidSignatureSHA256WithRSA, RSA, crypto.SHA256},
+ {SHA384WithRSA, oidSignatureSHA384WithRSA, RSA, crypto.SHA384},
+ {SHA512WithRSA, oidSignatureSHA512WithRSA, RSA, crypto.SHA512},
+ {DSAWithSHA1, oidSignatureDSAWithSHA1, DSA, crypto.SHA1},
+ {DSAWithSHA256, oidSignatureDSAWithSHA256, DSA, crypto.SHA256},
+ {ECDSAWithSHA1, oidSignatureECDSAWithSHA1, ECDSA, crypto.SHA1},
+ {ECDSAWithSHA256, oidSignatureECDSAWithSHA256, ECDSA, crypto.SHA256},
+ {ECDSAWithSHA384, oidSignatureECDSAWithSHA384, ECDSA, crypto.SHA384},
+ {ECDSAWithSHA512, oidSignatureECDSAWithSHA512, ECDSA, crypto.SHA512},
+}
+
func getSignatureAlgorithmFromOID(oid asn1.ObjectIdentifier) SignatureAlgorithm {
- switch {
- case oid.Equal(oidSignatureMD2WithRSA):
- return MD2WithRSA
- case oid.Equal(oidSignatureMD5WithRSA):
- return MD5WithRSA
- case oid.Equal(oidSignatureSHA1WithRSA):
- return SHA1WithRSA
- case oid.Equal(oidSignatureSHA256WithRSA):
- return SHA256WithRSA
- case oid.Equal(oidSignatureSHA384WithRSA):
- return SHA384WithRSA
- case oid.Equal(oidSignatureSHA512WithRSA):
- return SHA512WithRSA
- case oid.Equal(oidSignatureDSAWithSHA1):
- return DSAWithSHA1
- case oid.Equal(oidSignatureDSAWithSHA256):
- return DSAWithSHA256
- case oid.Equal(oidSignatureECDSAWithSHA1):
- return ECDSAWithSHA1
- case oid.Equal(oidSignatureECDSAWithSHA256):
- return ECDSAWithSHA256
- case oid.Equal(oidSignatureECDSAWithSHA384):
- return ECDSAWithSHA384
- case oid.Equal(oidSignatureECDSAWithSHA512):
- return ECDSAWithSHA512
+ for _, details := range signatureAlgorithmDetails {
+ if oid.Equal(details.oid) {
+ return details.algo
+ }
}
return UnknownSignatureAlgorithm
}
@@ -493,6 +494,11 @@ type Certificate struct {
BasicConstraintsValid bool // if true then the next two fields are valid.
IsCA bool
MaxPathLen int
+ // MaxPathLenZero indicates that BasicConstraintsValid==true and
+ // MaxPathLen==0 should be interpreted as an actual maximum path length
+ // of zero. Otherwise, that combination is interpreted as MaxPathLen
+ // not being set.
+ MaxPathLenZero bool
SubjectKeyId []byte
AuthorityKeyId []byte
@@ -790,6 +796,58 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{
}
}
+func parseSANExtension(value []byte) (dnsNames, emailAddresses []string, ipAddresses []net.IP, err error) {
+ // RFC 5280, 4.2.1.6
+
+ // SubjectAltName ::= GeneralNames
+ //
+ // GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
+ //
+ // GeneralName ::= CHOICE {
+ // otherName [0] OtherName,
+ // rfc822Name [1] IA5String,
+ // dNSName [2] IA5String,
+ // x400Address [3] ORAddress,
+ // directoryName [4] Name,
+ // ediPartyName [5] EDIPartyName,
+ // uniformResourceIdentifier [6] IA5String,
+ // iPAddress [7] OCTET STRING,
+ // registeredID [8] OBJECT IDENTIFIER }
+ var seq asn1.RawValue
+ if _, err = asn1.Unmarshal(value, &seq); err != nil {
+ return
+ }
+ if !seq.IsCompound || seq.Tag != 16 || seq.Class != 0 {
+ err = asn1.StructuralError{Msg: "bad SAN sequence"}
+ return
+ }
+
+ rest := seq.Bytes
+ for len(rest) > 0 {
+ var v asn1.RawValue
+ rest, err = asn1.Unmarshal(rest, &v)
+ if err != nil {
+ return
+ }
+ switch v.Tag {
+ case 1:
+ emailAddresses = append(emailAddresses, string(v.Bytes))
+ case 2:
+ dnsNames = append(dnsNames, string(v.Bytes))
+ case 7:
+ switch len(v.Bytes) {
+ case net.IPv4len, net.IPv6len:
+ ipAddresses = append(ipAddresses, v.Bytes)
+ default:
+ err = errors.New("x509: certificate contained IP address of length " + strconv.Itoa(len(v.Bytes)))
+ return
+ }
+ }
+ }
+
+ return
+}
+
func parseCertificate(in *certificate) (*Certificate, error) {
out := new(Certificate)
out.Raw = in.Raw
@@ -860,61 +918,16 @@ func parseCertificate(in *certificate) (*Certificate, error) {
out.BasicConstraintsValid = true
out.IsCA = constraints.IsCA
out.MaxPathLen = constraints.MaxPathLen
+ out.MaxPathLenZero = out.MaxPathLen == 0
continue
}
case 17:
- // RFC 5280, 4.2.1.6
-
- // SubjectAltName ::= GeneralNames
- //
- // GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
- //
- // GeneralName ::= CHOICE {
- // otherName [0] OtherName,
- // rfc822Name [1] IA5String,
- // dNSName [2] IA5String,
- // x400Address [3] ORAddress,
- // directoryName [4] Name,
- // ediPartyName [5] EDIPartyName,
- // uniformResourceIdentifier [6] IA5String,
- // iPAddress [7] OCTET STRING,
- // registeredID [8] OBJECT IDENTIFIER }
- var seq asn1.RawValue
- _, err := asn1.Unmarshal(e.Value, &seq)
+ out.DNSNames, out.EmailAddresses, out.IPAddresses, err = parseSANExtension(e.Value)
if err != nil {
return nil, err
}
- if !seq.IsCompound || seq.Tag != 16 || seq.Class != 0 {
- return nil, asn1.StructuralError{Msg: "bad SAN sequence"}
- }
- parsedName := false
-
- rest := seq.Bytes
- for len(rest) > 0 {
- var v asn1.RawValue
- rest, err = asn1.Unmarshal(rest, &v)
- if err != nil {
- return nil, err
- }
- switch v.Tag {
- case 1:
- out.EmailAddresses = append(out.EmailAddresses, string(v.Bytes))
- parsedName = true
- case 2:
- out.DNSNames = append(out.DNSNames, string(v.Bytes))
- parsedName = true
- case 7:
- switch len(v.Bytes) {
- case net.IPv4len, net.IPv6len:
- out.IPAddresses = append(out.IPAddresses, v.Bytes)
- default:
- return nil, errors.New("x509: certificate contained IP address of length " + strconv.Itoa(len(v.Bytes)))
- }
- }
- }
-
- if parsedName {
+ if len(out.DNSNames) > 0 || len(out.EmailAddresses) > 0 || len(out.IPAddresses) > 0 {
continue
}
// If we didn't parse any of the names then we
@@ -1151,6 +1164,27 @@ func oidInExtensions(oid asn1.ObjectIdentifier, extensions []pkix.Extension) boo
return false
}
+// marshalSANs marshals a list of addresses into a the contents of an X.509
+// SubjectAlternativeName extension.
+func marshalSANs(dnsNames, emailAddresses []string, ipAddresses []net.IP) (derBytes []byte, err error) {
+ var rawValues []asn1.RawValue
+ for _, name := range dnsNames {
+ rawValues = append(rawValues, asn1.RawValue{Tag: 2, Class: 2, Bytes: []byte(name)})
+ }
+ for _, email := range emailAddresses {
+ rawValues = append(rawValues, asn1.RawValue{Tag: 1, Class: 2, Bytes: []byte(email)})
+ }
+ for _, rawIP := range ipAddresses {
+ // If possible, we always want to encode IPv4 addresses in 4 bytes.
+ ip := rawIP.To4()
+ if ip == nil {
+ ip = rawIP
+ }
+ rawValues = append(rawValues, asn1.RawValue{Tag: 7, Class: 2, Bytes: ip})
+ }
+ return asn1.Marshal(rawValues)
+}
+
func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) {
ret = make([]pkix.Extension, 10 /* maximum number of elements. */)
n := 0
@@ -1199,8 +1233,15 @@ func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) {
}
if template.BasicConstraintsValid && !oidInExtensions(oidExtensionBasicConstraints, template.ExtraExtensions) {
+ // Leaving MaxPathLen as zero indicates that no maximum path
+ // length is desired, unless MaxPathLenZero is set. A value of
+ // -1 causes encoding/asn1 to omit the value as desired.
+ maxPathLen := template.MaxPathLen
+ if maxPathLen == 0 && !template.MaxPathLenZero {
+ maxPathLen = -1
+ }
ret[n].Id = oidExtensionBasicConstraints
- ret[n].Value, err = asn1.Marshal(basicConstraints{template.IsCA, template.MaxPathLen})
+ ret[n].Value, err = asn1.Marshal(basicConstraints{template.IsCA, maxPathLen})
ret[n].Critical = true
if err != nil {
return
@@ -1252,22 +1293,7 @@ func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) {
if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0) &&
!oidInExtensions(oidExtensionSubjectAltName, template.ExtraExtensions) {
ret[n].Id = oidExtensionSubjectAltName
- var rawValues []asn1.RawValue
- for _, name := range template.DNSNames {
- rawValues = append(rawValues, asn1.RawValue{Tag: 2, Class: 2, Bytes: []byte(name)})
- }
- for _, email := range template.EmailAddresses {
- rawValues = append(rawValues, asn1.RawValue{Tag: 1, Class: 2, Bytes: []byte(email)})
- }
- for _, rawIP := range template.IPAddresses {
- // If possible, we always want to encode IPv4 addresses in 4 bytes.
- ip := rawIP.To4()
- if ip == nil {
- ip = rawIP
- }
- rawValues = append(rawValues, asn1.RawValue{Tag: 7, Class: 2, Bytes: ip})
- }
- ret[n].Value, err = asn1.Marshal(rawValues)
+ ret[n].Value, err = marshalSANs(template.DNSNames, template.EmailAddresses, template.IPAddresses)
if err != nil {
return
}
@@ -1315,7 +1341,7 @@ func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) {
dp := distributionPoint{
DistributionPoint: distributionPointName{
- FullName: asn1.RawValue{Tag: 0, Class: 2, Bytes: rawFullName},
+ FullName: asn1.RawValue{Tag: 0, Class: 2, IsCompound: true, Bytes: rawFullName},
},
}
crlDp = append(crlDp, dp)
@@ -1342,11 +1368,76 @@ func subjectBytes(cert *Certificate) ([]byte, error) {
return asn1.Marshal(cert.Subject.ToRDNSequence())
}
+// signingParamsForPrivateKey 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) {
+ var pubType PublicKeyAlgorithm
+
+ switch priv := priv.(type) {
+ case *rsa.PrivateKey:
+ pubType = RSA
+ sigAlgo.Algorithm = oidSignatureSHA256WithRSA
+ hashFunc = crypto.SHA256
+
+ case *ecdsa.PrivateKey:
+ pubType = ECDSA
+
+ switch priv.Curve {
+ case elliptic.P224(), elliptic.P256():
+ hashFunc = crypto.SHA256
+ sigAlgo.Algorithm = oidSignatureECDSAWithSHA256
+ case elliptic.P384():
+ hashFunc = crypto.SHA384
+ sigAlgo.Algorithm = oidSignatureECDSAWithSHA384
+ case elliptic.P521():
+ hashFunc = crypto.SHA512
+ sigAlgo.Algorithm = oidSignatureECDSAWithSHA512
+ default:
+ err = errors.New("x509: unknown elliptic curve")
+ }
+
+ default:
+ err = errors.New("x509: only RSA and ECDSA private keys supported")
+ }
+
+ if err != nil {
+ return
+ }
+
+ if requestedSigAlgo == 0 {
+ return
+ }
+
+ found := false
+ for _, details := range signatureAlgorithmDetails {
+ if details.algo == requestedSigAlgo {
+ if details.pubKeyAlgo != pubType {
+ err = errors.New("x509: requested SignatureAlgorithm does not match private key type")
+ return
+ }
+ sigAlgo.Algorithm, hashFunc = details.oid, details.hash
+ if hashFunc == 0 {
+ err = errors.New("x509: cannot sign with hash function requested")
+ return
+ }
+ found = true
+ break
+ }
+ }
+
+ if !found {
+ err = errors.New("x509: unknown SignatureAlgorithm")
+ }
+
+ return
+}
+
// CreateCertificate creates a new certificate based on a template. The
// following members of template are used: SerialNumber, Subject, NotBefore,
// NotAfter, KeyUsage, ExtKeyUsage, UnknownExtKeyUsage, BasicConstraintsValid,
// IsCA, MaxPathLen, SubjectKeyId, DNSNames, PermittedDNSDomainsCritical,
-// PermittedDNSDomains.
+// PermittedDNSDomains, SignatureAlgorithm.
//
// The certificate is signed by parent. If parent is equal to template then the
// certificate is self-signed. The parameter pub is the public key of the
@@ -1355,38 +1446,16 @@ func subjectBytes(cert *Certificate) ([]byte, error) {
// 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.PublicKey for priv).
+// *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) {
- var publicKeyBytes []byte
- var publicKeyAlgorithm pkix.AlgorithmIdentifier
-
- if publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(pub); err != nil {
+ hashFunc, signatureAlgorithm, err := signingParamsForPrivateKey(priv, template.SignatureAlgorithm)
+ if err != nil {
return nil, err
}
- var signatureAlgorithm pkix.AlgorithmIdentifier
- var hashFunc crypto.Hash
-
- switch priv := priv.(type) {
- case *rsa.PrivateKey:
- signatureAlgorithm.Algorithm = oidSignatureSHA1WithRSA
- hashFunc = crypto.SHA1
- case *ecdsa.PrivateKey:
- switch priv.Curve {
- case elliptic.P224(), elliptic.P256():
- hashFunc = crypto.SHA256
- signatureAlgorithm.Algorithm = oidSignatureECDSAWithSHA256
- case elliptic.P384():
- hashFunc = crypto.SHA384
- signatureAlgorithm.Algorithm = oidSignatureECDSAWithSHA384
- case elliptic.P521():
- hashFunc = crypto.SHA512
- signatureAlgorithm.Algorithm = oidSignatureECDSAWithSHA512
- default:
- return nil, errors.New("x509: unknown elliptic curve")
- }
- default:
- return nil, errors.New("x509: only RSA and ECDSA private keys supported")
+ publicKeyBytes, publicKeyAlgorithm, err := marshalPublicKey(pub)
+ if err != nil {
+ return nil, err
}
if err != nil {
@@ -1535,3 +1604,313 @@ func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts [
SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
})
}
+
+// CertificateRequest represents a PKCS #10, certificate signature request.
+type CertificateRequest struct {
+ Raw []byte // Complete ASN.1 DER content (CSR, signature algorithm and signature).
+ RawTBSCertificateRequest []byte // Certificate request info part of raw ASN.1 DER content.
+ RawSubjectPublicKeyInfo []byte // DER encoded SubjectPublicKeyInfo.
+ RawSubject []byte // DER encoded Subject.
+
+ Version int
+ Signature []byte
+ SignatureAlgorithm SignatureAlgorithm
+
+ PublicKeyAlgorithm PublicKeyAlgorithm
+ PublicKey interface{}
+
+ Subject pkix.Name
+
+ // Attributes is a collection of attributes providing
+ // additional information about the subject of the certificate.
+ // See RFC 2986 section 4.1.
+ Attributes []pkix.AttributeTypeAndValueSET
+
+ // Extensions contains raw X.509 extensions. When parsing CSRs, this
+ // can be used to extract extensions that are not parsed by this
+ // package.
+ Extensions []pkix.Extension
+
+ // ExtraExtensions contains extensions to be copied, raw, into any
+ // marshaled CSR. Values override any extensions that would otherwise
+ // be produced based on the other fields but are overridden by any
+ // extensions specified in Attributes.
+ //
+ // The ExtraExtensions field is not populated when parsing CSRs, see
+ // Extensions.
+ ExtraExtensions []pkix.Extension
+
+ // Subject Alternate Name values.
+ DNSNames []string
+ EmailAddresses []string
+ IPAddresses []net.IP
+}
+
+// These structures reflect the ASN.1 structure of X.509 certificate
+// signature requests (see RFC 2986):
+
+type tbsCertificateRequest struct {
+ Raw asn1.RawContent
+ Version int
+ Subject asn1.RawValue
+ PublicKey publicKeyInfo
+ Attributes []pkix.AttributeTypeAndValueSET `asn1:"tag:0"`
+}
+
+type certificateRequest struct {
+ Raw asn1.RawContent
+ TBSCSR tbsCertificateRequest
+ SignatureAlgorithm pkix.AlgorithmIdentifier
+ SignatureValue asn1.BitString
+}
+
+// oidExtensionRequest is a PKCS#9 OBJECT IDENTIFIER that indicates requested
+// extensions in a CSR.
+var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14}
+
+// CreateCertificateRequest creates a new certificate based on a template. The
+// following members of template are used: Subject, Attributes,
+// SignatureAlgorithm, Extensions, DNSNames, EmailAddresses, and IPAddresses.
+// The private key is the private key of the signer.
+//
+// The returned slice is the certificate request in DER encoding.
+//
+// The only supported key types are RSA (*rsa.PrivateKey) and ECDSA
+// (*ecdsa.PrivateKey).
+func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv interface{}) (csr []byte, err error) {
+ hashFunc, sigAlgo, err := signingParamsForPrivateKey(priv, 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")
+ }
+
+ if err != nil {
+ return nil, err
+ }
+
+ var extensions []pkix.Extension
+
+ if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0) &&
+ !oidInExtensions(oidExtensionSubjectAltName, template.ExtraExtensions) {
+ sanBytes, err := marshalSANs(template.DNSNames, template.EmailAddresses, template.IPAddresses)
+ if err != nil {
+ return nil, err
+ }
+
+ extensions = append(extensions, pkix.Extension{
+ Id: oidExtensionSubjectAltName,
+ Value: sanBytes,
+ })
+ }
+
+ extensions = append(extensions, template.ExtraExtensions...)
+
+ var attributes []pkix.AttributeTypeAndValueSET
+ attributes = append(attributes, template.Attributes...)
+
+ if len(extensions) > 0 {
+ // specifiedExtensions contains all the extensions that we
+ // found specified via template.Attributes.
+ specifiedExtensions := make(map[string]bool)
+
+ for _, atvSet := range template.Attributes {
+ if !atvSet.Type.Equal(oidExtensionRequest) {
+ continue
+ }
+
+ for _, atvs := range atvSet.Value {
+ for _, atv := range atvs {
+ specifiedExtensions[atv.Type.String()] = true
+ }
+ }
+ }
+
+ atvs := make([]pkix.AttributeTypeAndValue, 0, len(extensions))
+ for _, e := range extensions {
+ if specifiedExtensions[e.Id.String()] {
+ // Attributes already contained a value for
+ // this extension and it takes priority.
+ continue
+ }
+
+ atvs = append(atvs, pkix.AttributeTypeAndValue{
+ // There is no place for the critical flag in a CSR.
+ Type: e.Id,
+ Value: e.Value,
+ })
+ }
+
+ // Append the extensions to an existing attribute if possible.
+ appended := false
+ for _, atvSet := range attributes {
+ if !atvSet.Type.Equal(oidExtensionRequest) || len(atvSet.Value) == 0 {
+ continue
+ }
+
+ atvSet.Value[0] = append(atvSet.Value[0], atvs...)
+ appended = true
+ break
+ }
+
+ // Otherwise, add a new attribute for the extensions.
+ if !appended {
+ attributes = append(attributes, pkix.AttributeTypeAndValueSET{
+ Type: oidExtensionRequest,
+ Value: [][]pkix.AttributeTypeAndValue{
+ atvs,
+ },
+ })
+ }
+ }
+
+ asn1Subject := template.RawSubject
+ if len(asn1Subject) == 0 {
+ asn1Subject, err = asn1.Marshal(template.Subject.ToRDNSequence())
+ if err != nil {
+ return
+ }
+ }
+
+ tbsCSR := tbsCertificateRequest{
+ Version: 0, // PKCS #10, RFC 2986
+ Subject: asn1.RawValue{FullBytes: asn1Subject},
+ PublicKey: publicKeyInfo{
+ Algorithm: publicKeyAlgorithm,
+ PublicKey: asn1.BitString{
+ Bytes: publicKeyBytes,
+ BitLength: len(publicKeyBytes) * 8,
+ },
+ },
+ Attributes: attributes,
+ }
+
+ tbsCSRContents, err := asn1.Marshal(tbsCSR)
+ if err != nil {
+ return
+ }
+ tbsCSR.Raw = tbsCSRContents
+
+ h := hashFunc.New()
+ h.Write(tbsCSRContents)
+ 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")
+ }
+
+ if err != nil {
+ return
+ }
+
+ return asn1.Marshal(certificateRequest{
+ TBSCSR: tbsCSR,
+ SignatureAlgorithm: sigAlgo,
+ SignatureValue: asn1.BitString{
+ Bytes: signature,
+ BitLength: len(signature) * 8,
+ },
+ })
+}
+
+// ParseCertificateRequest parses a single certificate request from the
+// given ASN.1 DER data.
+func ParseCertificateRequest(asn1Data []byte) (*CertificateRequest, error) {
+ var csr certificateRequest
+
+ rest, err := asn1.Unmarshal(asn1Data, &csr)
+ if err != nil {
+ return nil, err
+ } else if len(rest) != 0 {
+ return nil, asn1.SyntaxError{Msg: "trailing data"}
+ }
+
+ return parseCertificateRequest(&csr)
+}
+
+func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error) {
+ out := &CertificateRequest{
+ Raw: in.Raw,
+ RawTBSCertificateRequest: in.TBSCSR.Raw,
+ RawSubjectPublicKeyInfo: in.TBSCSR.PublicKey.Raw,
+ RawSubject: in.TBSCSR.Subject.FullBytes,
+
+ Signature: in.SignatureValue.RightAlign(),
+ SignatureAlgorithm: getSignatureAlgorithmFromOID(in.SignatureAlgorithm.Algorithm),
+
+ PublicKeyAlgorithm: getPublicKeyAlgorithmFromOID(in.TBSCSR.PublicKey.Algorithm.Algorithm),
+
+ Version: in.TBSCSR.Version,
+ Attributes: in.TBSCSR.Attributes,
+ }
+
+ var err error
+ out.PublicKey, err = parsePublicKey(out.PublicKeyAlgorithm, &in.TBSCSR.PublicKey)
+ if err != nil {
+ return nil, err
+ }
+
+ var subject pkix.RDNSequence
+ if _, err := asn1.Unmarshal(in.TBSCSR.Subject.FullBytes, &subject); err != nil {
+ return nil, err
+ }
+
+ out.Subject.FillFromRDNSequence(&subject)
+
+ var extensions []pkix.AttributeTypeAndValue
+
+ for _, atvSet := range in.TBSCSR.Attributes {
+ if !atvSet.Type.Equal(oidExtensionRequest) {
+ continue
+ }
+
+ for _, atvs := range atvSet.Value {
+ extensions = append(extensions, atvs...)
+ }
+ }
+
+ out.Extensions = make([]pkix.Extension, 0, len(extensions))
+
+ for _, e := range extensions {
+ value, ok := e.Value.([]byte)
+ if !ok {
+ return nil, errors.New("x509: extension attribute contained non-OCTET STRING data")
+ }
+
+ out.Extensions = append(out.Extensions, pkix.Extension{
+ Id: e.Type,
+ Value: value,
+ })
+
+ if len(e.Type) == 4 && e.Type[0] == 2 && e.Type[1] == 5 && e.Type[2] == 29 {
+ switch e.Type[3] {
+ case 17:
+ out.DNSNames, out.EmailAddresses, out.IPAddresses, err = parseSANExtension(value)
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+ }
+
+ return out, nil
+}
diff --git a/libgo/go/crypto/x509/x509_test.go b/libgo/go/crypto/x509/x509_test.go
index f1097e992e..4f1f0c2cc6 100644
--- a/libgo/go/crypto/x509/x509_test.go
+++ b/libgo/go/crypto/x509/x509_test.go
@@ -20,7 +20,9 @@ import (
"encoding/pem"
"math/big"
"net"
+ "os/exec"
"reflect"
+ "runtime"
"testing"
"time"
)
@@ -305,11 +307,12 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
name string
pub, priv interface{}
checkSig bool
+ sigAlgo SignatureAlgorithm
}{
- {"RSA/RSA", &rsaPriv.PublicKey, rsaPriv, true},
- {"RSA/ECDSA", &rsaPriv.PublicKey, ecdsaPriv, false},
- {"ECDSA/RSA", &ecdsaPriv.PublicKey, rsaPriv, false},
- {"ECDSA/ECDSA", &ecdsaPriv.PublicKey, ecdsaPriv, true},
+ {"RSA/RSA", &rsaPriv.PublicKey, rsaPriv, true, SHA1WithRSA},
+ {"RSA/ECDSA", &rsaPriv.PublicKey, ecdsaPriv, false, ECDSAWithSHA384},
+ {"ECDSA/RSA", &ecdsaPriv.PublicKey, rsaPriv, false, SHA256WithRSA},
+ {"ECDSA/ECDSA", &ecdsaPriv.PublicKey, ecdsaPriv, true, ECDSAWithSHA1},
}
testExtKeyUsage := []ExtKeyUsage{ExtKeyUsageClientAuth, ExtKeyUsageServerAuth}
@@ -327,6 +330,8 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
NotBefore: time.Unix(1000, 0),
NotAfter: time.Unix(100000, 0),
+ SignatureAlgorithm: test.sigAlgo,
+
SubjectKeyId: []byte{1, 2, 3, 4},
KeyUsage: KeyUsageCertSign,
@@ -390,6 +395,10 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
t.Errorf("%s: issuer wasn't correctly copied from the template. Got %s, want %s", test.name, cert.Issuer.CommonName, commonName)
}
+ if cert.SignatureAlgorithm != test.sigAlgo {
+ t.Errorf("%s: SignatureAlgorithm wasn't copied from template. Got %v, want %v", test.name, cert.SignatureAlgorithm, test.sigAlgo)
+ }
+
if !reflect.DeepEqual(cert.ExtKeyUsage, testExtKeyUsage) {
t.Errorf("%s: extkeyusage wasn't correctly copied from the template. Got %v, want %v", test.name, cert.ExtKeyUsage, testExtKeyUsage)
}
@@ -671,11 +680,11 @@ func TestCRLCreation(t *testing.T) {
func fromBase64(in string) []byte {
out := make([]byte, base64.StdEncoding.DecodedLen(len(in)))
- _, err := base64.StdEncoding.Decode(out, []byte(in))
+ n, err := base64.StdEncoding.Decode(out, []byte(in))
if err != nil {
panic("failed to base64 decode")
}
- return out
+ return out[:n]
}
func TestParseDERCRL(t *testing.T) {
@@ -698,6 +707,17 @@ func TestParseDERCRL(t *testing.T) {
// Can't check the signature here without a package cycle.
}
+func TestCRLWithoutExpiry(t *testing.T) {
+ derBytes := fromBase64("MIHYMIGZMAkGByqGSM44BAMwEjEQMA4GA1UEAxMHQ2FybERTUxcNOTkwODI3MDcwMDAwWjBpMBMCAgDIFw05OTA4MjIwNzAwMDBaMBMCAgDJFw05OTA4MjIwNzAwMDBaMBMCAgDTFw05OTA4MjIwNzAwMDBaMBMCAgDSFw05OTA4MjIwNzAwMDBaMBMCAgDUFw05OTA4MjQwNzAwMDBaMAkGByqGSM44BAMDLwAwLAIUfmVSdjP+NHMX0feW+aDU2G1cfT0CFAJ6W7fVWxjBz4fvftok8yqDnDWh")
+ certList, err := ParseDERCRL(derBytes)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !certList.TBSCertList.NextUpdate.IsZero() {
+ t.Errorf("NextUpdate is not the zero value")
+ }
+}
+
func TestParsePEMCRL(t *testing.T) {
pemBytes := fromBase64(pemCRLBase64)
certList, err := ParseCRL(pemBytes)
@@ -718,6 +738,291 @@ func TestParsePEMCRL(t *testing.T) {
// Can't check the signature here without a package cycle.
}
+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)
+ }
+
+ if err := exec.Command("go", "run", "x509_test_import.go").Run(); err != nil {
+ t.Errorf("failed to run x509_test_import.go: %s", err)
+ }
+}
+
const derCRLBase64 = "MIINqzCCDJMCAQEwDQYJKoZIhvcNAQEFBQAwVjEZMBcGA1UEAxMQUEtJIEZJTk1FQ0NBTklDQTEVMBMGA1UEChMMRklOTUVDQ0FOSUNBMRUwEwYDVQQLEwxGSU5NRUNDQU5JQ0ExCzAJBgNVBAYTAklUFw0xMTA1MDQxNjU3NDJaFw0xMTA1MDQyMDU3NDJaMIIMBzAhAg4Ze1od49Lt1qIXBydAzhcNMDkwNzE2MDg0MzIyWjAAMCECDl0HSL9bcZ1Ci/UHJ0DPFw0wOTA3MTYwODQzMTNaMAAwIQIOESB9tVAmX3cY7QcnQNAXDTA5MDcxNjA4NDUyMlowADAhAg4S1tGAQ3mHt8uVBydA1RcNMDkwODA0MTUyNTIyWjAAMCECDlQ249Y7vtC25ScHJ0DWFw0wOTA4MDQxNTI1MzdaMAAwIQIOISMop3NkA4PfYwcnQNkXDTA5MDgwNDExMDAzNFowADAhAg56/BMoS29KEShTBydA2hcNMDkwODA0MTEwMTAzWjAAMCECDnBp/22HPH5CSWoHJ0DbFw0wOTA4MDQxMDU0NDlaMAAwIQIOV9IP+8CD8bK+XAcnQNwXDTA5MDgwNDEwNTcxN1owADAhAg4v5aRz0IxWqYiXBydA3RcNMDkwODA0MTA1NzQ1WjAAMCECDlOU34VzvZAybQwHJ0DeFw0wOTA4MDQxMDU4MjFaMAAwIAINO4CD9lluIxcwBydBAxcNMDkwNzIyMTUzMTU5WjAAMCECDgOllfO8Y1QA7/wHJ0ExFw0wOTA3MjQxMTQxNDNaMAAwIQIOJBX7jbiCdRdyjgcnQUQXDTA5MDkxNjA5MzAwOFowADAhAg5iYSAgmDrlH/RZBydBRRcNMDkwOTE2MDkzMDE3WjAAMCECDmu6k6srP3jcMaQHJ0FRFw0wOTA4MDQxMDU2NDBaMAAwIQIOX8aHlO0V+WVH4QcnQVMXDTA5MDgwNDEwNTcyOVowADAhAg5flK2rg3NnsRgDBydBzhcNMTEwMjAxMTUzMzQ2WjAAMCECDg35yJDL1jOPTgoHJ0HPFw0xMTAyMDExNTM0MjZaMAAwIQIOMyFJ6+e9iiGVBQcnQdAXDTA5MDkxODEzMjAwNVowADAhAg5Emb/Oykucmn8fBydB1xcNMDkwOTIxMTAxMDQ3WjAAMCECDjQKCncV+MnUavMHJ0HaFw0wOTA5MjIwODE1MjZaMAAwIQIOaxiFUt3dpd+tPwcnQfQXDTEwMDYxODA4NDI1MVowADAhAg5G7P8nO0tkrMt7BydB9RcNMTAwNjE4MDg0MjMwWjAAMCECDmTCC3SXhmDRst4HJ0H2Fw0wOTA5MjgxMjA3MjBaMAAwIQIOHoGhUr/pRwzTKgcnQfcXDTA5MDkyODEyMDcyNFowADAhAg50wrcrCiw8mQmPBydCBBcNMTAwMjE2MTMwMTA2WjAAMCECDifWmkvwyhEqwEcHJ0IFFw0xMDAyMTYxMzAxMjBaMAAwIQIOfgPmlW9fg+osNgcnQhwXDTEwMDQxMzA5NTIwMFowADAhAg4YHAGuA6LgCk7tBydCHRcNMTAwNDEzMDk1MTM4WjAAMCECDi1zH1bxkNJhokAHJ0IsFw0xMDA0MTMwOTU5MzBaMAAwIQIOMipNccsb/wo2fwcnQi0XDTEwMDQxMzA5NTkwMFowADAhAg46lCmvPl4GpP6ABydCShcNMTAwMTE5MDk1MjE3WjAAMCECDjaTcaj+wBpcGAsHJ0JLFw0xMDAxMTkwOTUyMzRaMAAwIQIOOMC13EOrBuxIOQcnQloXDTEwMDIwMTA5NDcwNVowADAhAg5KmZl+krz4RsmrBydCWxcNMTAwMjAxMDk0NjQwWjAAMCECDmLG3zQJ/fzdSsUHJ0JiFw0xMDAzMDEwOTUxNDBaMAAwIQIOP39ksgHdojf4owcnQmMXDTEwMDMwMTA5NTExN1owADAhAg4LDQzvWNRlD6v9BydCZBcNMTAwMzAxMDk0NjIyWjAAMCECDkmNfeclaFhIaaUHJ0JlFw0xMDAzMDEwOTQ2MDVaMAAwIQIOT/qWWfpH/m8NTwcnQpQXDTEwMDUxMTA5MTgyMVowADAhAg5m/ksYxvCEgJSvBydClRcNMTAwNTExMDkxODAxWjAAMCECDgvf3Ohq6JOPU9AHJ0KWFw0xMDA1MTEwOTIxMjNaMAAwIQIOKSPas10z4jNVIQcnQpcXDTEwMDUxMTA5MjEwMlowADAhAg4mCWmhoZ3lyKCDBydCohcNMTEwNDI4MTEwMjI1WjAAMCECDkeiyRsBMK0Gvr4HJ0KjFw0xMTA0MjgxMTAyMDdaMAAwIQIOa09b/nH2+55SSwcnQq4XDTExMDQwMTA4Mjk0NlowADAhAg5O7M7iq7gGplr1BydCrxcNMTEwNDAxMDgzMDE3WjAAMCECDjlT6mJxUjTvyogHJ0K1Fw0xMTAxMjcxNTQ4NTJaMAAwIQIODS/l4UUFLe21NAcnQrYXDTExMDEyNzE1NDgyOFowADAhAg5lPRA0XdOUF6lSBydDHhcNMTEwMTI4MTQzNTA1WjAAMCECDixKX4fFGGpENwgHJ0MfFw0xMTAxMjgxNDM1MzBaMAAwIQIORNBkqsPnpKTtbAcnQ08XDTEwMDkwOTA4NDg0MlowADAhAg5QL+EMM3lohedEBydDUBcNMTAwOTA5MDg0ODE5WjAAMCECDlhDnHK+HiTRAXcHJ0NUFw0xMDEwMTkxNjIxNDBaMAAwIQIOdBFqAzq/INz53gcnQ1UXDTEwMTAxOTE2MjA0NFowADAhAg4OjR7s8MgKles1BydDWhcNMTEwMTI3MTY1MzM2WjAAMCECDmfR/elHee+d0SoHJ0NbFw0xMTAxMjcxNjUzNTZaMAAwIQIOBTKv2ui+KFMI+wcnQ5YXDTEwMDkxNTEwMjE1N1owADAhAg49F3c/GSah+oRUBydDmxcNMTEwMTI3MTczMjMzWjAAMCECDggv4I61WwpKFMMHJ0OcFw0xMTAxMjcxNzMyNTVaMAAwIQIOXx/Y8sEvwS10LAcnQ6UXDTExMDEyODExMjkzN1owADAhAg5LSLbnVrSKaw/9BydDphcNMTEwMTI4MTEyOTIwWjAAMCECDmFFoCuhKUeACQQHJ0PfFw0xMTAxMTExMDE3MzdaMAAwIQIOQTDdFh2fSPF6AAcnQ+AXDTExMDExMTEwMTcxMFowADAhAg5B8AOXX61FpvbbBydD5RcNMTAxMDA2MTAxNDM2WjAAMCECDh41P2Gmi7PkwI4HJ0PmFw0xMDEwMDYxMDE2MjVaMAAwIQIOWUHGLQCd+Ale9gcnQ/0XDTExMDUwMjA3NTYxMFowADAhAg5Z2c9AYkikmgWOBydD/hcNMTEwNTAyMDc1NjM0WjAAMCECDmf/UD+/h8nf+74HJ0QVFw0xMTA0MTUwNzI4MzNaMAAwIQIOICvj4epy3MrqfwcnRBYXDTExMDQxNTA3Mjg1NlowADAhAg4bouRMfOYqgv4xBydEHxcNMTEwMzA4MTYyNDI1WjAAMCECDhebWHGoKiTp7pEHJ0QgFw0xMTAzMDgxNjI0NDhaMAAwIQIOX+qnxxAqJ8LtawcnRDcXDTExMDEzMTE1MTIyOFowADAhAg4j0fICqZ+wkOdqBydEOBcNMTEwMTMxMTUxMTQxWjAAMCECDhmXjsV4SUpWtAMHJ0RLFw0xMTAxMjgxMTI0MTJaMAAwIQIODno/w+zG43kkTwcnREwXDTExMDEyODExMjM1MlowADAhAg4b1gc88767Fr+LBydETxcNMTEwMTI4MTEwMjA4WjAAMCECDn+M3Pa1w2nyFeUHJ0RQFw0xMTAxMjgxMDU4NDVaMAAwIQIOaduoyIH61tqybAcnRJUXDTEwMTIxNTA5NDMyMlowADAhAg4nLqQPkyi3ESAKBydElhcNMTAxMjE1MDk0MzM2WjAAMCECDi504NIMH8578gQHJ0SbFw0xMTAyMTQxNDA1NDFaMAAwIQIOGuaM8PDaC5u1egcnRJwXDTExMDIxNDE0MDYwNFowADAhAg4ehYq/BXGnB5PWBydEnxcNMTEwMjA0MDgwOTUxWjAAMCECDkSD4eS4FxW5H20HJ0SgFw0xMTAyMDQwODA5MjVaMAAwIQIOOCcb6ilYObt1egcnRKEXDTExMDEyNjEwNDEyOVowADAhAg58tISWCCwFnKGnBydEohcNMTEwMjA0MDgxMzQyWjAAMCECDn5rjtabY/L/WL0HJ0TJFw0xMTAyMDQxMTAzNDFaMAAwDQYJKoZIhvcNAQEFBQADggEBAGnF2Gs0+LNiYCW1Ipm83OXQYP/bd5tFFRzyz3iepFqNfYs4D68/QihjFoRHQoXEB0OEe1tvaVnnPGnEOpi6krwekquMxo4H88B5SlyiFIqemCOIss0SxlCFs69LmfRYvPPvPEhoXtQ3ZThe0UvKG83GOklhvGl6OaiRf4Mt+m8zOT4Wox/j6aOBK6cw6qKCdmD+Yj1rrNqFGg1CnSWMoD6S6mwNgkzwdBUJZ22BwrzAAo4RHa2Uy3ef1FjwD0XtU5N3uDSxGGBEDvOe5z82rps3E22FpAA8eYl8kaXtmWqyvYU0epp4brGuTxCuBMCAsxt/OjIjeNNQbBGkwxgfYA0="
const pemCRLBase64 = "LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0tDQpNSUlCOWpDQ0FWOENBUUV3RFFZSktvWklodmNOQVFFRkJRQXdiREVhTUJnR0ExVUVDaE1SVWxOQklGTmxZM1Z5DQphWFI1SUVsdVl5NHhIakFjQmdOVkJBTVRGVkpUUVNCUWRXSnNhV01nVW05dmRDQkRRU0IyTVRFdU1Dd0dDU3FHDQpTSWIzRFFFSkFSWWZjbk5oYTJWdmJuSnZiM1J6YVdkdVFISnpZWE5sWTNWeWFYUjVMbU52YlJjTk1URXdNakl6DQpNVGt5T0RNd1doY05NVEV3T0RJeU1Ua3lPRE13V2pDQmpEQktBaEVBckRxb2g5RkhKSFhUN09QZ3V1bjQrQmNODQpNRGt4TVRBeU1UUXlOekE1V2pBbU1Bb0dBMVVkRlFRRENnRUpNQmdHQTFVZEdBUVJHQTh5TURBNU1URXdNakUwDQpNalExTlZvd1BnSVJBTEd6blowOTVQQjVhQU9MUGc1N2ZNTVhEVEF5TVRBeU16RTBOVEF4TkZvd0dqQVlCZ05WDQpIUmdFRVJnUE1qQXdNakV3TWpNeE5EVXdNVFJhb0RBd0xqQWZCZ05WSFNNRUdEQVdnQlQxVERGNlVRTS9MTmVMDQpsNWx2cUhHUXEzZzltekFMQmdOVkhSUUVCQUlDQUlRd0RRWUpLb1pJaHZjTkFRRUZCUUFEZ1lFQUZVNUFzNk16DQpxNVBSc2lmYW9iUVBHaDFhSkx5QytNczVBZ2MwYld5QTNHQWR4dXI1U3BQWmVSV0NCamlQL01FSEJXSkNsQkhQDQpHUmNxNXlJZDNFakRrYUV5eFJhK2k2N0x6dmhJNmMyOUVlNks5cFNZd2ppLzdSVWhtbW5Qclh0VHhsTDBsckxyDQptUVFKNnhoRFJhNUczUUE0Q21VZHNITnZicnpnbUNZcHZWRT0NCi0tLS0tRU5EIFg1MDkgQ1JMLS0tLS0NCg0K"
+
+func TestCreateCertificateRequest(t *testing.T) {
+ random := rand.Reader
+
+ block, _ := pem.Decode([]byte(pemPrivateKey))
+ rsaPriv, err := ParsePKCS1PrivateKey(block.Bytes)
+ if err != nil {
+ t.Fatalf("Failed to parse private key: %s", err)
+ }
+
+ ecdsa256Priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ t.Fatalf("Failed to generate ECDSA key: %s", err)
+ }
+
+ ecdsa384Priv, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
+ if err != nil {
+ t.Fatalf("Failed to generate ECDSA key: %s", err)
+ }
+
+ ecdsa521Priv, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
+ if err != nil {
+ t.Fatalf("Failed to generate ECDSA key: %s", err)
+ }
+
+ tests := []struct {
+ name string
+ priv interface{}
+ sigAlgo SignatureAlgorithm
+ }{
+ {"RSA", rsaPriv, SHA1WithRSA},
+ {"ECDSA-256", ecdsa256Priv, ECDSAWithSHA1},
+ {"ECDSA-384", ecdsa384Priv, ECDSAWithSHA1},
+ {"ECDSA-521", ecdsa521Priv, ECDSAWithSHA1},
+ }
+
+ for _, test := range tests {
+ template := CertificateRequest{
+ Subject: pkix.Name{
+ CommonName: "test.example.com",
+ Organization: []string{"Σ Acme Co"},
+ },
+ SignatureAlgorithm: test.sigAlgo,
+ DNSNames: []string{"test.example.com"},
+ EmailAddresses: []string{"gopher@golang.org"},
+ IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1).To4(), net.ParseIP("2001:4860:0:2001::68")},
+ }
+
+ derBytes, err := CreateCertificateRequest(random, &template, test.priv)
+ if err != nil {
+ t.Errorf("%s: failed to create certificate request: %s", test.name, err)
+ continue
+ }
+
+ out, err := ParseCertificateRequest(derBytes)
+ if err != nil {
+ t.Errorf("%s: failed to create certificate request: %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) {
+ t.Errorf("%s: output subject organisation and template subject organisation don't match", test.name)
+ } else if len(out.DNSNames) != len(template.DNSNames) {
+ t.Errorf("%s: output DNS names and template DNS names don't match", test.name)
+ } else if len(out.EmailAddresses) != len(template.EmailAddresses) {
+ t.Errorf("%s: output email addresses and template email addresses don't match", test.name)
+ } else if len(out.IPAddresses) != len(template.IPAddresses) {
+ t.Errorf("%s: output IP addresses and template IP addresses names don't match", test.name)
+ }
+ }
+}
+
+func marshalAndParseCSR(t *testing.T, template *CertificateRequest) *CertificateRequest {
+ block, _ := pem.Decode([]byte(pemPrivateKey))
+ rsaPriv, err := ParsePKCS1PrivateKey(block.Bytes)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ derBytes, err := CreateCertificateRequest(rand.Reader, template, rsaPriv)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ csr, err := ParseCertificateRequest(derBytes)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ return csr
+}
+
+func TestCertificateRequestOverrides(t *testing.T) {
+ sanContents, err := marshalSANs([]string{"foo.example.com"}, nil, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ template := CertificateRequest{
+ Subject: pkix.Name{
+ CommonName: "test.example.com",
+ Organization: []string{"Σ Acme Co"},
+ },
+ DNSNames: []string{"test.example.com"},
+
+ // An explicit extension should override the DNSNames from the
+ // template.
+ ExtraExtensions: []pkix.Extension{
+ {
+ Id: oidExtensionSubjectAltName,
+ Value: sanContents,
+ },
+ },
+ }
+
+ csr := marshalAndParseCSR(t, &template)
+
+ if len(csr.DNSNames) != 1 || csr.DNSNames[0] != "foo.example.com" {
+ t.Errorf("Extension did not override template. Got %v\n", csr.DNSNames)
+ }
+
+ // If there is already an attribute with X.509 extensions then the
+ // extra extensions should be added to it rather than creating a CSR
+ // with two extension attributes.
+
+ template.Attributes = []pkix.AttributeTypeAndValueSET{
+ {
+ Type: oidExtensionRequest,
+ Value: [][]pkix.AttributeTypeAndValue{
+ {
+ {
+ Type: oidExtensionAuthorityInfoAccess,
+ Value: []byte("foo"),
+ },
+ },
+ },
+ },
+ }
+
+ csr = marshalAndParseCSR(t, &template)
+ if l := len(csr.Attributes); l != 1 {
+ t.Errorf("incorrect number of attributes: %d\n", l)
+ }
+
+ if !csr.Attributes[0].Type.Equal(oidExtensionRequest) ||
+ len(csr.Attributes[0].Value) != 1 ||
+ len(csr.Attributes[0].Value[0]) != 2 {
+ t.Errorf("bad attributes: %#v\n", csr.Attributes)
+ }
+
+ sanContents2, err := marshalSANs([]string{"foo2.example.com"}, nil, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Extensions in Attributes should override those in ExtraExtensions.
+ template.Attributes[0].Value[0] = append(template.Attributes[0].Value[0], pkix.AttributeTypeAndValue{
+ Type: oidExtensionSubjectAltName,
+ Value: sanContents2,
+ })
+
+ csr = marshalAndParseCSR(t, &template)
+
+ if len(csr.DNSNames) != 1 || csr.DNSNames[0] != "foo2.example.com" {
+ t.Errorf("Attributes did not override ExtraExtensions. Got %v\n", csr.DNSNames)
+ }
+}
+
+func TestParseCertificateRequest(t *testing.T) {
+ 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.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)
+ }
+
+ 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")
+ }
+}
+
+func TestMaxPathLen(t *testing.T) {
+ block, _ := pem.Decode([]byte(pemPrivateKey))
+ rsaPriv, err := ParsePKCS1PrivateKey(block.Bytes)
+ if err != nil {
+ t.Fatalf("Failed to parse private key: %s", err)
+ }
+
+ template := &Certificate{
+ SerialNumber: big.NewInt(1),
+ Subject: pkix.Name{
+ CommonName: "Σ Acme Co",
+ },
+ NotBefore: time.Unix(1000, 0),
+ NotAfter: time.Unix(100000, 0),
+
+ BasicConstraintsValid: true,
+ IsCA: true,
+ }
+
+ serialiseAndParse := func(template *Certificate) *Certificate {
+ derBytes, err := CreateCertificate(rand.Reader, template, template, &rsaPriv.PublicKey, rsaPriv)
+ if err != nil {
+ t.Fatalf("failed to create certificate: %s", err)
+ return nil
+ }
+
+ cert, err := ParseCertificate(derBytes)
+ if err != nil {
+ t.Fatalf("failed to parse certificate: %s", err)
+ return nil
+ }
+
+ return cert
+ }
+
+ cert1 := serialiseAndParse(template)
+ if m := cert1.MaxPathLen; m != -1 {
+ t.Errorf("Omitting MaxPathLen didn't turn into -1, got %d", m)
+ }
+ if cert1.MaxPathLenZero {
+ t.Errorf("Omitting MaxPathLen resulted in MaxPathLenZero")
+ }
+
+ template.MaxPathLen = 1
+ cert2 := serialiseAndParse(template)
+ if m := cert2.MaxPathLen; m != 1 {
+ t.Errorf("Setting MaxPathLen didn't work. Got %d but set 1", m)
+ }
+ if cert2.MaxPathLenZero {
+ t.Errorf("Setting MaxPathLen resulted in MaxPathLenZero")
+ }
+
+ template.MaxPathLen = 0
+ template.MaxPathLenZero = true
+ cert3 := serialiseAndParse(template)
+ if m := cert3.MaxPathLen; m != 0 {
+ t.Errorf("Setting MaxPathLenZero didn't work, got %d", m)
+ }
+ if !cert3.MaxPathLenZero {
+ t.Errorf("Setting MaxPathLen to zero didn't result in MaxPathLenZero")
+ }
+}
+
+// This CSR was generated with OpenSSL:
+// openssl req -out CSR.csr -new -newkey rsa:2048 -nodes -keyout privateKey.key -config openssl.cnf
+//
+// The openssl.cnf needs to include this section:
+// [ 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="
diff --git a/libgo/go/crypto/x509/x509_test_import.go b/libgo/go/crypto/x509/x509_test_import.go
new file mode 100644
index 0000000000..3fda7da188
--- /dev/null
+++ b/libgo/go/crypto/x509/x509_test_import.go
@@ -0,0 +1,53 @@
+// 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 ignore
+
+// This file is run by the x509 tests to ensure that a program with minimal
+// imports can sign certificates without errors resulting from missing hash
+// functions.
+package main
+
+import (
+ "crypto/rand"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "encoding/pem"
+ "math/big"
+ "time"
+)
+
+func main() {
+ block, _ := pem.Decode([]byte(pemPrivateKey))
+ rsaPriv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
+ if err != nil {
+ panic("Failed to parse private key: " + err.Error())
+ }
+
+ template := x509.Certificate{
+ SerialNumber: big.NewInt(1),
+ Subject: pkix.Name{
+ CommonName: "test",
+ Organization: []string{"Σ Acme Co"},
+ },
+ NotBefore: time.Unix(1000, 0),
+ NotAfter: time.Unix(100000, 0),
+ KeyUsage: x509.KeyUsageCertSign,
+ }
+
+ if _, err = x509.CreateCertificate(rand.Reader, &template, &template, &rsaPriv.PublicKey, rsaPriv); err != nil {
+ panic("failed to create certificate with basic imports: " + err.Error())
+ }
+}
+
+var pemPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
+MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
+fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
+/ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
+RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
+EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
+IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
+tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
+-----END RSA PRIVATE KEY-----
+`
diff --git a/libgo/go/database/sql/convert.go b/libgo/go/database/sql/convert.go
index c04adde1fc..c0b38a2494 100644
--- a/libgo/go/database/sql/convert.go
+++ b/libgo/go/database/sql/convert.go
@@ -160,27 +160,19 @@ func convertAssign(dest, src interface{}) error {
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
reflect.Float32, reflect.Float64:
- *d = fmt.Sprintf("%v", src)
+ *d = asString(src)
return nil
}
case *[]byte:
sv = reflect.ValueOf(src)
- switch sv.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:
- *d = []byte(fmt.Sprintf("%v", src))
+ if b, ok := asBytes(nil, sv); ok {
+ *d = b
return nil
}
case *RawBytes:
sv = reflect.ValueOf(src)
- switch sv.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:
- *d = RawBytes(fmt.Sprintf("%v", src))
+ if b, ok := asBytes([]byte(*d)[:0], sv); ok {
+ *d = RawBytes(b)
return nil
}
case *bool:
@@ -271,5 +263,37 @@ func asString(src interface{}) string {
case []byte:
return string(v)
}
+ rv := reflect.ValueOf(src)
+ switch rv.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return strconv.FormatInt(rv.Int(), 10)
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ return strconv.FormatUint(rv.Uint(), 10)
+ case reflect.Float64:
+ return strconv.FormatFloat(rv.Float(), 'g', -1, 64)
+ case reflect.Float32:
+ return strconv.FormatFloat(rv.Float(), 'g', -1, 32)
+ case reflect.Bool:
+ return strconv.FormatBool(rv.Bool())
+ }
return fmt.Sprintf("%v", src)
}
+
+func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) {
+ switch rv.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return strconv.AppendInt(buf, rv.Int(), 10), true
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ return strconv.AppendUint(buf, rv.Uint(), 10), true
+ case reflect.Float32:
+ return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 32), true
+ case reflect.Float64:
+ return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 64), true
+ case reflect.Bool:
+ return strconv.AppendBool(buf, rv.Bool()), true
+ case reflect.String:
+ s := rv.String()
+ return append(buf, s...), true
+ }
+ return
+}
diff --git a/libgo/go/database/sql/convert_test.go b/libgo/go/database/sql/convert_test.go
index a39c2c54fb..98af9fb64c 100644
--- a/libgo/go/database/sql/convert_test.go
+++ b/libgo/go/database/sql/convert_test.go
@@ -8,6 +8,7 @@ import (
"database/sql/driver"
"fmt"
"reflect"
+ "runtime"
"testing"
"time"
)
@@ -279,3 +280,69 @@ func TestValueConverters(t *testing.T) {
}
}
}
+
+// Tests that assigning to RawBytes doesn't allocate (and also works).
+func TestRawBytesAllocs(t *testing.T) {
+ var tests = []struct {
+ name string
+ in interface{}
+ want string
+ }{
+ {"uint64", uint64(12345678), "12345678"},
+ {"uint32", uint32(1234), "1234"},
+ {"uint16", uint16(12), "12"},
+ {"uint8", uint8(1), "1"},
+ {"uint", uint(123), "123"},
+ {"int", int(123), "123"},
+ {"int8", int8(1), "1"},
+ {"int16", int16(12), "12"},
+ {"int32", int32(1234), "1234"},
+ {"int64", int64(12345678), "12345678"},
+ {"float32", float32(1.5), "1.5"},
+ {"float64", float64(64), "64"},
+ {"bool", false, "false"},
+ }
+
+ buf := make(RawBytes, 10)
+ test := func(name string, in interface{}, want string) {
+ if err := convertAssign(&buf, in); err != nil {
+ t.Fatalf("%s: convertAssign = %v", name, err)
+ }
+ match := len(buf) == len(want)
+ if match {
+ for i, b := range buf {
+ if want[i] != b {
+ match = false
+ break
+ }
+ }
+ }
+ if !match {
+ t.Fatalf("%s: got %q (len %d); want %q (len %d)", name, buf, len(buf), want, len(want))
+ }
+ }
+
+ n := testing.AllocsPerRun(100, func() {
+ for _, tt := range tests {
+ test(tt.name, tt.in, tt.want)
+ }
+ })
+
+ // The numbers below are only valid for 64-bit interface word sizes,
+ // and gc. With 32-bit words there are more convT2E allocs, and
+ // with gccgo, only pointers currently go in interface data.
+ // So only care on amd64 gc for now.
+ measureAllocs := runtime.GOARCH == "amd64" && runtime.Compiler == "gc"
+
+ if n > 0.5 && measureAllocs {
+ t.Fatalf("allocs = %v; want 0", n)
+ }
+
+ // This one involves a convT2E allocation, string -> interface{}
+ n = testing.AllocsPerRun(100, func() {
+ test("string", "foo", "foo")
+ })
+ if n > 1.5 && measureAllocs {
+ t.Fatalf("allocs = %v; want max 1", n)
+ }
+}
diff --git a/libgo/go/database/sql/driver/driver.go b/libgo/go/database/sql/driver/driver.go
index 0828e63c65..eca25f29a0 100644
--- a/libgo/go/database/sql/driver/driver.go
+++ b/libgo/go/database/sql/driver/driver.go
@@ -134,7 +134,7 @@ type Stmt interface {
// as an INSERT or UPDATE.
Exec(args []Value) (Result, error)
- // Exec executes a query that may return rows, such as a
+ // Query executes a query that may return rows, such as a
// SELECT.
Query(args []Value) (Rows, error)
}
diff --git a/libgo/go/database/sql/fakedb_test.go b/libgo/go/database/sql/fakedb_test.go
index a8adfdd942..a993fd46ed 100644
--- a/libgo/go/database/sql/fakedb_test.go
+++ b/libgo/go/database/sql/fakedb_test.go
@@ -10,6 +10,7 @@ import (
"fmt"
"io"
"log"
+ "sort"
"strconv"
"strings"
"sync"
@@ -23,7 +24,7 @@ var _ = log.Printf
// interface, just for testing.
//
// It speaks a query language that's semantically similar to but
-// syntantically different and simpler than SQL. The syntax is as
+// syntactically different and simpler than SQL. The syntax is as
// follows:
//
// WIPE
@@ -126,6 +127,29 @@ func init() {
Register("test", fdriver)
}
+func contains(list []string, y string) bool {
+ for _, x := range list {
+ if x == y {
+ return true
+ }
+ }
+ return false
+}
+
+type Dummy struct {
+ driver.Driver
+}
+
+func TestDrivers(t *testing.T) {
+ unregisterAllDrivers()
+ Register("test", fdriver)
+ Register("invalid", Dummy{})
+ all := Drivers()
+ if len(all) < 2 || !sort.StringsAreSorted(all) || !contains(all, "test") || !contains(all, "invalid") {
+ t.Fatalf("Drivers = %v, want sorted list with at least [invalid, test]", all)
+ }
+}
+
// Supports dsn forms:
// <dbname>
// <dbname>;<opts> (only currently supported option is `badConn`,
@@ -433,11 +457,19 @@ func (c *fakeConn) prepareInsert(stmt *fakeStmt, parts []string) (driver.Stmt, e
return stmt, nil
}
+// hook to simulate broken connections
+var hookPrepareBadConn func() bool
+
func (c *fakeConn) Prepare(query string) (driver.Stmt, error) {
c.numPrepare++
if c.db == nil {
panic("nil c.db; conn = " + fmt.Sprintf("%#v", c))
}
+
+ if hookPrepareBadConn != nil && hookPrepareBadConn() {
+ return nil, driver.ErrBadConn
+ }
+
parts := strings.Split(query, "|")
if len(parts) < 1 {
return nil, errf("empty query")
@@ -489,10 +521,18 @@ func (s *fakeStmt) Close() error {
var errClosed = errors.New("fakedb: statement has been closed")
+// hook to simulate broken connections
+var hookExecBadConn func() bool
+
func (s *fakeStmt) Exec(args []driver.Value) (driver.Result, error) {
if s.closed {
return nil, errClosed
}
+
+ if hookExecBadConn != nil && hookExecBadConn() {
+ return nil, driver.ErrBadConn
+ }
+
err := checkSubsetTypes(args)
if err != nil {
return nil, err
@@ -565,10 +605,18 @@ func (s *fakeStmt) execInsert(args []driver.Value, doInsert bool) (driver.Result
return driver.RowsAffected(1), nil
}
+// hook to simulate broken connections
+var hookQueryBadConn func() bool
+
func (s *fakeStmt) Query(args []driver.Value) (driver.Rows, error) {
if s.closed {
return nil, errClosed
}
+
+ if hookQueryBadConn != nil && hookQueryBadConn() {
+ return nil, driver.ErrBadConn
+ }
+
err := checkSubsetTypes(args)
if err != nil {
return nil, err
@@ -686,7 +734,13 @@ func (rc *rowsCursor) Columns() []string {
return rc.cols
}
+var rowsCursorNextHook func(dest []driver.Value) error
+
func (rc *rowsCursor) Next(dest []driver.Value) error {
+ if rowsCursorNextHook != nil {
+ return rowsCursorNextHook(dest)
+ }
+
if rc.closed {
return errors.New("fakedb: cursor is closed")
}
diff --git a/libgo/go/database/sql/sql.go b/libgo/go/database/sql/sql.go
index 84a0965132..6e6f246aee 100644
--- a/libgo/go/database/sql/sql.go
+++ b/libgo/go/database/sql/sql.go
@@ -13,12 +13,12 @@
package sql
import (
- "container/list"
"database/sql/driver"
"errors"
"fmt"
"io"
"runtime"
+ "sort"
"sync"
)
@@ -37,6 +37,21 @@ func Register(name string, driver driver.Driver) {
drivers[name] = driver
}
+func unregisterAllDrivers() {
+ // For tests.
+ drivers = make(map[string]driver.Driver)
+}
+
+// Drivers returns a sorted list of the names of the registered drivers.
+func Drivers() []string {
+ var list []string
+ for name := range drivers {
+ list = append(list, name)
+ }
+ sort.Strings(list)
+ return list
+}
+
// RawBytes is a byte slice that holds a reference to memory owned by
// the database itself. After a Scan into a RawBytes, the slice is only
// valid until the next call to Next, Scan, or Close.
@@ -181,7 +196,8 @@ type Scanner interface {
// defers this error until a Scan.
var ErrNoRows = errors.New("sql: no rows in result set")
-// DB is a database handle. It's safe for concurrent use by multiple
+// DB is a database handle representing a pool of zero or more
+// underlying connections. It's safe for concurrent use by multiple
// goroutines.
//
// The sql package creates and frees connections automatically; it
@@ -197,8 +213,8 @@ type DB struct {
dsn string
mu sync.Mutex // protects following fields
- freeConn *list.List // of *driverConn
- connRequests *list.List // of connRequest
+ freeConn []*driverConn
+ connRequests []chan connRequest
numOpen int
pendingOpens int
// Used to signal the need for new connections
@@ -231,9 +247,6 @@ type driverConn struct {
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
- // This is the Element returned by db.freeConn.PushFront(conn).
- // It's used by connIfFree to remove the conn from the freeConn list.
- listElem *list.Element
}
func (dc *driverConn) releaseConn(err error) {
@@ -256,7 +269,7 @@ func (dc *driverConn) prepareLocked(query string) (driver.Stmt, error) {
// stmt closes if the conn is about to close anyway? For now
// do the safe thing, in case stmts need to be closed.
//
- // TODO(bradfitz): after Go 1.1, closing driver.Stmts
+ // TODO(bradfitz): after Go 1.2, closing driver.Stmts
// should be moved to driverStmt, using unique
// *driverStmts everywhere (including from
// *Stmt.connStmt, instead of returning a
@@ -405,7 +418,7 @@ func (db *DB) removeDepLocked(x finalCloser, dep interface{}) func() error {
// This value should be larger than the maximum typical value
// used for db.maxOpen. If maxOpen is significantly larger than
// connectionRequestQueueSize then it is possible for ALL calls into the *DB
-// to block until the connectionOpener can satify the backlog of requests.
+// to block until the connectionOpener can satisfy the backlog of requests.
var connectionRequestQueueSize = 1000000
// Open opens a database specified by its database driver name and a
@@ -420,6 +433,11 @@ var connectionRequestQueueSize = 1000000
// Open may just validate its arguments without creating a connection
// to the database. To verify that the data source name is valid, call
// Ping.
+//
+// The returned DB is safe for concurrent use by multiple goroutines
+// and maintains its own pool of idle connections. Thus, the Open
+// function should be called just once. It is rarely necessary to
+// close a DB.
func Open(driverName, dataSourceName string) (*DB, error) {
driveri, ok := drivers[driverName]
if !ok {
@@ -431,8 +449,6 @@ func Open(driverName, dataSourceName string) (*DB, error) {
openerCh: make(chan struct{}, connectionRequestQueueSize),
lastPut: make(map[*driverConn]string),
}
- db.freeConn = list.New()
- db.connRequests = list.New()
go db.connectionOpener()
return db, nil
}
@@ -452,6 +468,9 @@ func (db *DB) Ping() error {
}
// Close closes the database, releasing any open resources.
+//
+// It is rare to Close a DB, as the DB handle is meant to be
+// long-lived and shared between many goroutines.
func (db *DB) Close() error {
db.mu.Lock()
if db.closed { // Make DB.Close idempotent
@@ -460,17 +479,13 @@ func (db *DB) Close() error {
}
close(db.openerCh)
var err error
- fns := make([]func() error, 0, db.freeConn.Len())
- for db.freeConn.Front() != nil {
- dc := db.freeConn.Front().Value.(*driverConn)
- dc.listElem = nil
+ fns := make([]func() error, 0, len(db.freeConn))
+ for _, dc := range db.freeConn {
fns = append(fns, dc.closeDBLocked())
- db.freeConn.Remove(db.freeConn.Front())
}
+ db.freeConn = nil
db.closed = true
- for db.connRequests.Front() != nil {
- req := db.connRequests.Front().Value.(connRequest)
- db.connRequests.Remove(db.connRequests.Front())
+ for _, req := range db.connRequests {
close(req)
}
db.mu.Unlock()
@@ -518,11 +533,11 @@ func (db *DB) SetMaxIdleConns(n int) {
db.maxIdle = db.maxOpen
}
var closing []*driverConn
- for db.freeConn.Len() > db.maxIdleConnsLocked() {
- dc := db.freeConn.Back().Value.(*driverConn)
- dc.listElem = nil
- db.freeConn.Remove(db.freeConn.Back())
- closing = append(closing, dc)
+ idleCount := len(db.freeConn)
+ maxIdle := db.maxIdleConnsLocked()
+ if idleCount > maxIdle {
+ closing = db.freeConn[maxIdle:]
+ db.freeConn = db.freeConn[:maxIdle]
}
db.mu.Unlock()
for _, c := range closing {
@@ -555,7 +570,7 @@ func (db *DB) SetMaxOpenConns(n int) {
// If there are connRequests and the connection limit hasn't been reached,
// then tell the connectionOpener to open new connections.
func (db *DB) maybeOpenNewConnections() {
- numRequests := db.connRequests.Len() - db.pendingOpens
+ numRequests := len(db.connRequests) - db.pendingOpens
if db.maxOpen > 0 {
numCanOpen := db.maxOpen - (db.numOpen + db.pendingOpens)
if numRequests > numCanOpen {
@@ -569,9 +584,9 @@ func (db *DB) maybeOpenNewConnections() {
}
}
-// Runs in a seperate goroutine, opens new connections when requested.
+// Runs in a separate goroutine, opens new connections when requested.
func (db *DB) connectionOpener() {
- for _ = range db.openerCh {
+ for range db.openerCh {
db.openNewConnection()
}
}
@@ -607,7 +622,10 @@ func (db *DB) openNewConnection() {
// connRequest represents one request for a new connection
// When there are no idle connections available, DB.conn will create
// a new connRequest and put it on the db.connRequests list.
-type connRequest chan<- interface{} // takes either a *driverConn or an error
+type connRequest struct {
+ conn *driverConn
+ err error
+}
var errDBClosed = errors.New("sql: database is closed")
@@ -621,44 +639,36 @@ func (db *DB) conn() (*driverConn, error) {
// 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 && db.freeConn.Len() == 0 {
+ if db.maxOpen > 0 && db.numOpen >= db.maxOpen && len(db.freeConn) == 0 {
// Make the connRequest channel. It's buffered so that the
// connectionOpener doesn't block while waiting for the req to be read.
- ch := make(chan interface{}, 1)
- req := connRequest(ch)
- db.connRequests.PushBack(req)
+ req := make(chan connRequest, 1)
+ db.connRequests = append(db.connRequests, req)
db.maybeOpenNewConnections()
db.mu.Unlock()
- ret, ok := <-ch
- if !ok {
- return nil, errDBClosed
- }
- switch ret.(type) {
- case *driverConn:
- return ret.(*driverConn), nil
- case error:
- return nil, ret.(error)
- default:
- panic("sql: Unexpected type passed through connRequest.ch")
- }
+ ret := <-req
+ return ret.conn, ret.err
}
- if f := db.freeConn.Front(); f != nil {
- conn := f.Value.(*driverConn)
- conn.listElem = nil
- db.freeConn.Remove(f)
+ 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)
if err != nil {
+ db.mu.Lock()
+ db.numOpen-- // correct for earlier optimism
+ db.mu.Unlock()
return nil, err
}
db.mu.Lock()
- db.numOpen++
dc := &driverConn{
db: db,
ci: ci,
@@ -690,9 +700,15 @@ func (db *DB) connIfFree(wanted *driverConn) (*driverConn, error) {
if wanted.inUse {
return nil, errConnBusy
}
- if wanted.listElem != nil {
- db.freeConn.Remove(wanted.listElem)
- wanted.listElem = nil
+ 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
}
@@ -774,37 +790,46 @@ func (db *DB) putConn(dc *driverConn, err error) {
// Satisfy a connRequest or put the driverConn in the idle pool and return true
// or return false.
// putConnDBLocked will satisfy a connRequest if there is one, or it will
-// return the *driverConn to the freeConn list if err != nil and the idle
-// connection limit would not be reached.
+// return the *driverConn to the freeConn list if err == nil and the idle
+// connection limit will not be exceeded.
// If err != nil, the value of dc is ignored.
// If err == nil, then dc must not equal nil.
-// If a connRequest was fullfilled or the *driverConn was placed in the
+// 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.connRequests.Len() > 0 {
- req := db.connRequests.Front().Value.(connRequest)
- db.connRequests.Remove(db.connRequests.Front())
- if err != nil {
- req <- err
- } else {
+ if c := len(db.connRequests); c > 0 {
+ req := db.connRequests[0]
+ // This copy is O(n) but in practice faster than a linked list.
+ // TODO: consider compacting it down less often and
+ // moving the base instead?
+ copy(db.connRequests, db.connRequests[1:])
+ db.connRequests = db.connRequests[:c-1]
+ if err == nil {
dc.inUse = true
- req <- dc
+ }
+ req <- connRequest{
+ conn: dc,
+ err: err,
}
return true
- } else if err == nil && !db.closed && db.maxIdleConnsLocked() > 0 && db.maxIdleConnsLocked() > db.freeConn.Len() {
- dc.listElem = db.freeConn.PushFront(dc)
+ } else if err == nil && !db.closed && db.maxIdleConnsLocked() > len(db.freeConn) {
+ db.freeConn = append(db.freeConn, dc)
return true
}
return false
}
+// maxBadConnRetries is the number of maximum retries if the driver returns
+// driver.ErrBadConn to signal a broken connection.
+const maxBadConnRetries = 10
+
// Prepare creates a prepared statement for later queries or executions.
// Multiple queries or executions may be run concurrently from the
// returned statement.
func (db *DB) Prepare(query string) (*Stmt, error) {
var stmt *Stmt
var err error
- for i := 0; i < 10; i++ {
+ for i := 0; i < maxBadConnRetries; i++ {
stmt, err = db.prepare(query)
if err != driver.ErrBadConn {
break
@@ -846,7 +871,7 @@ func (db *DB) prepare(query string) (*Stmt, error) {
func (db *DB) Exec(query string, args ...interface{}) (Result, error) {
var res Result
var err error
- for i := 0; i < 10; i++ {
+ for i := 0; i < maxBadConnRetries; i++ {
res, err = db.exec(query, args)
if err != driver.ErrBadConn {
break
@@ -895,7 +920,7 @@ func (db *DB) exec(query string, args []interface{}) (res Result, err error) {
func (db *DB) Query(query string, args ...interface{}) (*Rows, error) {
var rows *Rows
var err error
- for i := 0; i < 10; i++ {
+ for i := 0; i < maxBadConnRetries; i++ {
rows, err = db.query(query, args)
if err != driver.ErrBadConn {
break
@@ -983,7 +1008,7 @@ func (db *DB) QueryRow(query string, args ...interface{}) *Row {
func (db *DB) Begin() (*Tx, error) {
var tx *Tx
var err error
- for i := 0; i < 10; i++ {
+ for i := 0; i < maxBadConnRetries; i++ {
tx, err = db.begin()
if err != driver.ErrBadConn {
break
@@ -1034,6 +1059,13 @@ type Tx struct {
// or Rollback. once done, all operations fail with
// ErrTxDone.
done bool
+
+ // All Stmts prepared for this transaction. These will be closed after the
+ // transaction has been committed or rolled back.
+ stmts struct {
+ sync.Mutex
+ v []*Stmt
+ }
}
var ErrTxDone = errors.New("sql: Transaction has already been committed or rolled back")
@@ -1055,6 +1087,15 @@ func (tx *Tx) grabConn() (*driverConn, error) {
return tx.dc, nil
}
+// Closes all Stmts prepared for this transaction.
+func (tx *Tx) closePrepared() {
+ tx.stmts.Lock()
+ for _, stmt := range tx.stmts.v {
+ stmt.Close()
+ }
+ tx.stmts.Unlock()
+}
+
// Commit commits the transaction.
func (tx *Tx) Commit() error {
if tx.done {
@@ -1062,8 +1103,12 @@ func (tx *Tx) Commit() error {
}
defer tx.close()
tx.dc.Lock()
- defer tx.dc.Unlock()
- return tx.txi.Commit()
+ err := tx.txi.Commit()
+ tx.dc.Unlock()
+ if err != driver.ErrBadConn {
+ tx.closePrepared()
+ }
+ return err
}
// Rollback aborts the transaction.
@@ -1073,8 +1118,12 @@ func (tx *Tx) Rollback() error {
}
defer tx.close()
tx.dc.Lock()
- defer tx.dc.Unlock()
- return tx.txi.Rollback()
+ err := tx.txi.Rollback()
+ tx.dc.Unlock()
+ if err != driver.ErrBadConn {
+ tx.closePrepared()
+ }
+ return err
}
// Prepare creates a prepared statement for use within a transaction.
@@ -1118,6 +1167,9 @@ func (tx *Tx) Prepare(query string) (*Stmt, error) {
},
query: query,
}
+ tx.stmts.Lock()
+ tx.stmts.v = append(tx.stmts.v, stmt)
+ tx.stmts.Unlock()
return stmt, nil
}
@@ -1146,7 +1198,7 @@ func (tx *Tx) Stmt(stmt *Stmt) *Stmt {
dc.Lock()
si, err := dc.ci.Prepare(stmt.query)
dc.Unlock()
- return &Stmt{
+ txs := &Stmt{
db: tx.db,
tx: tx,
txsi: &driverStmt{
@@ -1156,6 +1208,10 @@ func (tx *Tx) Stmt(stmt *Stmt) *Stmt {
query: stmt.query,
stickyErr: err,
}
+ tx.stmts.Lock()
+ tx.stmts.v = append(tx.stmts.v, txs)
+ tx.stmts.Unlock()
+ return txs
}
// Exec executes a query that doesn't return rows.
@@ -1245,13 +1301,24 @@ type Stmt struct {
func (s *Stmt) Exec(args ...interface{}) (Result, error) {
s.closemu.RLock()
defer s.closemu.RUnlock()
- dc, releaseConn, si, err := s.connStmt()
- if err != nil {
- return nil, err
- }
- defer releaseConn(nil)
- return resultFromStatement(driverStmt{dc, si}, args...)
+ var res Result
+ for i := 0; i < maxBadConnRetries; i++ {
+ dc, releaseConn, si, err := s.connStmt()
+ if err != nil {
+ if err == driver.ErrBadConn {
+ continue
+ }
+ return nil, err
+ }
+
+ res, err = resultFromStatement(driverStmt{dc, si}, args...)
+ releaseConn(err)
+ if err != driver.ErrBadConn {
+ return res, err
+ }
+ }
+ return nil, driver.ErrBadConn
}
func resultFromStatement(ds driverStmt, args ...interface{}) (Result, error) {
@@ -1306,15 +1373,12 @@ func (s *Stmt) connStmt() (ci *driverConn, releaseConn func(error), si driver.St
return ci, releaseConn, s.txsi.si, nil
}
- var cs connStmt
- match := false
for i := 0; i < len(s.css); i++ {
v := s.css[i]
_, err := s.db.connIfFree(v.dc)
if err == nil {
- match = true
- cs = v
- break
+ s.mu.Unlock()
+ return v.dc, v.dc.releaseConn, v.si, nil
}
if err == errConnClosed {
// Lazily remove dead conn from our freelist.
@@ -1326,33 +1390,41 @@ func (s *Stmt) connStmt() (ci *driverConn, releaseConn func(error), si driver.St
}
s.mu.Unlock()
- // Make a new conn if all are busy.
- // TODO(bradfitz): or wait for one? make configurable later?
- if !match {
- for i := 0; ; i++ {
- dc, err := s.db.conn()
- if err != nil {
- return nil, nil, nil, err
- }
- dc.Lock()
- si, err := dc.prepareLocked(s.query)
- dc.Unlock()
- if err == driver.ErrBadConn && i < 10 {
- continue
- }
- if err != nil {
- return nil, nil, nil, err
- }
- s.mu.Lock()
- cs = connStmt{dc, si}
- s.css = append(s.css, cs)
+ // 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()
+ 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 {
s.mu.Unlock()
- break
+ return dc, dc.releaseConn, v.si, nil
}
}
+ s.mu.Unlock()
- conn := cs.dc
- return conn, conn.releaseConn, cs.si, nil
+ // No luck; we need to prepare the statement on this connection
+ dc.Lock()
+ si, err = dc.prepareLocked(s.query)
+ dc.Unlock()
+ if err != nil {
+ s.db.putConn(dc, err)
+ return nil, nil, nil, err
+ }
+ s.mu.Lock()
+ cs := connStmt{dc, si}
+ s.css = append(s.css, cs)
+ s.mu.Unlock()
+
+ return dc, dc.releaseConn, si, nil
}
// Query executes a prepared query statement with the given arguments
@@ -1361,31 +1433,39 @@ func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
s.closemu.RLock()
defer s.closemu.RUnlock()
- dc, releaseConn, si, err := s.connStmt()
- if err != nil {
- return nil, err
- }
+ var rowsi driver.Rows
+ for i := 0; i < maxBadConnRetries; i++ {
+ dc, releaseConn, si, err := s.connStmt()
+ if err != nil {
+ if err == driver.ErrBadConn {
+ continue
+ }
+ return nil, err
+ }
- ds := driverStmt{dc, si}
- rowsi, err := rowsiFromStatement(ds, args...)
- if err != nil {
- releaseConn(err)
- return nil, err
- }
+ rowsi, err = rowsiFromStatement(driverStmt{dc, si}, args...)
+ if err == nil {
+ // Note: ownership of ci passes to the *Rows, to be freed
+ // with releaseConn.
+ rows := &Rows{
+ dc: dc,
+ rowsi: rowsi,
+ // releaseConn set below
+ }
+ s.db.addDep(s, rows)
+ rows.releaseConn = func(err error) {
+ releaseConn(err)
+ s.db.removeDep(s, rows)
+ }
+ return rows, nil
+ }
- // Note: ownership of ci passes to the *Rows, to be freed
- // with releaseConn.
- rows := &Rows{
- dc: dc,
- rowsi: rowsi,
- // releaseConn set below
- }
- s.db.addDep(s, rows)
- rows.releaseConn = func(err error) {
releaseConn(err)
- s.db.removeDep(s, rows)
+ if err != driver.ErrBadConn {
+ return nil, err
+ }
}
- return rows, nil
+ return nil, driver.ErrBadConn
}
func rowsiFromStatement(ds driverStmt, args ...interface{}) (driver.Rows, error) {
@@ -1476,6 +1556,7 @@ func (s *Stmt) finalClose() error {
//
// rows, err := db.Query("SELECT ...")
// ...
+// defer rows.Close()
// for rows.Next() {
// var id int
// var name string
@@ -1495,10 +1576,12 @@ type Rows struct {
closeStmt driver.Stmt // if non-nil, statement to Close on close
}
-// Next prepares the next result row for reading with the Scan method.
-// It returns true on success, false if there is no next result row.
-// Every call to Scan, even the first one, must be preceded by a call
-// to Next.
+// Next prepares the next result row for reading with the Scan method. It
+// returns true on success, or false if there is no next result row or an error
+// happened while preparing it. Err should be consulted to distinguish between
+// the two cases.
+//
+// Every call to Scan, even the first one, must be preceded by a call to Next.
func (rs *Rows) Next() bool {
if rs.closed {
return false
@@ -1625,12 +1708,19 @@ func (r *Row) Scan(dest ...interface{}) error {
}
if !r.rows.Next() {
+ if err := r.rows.Err(); err != nil {
+ return err
+ }
return ErrNoRows
}
err := r.rows.Scan(dest...)
if err != nil {
return err
}
+ // Make sure the query can be processed to completion with no errors.
+ if err := r.rows.Close(); err != nil {
+ return err
+ }
return nil
}
diff --git a/libgo/go/database/sql/sql_test.go b/libgo/go/database/sql/sql_test.go
index 787a5c9f74..34efdf254c 100644
--- a/libgo/go/database/sql/sql_test.go
+++ b/libgo/go/database/sql/sql_test.go
@@ -24,7 +24,14 @@ func init() {
}
freedFrom := make(map[dbConn]string)
putConnHook = func(db *DB, c *driverConn) {
- if c.listElem != nil {
+ idx := -1
+ for i, v := range db.freeConn {
+ if v == c {
+ idx = i
+ break
+ }
+ }
+ if idx >= 0 {
// print before panic, as panic may get lost due to conflicting panic
// (all goroutines asleep) elsewhere, since we might not unlock
// the mutex in freeConn here.
@@ -79,15 +86,14 @@ func closeDB(t testing.TB, db *DB) {
t.Errorf("Error closing fakeConn: %v", err)
}
})
- for node, i := db.freeConn.Front(), 0; node != nil; node, i = node.Next(), i+1 {
- dc := node.Value.(*driverConn)
+ for i, dc := range db.freeConn {
if n := len(dc.openStmt); n > 0 {
// Just a sanity check. This is legal in
// general, but if we make the tests clean up
// their statements first, then we can safely
// verify this is always zero here, and any
// other value is a leak.
- t.Errorf("while closing db, freeConn %d/%d had %d open stmts; want 0", i, db.freeConn.Len(), n)
+ t.Errorf("while closing db, freeConn %d/%d had %d open stmts; want 0", i, len(db.freeConn), n)
}
}
err := db.Close()
@@ -105,10 +111,10 @@ func closeDB(t testing.TB, db *DB) {
// numPrepares assumes that db has exactly 1 idle conn and returns
// its count of calls to Prepare
func numPrepares(t *testing.T, db *DB) int {
- if n := db.freeConn.Len(); n != 1 {
+ if n := len(db.freeConn); n != 1 {
t.Fatalf("free conns = %d; want 1", n)
}
- return (db.freeConn.Front().Value.(*driverConn)).ci.(*fakeConn).numPrepare
+ return db.freeConn[0].ci.(*fakeConn).numPrepare
}
func (db *DB) numDeps() int {
@@ -133,7 +139,7 @@ func (db *DB) numDepsPollUntil(want int, d time.Duration) int {
func (db *DB) numFreeConns() int {
db.mu.Lock()
defer db.mu.Unlock()
- return db.freeConn.Len()
+ return len(db.freeConn)
}
func (db *DB) dumpDeps(t *testing.T) {
@@ -348,7 +354,6 @@ func TestStatementQueryRow(t *testing.T) {
t.Errorf("%d: age=%d, want %d", n, age, tt.want)
}
}
-
}
// golang.org/issue/3734
@@ -436,6 +441,33 @@ func TestExec(t *testing.T) {
}
}
+func TestTxPrepare(t *testing.T) {
+ db := newTestDB(t, "")
+ defer closeDB(t, db)
+ exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool")
+ tx, err := db.Begin()
+ if err != nil {
+ t.Fatalf("Begin = %v", err)
+ }
+ stmt, err := tx.Prepare("INSERT|t1|name=?,age=?")
+ if err != nil {
+ t.Fatalf("Stmt, err = %v, %v", stmt, err)
+ }
+ defer stmt.Close()
+ _, err = stmt.Exec("Bobby", 7)
+ if err != nil {
+ t.Fatalf("Exec = %v", err)
+ }
+ err = tx.Commit()
+ if err != nil {
+ t.Fatalf("Commit = %v", err)
+ }
+ // Commit() should have closed the statement
+ if !stmt.closed {
+ t.Fatal("Stmt not closed after Commit")
+ }
+}
+
func TestTxStmt(t *testing.T) {
db := newTestDB(t, "")
defer closeDB(t, db)
@@ -459,10 +491,14 @@ func TestTxStmt(t *testing.T) {
if err != nil {
t.Fatalf("Commit = %v", err)
}
+ // Commit() should have closed the statement
+ if !txs.closed {
+ t.Fatal("Stmt not closed after Commit")
+ }
}
// Issue: http://golang.org/issue/2784
-// This test didn't fail before because we got luckly with the fakedb driver.
+// 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) {
db := newTestDB(t, "")
@@ -651,15 +687,44 @@ func TestQueryRowClosingStmt(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- if db.freeConn.Len() != 1 {
+ if len(db.freeConn) != 1 {
t.Fatalf("expected 1 free conn")
}
- fakeConn := (db.freeConn.Front().Value.(*driverConn)).ci.(*fakeConn)
+ fakeConn := db.freeConn[0].ci.(*fakeConn)
if made, closed := fakeConn.stmtsMade, fakeConn.stmtsClosed; made != closed {
t.Errorf("statement close mismatch: made %d, closed %d", made, closed)
}
}
+// Test issue 6651
+func TestIssue6651(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+
+ var v string
+
+ want := "error in rows.Next"
+ rowsCursorNextHook = func(dest []driver.Value) error {
+ return fmt.Errorf(want)
+ }
+ defer func() { rowsCursorNextHook = nil }()
+ err := db.QueryRow("SELECT|people|name|").Scan(&v)
+ if err == nil || err.Error() != want {
+ t.Errorf("error = %q; want %q", err, want)
+ }
+ rowsCursorNextHook = nil
+
+ want = "error in rows.Close"
+ rowsCloseHook = func(rows *Rows, err *error) {
+ *err = fmt.Errorf(want)
+ }
+ defer func() { rowsCloseHook = nil }()
+ err = db.QueryRow("SELECT|people|name|").Scan(&v)
+ if err == nil || err.Error() != want {
+ t.Errorf("error = %q; want %q", err, want)
+ }
+}
+
type nullTestRow struct {
nullParam interface{}
notNullParam interface{}
@@ -850,13 +915,13 @@ func TestMaxIdleConns(t *testing.T) {
t.Fatal(err)
}
tx.Commit()
- if got := db.freeConn.Len(); got != 1 {
+ if got := len(db.freeConn); got != 1 {
t.Errorf("freeConns = %d; want 1", got)
}
db.SetMaxIdleConns(0)
- if got := db.freeConn.Len(); got != 0 {
+ if got := len(db.freeConn); got != 0 {
t.Errorf("freeConns after set to zero = %d; want 0", got)
}
@@ -865,7 +930,7 @@ func TestMaxIdleConns(t *testing.T) {
t.Fatal(err)
}
tx.Commit()
- if got := db.freeConn.Len(); got != 0 {
+ if got := len(db.freeConn); got != 0 {
t.Errorf("freeConns = %d; want 0", got)
}
}
@@ -1152,10 +1217,10 @@ func TestCloseConnBeforeStmts(t *testing.T) {
t.Fatal(err)
}
- if db.freeConn.Len() != 1 {
- t.Fatalf("expected 1 freeConn; got %d", db.freeConn.Len())
+ if len(db.freeConn) != 1 {
+ t.Fatalf("expected 1 freeConn; got %d", len(db.freeConn))
}
- dc := db.freeConn.Front().Value.(*driverConn)
+ dc := db.freeConn[0]
if dc.closed {
t.Errorf("conn shouldn't be closed")
}
@@ -1249,6 +1314,112 @@ func TestStmtCloseOrder(t *testing.T) {
}
}
+// golang.org/issue/5781
+func TestErrBadConnReconnect(t *testing.T) {
+ db := newTestDB(t, "foo")
+ defer closeDB(t, db)
+ exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool")
+
+ simulateBadConn := func(name string, hook *func() bool, op func() error) {
+ broken, retried := false, false
+ numOpen := db.numOpen
+
+ // simulate a broken connection on the first try
+ *hook = func() bool {
+ if !broken {
+ broken = true
+ return true
+ }
+ retried = true
+ return false
+ }
+
+ if err := op(); err != nil {
+ t.Errorf(name+": %v", err)
+ return
+ }
+
+ if !broken || !retried {
+ t.Error(name + ": Failed to simulate broken connection")
+ }
+ *hook = nil
+
+ if numOpen != db.numOpen {
+ t.Errorf(name+": leaked %d connection(s)!", db.numOpen-numOpen)
+ numOpen = db.numOpen
+ }
+ }
+
+ // db.Exec
+ dbExec := func() error {
+ _, err := db.Exec("INSERT|t1|name=?,age=?,dead=?", "Gordon", 3, true)
+ return err
+ }
+ simulateBadConn("db.Exec prepare", &hookPrepareBadConn, dbExec)
+ simulateBadConn("db.Exec exec", &hookExecBadConn, dbExec)
+
+ // db.Query
+ dbQuery := func() error {
+ rows, err := db.Query("SELECT|t1|age,name|")
+ if err == nil {
+ err = rows.Close()
+ }
+ return err
+ }
+ simulateBadConn("db.Query prepare", &hookPrepareBadConn, dbQuery)
+ simulateBadConn("db.Query query", &hookQueryBadConn, dbQuery)
+
+ // db.Prepare
+ simulateBadConn("db.Prepare", &hookPrepareBadConn, func() error {
+ stmt, err := db.Prepare("INSERT|t1|name=?,age=?,dead=?")
+ if err != nil {
+ return err
+ }
+ stmt.Close()
+ return nil
+ })
+
+ // Provide a way to force a re-prepare of a statement on next execution
+ forcePrepare := func(stmt *Stmt) {
+ stmt.css = nil
+ }
+
+ // stmt.Exec
+ stmt1, err := db.Prepare("INSERT|t1|name=?,age=?,dead=?")
+ if err != nil {
+ t.Fatalf("prepare: %v", err)
+ }
+ defer stmt1.Close()
+ // make sure we must prepare the stmt first
+ forcePrepare(stmt1)
+
+ stmtExec := func() error {
+ _, err := stmt1.Exec("Gopher", 3, false)
+ return err
+ }
+ simulateBadConn("stmt.Exec prepare", &hookPrepareBadConn, stmtExec)
+ simulateBadConn("stmt.Exec exec", &hookExecBadConn, stmtExec)
+
+ // stmt.Query
+ stmt2, err := db.Prepare("SELECT|t1|age,name|")
+ if err != nil {
+ t.Fatalf("prepare: %v", err)
+ }
+ defer stmt2.Close()
+ // make sure we must prepare the stmt first
+ forcePrepare(stmt2)
+
+ stmtQuery := func() error {
+ rows, err := stmt2.Query()
+ if err == nil {
+ err = rows.Close()
+ }
+ return err
+ }
+ simulateBadConn("stmt.Query prepare", &hookPrepareBadConn, stmtQuery)
+ simulateBadConn("stmt.Query exec", &hookQueryBadConn, stmtQuery)
+}
+
type concurrentTest interface {
init(t testing.TB, db *DB)
finish(t testing.TB)
@@ -1575,7 +1746,7 @@ func doConcurrentTest(t testing.TB, ct concurrentTest) {
for i := 0; i < maxProcs*2; i++ {
go func() {
- for _ = range reqs {
+ for range reqs {
err := ct.test(t)
if err != nil {
wg.Done()
@@ -1617,7 +1788,7 @@ func manyConcurrentQueries(t testing.TB) {
for i := 0; i < maxProcs*2; i++ {
go func() {
- for _ = range reqs {
+ for range reqs {
rows, err := stmt.Query()
if err != nil {
t.Errorf("error on query: %v", err)
diff --git a/libgo/go/debug/dwarf/const.go b/libgo/go/debug/dwarf/const.go
index 68503c742f..6cc6bc937a 100644
--- a/libgo/go/debug/dwarf/const.go
+++ b/libgo/go/debug/dwarf/const.go
@@ -207,10 +207,15 @@ const (
formRef8 format = 0x14
formRefUdata format = 0x15
formIndirect format = 0x16
+ // The following are new in DWARF 4.
formSecOffset format = 0x17
formExprloc format = 0x18
formFlagPresent format = 0x19
formRefSig8 format = 0x20
+ // Extensions for multi-file compression (.dwz)
+ // http://www.dwarfstd.org/ShowIssue.php?issue=120604.1
+ formGnuRefAlt format = 0x1f20
+ formGnuStrpAlt format = 0x1f21
)
// A Tag is the classification (the type) of an Entry.
@@ -264,15 +269,22 @@ const (
TagVariantPart Tag = 0x33
TagVariable Tag = 0x34
TagVolatileType Tag = 0x35
- TagDwarfProcedure Tag = 0x36
- TagRestrictType Tag = 0x37
- TagInterfaceType Tag = 0x38
- TagNamespace Tag = 0x39
- TagImportedModule Tag = 0x3A
- TagUnspecifiedType Tag = 0x3B
- TagPartialUnit Tag = 0x3C
- TagImportedUnit Tag = 0x3D
- TagMutableType Tag = 0x3E
+ // The following are new in DWARF 3.
+ TagDwarfProcedure Tag = 0x36
+ TagRestrictType Tag = 0x37
+ TagInterfaceType Tag = 0x38
+ TagNamespace Tag = 0x39
+ TagImportedModule Tag = 0x3A
+ TagUnspecifiedType Tag = 0x3B
+ TagPartialUnit Tag = 0x3C
+ TagImportedUnit Tag = 0x3D
+ TagMutableType Tag = 0x3E // Later removed from DWARF.
+ TagCondition Tag = 0x3F
+ TagSharedType Tag = 0x40
+ // The following are new in DWARF 4.
+ TagTypeUnit Tag = 0x41
+ TagRvalueReferenceType Tag = 0x42
+ TagTemplateAlias Tag = 0x43
)
var tagNames = [...]string{
@@ -332,6 +344,11 @@ var tagNames = [...]string{
TagPartialUnit: "PartialUnit",
TagImportedUnit: "ImportedUnit",
TagMutableType: "MutableType",
+ TagCondition: "Condition",
+ TagSharedType: "SharedType",
+ TagTypeUnit: "TypeUnit",
+ TagRvalueReferenceType: "RvalueReferenceType",
+ TagTemplateAlias: "TemplateAlias",
}
func (t Tag) String() string {
diff --git a/libgo/go/debug/dwarf/entry.go b/libgo/go/debug/dwarf/entry.go
index e0d3229fb4..b6ba8c0d1c 100644
--- a/libgo/go/debug/dwarf/entry.go
+++ b/libgo/go/debug/dwarf/entry.go
@@ -241,10 +241,10 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
// lineptr, loclistptr, macptr, rangelistptr
// New in DWARF 4, but clang can generate them with -gdwarf-2.
// Section reference, replacing use of formData4 and formData8.
- case formSecOffset:
+ case formSecOffset, formGnuRefAlt, formGnuStrpAlt:
is64, known := b.format.dwarf64()
if !known {
- b.error("unknown size for DW_FORM_sec_offset")
+ b.error("unknown size for form 0x" + strconv.FormatInt(int64(fmt), 16))
} else if is64 {
val = int64(b.uint64())
} else {
@@ -396,3 +396,15 @@ func (r *Reader) SkipChildren() {
}
}
}
+
+// clone returns a copy of the reader. This is used by the typeReader
+// interface.
+func (r *Reader) clone() typeReader {
+ return r.d.Reader()
+}
+
+// offset returns the current buffer offset. This is used by the
+// typeReader interface.
+func (r *Reader) offset() Offset {
+ return r.b.off
+}
diff --git a/libgo/go/debug/dwarf/open.go b/libgo/go/debug/dwarf/open.go
index 7579892529..c1b3f37aca 100644
--- a/libgo/go/debug/dwarf/open.go
+++ b/libgo/go/debug/dwarf/open.go
@@ -26,6 +26,7 @@ type Data struct {
abbrevCache map[uint32]abbrevTable
order binary.ByteOrder
typeCache map[Offset]Type
+ typeSigs map[uint64]*typeUnit
unit []unit
}
@@ -49,6 +50,7 @@ func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Dat
str: str,
abbrevCache: make(map[uint32]abbrevTable),
typeCache: make(map[Offset]Type),
+ typeSigs: make(map[uint64]*typeUnit),
}
// Sniff .debug_info to figure out byte order.
@@ -75,3 +77,11 @@ func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Dat
d.unit = u
return d, nil
}
+
+// AddTypes will add one .debug_types section to the DWARF data. A
+// typical object with DWARF version 4 debug info will have multiple
+// .debug_types sections. The name is used for error reporting only,
+// and serves to distinguish one .debug_types section from another.
+func (d *Data) AddTypes(name string, types []byte) error {
+ return d.parseTypes(name, types)
+}
diff --git a/libgo/go/debug/dwarf/testdata/typedef.elf4 b/libgo/go/debug/dwarf/testdata/typedef.elf4
new file mode 100644
index 0000000000..3d5a5a1b16
--- /dev/null
+++ b/libgo/go/debug/dwarf/testdata/typedef.elf4
Binary files differ
diff --git a/libgo/go/debug/dwarf/type.go b/libgo/go/debug/dwarf/type.go
index 1fbae6c144..6986b19e72 100644
--- a/libgo/go/debug/dwarf/type.go
+++ b/libgo/go/debug/dwarf/type.go
@@ -88,6 +88,11 @@ type AddrType struct {
BasicType
}
+// An UnspecifiedType represents an implicit, unknown, ambiguous or nonexistent type.
+type UnspecifiedType struct {
+ BasicType
+}
+
// qualifiers
// A QualType represents a type that has the C/C++ "const", "restrict", or "volatile" qualifier.
@@ -113,7 +118,12 @@ func (t *ArrayType) String() string {
return "[" + strconv.FormatInt(t.Count, 10) + "]" + t.Type.String()
}
-func (t *ArrayType) Size() int64 { return t.Count * t.Type.Size() }
+func (t *ArrayType) Size() int64 {
+ if t.Count == -1 {
+ return 0
+ }
+ return t.Count * t.Type.Size()
+}
// A VoidType represents the C void type.
type VoidType struct {
@@ -251,23 +261,37 @@ func (t *TypedefType) String() string { return t.Name }
func (t *TypedefType) Size() int64 { return t.Type.Size() }
+// typeReader is used to read from either the info section or the
+// types section.
+type typeReader interface {
+ Seek(Offset)
+ Next() (*Entry, error)
+ clone() typeReader
+ offset() Offset
+}
+
+// Type reads the type at off in the DWARF ``info'' section.
func (d *Data) Type(off Offset) (Type, error) {
- if t, ok := d.typeCache[off]; ok {
+ return d.readType("info", d.Reader(), off, d.typeCache)
+}
+
+// readType reads a type from r at off of name using and updating a
+// type cache.
+func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Offset]Type) (Type, error) {
+ if t, ok := typeCache[off]; ok {
return t, nil
}
-
- r := d.Reader()
r.Seek(off)
e, err := r.Next()
if err != nil {
return nil, err
}
if e == nil || e.Offset != off {
- return nil, DecodeError{"info", off, "no type at offset"}
+ return nil, DecodeError{name, off, "no type at offset"}
}
// Parse type from Entry.
- // Must always set d.typeCache[off] before calling
+ // Must always set typeCache[off] before calling
// d.Type recursively, to handle circular types correctly.
var typ Type
@@ -290,7 +314,7 @@ func (d *Data) Type(off Offset) (Type, error) {
return nil
}
if kid == nil {
- err = DecodeError{"info", r.b.off, "unexpected end of DWARF entries"}
+ err = DecodeError{name, r.offset(), "unexpected end of DWARF entries"}
return nil
}
if kid.Tag == 0 {
@@ -313,15 +337,21 @@ func (d *Data) Type(off Offset) (Type, error) {
// Get Type referred to by Entry's AttrType field.
// Set err if error happens. Not having a type is an error.
typeOf := func(e *Entry) Type {
- toff, ok := e.Val(AttrType).(Offset)
- if !ok {
+ tval := e.Val(AttrType)
+ var t Type
+ switch toff := tval.(type) {
+ case Offset:
+ if t, err = d.readType(name, r.clone(), toff, typeCache); err != nil {
+ return nil
+ }
+ case uint64:
+ if t, err = d.sigToType(toff); err != nil {
+ return nil
+ }
+ default:
// It appears that no Type means "void".
return new(VoidType)
}
- var t Type
- if t, err = d.Type(toff); err != nil {
- return nil
- }
return t
}
@@ -337,39 +367,43 @@ func (d *Data) Type(off Offset) (Type, error) {
// dimensions are in left to right order.
t := new(ArrayType)
typ = t
- d.typeCache[off] = t
+ typeCache[off] = t
if t.Type = typeOf(e); err != nil {
goto Error
}
t.StrideBitSize, _ = e.Val(AttrStrideSize).(int64)
// Accumulate dimensions,
- ndim := 0
+ var dims []int64
for kid := next(); kid != nil; kid = next() {
// TODO(rsc): Can also be TagEnumerationType
// but haven't seen that in the wild yet.
switch kid.Tag {
case TagSubrangeType:
- max, ok := kid.Val(AttrUpperBound).(int64)
+ count, ok := kid.Val(AttrCount).(int64)
if !ok {
- max = -2 // Count == -1, as in x[].
- }
- if ndim == 0 {
- t.Count = max + 1
- } else {
- // Multidimensional array.
- // Create new array type underneath this one.
- t.Type = &ArrayType{Type: t.Type, Count: max + 1}
+ // Old binaries may have an upper bound instead.
+ count, ok = kid.Val(AttrUpperBound).(int64)
+ if ok {
+ count++ // Length is one more than upper bound.
+ } else if len(dims) == 0 {
+ count = -1 // As in x[].
+ }
}
- ndim++
+ dims = append(dims, count)
case TagEnumerationType:
- err = DecodeError{"info", kid.Offset, "cannot handle enumeration type as array bound"}
+ err = DecodeError{name, kid.Offset, "cannot handle enumeration type as array bound"}
goto Error
}
}
- if ndim == 0 {
+ if len(dims) == 0 {
// LLVM generates this for x[].
- t.Count = -1
+ dims = []int64{-1}
+ }
+
+ t.Count = dims[0]
+ for i := len(dims) - 1; i >= 1; i-- {
+ t.Type = &ArrayType{Type: t.Type, Count: dims[i]}
}
case TagBaseType:
@@ -383,12 +417,12 @@ func (d *Data) Type(off Offset) (Type, error) {
name, _ := e.Val(AttrName).(string)
enc, ok := e.Val(AttrEncoding).(int64)
if !ok {
- err = DecodeError{"info", e.Offset, "missing encoding attribute for " + name}
+ err = DecodeError{name, e.Offset, "missing encoding attribute for " + name}
goto Error
}
switch enc {
default:
- err = DecodeError{"info", e.Offset, "unrecognized encoding attribute value"}
+ err = DecodeError{name, e.Offset, "unrecognized encoding attribute value"}
goto Error
case encAddress:
@@ -397,6 +431,17 @@ func (d *Data) Type(off Offset) (Type, error) {
typ = new(BoolType)
case encComplexFloat:
typ = new(ComplexType)
+ if name == "complex" {
+ // clang writes out 'complex' instead of 'complex float' or 'complex double'.
+ // clang also writes out a byte size that we can use to distinguish.
+ // See issue 8694.
+ switch byteSize, _ := e.Val(AttrByteSize).(int64); byteSize {
+ case 8:
+ name = "complex float"
+ case 16:
+ name = "complex double"
+ }
+ }
case encFloat:
typ = new(FloatType)
case encSigned:
@@ -408,7 +453,7 @@ func (d *Data) Type(off Offset) (Type, error) {
case encUnsignedChar:
typ = new(UcharType)
}
- d.typeCache[off] = typ
+ typeCache[off] = typ
t := typ.(interface {
Basic() *BasicType
}).Basic()
@@ -433,7 +478,7 @@ func (d *Data) Type(off Offset) (Type, error) {
// There is much more to handle C++, all ignored for now.
t := new(StructType)
typ = t
- d.typeCache[off] = t
+ typeCache[off] = t
switch e.Tag {
case TagClassType:
t.Kind = "class"
@@ -445,7 +490,7 @@ func (d *Data) Type(off Offset) (Type, error) {
t.StructName, _ = e.Val(AttrName).(string)
t.Incomplete = e.Val(AttrDeclaration) != nil
t.Field = make([]*StructField, 0, 8)
- var lastFieldType Type
+ var lastFieldType *Type
var lastFieldBitOffset int64
for kid := next(); kid != nil; kid = next() {
if kid.Tag == TagMember {
@@ -453,12 +498,13 @@ func (d *Data) Type(off Offset) (Type, error) {
if f.Type = typeOf(kid); err != nil {
goto Error
}
- if loc, ok := kid.Val(AttrDataMemberLoc).([]byte); ok {
+ switch loc := kid.Val(AttrDataMemberLoc).(type) {
+ case []byte:
// TODO: Should have original compilation
// unit here, not unknownFormat.
b := makeBuf(d, unknownFormat{}, "location", 0, loc)
if b.uint8() != opPlusUconst {
- err = DecodeError{"info", kid.Offset, "unexpected opcode"}
+ err = DecodeError{name, kid.Offset, "unexpected opcode"}
goto Error
}
f.ByteOffset = int64(b.uint())
@@ -466,6 +512,8 @@ func (d *Data) Type(off Offset) (Type, error) {
err = b.err
goto Error
}
+ case int64:
+ f.ByteOffset = loc
}
haveBitOffset := false
@@ -484,7 +532,7 @@ func (d *Data) Type(off Offset) (Type, error) {
// (DWARF writes out 0-length arrays as if they were 1-length arrays.)
zeroArray(lastFieldType)
}
- lastFieldType = f.Type
+ lastFieldType = &f.Type
lastFieldBitOffset = bito
}
}
@@ -502,7 +550,7 @@ func (d *Data) Type(off Offset) (Type, error) {
// AttrType: subtype
t := new(QualType)
typ = t
- d.typeCache[off] = t
+ typeCache[off] = t
if t.Type = typeOf(e); err != nil {
goto Error
}
@@ -526,7 +574,7 @@ func (d *Data) Type(off Offset) (Type, error) {
// AttrConstValue: value of constant
t := new(EnumType)
typ = t
- d.typeCache[off] = t
+ typeCache[off] = t
t.EnumName, _ = e.Val(AttrName).(string)
t.Val = make([]*EnumValue, 0, 8)
for kid := next(); kid != nil; kid = next() {
@@ -552,7 +600,7 @@ func (d *Data) Type(off Offset) (Type, error) {
// AttrAddrClass: address class [ignored]
t := new(PtrType)
typ = t
- d.typeCache[off] = t
+ typeCache[off] = t
if e.Val(AttrType) == nil {
t.Type = &VoidType{}
break
@@ -571,7 +619,7 @@ func (d *Data) Type(off Offset) (Type, error) {
// TagUnspecifiedParameter: final ...
t := new(FuncType)
typ = t
- d.typeCache[off] = t
+ typeCache[off] = t
if t.ReturnType = typeOf(e); err != nil {
goto Error
}
@@ -598,9 +646,18 @@ func (d *Data) Type(off Offset) (Type, error) {
// AttrType: type definition [required]
t := new(TypedefType)
typ = t
- d.typeCache[off] = t
+ typeCache[off] = t
t.Name, _ = e.Val(AttrName).(string)
t.Type = typeOf(e)
+
+ case TagUnspecifiedType:
+ // Unspecified type (DWARF v3 §5.2)
+ // Attributes:
+ // AttrName: name
+ t := new(UnspecifiedType)
+ typ = t
+ typeCache[off] = t
+ t.Name, _ = e.Val(AttrName).(string)
}
if err != nil {
@@ -620,17 +677,20 @@ Error:
// If the parse fails, take the type out of the cache
// so that the next call with this offset doesn't hit
// the cache and return success.
- delete(d.typeCache, off)
+ delete(typeCache, off)
return nil, err
}
-func zeroArray(t Type) {
- for {
- at, ok := t.(*ArrayType)
- if !ok {
- break
- }
- at.Count = 0
- t = at.Type
+func zeroArray(t *Type) {
+ if t == nil {
+ return
+ }
+ at, ok := (*t).(*ArrayType)
+ if !ok || at.Type.Size() == 0 {
+ return
}
+ // Make a copy to avoid invalidating typeCache.
+ tt := *at
+ tt.Count = 0
+ *t = &tt
}
diff --git a/libgo/go/debug/dwarf/type_test.go b/libgo/go/debug/dwarf/type_test.go
index b5b255f6f4..2cb85e74bb 100644
--- a/libgo/go/debug/dwarf/type_test.go
+++ b/libgo/go/debug/dwarf/type_test.go
@@ -73,6 +73,8 @@ func TestTypedefsMachO(t *testing.T) {
testTypedefs(t, machoData(t, "testdata/typedef.macho"), "macho")
}
+func TestTypedefsELFDwarf4(t *testing.T) { testTypedefs(t, elfData(t, "testdata/typedef.elf4"), "elf") }
+
func testTypedefs(t *testing.T, d *Data, kind string) {
r := d.Reader()
seen := make(map[string]bool)
diff --git a/libgo/go/debug/dwarf/typeunit.go b/libgo/go/debug/dwarf/typeunit.go
new file mode 100644
index 0000000000..3fd1c9973e
--- /dev/null
+++ b/libgo/go/debug/dwarf/typeunit.go
@@ -0,0 +1,166 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package dwarf
+
+import (
+ "fmt"
+ "strconv"
+)
+
+// Parse the type units stored in a DWARF4 .debug_types section. Each
+// type unit defines a single primary type and an 8-byte signature.
+// Other sections may then use formRefSig8 to refer to the type.
+
+// The typeUnit format is a single type with a signature. It holds
+// the same data as a compilation unit.
+type typeUnit struct {
+ unit
+ toff Offset // Offset to signature type within data.
+ name string // Name of .debug_type section.
+ cache Type // Cache the type, nil to start.
+}
+
+// Parse a .debug_types section.
+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
+ }
+ hdroff := b.off
+ vers := b.uint16()
+ if vers != 4 {
+ b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
+ return b.err
+ }
+ var ao uint32
+ if !dwarf64 {
+ ao = b.uint32()
+ } else {
+ ao64 := b.uint64()
+ if ao64 != uint64(uint32(ao64)) {
+ b.error("type unit abbrev offset overflow")
+ return b.err
+ }
+ ao = uint32(ao64)
+ }
+ atable, err := d.parseAbbrev(ao)
+ if err != nil {
+ return err
+ }
+ asize := b.uint8()
+ sig := b.uint64()
+
+ var toff uint32
+ if !dwarf64 {
+ toff = b.uint32()
+ } else {
+ to64 := b.uint64()
+ if to64 != uint64(uint32(to64)) {
+ b.error("type unit type offset overflow")
+ return b.err
+ }
+ toff = uint32(to64)
+ }
+
+ boff := b.off
+ d.typeSigs[sig] = &typeUnit{
+ unit: unit{
+ base: base,
+ off: boff,
+ data: b.bytes(int(Offset(n) - (b.off - hdroff))),
+ atable: atable,
+ asize: int(asize),
+ vers: int(vers),
+ is64: dwarf64,
+ },
+ toff: Offset(toff),
+ name: name,
+ }
+ if b.err != nil {
+ return b.err
+ }
+ }
+ return nil
+}
+
+// Return the type for a type signature.
+func (d *Data) sigToType(sig uint64) (Type, error) {
+ tu := d.typeSigs[sig]
+ if tu == nil {
+ return nil, fmt.Errorf("no type unit with signature %v", sig)
+ }
+ if tu.cache != nil {
+ return tu.cache, nil
+ }
+
+ b := makeBuf(d, tu, tu.name, tu.off, tu.data)
+ r := &typeUnitReader{d: d, tu: tu, b: b}
+ t, err := d.readType(tu.name, r, Offset(tu.toff), make(map[Offset]Type))
+ if err != nil {
+ return nil, err
+ }
+
+ tu.cache = t
+ return t, nil
+}
+
+// typeUnitReader is a typeReader for a tagTypeUnit.
+type typeUnitReader struct {
+ d *Data
+ tu *typeUnit
+ b buf
+ err error
+}
+
+// Seek to a new position in the type unit.
+func (tur *typeUnitReader) Seek(off Offset) {
+ tur.err = nil
+ doff := off - tur.tu.off
+ if doff < 0 || doff >= Offset(len(tur.tu.data)) {
+ tur.err = fmt.Errorf("%s: offset %d out of range; max %d", tur.tu.name, doff, len(tur.tu.data))
+ return
+ }
+ tur.b = makeBuf(tur.d, tur.tu, tur.tu.name, off, tur.tu.data[doff:])
+}
+
+// Next reads the next Entry from the type unit.
+func (tur *typeUnitReader) Next() (*Entry, error) {
+ if tur.err != nil {
+ return nil, tur.err
+ }
+ if len(tur.tu.data) == 0 {
+ return nil, nil
+ }
+ e := tur.b.entry(tur.tu.atable, tur.tu.base)
+ if tur.b.err != nil {
+ tur.err = tur.b.err
+ return nil, tur.err
+ }
+ return e, nil
+}
+
+// clone returns a new reader for the type unit.
+func (tur *typeUnitReader) clone() typeReader {
+ return &typeUnitReader{
+ d: tur.d,
+ tu: tur.tu,
+ b: makeBuf(tur.d, tur.tu, tur.tu.name, tur.tu.off, tur.tu.data),
+ }
+}
+
+// offset returns the current offset.
+func (tur *typeUnitReader) offset() Offset {
+ return tur.b.off
+}
diff --git a/libgo/go/debug/dwarf/unit.go b/libgo/go/debug/dwarf/unit.go
index 8e09298a8b..be6093519d 100644
--- a/libgo/go/debug/dwarf/unit.go
+++ b/libgo/go/debug/dwarf/unit.go
@@ -76,7 +76,7 @@ func (d *Data) parseUnits() ([]unit, error) {
n = uint32(b.uint64())
}
vers := b.uint16()
- if vers < 2 || vers > 4 {
+ if vers != 2 && vers != 3 && vers != 4 {
b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
break
}
diff --git a/libgo/go/debug/elf/elf.go b/libgo/go/debug/elf/elf.go
index 6d6433d1ca..a9466bbdcd 100644
--- a/libgo/go/debug/elf/elf.go
+++ b/libgo/go/debug/elf/elf.go
@@ -519,7 +519,7 @@ const (
DT_INIT_ARRAY DynTag = 25 /* Address of the array of pointers to initialization functions */
DT_FINI_ARRAY DynTag = 26 /* Address of the array of pointers to termination functions */
DT_INIT_ARRAYSZ DynTag = 27 /* Size in bytes of the array of initialization functions. */
- DT_FINI_ARRAYSZ DynTag = 28 /* Size in bytes of the array of terminationfunctions. */
+ DT_FINI_ARRAYSZ DynTag = 28 /* Size in bytes of the array of termination functions. */
DT_RUNPATH DynTag = 29 /* String table offset of a null-terminated library search path string. */
DT_FLAGS DynTag = 30 /* Object specific flag values. */
DT_ENCODING DynTag = 32 /* Values greater than or equal to DT_ENCODING
@@ -1414,6 +1414,250 @@ 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.
+type R_PPC64 int
+
+const (
+ R_PPC64_NONE R_PPC64 = 0
+ R_PPC64_ADDR32 R_PPC64 = 1
+ R_PPC64_ADDR24 R_PPC64 = 2
+ R_PPC64_ADDR16 R_PPC64 = 3
+ R_PPC64_ADDR16_LO R_PPC64 = 4
+ R_PPC64_ADDR16_HI R_PPC64 = 5
+ R_PPC64_ADDR16_HA R_PPC64 = 6
+ R_PPC64_ADDR14 R_PPC64 = 7
+ R_PPC64_ADDR14_BRTAKEN R_PPC64 = 8
+ R_PPC64_ADDR14_BRNTAKEN R_PPC64 = 9
+ R_PPC64_REL24 R_PPC64 = 10
+ R_PPC64_REL14 R_PPC64 = 11
+ R_PPC64_REL14_BRTAKEN R_PPC64 = 12
+ R_PPC64_REL14_BRNTAKEN R_PPC64 = 13
+ R_PPC64_GOT16 R_PPC64 = 14
+ R_PPC64_GOT16_LO R_PPC64 = 15
+ R_PPC64_GOT16_HI R_PPC64 = 16
+ R_PPC64_GOT16_HA R_PPC64 = 17
+ R_PPC64_JMP_SLOT R_PPC64 = 21
+ R_PPC64_REL32 R_PPC64 = 26
+ R_PPC64_ADDR64 R_PPC64 = 38
+ R_PPC64_ADDR16_HIGHER R_PPC64 = 39
+ R_PPC64_ADDR16_HIGHERA R_PPC64 = 40
+ R_PPC64_ADDR16_HIGHEST R_PPC64 = 41
+ R_PPC64_ADDR16_HIGHESTA R_PPC64 = 42
+ R_PPC64_REL64 R_PPC64 = 44
+ R_PPC64_TOC16 R_PPC64 = 47
+ R_PPC64_TOC16_LO R_PPC64 = 48
+ R_PPC64_TOC16_HI R_PPC64 = 49
+ R_PPC64_TOC16_HA R_PPC64 = 50
+ R_PPC64_TOC R_PPC64 = 51
+ R_PPC64_ADDR16_DS R_PPC64 = 56
+ R_PPC64_ADDR16_LO_DS R_PPC64 = 57
+ R_PPC64_GOT16_DS R_PPC64 = 58
+ R_PPC64_GOT16_LO_DS R_PPC64 = 59
+ R_PPC64_TOC16_DS R_PPC64 = 63
+ R_PPC64_TOC16_LO_DS R_PPC64 = 64
+ R_PPC64_TLS R_PPC64 = 67
+ R_PPC64_DTPMOD64 R_PPC64 = 68
+ R_PPC64_TPREL16 R_PPC64 = 69
+ R_PPC64_TPREL16_LO R_PPC64 = 70
+ R_PPC64_TPREL16_HI R_PPC64 = 71
+ R_PPC64_TPREL16_HA R_PPC64 = 72
+ R_PPC64_TPREL64 R_PPC64 = 73
+ R_PPC64_DTPREL16 R_PPC64 = 74
+ R_PPC64_DTPREL16_LO R_PPC64 = 75
+ R_PPC64_DTPREL16_HI R_PPC64 = 76
+ R_PPC64_DTPREL16_HA R_PPC64 = 77
+ R_PPC64_DTPREL64 R_PPC64 = 78
+ R_PPC64_GOT_TLSGD16 R_PPC64 = 79
+ R_PPC64_GOT_TLSGD16_LO R_PPC64 = 80
+ R_PPC64_GOT_TLSGD16_HI R_PPC64 = 81
+ R_PPC64_GOT_TLSGD16_HA R_PPC64 = 82
+ R_PPC64_GOT_TLSLD16 R_PPC64 = 83
+ R_PPC64_GOT_TLSLD16_LO R_PPC64 = 84
+ R_PPC64_GOT_TLSLD16_HI R_PPC64 = 85
+ R_PPC64_GOT_TLSLD16_HA R_PPC64 = 86
+ R_PPC64_GOT_TPREL16_DS R_PPC64 = 87
+ R_PPC64_GOT_TPREL16_LO_DS R_PPC64 = 88
+ R_PPC64_GOT_TPREL16_HI R_PPC64 = 89
+ R_PPC64_GOT_TPREL16_HA R_PPC64 = 90
+ R_PPC64_GOT_DTPREL16_DS R_PPC64 = 91
+ R_PPC64_GOT_DTPREL16_LO_DS R_PPC64 = 92
+ R_PPC64_GOT_DTPREL16_HI R_PPC64 = 93
+ R_PPC64_GOT_DTPREL16_HA R_PPC64 = 94
+ R_PPC64_TPREL16_DS R_PPC64 = 95
+ R_PPC64_TPREL16_LO_DS R_PPC64 = 96
+ R_PPC64_TPREL16_HIGHER R_PPC64 = 97
+ R_PPC64_TPREL16_HIGHERA R_PPC64 = 98
+ R_PPC64_TPREL16_HIGHEST R_PPC64 = 99
+ R_PPC64_TPREL16_HIGHESTA R_PPC64 = 100
+ R_PPC64_DTPREL16_DS R_PPC64 = 101
+ R_PPC64_DTPREL16_LO_DS R_PPC64 = 102
+ R_PPC64_DTPREL16_HIGHER R_PPC64 = 103
+ R_PPC64_DTPREL16_HIGHERA R_PPC64 = 104
+ R_PPC64_DTPREL16_HIGHEST R_PPC64 = 105
+ R_PPC64_DTPREL16_HIGHESTA R_PPC64 = 106
+ R_PPC64_TLSGD R_PPC64 = 107
+ R_PPC64_TLSLD R_PPC64 = 108
+ R_PPC64_REL16 R_PPC64 = 249
+ R_PPC64_REL16_LO R_PPC64 = 250
+ R_PPC64_REL16_HI R_PPC64 = 251
+ R_PPC64_REL16_HA R_PPC64 = 252
+)
+
+var rppc64Strings = []intName{
+ {0, "R_PPC64_NONE"},
+ {1, "R_PPC64_ADDR32"},
+ {2, "R_PPC64_ADDR24"},
+ {3, "R_PPC64_ADDR16"},
+ {4, "R_PPC64_ADDR16_LO"},
+ {5, "R_PPC64_ADDR16_HI"},
+ {6, "R_PPC64_ADDR16_HA"},
+ {7, "R_PPC64_ADDR14"},
+ {8, "R_PPC64_ADDR14_BRTAKEN"},
+ {9, "R_PPC64_ADDR14_BRNTAKEN"},
+ {10, "R_PPC64_REL24"},
+ {11, "R_PPC64_REL14"},
+ {12, "R_PPC64_REL14_BRTAKEN"},
+ {13, "R_PPC64_REL14_BRNTAKEN"},
+ {14, "R_PPC64_GOT16"},
+ {15, "R_PPC64_GOT16_LO"},
+ {16, "R_PPC64_GOT16_HI"},
+ {17, "R_PPC64_GOT16_HA"},
+ {21, "R_PPC64_JMP_SLOT"},
+ {26, "R_PPC64_REL32"},
+ {38, "R_PPC64_ADDR64"},
+ {39, "R_PPC64_ADDR16_HIGHER"},
+ {40, "R_PPC64_ADDR16_HIGHERA"},
+ {41, "R_PPC64_ADDR16_HIGHEST"},
+ {42, "R_PPC64_ADDR16_HIGHESTA"},
+ {44, "R_PPC64_REL64"},
+ {47, "R_PPC64_TOC16"},
+ {48, "R_PPC64_TOC16_LO"},
+ {49, "R_PPC64_TOC16_HI"},
+ {50, "R_PPC64_TOC16_HA"},
+ {51, "R_PPC64_TOC"},
+ {56, "R_PPC64_ADDR16_DS"},
+ {57, "R_PPC64_ADDR16_LO_DS"},
+ {58, "R_PPC64_GOT16_DS"},
+ {59, "R_PPC64_GOT16_LO_DS"},
+ {63, "R_PPC64_TOC16_DS"},
+ {64, "R_PPC64_TOC16_LO_DS"},
+ {67, "R_PPC64_TLS"},
+ {68, "R_PPC64_DTPMOD64"},
+ {69, "R_PPC64_TPREL16"},
+ {70, "R_PPC64_TPREL16_LO"},
+ {71, "R_PPC64_TPREL16_HI"},
+ {72, "R_PPC64_TPREL16_HA"},
+ {73, "R_PPC64_TPREL64"},
+ {74, "R_PPC64_DTPREL16"},
+ {75, "R_PPC64_DTPREL16_LO"},
+ {76, "R_PPC64_DTPREL16_HI"},
+ {77, "R_PPC64_DTPREL16_HA"},
+ {78, "R_PPC64_DTPREL64"},
+ {79, "R_PPC64_GOT_TLSGD16"},
+ {80, "R_PPC64_GOT_TLSGD16_LO"},
+ {81, "R_PPC64_GOT_TLSGD16_HI"},
+ {82, "R_PPC64_GOT_TLSGD16_HA"},
+ {83, "R_PPC64_GOT_TLSLD16"},
+ {84, "R_PPC64_GOT_TLSLD16_LO"},
+ {85, "R_PPC64_GOT_TLSLD16_HI"},
+ {86, "R_PPC64_GOT_TLSLD16_HA"},
+ {87, "R_PPC64_GOT_TPREL16_DS"},
+ {88, "R_PPC64_GOT_TPREL16_LO_DS"},
+ {89, "R_PPC64_GOT_TPREL16_HI"},
+ {90, "R_PPC64_GOT_TPREL16_HA"},
+ {91, "R_PPC64_GOT_DTPREL16_DS"},
+ {92, "R_PPC64_GOT_DTPREL16_LO_DS"},
+ {93, "R_PPC64_GOT_DTPREL16_HI"},
+ {94, "R_PPC64_GOT_DTPREL16_HA"},
+ {95, "R_PPC64_TPREL16_DS"},
+ {96, "R_PPC64_TPREL16_LO_DS"},
+ {97, "R_PPC64_TPREL16_HIGHER"},
+ {98, "R_PPC64_TPREL16_HIGHERA"},
+ {99, "R_PPC64_TPREL16_HIGHEST"},
+ {100, "R_PPC64_TPREL16_HIGHESTA"},
+ {101, "R_PPC64_DTPREL16_DS"},
+ {102, "R_PPC64_DTPREL16_LO_DS"},
+ {103, "R_PPC64_DTPREL16_HIGHER"},
+ {104, "R_PPC64_DTPREL16_HIGHERA"},
+ {105, "R_PPC64_DTPREL16_HIGHEST"},
+ {106, "R_PPC64_DTPREL16_HIGHESTA"},
+ {107, "R_PPC64_TLSGD"},
+ {108, "R_PPC64_TLSLD"},
+ {249, "R_PPC64_REL16"},
+ {250, "R_PPC64_REL16_LO"},
+ {251, "R_PPC64_REL16_HI"},
+ {252, "R_PPC64_REL16_HA"},
+}
+
+func (i R_PPC64) String() string { return stringName(uint32(i), rppc64Strings, false) }
+func (i R_PPC64) GoString() string { return stringName(uint32(i), rppc64Strings, true) }
+
+// Relocation types for s390
+type R_390 int
+
+const (
+ R_390_NONE R_390 = 0
+ R_390_8 R_390 = 1
+ R_390_12 R_390 = 2
+ R_390_16 R_390 = 3
+ R_390_32 R_390 = 4
+ R_390_PC32 R_390 = 5
+ R_390_GOT12 R_390 = 6
+ R_390_GOT32 R_390 = 7
+ R_390_PLT32 R_390 = 8
+ R_390_COPY R_390 = 9
+ R_390_GLOB_DAT R_390 = 10
+ R_390_JMP_SLOT R_390 = 11
+ R_390_RELATIVE R_390 = 12
+ R_390_GOTOFF R_390 = 13
+ R_390_GOTPC R_390 = 14
+ R_390_GOT16 R_390 = 15
+ R_390_PC16 R_390 = 16
+ R_390_PC16DBL R_390 = 17
+ R_390_PLT16DBL R_390 = 18
+ R_390_PC32DBL R_390 = 19
+ R_390_PLT32DBL R_390 = 20
+ R_390_GOTPCDBL R_390 = 21
+ R_390_64 R_390 = 22
+ R_390_PC64 R_390 = 23
+ R_390_GOT64 R_390 = 24
+ R_390_PLT64 R_390 = 25
+ R_390_GOTENT R_390 = 26
+)
+
+var r390Strings = []intName{
+ {0, "R_390_NONE"},
+ {1, "R_390_8"},
+ {2, "R_390_12"},
+ {3, "R_390_16"},
+ {4, "R_390_32"},
+ {5, "R_390_PC32"},
+ {6, "R_390_GOT12"},
+ {7, "R_390_GOT32"},
+ {8, "R_390_PLT32"},
+ {9, "R_390_COPY"},
+ {10, "R_390_GLOB_DAT"},
+ {11, "R_390_JMP_SLOT"},
+ {12, "R_390_RELATIVE"},
+ {13, "R_390_GOTOFF"},
+ {14, "R_390_GOTPC"},
+ {15, "R_390_GOT16"},
+ {16, "R_390_PC16"},
+ {17, "R_390_PC16DBL"},
+ {18, "R_390_PLT16DBL"},
+ {19, "R_390_PC32DBL"},
+ {20, "R_390_PLT32DBL"},
+ {21, "R_390_GOTPCDBL"},
+ {22, "R_390_64"},
+ {23, "R_390_PC64"},
+ {24, "R_390_GOT64"},
+ {25, "R_390_PLT64"},
+ {26, "R_390_GOTENT"},
+}
+
+func (i R_390) String() string { return stringName(uint32(i), r390Strings, false) }
+func (i R_390) GoString() string { return stringName(uint32(i), r390Strings, true) }
+
// Relocation types for SPARC.
type R_SPARC int
diff --git a/libgo/go/debug/elf/elf_test.go b/libgo/go/debug/elf/elf_test.go
index 67b961b5c6..e3c51bb717 100644
--- a/libgo/go/debug/elf/elf_test.go
+++ b/libgo/go/debug/elf/elf_test.go
@@ -43,7 +43,7 @@ func TestNames(t *testing.T) {
for i, tt := range nameTests {
s := fmt.Sprint(tt.val)
if s != tt.str {
- t.Errorf("#%d: want %q have %q", i, s, tt.str)
+ t.Errorf("#%d: Sprint(%d) = %q, want %q", i, tt.val, s, tt.str)
}
}
}
diff --git a/libgo/go/debug/elf/file.go b/libgo/go/debug/elf/file.go
index f6e7e31a8e..0135f7f8db 100644
--- a/libgo/go/debug/elf/file.go
+++ b/libgo/go/debug/elf/file.go
@@ -76,6 +76,9 @@ type Section struct {
func (s *Section) Data() ([]byte, error) {
dat := make([]byte, s.sr.Size())
n, err := s.sr.ReadAt(dat, 0)
+ if n == len(dat) {
+ err = nil
+ }
return dat[0:n], err
}
@@ -402,17 +405,21 @@ func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, error) {
return nil, nil, errors.New("not implemented")
}
+// ErrNoSymbols is returned by File.Symbols and File.DynamicSymbols
+// if there is no such section in the File.
+var ErrNoSymbols = errors.New("no symbol section")
+
func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) {
symtabSection := f.SectionByType(typ)
if symtabSection == nil {
- return nil, nil, errors.New("no symbol section")
+ return nil, nil, ErrNoSymbols
}
data, err := symtabSection.Data()
if err != nil {
return nil, nil, errors.New("cannot load symbol section")
}
- symtab := bytes.NewBuffer(data)
+ symtab := bytes.NewReader(data)
if symtab.Len()%Sym32Size != 0 {
return nil, nil, errors.New("length of symbol section is not a multiple of SymSize")
}
@@ -448,14 +455,14 @@ func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) {
func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) {
symtabSection := f.SectionByType(typ)
if symtabSection == nil {
- return nil, nil, errors.New("no symbol section")
+ return nil, nil, ErrNoSymbols
}
data, err := symtabSection.Data()
if err != nil {
return nil, nil, errors.New("cannot load symbol section")
}
- symtab := bytes.NewBuffer(data)
+ symtab := bytes.NewReader(data)
if symtab.Len()%Sym64Size != 0 {
return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size")
}
@@ -519,16 +526,29 @@ func (f *File) applyRelocations(dst []byte, rels []byte) error {
if f.Class == ELFCLASS64 && f.Machine == EM_X86_64 {
return f.applyRelocationsAMD64(dst, rels)
}
+ if f.Class == ELFCLASS32 && f.Machine == EM_386 {
+ return f.applyRelocations386(dst, rels)
+ }
if f.Class == ELFCLASS64 && f.Machine == EM_AARCH64 {
return f.applyRelocationsARM64(dst, rels)
}
+ if f.Class == ELFCLASS32 && f.Machine == EM_PPC {
+ return f.applyRelocationsPPC(dst, rels)
+ }
+ if f.Class == ELFCLASS64 && f.Machine == EM_PPC64 {
+ return f.applyRelocationsPPC64(dst, rels)
+ }
+ if f.Class == ELFCLASS64 && f.Machine == EM_S390 {
+ return f.applyRelocationsS390x(dst, rels)
+ }
return errors.New("not implemented")
}
func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
- if len(rels)%Sym64Size != 0 {
- return errors.New("length of relocation section is not a multiple of Sym64Size")
+ // 24 is the size of Rela64.
+ if len(rels)%24 != 0 {
+ return errors.New("length of relocation section is not a multiple of 24")
}
symbols, _, err := f.getSymbols(SHT_SYMTAB)
@@ -536,7 +556,7 @@ func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
return err
}
- b := bytes.NewBuffer(rels)
+ b := bytes.NewReader(rels)
var rela Rela64
for b.Len() > 0 {
@@ -553,6 +573,10 @@ func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
continue
}
+ // There are relocations, so this must be a normal
+ // object file, and we only look at section symbols,
+ // so we assume that the symbol value is 0.
+
switch t {
case R_X86_64_64:
if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
@@ -570,6 +594,43 @@ func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
return nil
}
+func (f *File) applyRelocations386(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_386(rel.Info & 0xff)
+
+ if symNo == 0 || symNo > uint32(len(symbols)) {
+ continue
+ }
+ sym := &symbols[symNo-1]
+
+ if t == R_386_32 {
+ 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 {
@@ -598,6 +659,10 @@ func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error {
continue
}
+ // There are relocations, so this must be a normal
+ // object file, and we only look at section symbols,
+ // so we assume that the symbol value is 0.
+
switch t {
case R_AARCH64_ABS64:
if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
@@ -615,6 +680,132 @@ func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error {
return nil
}
+func (f *File) applyRelocationsPPC(dst []byte, rels []byte) error {
+ // 12 is the size of Rela32.
+ if len(rels)%12 != 0 {
+ return errors.New("length of relocation section is not a multiple of 12")
+ }
+
+ symbols, _, err := f.getSymbols(SHT_SYMTAB)
+ if err != nil {
+ return err
+ }
+
+ b := bytes.NewReader(rels)
+ var rela Rela32
+
+ for b.Len() > 0 {
+ binary.Read(b, f.ByteOrder, &rela)
+ symNo := rela.Info >> 8
+ t := R_PPC(rela.Info & 0xff)
+
+ if symNo == 0 || symNo > uint32(len(symbols)) {
+ continue
+ }
+ sym := &symbols[symNo-1]
+ if SymType(sym.Info&0xf) != STT_SECTION {
+ // We don't handle non-section relocations for now.
+ continue
+ }
+
+ switch t {
+ case R_PPC_ADDR32:
+ if rela.Off+4 >= uint32(len(dst)) || rela.Addend < 0 {
+ continue
+ }
+ f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
+ }
+ }
+
+ return nil
+}
+
+func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error {
+ // 24 is the size of Rela64.
+ if len(rels)%24 != 0 {
+ return errors.New("length of relocation section is not a multiple of 24")
+ }
+
+ symbols, _, err := f.getSymbols(SHT_SYMTAB)
+ if err != nil {
+ return err
+ }
+
+ b := bytes.NewReader(rels)
+ var rela Rela64
+
+ for b.Len() > 0 {
+ binary.Read(b, f.ByteOrder, &rela)
+ symNo := rela.Info >> 32
+ t := R_PPC64(rela.Info & 0xffff)
+
+ if symNo == 0 || symNo > uint64(len(symbols)) {
+ continue
+ }
+ sym := &symbols[symNo-1]
+ if SymType(sym.Info&0xf) != STT_SECTION {
+ // We don't handle non-section relocations for now.
+ continue
+ }
+
+ switch t {
+ case R_PPC64_ADDR64:
+ if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
+ continue
+ }
+ f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
+ case R_PPC64_ADDR32:
+ if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
+ continue
+ }
+ f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
+ }
+ }
+
+ return nil
+}
+
+func (f *File) applyRelocationsS390x(dst []byte, rels []byte) error {
+ // 24 is the size of Rela64.
+ if len(rels)%24 != 0 {
+ return errors.New("length of relocation section is not a multiple of 24")
+ }
+
+ symbols, _, err := f.getSymbols(SHT_SYMTAB)
+ if err != nil {
+ return err
+ }
+
+ b := bytes.NewBuffer(rels)
+ var rela Rela64
+
+ for b.Len() > 0 {
+ binary.Read(b, f.ByteOrder, &rela)
+ symNo := rela.Info >> 32
+ t := R_390(rela.Info & 0xffff)
+
+ if symNo == 0 || symNo > uint64(len(symbols)) {
+ continue
+ }
+ sym := &symbols[symNo-1]
+
+ switch t {
+ case R_390_64:
+ if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
+ continue
+ }
+ f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)+uint64(sym.Value))
+ case R_390_32:
+ if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
+ continue
+ }
+ f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)+uint32(sym.Value))
+ }
+ }
+
+ return nil
+}
+
func (f *File) DWARF() (*dwarf.Data, error) {
// There are many other DWARF sections, but these
// are the required ones, and the debug/dwarf package
@@ -637,7 +828,7 @@ func (f *File) DWARF() (*dwarf.Data, error) {
// 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) {
+ 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
@@ -648,11 +839,62 @@ func (f *File) DWARF() (*dwarf.Data, error) {
}
}
+ // 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
+ }
+ err = f.applyRelocations(dat[1], data)
+ if err != nil {
+ return nil, err
+ }
+ }
+
abbrev, info, line, ranges, str := dat[0], dat[1], dat[2], dat[3], dat[4]
- return dwarf.New(abbrev, nil, nil, info, line, nil, ranges, str)
+ d, err := dwarf.New(abbrev, nil, nil, info, line, nil, ranges, str)
+ if err != nil {
+ return nil, err
+ }
+
+ // 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 {
+ 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
+ }
+ }
+ }
+
+ return d, nil
}
-// Symbols returns the symbol table for f.
+// Symbols returns the symbol table for f. The symbols will be listed in the order
+// they appear in f.
//
// For compatibility with Go 1.0, Symbols omits the null symbol at index 0.
// After retrieving the symbols as symtab, an externally supplied index x
@@ -662,6 +904,17 @@ func (f *File) Symbols() ([]Symbol, error) {
return sym, err
}
+// DynamicSymbols returns the dynamic symbol table for f. The symbols
+// will be listed in the order they appear in f.
+//
+// For compatibility with Symbols, DynamicSymbols omits the null symbol at index 0.
+// After retrieving the symbols as symtab, an externally supplied index x
+// corresponds to symtab[x-1], not symtab[x].
+func (f *File) DynamicSymbols() ([]Symbol, error) {
+ sym, _, err := f.getSymbols(SHT_DYNSYM)
+ return sym, err
+}
+
type ImportedSymbol struct {
Name string
Version string
diff --git a/libgo/go/debug/elf/file_test.go b/libgo/go/debug/elf/file_test.go
index 38b5f9e707..56e2604d9d 100644
--- a/libgo/go/debug/elf/file_test.go
+++ b/libgo/go/debug/elf/file_test.go
@@ -166,11 +166,11 @@ func TestOpen(t *testing.T) {
} else {
f, err = Open(tt.file)
}
- defer f.Close()
if err != nil {
t.Errorf("cannot open file %s: %v", tt.file, err)
continue
}
+ defer f.Close()
if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
continue
@@ -261,6 +261,30 @@ var relocationTests = []relocationTest{
},
},
{
+ "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"}, 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)}}}},
+ },
+ },
+ {
+ "testdata/go-relocation-test-gcc482-ppc64le.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)}}}},
+ },
+ },
+ {
+ "testdata/go-relocation-test-gcc482-aarch64.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)}}}},
+ },
+ },
+ {
+ "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"}}}},
+ },
+ },
+ {
"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}}}}},
diff --git a/libgo/go/debug/elf/symbols_test.go b/libgo/go/debug/elf/symbols_test.go
new file mode 100644
index 0000000000..1b79520e3c
--- /dev/null
+++ b/libgo/go/debug/elf/symbols_test.go
@@ -0,0 +1,834 @@
+// 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 elf
+
+import (
+ "io"
+ "path"
+ "reflect"
+ "testing"
+)
+
+// TODO: remove duplicate code
+func TestSymbols(t *testing.T) {
+ do := func(file string, ts []Symbol, getfunc func(*File) ([]Symbol, error)) {
+ var f *File
+ var err error
+ if path.Ext(file) == ".gz" {
+ var r io.ReaderAt
+ if r, err = decompress(file); err == nil {
+ f, err = NewFile(r)
+ }
+ } else {
+ f, err = Open(file)
+ }
+ if err != nil {
+ t.Errorf("TestSymbols: cannot open file %s: %v", file, err)
+ return
+ }
+ defer f.Close()
+ fs, err := getfunc(f)
+ if err != nil && err != ErrNoSymbols {
+ t.Error(err)
+ return
+ } else if err == ErrNoSymbols {
+ fs = []Symbol{}
+ }
+ if !reflect.DeepEqual(ts, fs) {
+ t.Errorf("%s: Symbols = %v, want %v", file, ts, fs)
+ }
+ }
+ for file, ts := range symbolsGolden {
+ do(file, ts, (*File).Symbols)
+ }
+ for file, ts := range dynamicSymbolsGolden {
+ do(file, ts, (*File).DynamicSymbols)
+ }
+}
+
+// golden symbol table data generated by testdata/getgoldsym.c
+
+var symbolsGolden = map[string][]Symbol{
+ "testdata/gcc-amd64-linux-exec": {
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x1,
+ Value: 0x400200,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x2,
+ Value: 0x40021C,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x3,
+ Value: 0x400240,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x4,
+ Value: 0x400268,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x5,
+ Value: 0x400288,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x6,
+ Value: 0x4002E8,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x7,
+ Value: 0x400326,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x8,
+ Value: 0x400330,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x9,
+ Value: 0x400350,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0xA,
+ Value: 0x400368,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0xB,
+ Value: 0x400398,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0xC,
+ Value: 0x4003B0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0xD,
+ Value: 0x4003E0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0xE,
+ Value: 0x400594,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0xF,
+ Value: 0x4005A4,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x10,
+ Value: 0x4005B8,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x11,
+ Value: 0x4005E0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x12,
+ Value: 0x600688,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x13,
+ Value: 0x600698,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x14,
+ Value: 0x6006A8,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x15,
+ Value: 0x6006B0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x16,
+ Value: 0x600850,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x17,
+ Value: 0x600858,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x18,
+ Value: 0x600880,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x19,
+ Value: 0x600898,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x1A,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x1B,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x1C,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x1D,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x1E,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x1F,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x20,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x21,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "init.c",
+ Info: 0x4,
+ Other: 0x0,
+ Section: 0xFFF1,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "initfini.c",
+ Info: 0x4,
+ Other: 0x0,
+ Section: 0xFFF1,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "call_gmon_start",
+ Info: 0x2,
+ Other: 0x0,
+ Section: 0xD,
+ Value: 0x40040C,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "crtstuff.c",
+ Info: 0x4,
+ Other: 0x0,
+ Section: 0xFFF1,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "__CTOR_LIST__",
+ Info: 0x1,
+ Other: 0x0,
+ Section: 0x12,
+ Value: 0x600688,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "__DTOR_LIST__",
+ Info: 0x1,
+ Other: 0x0,
+ Section: 0x13,
+ Value: 0x600698,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "__JCR_LIST__",
+ Info: 0x1,
+ Other: 0x0,
+ Section: 0x14,
+ Value: 0x6006A8,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "__do_global_dtors_aux",
+ Info: 0x2,
+ Other: 0x0,
+ Section: 0xD,
+ Value: 0x400430,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "completed.6183",
+ Info: 0x1,
+ Other: 0x0,
+ Section: 0x19,
+ Value: 0x600898,
+ Size: 0x1,
+ },
+ Symbol{
+ Name: "p.6181",
+ Info: 0x1,
+ Other: 0x0,
+ Section: 0x18,
+ Value: 0x600890,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "frame_dummy",
+ Info: 0x2,
+ Other: 0x0,
+ Section: 0xD,
+ Value: 0x400470,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "crtstuff.c",
+ Info: 0x4,
+ Other: 0x0,
+ Section: 0xFFF1,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "__CTOR_END__",
+ Info: 0x1,
+ Other: 0x0,
+ Section: 0x12,
+ Value: 0x600690,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "__DTOR_END__",
+ Info: 0x1,
+ Other: 0x0,
+ Section: 0x13,
+ Value: 0x6006A0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "__FRAME_END__",
+ Info: 0x1,
+ Other: 0x0,
+ Section: 0x11,
+ Value: 0x400680,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "__JCR_END__",
+ Info: 0x1,
+ Other: 0x0,
+ Section: 0x14,
+ Value: 0x6006A8,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "__do_global_ctors_aux",
+ Info: 0x2,
+ Other: 0x0,
+ Section: 0xD,
+ Value: 0x400560,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "initfini.c",
+ Info: 0x4,
+ Other: 0x0,
+ Section: 0xFFF1,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "hello.c",
+ Info: 0x4,
+ Other: 0x0,
+ Section: 0xFFF1,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "_GLOBAL_OFFSET_TABLE_",
+ Info: 0x1,
+ Other: 0x2,
+ Section: 0x17,
+ Value: 0x600858,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "__init_array_end",
+ Info: 0x0,
+ Other: 0x2,
+ Section: 0x12,
+ Value: 0x600684,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "__init_array_start",
+ Info: 0x0,
+ Other: 0x2,
+ Section: 0x12,
+ Value: 0x600684,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "_DYNAMIC",
+ Info: 0x1,
+ Other: 0x2,
+ Section: 0x15,
+ Value: 0x6006B0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "data_start",
+ Info: 0x20,
+ Other: 0x0,
+ Section: 0x18,
+ Value: 0x600880,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "__libc_csu_fini",
+ Info: 0x12,
+ Other: 0x0,
+ Section: 0xD,
+ Value: 0x4004C0,
+ Size: 0x2,
+ },
+ Symbol{
+ Name: "_start",
+ Info: 0x12,
+ Other: 0x0,
+ Section: 0xD,
+ Value: 0x4003E0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "__gmon_start__",
+ Info: 0x20,
+ Other: 0x0,
+ Section: 0x0,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "_Jv_RegisterClasses",
+ Info: 0x20,
+ Other: 0x0,
+ Section: 0x0,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "puts@@GLIBC_2.2.5",
+ Info: 0x12,
+ Other: 0x0,
+ Section: 0x0,
+ Value: 0x0,
+ Size: 0x18C,
+ },
+ Symbol{
+ Name: "_fini",
+ Info: 0x12,
+ Other: 0x0,
+ Section: 0xE,
+ Value: 0x400594,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "__libc_start_main@@GLIBC_2.2.5",
+ Info: 0x12,
+ Other: 0x0,
+ Section: 0x0,
+ Value: 0x0,
+ Size: 0x1C2,
+ },
+ Symbol{
+ Name: "_IO_stdin_used",
+ Info: 0x11,
+ Other: 0x0,
+ Section: 0xF,
+ Value: 0x4005A4,
+ Size: 0x4,
+ },
+ Symbol{
+ Name: "__data_start",
+ Info: 0x10,
+ Other: 0x0,
+ Section: 0x18,
+ Value: 0x600880,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "__dso_handle",
+ Info: 0x11,
+ Other: 0x2,
+ Section: 0x18,
+ Value: 0x600888,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "__libc_csu_init",
+ Info: 0x12,
+ Other: 0x0,
+ Section: 0xD,
+ Value: 0x4004D0,
+ Size: 0x89,
+ },
+ Symbol{
+ Name: "__bss_start",
+ Info: 0x10,
+ Other: 0x0,
+ Section: 0xFFF1,
+ Value: 0x600898,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "_end",
+ Info: 0x10,
+ Other: 0x0,
+ Section: 0xFFF1,
+ Value: 0x6008A0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "_edata",
+ Info: 0x10,
+ Other: 0x0,
+ Section: 0xFFF1,
+ Value: 0x600898,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "main",
+ Info: 0x12,
+ Other: 0x0,
+ Section: 0xD,
+ Value: 0x400498,
+ Size: 0x1B,
+ },
+ Symbol{
+ Name: "_init",
+ Info: 0x12,
+ Other: 0x0,
+ Section: 0xB,
+ Value: 0x400398,
+ Size: 0x0,
+ },
+ },
+ "testdata/go-relocation-test-clang-x86.obj": {
+ Symbol{
+ Name: "go-relocation-test-clang.c",
+ Info: 0x4,
+ Other: 0x0,
+ Section: 0xFFF1,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: ".Linfo_string0",
+ Info: 0x0,
+ Other: 0x0,
+ Section: 0xC,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: ".Linfo_string1",
+ Info: 0x0,
+ Other: 0x0,
+ Section: 0xC,
+ Value: 0x2C,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: ".Linfo_string2",
+ Info: 0x0,
+ Other: 0x0,
+ Section: 0xC,
+ Value: 0x47,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: ".Linfo_string3",
+ Info: 0x0,
+ Other: 0x0,
+ Section: 0xC,
+ Value: 0x4C,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: ".Linfo_string4",
+ Info: 0x0,
+ Other: 0x0,
+ Section: 0xC,
+ Value: 0x4E,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x1,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x2,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x3,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x4,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x6,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x7,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x8,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0xA,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0xC,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0xD,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0xE,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0xF,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "",
+ Info: 0x3,
+ Other: 0x0,
+ Section: 0x10,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "v",
+ Info: 0x11,
+ Other: 0x0,
+ Section: 0xFFF2,
+ Value: 0x4,
+ Size: 0x4,
+ },
+ },
+ "testdata/hello-world-core.gz": {},
+}
+
+var dynamicSymbolsGolden = map[string][]Symbol{
+ "testdata/gcc-amd64-linux-exec": {
+ Symbol{
+ Name: "__gmon_start__",
+ Info: 0x20,
+ Other: 0x0,
+ Section: 0x0,
+ Value: 0x0,
+ Size: 0x0,
+ },
+ Symbol{
+ Name: "puts",
+ Info: 0x12,
+ Other: 0x0,
+ Section: 0x0,
+ Value: 0x0,
+ Size: 0x18C,
+ },
+ Symbol{
+ Name: "__libc_start_main",
+ Info: 0x12,
+ Other: 0x0,
+ Section: 0x0,
+ Value: 0x0,
+ Size: 0x1C2,
+ },
+ },
+ "testdata/go-relocation-test-clang-x86.obj": {},
+ "testdata/hello-world-core.gz": {},
+}
diff --git a/libgo/go/debug/elf/testdata/go-relocation-test-clang-x86.obj b/libgo/go/debug/elf/testdata/go-relocation-test-clang-x86.obj
new file mode 100644
index 0000000000..e909cf4e6e
--- /dev/null
+++ b/libgo/go/debug/elf/testdata/go-relocation-test-clang-x86.obj
Binary files differ
diff --git a/libgo/go/debug/elf/testdata/go-relocation-test-gcc482-aarch64.obj b/libgo/go/debug/elf/testdata/go-relocation-test-gcc482-aarch64.obj
new file mode 100644
index 0000000000..849e2644ec
--- /dev/null
+++ b/libgo/go/debug/elf/testdata/go-relocation-test-gcc482-aarch64.obj
Binary files differ
diff --git a/libgo/go/debug/elf/testdata/go-relocation-test-gcc482-ppc64le.obj b/libgo/go/debug/elf/testdata/go-relocation-test-gcc482-ppc64le.obj
new file mode 100644
index 0000000000..dad7445486
--- /dev/null
+++ b/libgo/go/debug/elf/testdata/go-relocation-test-gcc482-ppc64le.obj
Binary files differ
diff --git a/libgo/go/debug/elf/testdata/go-relocation-test-gcc5-ppc.obj b/libgo/go/debug/elf/testdata/go-relocation-test-gcc5-ppc.obj
new file mode 100644
index 0000000000..f4165af098
--- /dev/null
+++ b/libgo/go/debug/elf/testdata/go-relocation-test-gcc5-ppc.obj
Binary files differ
diff --git a/libgo/go/debug/elf/testdata/hello.c b/libgo/go/debug/elf/testdata/hello.c
new file mode 100644
index 0000000000..34d9ee7923
--- /dev/null
+++ b/libgo/go/debug/elf/testdata/hello.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+void
+main(int argc, char *argv[])
+{
+ printf("hello, world\n");
+}
diff --git a/libgo/go/debug/gosym/pclntab.go b/libgo/go/debug/gosym/pclntab.go
index 3e6a8046b3..6620aefb05 100644
--- a/libgo/go/debug/gosym/pclntab.go
+++ b/libgo/go/debug/gosym/pclntab.go
@@ -196,6 +196,33 @@ func (t *LineTable) go12Init() {
t.go12 = 1 // so far so good
}
+// go12Funcs returns a slice of Funcs derived from the Go 1.2 pcln table.
+func (t *LineTable) go12Funcs() []Func {
+ // Assume it is malformed and return nil on error.
+ defer func() {
+ recover()
+ }()
+
+ n := len(t.functab) / int(t.ptrsize) / 2
+ funcs := make([]Func, n)
+ for i := range funcs {
+ f := &funcs[i]
+ f.Entry = uint64(t.uintptr(t.functab[2*i*int(t.ptrsize):]))
+ f.End = uint64(t.uintptr(t.functab[(2*i+2)*int(t.ptrsize):]))
+ info := t.Data[t.uintptr(t.functab[(2*i+1)*int(t.ptrsize):]):]
+ f.LineTable = t
+ f.FrameSize = int(t.binary.Uint32(info[t.ptrsize+2*4:]))
+ f.Sym = &Sym{
+ Value: f.Entry,
+ Type: 'T',
+ Name: t.string(t.binary.Uint32(info[t.ptrsize:])),
+ GoType: 0,
+ Func: f,
+ }
+ }
+ return funcs
+}
+
// findFunc returns the func corresponding to the given program counter.
func (t *LineTable) findFunc(pc uint64) []byte {
if pc < t.uintptr(t.functab) || pc >= t.uintptr(t.functab[len(t.functab)-int(t.ptrsize):]) {
diff --git a/libgo/go/debug/gosym/symtab.go b/libgo/go/debug/gosym/symtab.go
index 9ab05bac2f..ee18499d11 100644
--- a/libgo/go/debug/gosym/symtab.go
+++ b/libgo/go/debug/gosym/symtab.go
@@ -129,6 +129,9 @@ var (
)
func walksymtab(data []byte, fn func(sym) error) error {
+ if len(data) == 0 { // missing symtab is okay
+ return nil
+ }
var order binary.ByteOrder = binary.BigEndian
newTable := false
switch {
@@ -399,7 +402,7 @@ func NewTable(symtab []byte, pcln *LineTable) (*Table, error) {
if n := len(t.Funcs); n > 0 {
t.Funcs[n-1].End = sym.Value
}
- if sym.Name == "etext" {
+ if sym.Name == "runtime.etext" || sym.Name == "etext" {
continue
}
@@ -455,6 +458,10 @@ func NewTable(symtab []byte, pcln *LineTable) (*Table, error) {
i = end - 1 // loop will i++
}
}
+
+ if t.go12line != nil && nf == 0 {
+ t.Funcs = t.go12line.go12Funcs()
+ }
if obj != nil {
obj.Funcs = t.Funcs[lastf:]
}
diff --git a/libgo/go/debug/macho/fat.go b/libgo/go/debug/macho/fat.go
new file mode 100644
index 0000000000..93b8315263
--- /dev/null
+++ b/libgo/go/debug/macho/fat.go
@@ -0,0 +1,146 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package macho
+
+import (
+ "encoding/binary"
+ "fmt"
+ "io"
+ "os"
+)
+
+// A FatFile is a Mach-O universal binary that contains at least one architecture.
+type FatFile struct {
+ Magic uint32
+ Arches []FatArch
+ closer io.Closer
+}
+
+// A FatArchHeader represents a fat header for a specific image architecture.
+type FatArchHeader struct {
+ Cpu Cpu
+ SubCpu uint32
+ Offset uint32
+ Size uint32
+ Align uint32
+}
+
+const fatArchHeaderSize = 5 * 4
+
+// A FatArch is a Mach-O File inside a FatFile.
+type FatArch struct {
+ FatArchHeader
+ *File
+}
+
+// ErrNotFat is returned from NewFatFile or OpenFat when the file is not a
+// universal binary but may be a thin binary, based on its magic number.
+var ErrNotFat = &FormatError{0, "not a fat Mach-O file", nil}
+
+// NewFatFile creates a new FatFile for accessing all the Mach-O images in a
+// universal binary. The Mach-O binary is expected to start at position 0 in
+// the ReaderAt.
+func NewFatFile(r io.ReaderAt) (*FatFile, error) {
+ var ff FatFile
+ sr := io.NewSectionReader(r, 0, 1<<63-1)
+
+ // Read the fat_header struct, which is always in big endian.
+ // Start with the magic number.
+ err := binary.Read(sr, binary.BigEndian, &ff.Magic)
+ if err != nil {
+ return nil, &FormatError{0, "error reading magic number", nil}
+ } else if ff.Magic != MagicFat {
+ // See if this is a Mach-O file via its magic number. The magic
+ // must be converted to little endian first though.
+ var buf [4]byte
+ binary.BigEndian.PutUint32(buf[:], ff.Magic)
+ leMagic := binary.LittleEndian.Uint32(buf[:])
+ if leMagic == Magic32 || leMagic == Magic64 {
+ return nil, ErrNotFat
+ } else {
+ return nil, &FormatError{0, "invalid magic number", nil}
+ }
+ }
+ offset := int64(4)
+
+ // Read the number of FatArchHeaders that come after the fat_header.
+ var narch uint32
+ err = binary.Read(sr, binary.BigEndian, &narch)
+ if err != nil {
+ return nil, &FormatError{offset, "invalid fat_header", nil}
+ }
+ offset += 4
+
+ if narch < 1 {
+ return nil, &FormatError{offset, "file contains no images", nil}
+ }
+
+ // Combine the Cpu and SubCpu (both uint32) into a uint64 to make sure
+ // there are not duplicate architectures.
+ seenArches := make(map[uint64]bool, narch)
+ // Make sure that all images are for the same MH_ type.
+ var machoType Type
+
+ // Following the fat_header comes narch fat_arch structs that index
+ // Mach-O images further in the file.
+ ff.Arches = make([]FatArch, narch)
+ for i := uint32(0); i < narch; i++ {
+ fa := &ff.Arches[i]
+ err = binary.Read(sr, binary.BigEndian, &fa.FatArchHeader)
+ if err != nil {
+ return nil, &FormatError{offset, "invalid fat_arch header", nil}
+ }
+ offset += fatArchHeaderSize
+
+ fr := io.NewSectionReader(r, int64(fa.Offset), int64(fa.Size))
+ fa.File, err = NewFile(fr)
+ if err != nil {
+ return nil, err
+ }
+
+ // Make sure the architecture for this image is not duplicate.
+ seenArch := (uint64(fa.Cpu) << 32) | uint64(fa.SubCpu)
+ if o, k := seenArches[seenArch]; o || k {
+ return nil, &FormatError{offset, fmt.Sprintf("duplicate architecture cpu=%v, subcpu=%#x", fa.Cpu, fa.SubCpu), nil}
+ }
+ seenArches[seenArch] = true
+
+ // Make sure the Mach-O type matches that of the first image.
+ if i == 0 {
+ machoType = fa.Type
+ } else {
+ if fa.Type != machoType {
+ return nil, &FormatError{offset, fmt.Sprintf("Mach-O type for architecture #%d (type=%#x) does not match first (type=%#x)", i, fa.Type, machoType), nil}
+ }
+ }
+ }
+
+ return &ff, nil
+}
+
+// OpenFat opens the named file using os.Open and prepares it for use as a Mach-O
+// universal binary.
+func OpenFat(name string) (ff *FatFile, err error) {
+ f, err := os.Open(name)
+ if err != nil {
+ return nil, err
+ }
+ ff, err = NewFatFile(f)
+ if err != nil {
+ f.Close()
+ return nil, err
+ }
+ ff.closer = f
+ return
+}
+
+func (ff *FatFile) Close() error {
+ var err error
+ if ff.closer != nil {
+ err = ff.closer.Close()
+ ff.closer = nil
+ }
+ return err
+}
diff --git a/libgo/go/debug/macho/file.go b/libgo/go/debug/macho/file.go
index 9d912e7a08..da13c51006 100644
--- a/libgo/go/debug/macho/file.go
+++ b/libgo/go/debug/macho/file.go
@@ -11,7 +11,6 @@ import (
"bytes"
"debug/dwarf"
"encoding/binary"
- "errors"
"fmt"
"io"
"os"
@@ -74,6 +73,9 @@ type Segment struct {
func (s *Segment) Data() ([]byte, error) {
dat := make([]byte, s.sr.Size())
n, err := s.sr.ReadAt(dat, 0)
+ if n == len(dat) {
+ err = nil
+ }
return dat[0:n], err
}
@@ -109,6 +111,9 @@ type Section struct {
func (s *Section) Data() ([]byte, error) {
dat := make([]byte, s.sr.Size())
n, err := s.sr.ReadAt(dat, 0)
+ if n == len(dat) {
+ err = nil
+ }
return dat[0:n], err
}
@@ -246,7 +251,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
case LoadCmdDylib:
var hdr DylibCmd
- b := bytes.NewBuffer(cmddat)
+ b := bytes.NewReader(cmddat)
if err := binary.Read(b, bo, &hdr); err != nil {
return nil, err
}
@@ -263,7 +268,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
case LoadCmdSymtab:
var hdr SymtabCmd
- b := bytes.NewBuffer(cmddat)
+ b := bytes.NewReader(cmddat)
if err := binary.Read(b, bo, &hdr); err != nil {
return nil, err
}
@@ -290,7 +295,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
case LoadCmdDysymtab:
var hdr DysymtabCmd
- b := bytes.NewBuffer(cmddat)
+ b := bytes.NewReader(cmddat)
if err := binary.Read(b, bo, &hdr); err != nil {
return nil, err
}
@@ -299,7 +304,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
return nil, err
}
x := make([]uint32, hdr.Nindirectsyms)
- if err := binary.Read(bytes.NewBuffer(dat), bo, x); err != nil {
+ if err := binary.Read(bytes.NewReader(dat), bo, x); err != nil {
return nil, err
}
st := new(Dysymtab)
@@ -311,7 +316,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
case LoadCmdSegment:
var seg32 Segment32
- b := bytes.NewBuffer(cmddat)
+ b := bytes.NewReader(cmddat)
if err := binary.Read(b, bo, &seg32); err != nil {
return nil, err
}
@@ -349,7 +354,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
case LoadCmdSegment64:
var seg64 Segment64
- b := bytes.NewBuffer(cmddat)
+ b := bytes.NewReader(cmddat)
if err := binary.Read(b, bo, &seg64); err != nil {
return nil, err
}
@@ -396,7 +401,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
func (f *File) parseSymtab(symdat, strtab, cmddat []byte, hdr *SymtabCmd, offset int64) (*Symtab, error) {
bo := f.ByteOrder
symtab := make([]Symbol, hdr.Nsyms)
- b := bytes.NewBuffer(symdat)
+ b := bytes.NewReader(symdat)
for i := range symtab {
var n Nlist64
if f.Magic == Magic64 {
@@ -475,7 +480,7 @@ func (f *File) DWARF() (*dwarf.Data, error) {
name = "__debug_" + name
s := f.Section(name)
if s == nil {
- return nil, errors.New("missing Mach-O section " + name)
+ continue
}
b, err := s.Data()
if err != nil && uint64(len(b)) < s.Size {
diff --git a/libgo/go/debug/macho/file_test.go b/libgo/go/debug/macho/file_test.go
index 640225b329..4797780ce7 100644
--- a/libgo/go/debug/macho/file_test.go
+++ b/libgo/go/debug/macho/file_test.go
@@ -165,3 +165,46 @@ func TestOpenFailure(t *testing.T) {
t.Errorf("open %s: succeeded unexpectedly", filename)
}
}
+
+func TestOpenFat(t *testing.T) {
+ ff, err := OpenFat("testdata/fat-gcc-386-amd64-darwin-exec")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if ff.Magic != MagicFat {
+ t.Errorf("OpenFat: got magic number %#x, want %#x", ff.Magic, MagicFat)
+ }
+ if len(ff.Arches) != 2 {
+ t.Errorf("OpenFat: got %d architectures, want 2", len(ff.Arches))
+ }
+
+ for i := range ff.Arches {
+ arch := &ff.Arches[i]
+ ftArch := &fileTests[i]
+
+ if arch.Cpu != ftArch.hdr.Cpu || arch.SubCpu != ftArch.hdr.SubCpu {
+ t.Errorf("OpenFat: architecture #%d got cpu=%#x subtype=%#x, expected cpu=%#x, subtype=%#x", i, arch.Cpu, arch.SubCpu, ftArch.hdr.Cpu, ftArch.hdr.SubCpu)
+ }
+
+ if !reflect.DeepEqual(arch.FileHeader, ftArch.hdr) {
+ t.Errorf("OpenFat header:\n\tgot %#v\n\twant %#v\n", arch.FileHeader, ftArch.hdr)
+ }
+ }
+}
+
+func TestOpenFatFailure(t *testing.T) {
+ filename := "file.go" // not a Mach-O file
+ if _, err := OpenFat(filename); err == nil {
+ t.Errorf("OpenFat %s: succeeded unexpectedly", filename)
+ }
+
+ filename = "testdata/gcc-386-darwin-exec" // not a fat Mach-O
+ ff, err := OpenFat(filename)
+ if err != ErrNotFat {
+ t.Errorf("OpenFat %s: got %v, want ErrNotFat", filename, err)
+ }
+ if ff != nil {
+ t.Errorf("OpenFat %s: got %v, want nil", filename, ff)
+ }
+}
diff --git a/libgo/go/debug/macho/macho.go b/libgo/go/debug/macho/macho.go
index bc14226c56..d9678c8eda 100644
--- a/libgo/go/debug/macho/macho.go
+++ b/libgo/go/debug/macho/macho.go
@@ -26,29 +26,40 @@ const (
)
const (
- Magic32 uint32 = 0xfeedface
- Magic64 uint32 = 0xfeedfacf
+ Magic32 uint32 = 0xfeedface
+ Magic64 uint32 = 0xfeedfacf
+ MagicFat uint32 = 0xcafebabe
)
-// A Type is a Mach-O file type, either an object or an executable.
+// A Type is the Mach-O file type, e.g. an object file, executable, or dynamic library.
type Type uint32
const (
- TypeObj Type = 1
- TypeExec Type = 2
+ TypeObj Type = 1
+ TypeExec Type = 2
+ TypeDylib Type = 6
+ TypeBundle Type = 8
)
// A Cpu is a Mach-O cpu type.
type Cpu uint32
+const cpuArch64 = 0x01000000
+
const (
Cpu386 Cpu = 7
- CpuAmd64 Cpu = Cpu386 + 1<<24
+ CpuAmd64 Cpu = Cpu386 | cpuArch64
+ CpuArm Cpu = 12
+ CpuPpc Cpu = 18
+ CpuPpc64 Cpu = CpuPpc | cpuArch64
)
var cpuStrings = []intName{
{uint32(Cpu386), "Cpu386"},
{uint32(CpuAmd64), "CpuAmd64"},
+ {uint32(CpuArm), "CpuArm"},
+ {uint32(CpuPpc), "CpuPpc"},
+ {uint32(CpuPpc64), "CpuPpc64"},
}
func (i Cpu) String() string { return stringName(uint32(i), cpuStrings, false) }
diff --git a/libgo/go/debug/macho/testdata/fat-gcc-386-amd64-darwin-exec b/libgo/go/debug/macho/testdata/fat-gcc-386-amd64-darwin-exec
new file mode 100644
index 0000000000..7efd19300b
--- /dev/null
+++ b/libgo/go/debug/macho/testdata/fat-gcc-386-amd64-darwin-exec
Binary files differ
diff --git a/libgo/go/debug/pe/file.go b/libgo/go/debug/pe/file.go
index f521566efa..759e5674fd 100644
--- a/libgo/go/debug/pe/file.go
+++ b/libgo/go/debug/pe/file.go
@@ -18,8 +18,9 @@ import (
// A File represents an open PE file.
type File struct {
FileHeader
- Sections []*Section
- Symbols []*Symbol
+ OptionalHeader interface{} // of type *OptionalHeader32 or *OptionalHeader64
+ Sections []*Section
+ Symbols []*Symbol
closer io.Closer
}
@@ -72,6 +73,9 @@ type ImportDirectory struct {
func (s *Section) Data() ([]byte, error) {
dat := make([]byte, s.sr.Size())
n, err := s.sr.ReadAt(dat, 0)
+ if n == len(dat) {
+ err = nil
+ }
return dat[0:n], err
}
@@ -120,6 +124,11 @@ func (f *File) Close() error {
return err
}
+var (
+ sizeofOptionalHeader32 = uint16(binary.Size(OptionalHeader32{}))
+ sizeofOptionalHeader64 = uint16(binary.Size(OptionalHeader64{}))
+)
+
// NewFile creates a new File for accessing a PE binary in an underlying reader.
func NewFile(r io.ReaderAt) (*File, error) {
f := new(File)
@@ -193,10 +202,33 @@ func NewFile(r io.ReaderAt) (*File, error) {
}
}
- // Process sections.
+ // Read optional header.
sr.Seek(base, os.SEEK_SET)
- binary.Read(sr, binary.LittleEndian, &f.FileHeader)
- sr.Seek(int64(f.FileHeader.SizeOfOptionalHeader), os.SEEK_CUR) //Skip OptionalHeader
+ if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil {
+ return nil, err
+ }
+ var oh32 OptionalHeader32
+ var oh64 OptionalHeader64
+ switch f.FileHeader.SizeOfOptionalHeader {
+ case sizeofOptionalHeader32:
+ if err := binary.Read(sr, binary.LittleEndian, &oh32); err != nil {
+ return nil, err
+ }
+ if oh32.Magic != 0x10b { // PE32
+ return nil, fmt.Errorf("pe32 optional header has unexpected Magic of 0x%x", oh32.Magic)
+ }
+ f.OptionalHeader = &oh32
+ case sizeofOptionalHeader64:
+ if err := binary.Read(sr, binary.LittleEndian, &oh64); err != nil {
+ return nil, err
+ }
+ if oh64.Magic != 0x20b { // PE32+
+ return nil, fmt.Errorf("pe32+ optional header has unexpected Magic of 0x%x", oh64.Magic)
+ }
+ f.OptionalHeader = &oh64
+ }
+
+ // Process sections.
f.Sections = make([]*Section, f.FileHeader.NumberOfSections)
for i := 0; i < int(f.FileHeader.NumberOfSections); i++ {
sh := new(SectionHeader32)
@@ -213,15 +245,15 @@ func NewFile(r io.ReaderAt) (*File, error) {
s := new(Section)
s.SectionHeader = SectionHeader{
Name: name,
- VirtualSize: uint32(sh.VirtualSize),
- VirtualAddress: uint32(sh.VirtualAddress),
- Size: uint32(sh.SizeOfRawData),
- Offset: uint32(sh.PointerToRawData),
- PointerToRelocations: uint32(sh.PointerToRelocations),
- PointerToLineNumbers: uint32(sh.PointerToLineNumbers),
- NumberOfRelocations: uint16(sh.NumberOfRelocations),
- NumberOfLineNumbers: uint16(sh.NumberOfLineNumbers),
- Characteristics: uint32(sh.Characteristics),
+ VirtualSize: sh.VirtualSize,
+ VirtualAddress: sh.VirtualAddress,
+ Size: sh.SizeOfRawData,
+ Offset: sh.PointerToRawData,
+ PointerToRelocations: sh.PointerToRelocations,
+ PointerToLineNumbers: sh.PointerToLineNumbers,
+ NumberOfRelocations: sh.NumberOfRelocations,
+ NumberOfLineNumbers: sh.NumberOfLineNumbers,
+ Characteristics: sh.Characteristics,
}
s.sr = io.NewSectionReader(r, int64(s.SectionHeader.Offset), int64(s.SectionHeader.Size))
s.ReaderAt = s.sr
diff --git a/libgo/go/debug/pe/file_test.go b/libgo/go/debug/pe/file_test.go
index c0f9fcb95d..0d73969bca 100644
--- a/libgo/go/debug/pe/file_test.go
+++ b/libgo/go/debug/pe/file_test.go
@@ -12,6 +12,7 @@ import (
type fileTest struct {
file string
hdr FileHeader
+ opthdr interface{}
sections []*SectionHeader
symbols []*Symbol
}
@@ -20,6 +21,7 @@ var fileTests = []fileTest{
{
"testdata/gcc-386-mingw-obj",
FileHeader{0x014c, 0x000c, 0x0, 0x64a, 0x1e, 0x0, 0x104},
+ nil,
[]*SectionHeader{
{".text", 0, 0, 36, 500, 1440, 0, 3, 0, 0x60300020},
{".data", 0, 0, 0, 0, 0, 0, 0, 0, 3224371264},
@@ -56,27 +58,137 @@ var fileTests = []fileTest{
{
"testdata/gcc-386-mingw-exec",
FileHeader{0x014c, 0x000f, 0x4c6a1b60, 0x3c00, 0x282, 0xe0, 0x107},
+ &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},
+ {0x5000, 0x3c8},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x7000, 0x18},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ },
+ },
[]*SectionHeader{
- {Name: ".text", VirtualSize: 0xcd8, VirtualAddress: 0x1000, Size: 0xe00, Offset: 0x400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x60500060},
- {Name: ".data", VirtualSize: 0x10, VirtualAddress: 0x2000, Size: 0x200, Offset: 0x1200, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
- {Name: ".rdata", VirtualSize: 0x120, VirtualAddress: 0x3000, Size: 0x200, Offset: 0x1400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x40300040},
- {Name: ".bss", VirtualSize: 0xdc, VirtualAddress: 0x4000, Size: 0x0, Offset: 0x0, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0400080},
- {Name: ".idata", VirtualSize: 0x3c8, VirtualAddress: 0x5000, Size: 0x400, Offset: 0x1600, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
- {Name: ".CRT", VirtualSize: 0x18, VirtualAddress: 0x6000, Size: 0x200, Offset: 0x1a00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
- {Name: ".tls", VirtualSize: 0x20, VirtualAddress: 0x7000, Size: 0x200, Offset: 0x1c00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
- {Name: ".debug_aranges", VirtualSize: 0x20, VirtualAddress: 0x8000, Size: 0x200, Offset: 0x1e00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
- {Name: ".debug_pubnames", VirtualSize: 0x51, VirtualAddress: 0x9000, Size: 0x200, Offset: 0x2000, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
- {Name: ".debug_pubtypes", VirtualSize: 0x91, VirtualAddress: 0xa000, Size: 0x200, Offset: 0x2200, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
- {Name: ".debug_info", VirtualSize: 0xe22, VirtualAddress: 0xb000, Size: 0x1000, Offset: 0x2400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
- {Name: ".debug_abbrev", VirtualSize: 0x157, VirtualAddress: 0xc000, Size: 0x200, Offset: 0x3400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
- {Name: ".debug_line", VirtualSize: 0x144, VirtualAddress: 0xd000, Size: 0x200, Offset: 0x3600, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
- {Name: ".debug_frame", VirtualSize: 0x34, VirtualAddress: 0xe000, Size: 0x200, Offset: 0x3800, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42300000},
- {Name: ".debug_loc", VirtualSize: 0x38, VirtualAddress: 0xf000, Size: 0x200, Offset: 0x3a00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+ {".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},
+ {".bss", 0xdc, 0x4000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0400080},
+ {".idata", 0x3c8, 0x5000, 0x400, 0x1600, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
+ {".CRT", 0x18, 0x6000, 0x200, 0x1a00, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
+ {".tls", 0x20, 0x7000, 0x200, 0x1c00, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
+ {".debug_aranges", 0x20, 0x8000, 0x200, 0x1e00, 0x0, 0x0, 0x0, 0x0, 0x42100000},
+ {".debug_pubnames", 0x51, 0x9000, 0x200, 0x2000, 0x0, 0x0, 0x0, 0x0, 0x42100000},
+ {".debug_pubtypes", 0x91, 0xa000, 0x200, 0x2200, 0x0, 0x0, 0x0, 0x0, 0x42100000},
+ {".debug_info", 0xe22, 0xb000, 0x1000, 0x2400, 0x0, 0x0, 0x0, 0x0, 0x42100000},
+ {".debug_abbrev", 0x157, 0xc000, 0x200, 0x3400, 0x0, 0x0, 0x0, 0x0, 0x42100000},
+ {".debug_line", 0x144, 0xd000, 0x200, 0x3600, 0x0, 0x0, 0x0, 0x0, 0x42100000},
+ {".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{
+ {".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},
+ {".rdata", 0x0, 0x0, 0x10, 0x134, 0x0, 0x0, 0x0, 0x0, 0x40500040},
+ {".xdata", 0x0, 0x0, 0xc, 0x144, 0x0, 0x0, 0x0, 0x0, 0x40300040},
+ {".pdata", 0x0, 0x0, 0xc, 0x150, 0x17a, 0x0, 0x3, 0x0, 0x40300040},
+ },
+ []*Symbol{
+ {".file", 0x0, -2, 0x0, 0x67},
+ {"main", 0x0, 1, 0x20, 0x2},
+ {".text", 0x0, 1, 0x0, 0x3},
+ {".data", 0x0, 2, 0x0, 0x3},
+ {".bss", 0x0, 3, 0x0, 0x3},
+ {".rdata", 0x0, 4, 0x0, 0x3},
+ {".xdata", 0x0, 5, 0x0, 0x3},
+ {".pdata", 0x0, 6, 0x0, 0x3},
+ {"__main", 0x0, 0, 0x20, 0x2},
+ {"puts", 0x0, 0, 0x20, 0x2},
+ },
+ },
+ {
+ "testdata/gcc-amd64-mingw-exec",
+ FileHeader{0x8664, 0x11, 0x53e4364f, 0x39600, 0x6fc, 0xf0, 0x27},
+ &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},
+ {0xe000, 0x990},
+ {0x0, 0x0},
+ {0xa000, 0x498},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x10000, 0x28},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0xe254, 0x218},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ }},
+ []*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},
+ {".pdata", 0x498, 0xa000, 0x600, 0x7a00, 0x0, 0x0, 0x0, 0x0, 0x40300040},
+ {".xdata", 0x488, 0xb000, 0x600, 0x8000, 0x0, 0x0, 0x0, 0x0, 0x40300040},
+ {".bss", 0x1410, 0xc000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0600080},
+ {".idata", 0x990, 0xe000, 0xa00, 0x8600, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
+ {".CRT", 0x68, 0xf000, 0x200, 0x9000, 0x0, 0x0, 0x0, 0x0, 0xc0400040},
+ {".tls", 0x48, 0x10000, 0x200, 0x9200, 0x0, 0x0, 0x0, 0x0, 0xc0600040},
+ {".debug_aranges", 0x600, 0x11000, 0x600, 0x9400, 0x0, 0x0, 0x0, 0x0, 0x42500040},
+ {".debug_info", 0x1316e, 0x12000, 0x13200, 0x9a00, 0x0, 0x0, 0x0, 0x0, 0x42100040},
+ {".debug_abbrev", 0x2ccb, 0x26000, 0x2e00, 0x1cc00, 0x0, 0x0, 0x0, 0x0, 0x42100040},
+ {".debug_line", 0x3c4d, 0x29000, 0x3e00, 0x1fa00, 0x0, 0x0, 0x0, 0x0, 0x42100040},
+ {".debug_frame", 0x18b8, 0x2d000, 0x1a00, 0x23800, 0x0, 0x0, 0x0, 0x0, 0x42400040},
+ {".debug_str", 0x396, 0x2f000, 0x400, 0x25200, 0x0, 0x0, 0x0, 0x0, 0x42100040},
+ {".debug_loc", 0x13240, 0x30000, 0x13400, 0x25600, 0x0, 0x0, 0x0, 0x0, 0x42100040},
+ {".debug_ranges", 0xa70, 0x44000, 0xc00, 0x38a00, 0x0, 0x0, 0x0, 0x0, 0x42100040},
},
[]*Symbol{},
},
}
+func isOptHdrEq(a, b interface{}) bool {
+ switch va := a.(type) {
+ case *OptionalHeader32:
+ vb, ok := b.(*OptionalHeader32)
+ if !ok {
+ return false
+ }
+ return *vb == *va
+ case *OptionalHeader64:
+ vb, ok := b.(*OptionalHeader64)
+ if !ok {
+ return false
+ }
+ return *vb == *va
+ case nil:
+ return b == nil
+ }
+ return false
+}
+
func TestOpen(t *testing.T) {
for i := range fileTests {
tt := &fileTests[i]
@@ -90,6 +202,10 @@ func TestOpen(t *testing.T) {
t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
continue
}
+ if !isOptHdrEq(tt.opthdr, f.OptionalHeader) {
+ t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.OptionalHeader, tt.opthdr)
+ continue
+ }
for i, sh := range f.Sections {
if i >= len(tt.sections) {
diff --git a/libgo/go/debug/pe/pe.go b/libgo/go/debug/pe/pe.go
index 0606217b3b..8e90b1b513 100644
--- a/libgo/go/debug/pe/pe.go
+++ b/libgo/go/debug/pe/pe.go
@@ -14,6 +14,78 @@ type FileHeader struct {
Characteristics uint16
}
+type DataDirectory struct {
+ VirtualAddress uint32
+ Size uint32
+}
+
+type OptionalHeader32 struct {
+ Magic uint16
+ MajorLinkerVersion uint8
+ MinorLinkerVersion uint8
+ SizeOfCode uint32
+ SizeOfInitializedData uint32
+ SizeOfUninitializedData uint32
+ AddressOfEntryPoint uint32
+ BaseOfCode uint32
+ BaseOfData uint32
+ ImageBase uint32
+ SectionAlignment uint32
+ FileAlignment uint32
+ MajorOperatingSystemVersion uint16
+ MinorOperatingSystemVersion uint16
+ MajorImageVersion uint16
+ MinorImageVersion uint16
+ MajorSubsystemVersion uint16
+ MinorSubsystemVersion uint16
+ Win32VersionValue uint32
+ SizeOfImage uint32
+ SizeOfHeaders uint32
+ CheckSum uint32
+ Subsystem uint16
+ DllCharacteristics uint16
+ SizeOfStackReserve uint32
+ SizeOfStackCommit uint32
+ SizeOfHeapReserve uint32
+ SizeOfHeapCommit uint32
+ LoaderFlags uint32
+ NumberOfRvaAndSizes uint32
+ DataDirectory [16]DataDirectory
+}
+
+type OptionalHeader64 struct {
+ Magic uint16
+ MajorLinkerVersion uint8
+ MinorLinkerVersion uint8
+ SizeOfCode uint32
+ SizeOfInitializedData uint32
+ SizeOfUninitializedData uint32
+ AddressOfEntryPoint uint32
+ BaseOfCode uint32
+ ImageBase uint64
+ SectionAlignment uint32
+ FileAlignment uint32
+ MajorOperatingSystemVersion uint16
+ MinorOperatingSystemVersion uint16
+ MajorImageVersion uint16
+ MinorImageVersion uint16
+ MajorSubsystemVersion uint16
+ MinorSubsystemVersion uint16
+ Win32VersionValue uint32
+ SizeOfImage uint32
+ SizeOfHeaders uint32
+ CheckSum uint32
+ Subsystem uint16
+ DllCharacteristics uint16
+ SizeOfStackReserve uint64
+ SizeOfStackCommit uint64
+ SizeOfHeapReserve uint64
+ SizeOfHeapCommit uint64
+ LoaderFlags uint32
+ NumberOfRvaAndSizes uint32
+ DataDirectory [16]DataDirectory
+}
+
type SectionHeader32 struct {
Name [8]uint8
VirtualSize uint32
diff --git a/libgo/go/debug/pe/testdata/gcc-amd64-mingw-exec b/libgo/go/debug/pe/testdata/gcc-amd64-mingw-exec
new file mode 100644
index 0000000000..ce6feb6b7b
--- /dev/null
+++ b/libgo/go/debug/pe/testdata/gcc-amd64-mingw-exec
Binary files differ
diff --git a/libgo/go/debug/pe/testdata/gcc-amd64-mingw-obj b/libgo/go/debug/pe/testdata/gcc-amd64-mingw-obj
new file mode 100644
index 0000000000..48ae7921f3
--- /dev/null
+++ b/libgo/go/debug/pe/testdata/gcc-amd64-mingw-obj
Binary files differ
diff --git a/libgo/go/debug/plan9obj/file.go b/libgo/go/debug/plan9obj/file.go
new file mode 100644
index 0000000000..b11ed86f18
--- /dev/null
+++ b/libgo/go/debug/plan9obj/file.go
@@ -0,0 +1,328 @@
+// 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 plan9obj implements access to Plan 9 a.out object files.
+package plan9obj
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "os"
+)
+
+// A FileHeader represents a Plan 9 a.out file header.
+type FileHeader struct {
+ Magic uint32
+ Bss uint32
+ Entry uint64
+ PtrSize int
+ LoadAddress uint64
+ HdrSize uint64
+}
+
+// A File represents an open Plan 9 a.out file.
+type File struct {
+ FileHeader
+ Sections []*Section
+ closer io.Closer
+}
+
+// A SectionHeader represents a single Plan 9 a.out section header.
+// This structure doesn't exist on-disk, but eases navigation
+// through the object file.
+type SectionHeader struct {
+ Name string
+ Size uint32
+ Offset uint32
+}
+
+// A Section represents a single section in a Plan 9 a.out file.
+type Section struct {
+ SectionHeader
+
+ // Embed ReaderAt for ReadAt method.
+ // Do not embed SectionReader directly
+ // to avoid having Read and Seek.
+ // If a client wants Read and Seek it must use
+ // Open() to avoid fighting over the seek offset
+ // with other clients.
+ io.ReaderAt
+ sr *io.SectionReader
+}
+
+// Data reads and returns the contents of the Plan 9 a.out section.
+func (s *Section) Data() ([]byte, error) {
+ dat := make([]byte, s.sr.Size())
+ n, err := s.sr.ReadAt(dat, 0)
+ if n == len(dat) {
+ err = nil
+ }
+ return dat[0:n], err
+}
+
+// Open returns a new ReadSeeker reading the Plan 9 a.out section.
+func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
+
+// A Symbol represents an entry in a Plan 9 a.out symbol table section.
+type Sym struct {
+ Value uint64
+ Type rune
+ Name string
+}
+
+/*
+ * Plan 9 a.out reader
+ */
+
+// formatError is returned by some operations if the data does
+// not have the correct format for an object file.
+type formatError struct {
+ off int
+ msg string
+ val interface{}
+}
+
+func (e *formatError) Error() string {
+ msg := e.msg
+ if e.val != nil {
+ msg += fmt.Sprintf(" '%v'", e.val)
+ }
+ msg += fmt.Sprintf(" in record at byte %#x", e.off)
+ return msg
+}
+
+// Open opens the named file using os.Open and prepares it for use as a Plan 9 a.out binary.
+func Open(name string) (*File, error) {
+ f, err := os.Open(name)
+ if err != nil {
+ return nil, err
+ }
+ ff, err := NewFile(f)
+ if err != nil {
+ f.Close()
+ return nil, err
+ }
+ ff.closer = f
+ return ff, nil
+}
+
+// Close closes the File.
+// If the File was created using NewFile directly instead of Open,
+// Close has no effect.
+func (f *File) Close() error {
+ var err error
+ if f.closer != nil {
+ err = f.closer.Close()
+ f.closer = nil
+ }
+ return err
+}
+
+func parseMagic(magic []byte) (uint32, error) {
+ m := binary.BigEndian.Uint32(magic)
+ switch m {
+ case Magic386, MagicAMD64, MagicARM:
+ return m, nil
+ }
+ return 0, &formatError{0, "bad magic number", magic}
+}
+
+// NewFile creates a new File for accessing a Plan 9 binary in an underlying reader.
+// The Plan 9 binary is expected to start at position 0 in the ReaderAt.
+func NewFile(r io.ReaderAt) (*File, error) {
+ sr := io.NewSectionReader(r, 0, 1<<63-1)
+ // Read and decode Plan 9 magic
+ var magic [4]byte
+ if _, err := r.ReadAt(magic[:], 0); err != nil {
+ return nil, err
+ }
+ _, err := parseMagic(magic[:])
+ if err != nil {
+ return nil, err
+ }
+
+ ph := new(prog)
+ if err := binary.Read(sr, binary.BigEndian, ph); err != nil {
+ return nil, err
+ }
+
+ f := &File{FileHeader: FileHeader{
+ Magic: ph.Magic,
+ Bss: ph.Bss,
+ Entry: uint64(ph.Entry),
+ PtrSize: 4,
+ LoadAddress: 0x1000,
+ HdrSize: 4 * 8,
+ }}
+
+ if ph.Magic&Magic64 != 0 {
+ if err := binary.Read(sr, binary.BigEndian, &f.Entry); err != nil {
+ return nil, err
+ }
+ f.PtrSize = 8
+ f.LoadAddress = 0x200000
+ f.HdrSize += 8
+ }
+
+ var sects = []struct {
+ name string
+ size uint32
+ }{
+ {"text", ph.Text},
+ {"data", ph.Data},
+ {"syms", ph.Syms},
+ {"spsz", ph.Spsz},
+ {"pcsz", ph.Pcsz},
+ }
+
+ f.Sections = make([]*Section, 5)
+
+ off := uint32(f.HdrSize)
+
+ for i, sect := range sects {
+ s := new(Section)
+ s.SectionHeader = SectionHeader{
+ Name: sect.name,
+ Size: sect.size,
+ Offset: off,
+ }
+ off += sect.size
+ s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Size))
+ s.ReaderAt = s.sr
+ f.Sections[i] = s
+ }
+
+ return f, nil
+}
+
+func walksymtab(data []byte, ptrsz int, fn func(sym) error) error {
+ var order binary.ByteOrder = binary.BigEndian
+ var s sym
+ p := data
+ for len(p) >= 4 {
+ // Symbol type, value.
+ if len(p) < ptrsz {
+ return &formatError{len(data), "unexpected EOF", nil}
+ }
+ // fixed-width value
+ if ptrsz == 8 {
+ s.value = order.Uint64(p[0:8])
+ p = p[8:]
+ } else {
+ s.value = uint64(order.Uint32(p[0:4]))
+ p = p[4:]
+ }
+
+ var typ byte
+ typ = p[0] & 0x7F
+ s.typ = typ
+ p = p[1:]
+
+ // Name.
+ var i int
+ var nnul int
+ for i = 0; i < len(p); i++ {
+ if p[i] == 0 {
+ nnul = 1
+ break
+ }
+ }
+ switch typ {
+ case 'z', 'Z':
+ p = p[i+nnul:]
+ for i = 0; i+2 <= len(p); i += 2 {
+ if p[i] == 0 && p[i+1] == 0 {
+ nnul = 2
+ break
+ }
+ }
+ }
+ if len(p) < i+nnul {
+ return &formatError{len(data), "unexpected EOF", nil}
+ }
+ s.name = p[0:i]
+ i += nnul
+ p = p[i:]
+
+ fn(s)
+ }
+ return nil
+}
+
+// NewTable decodes the Go symbol table in data,
+// returning an in-memory representation.
+func newTable(symtab []byte, ptrsz int) ([]Sym, error) {
+ var n int
+ err := walksymtab(symtab, ptrsz, func(s sym) error {
+ n++
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ fname := make(map[uint16]string)
+ syms := make([]Sym, 0, n)
+ err = walksymtab(symtab, ptrsz, func(s sym) error {
+ n := len(syms)
+ syms = syms[0 : n+1]
+ ts := &syms[n]
+ ts.Type = rune(s.typ)
+ ts.Value = s.value
+ switch s.typ {
+ default:
+ ts.Name = string(s.name[:])
+ case 'z', 'Z':
+ for i := 0; i < len(s.name); i += 2 {
+ eltIdx := binary.BigEndian.Uint16(s.name[i : i+2])
+ elt, ok := fname[eltIdx]
+ if !ok {
+ return &formatError{-1, "bad filename code", eltIdx}
+ }
+ if n := len(ts.Name); n > 0 && ts.Name[n-1] != '/' {
+ ts.Name += "/"
+ }
+ ts.Name += elt
+ }
+ }
+ switch s.typ {
+ case 'f':
+ fname[uint16(s.value)] = ts.Name
+ }
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ return syms, nil
+}
+
+// Symbols returns the symbol table for f.
+func (f *File) Symbols() ([]Sym, error) {
+ symtabSection := f.Section("syms")
+ if symtabSection == nil {
+ return nil, errors.New("no symbol section")
+ }
+
+ symtab, err := symtabSection.Data()
+ if err != nil {
+ return nil, errors.New("cannot load symbol section")
+ }
+
+ return newTable(symtab, f.PtrSize)
+}
+
+// Section returns a section with the given name, or nil if no such
+// section exists.
+func (f *File) Section(name string) *Section {
+ for _, s := range f.Sections {
+ if s.Name == name {
+ return s
+ }
+ }
+ return nil
+}
diff --git a/libgo/go/debug/plan9obj/file_test.go b/libgo/go/debug/plan9obj/file_test.go
new file mode 100644
index 0000000000..cfd7a61d1c
--- /dev/null
+++ b/libgo/go/debug/plan9obj/file_test.go
@@ -0,0 +1,81 @@
+// 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 plan9obj
+
+import (
+ "reflect"
+ "testing"
+)
+
+type fileTest struct {
+ file string
+ hdr FileHeader
+ sections []*SectionHeader
+}
+
+var fileTests = []fileTest{
+ {
+ "testdata/386-plan9-exec",
+ FileHeader{Magic386, 0x324, 0x14, 4, 0x1000, 32},
+ []*SectionHeader{
+ {"text", 0x4c5f, 0x20},
+ {"data", 0x94c, 0x4c7f},
+ {"syms", 0x2c2b, 0x55cb},
+ {"spsz", 0x0, 0x81f6},
+ {"pcsz", 0xf7a, 0x81f6},
+ },
+ },
+ {
+ "testdata/amd64-plan9-exec",
+ FileHeader{MagicAMD64, 0x618, 0x13, 8, 0x200000, 40},
+ []*SectionHeader{
+ {"text", 0x4213, 0x28},
+ {"data", 0xa80, 0x423b},
+ {"syms", 0x2c8c, 0x4cbb},
+ {"spsz", 0x0, 0x7947},
+ {"pcsz", 0xca0, 0x7947},
+ },
+ },
+}
+
+func TestOpen(t *testing.T) {
+ for i := range fileTests {
+ tt := &fileTests[i]
+
+ f, err := Open(tt.file)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
+ t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
+ continue
+ }
+
+ for i, sh := range f.Sections {
+ if i >= len(tt.sections) {
+ break
+ }
+ have := &sh.SectionHeader
+ want := tt.sections[i]
+ if !reflect.DeepEqual(have, want) {
+ t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
+ }
+ }
+ tn := len(tt.sections)
+ fn := len(f.Sections)
+ if tn != fn {
+ t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
+ }
+ }
+}
+
+func TestOpenFailure(t *testing.T) {
+ filename := "file.go" // not a Plan 9 a.out file
+ _, err := Open(filename) // don't crash
+ if err == nil {
+ t.Errorf("open %s: succeeded unexpectedly", filename)
+ }
+}
diff --git a/libgo/go/debug/plan9obj/plan9obj.go b/libgo/go/debug/plan9obj/plan9obj.go
new file mode 100644
index 0000000000..af9858562f
--- /dev/null
+++ b/libgo/go/debug/plan9obj/plan9obj.go
@@ -0,0 +1,36 @@
+// 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.
+
+/*
+ * Plan 9 a.out constants and data structures
+ */
+
+package plan9obj
+
+// Plan 9 Program header.
+type prog struct {
+ Magic uint32 /* magic number */
+ Text uint32 /* size of text segment */
+ Data uint32 /* size of initialized data */
+ Bss uint32 /* size of uninitialized data */
+ Syms uint32 /* size of symbol table */
+ Entry uint32 /* entry point */
+ Spsz uint32 /* size of pc/sp offset table */
+ Pcsz uint32 /* size of pc/line number table */
+}
+
+// Plan 9 symbol table entries.
+type sym struct {
+ value uint64
+ typ byte
+ name []byte
+}
+
+const (
+ Magic64 = 0x8000 // 64-bit expanded header
+
+ Magic386 = (4*11+0)*11 + 7
+ MagicAMD64 = (4*26+0)*26 + 7 + Magic64
+ MagicARM = (4*20+0)*20 + 7
+)
diff --git a/libgo/go/debug/plan9obj/testdata/386-plan9-exec b/libgo/go/debug/plan9obj/testdata/386-plan9-exec
new file mode 100644
index 0000000000..748e83f8e6
--- /dev/null
+++ b/libgo/go/debug/plan9obj/testdata/386-plan9-exec
Binary files differ
diff --git a/libgo/go/debug/plan9obj/testdata/amd64-plan9-exec b/libgo/go/debug/plan9obj/testdata/amd64-plan9-exec
new file mode 100644
index 0000000000..3e257dd8ff
--- /dev/null
+++ b/libgo/go/debug/plan9obj/testdata/amd64-plan9-exec
Binary files differ
diff --git a/libgo/go/debug/plan9obj/testdata/hello.c b/libgo/go/debug/plan9obj/testdata/hello.c
new file mode 100644
index 0000000000..c0d633e29f
--- /dev/null
+++ b/libgo/go/debug/plan9obj/testdata/hello.c
@@ -0,0 +1,8 @@
+#include <u.h>
+#include <libc.h>
+
+void
+main(void)
+{
+ print("hello, world\n");
+}
diff --git a/libgo/go/encoding/ascii85/ascii85.go b/libgo/go/encoding/ascii85/ascii85.go
index e2afc58714..4d7193873a 100644
--- a/libgo/go/encoding/ascii85/ascii85.go
+++ b/libgo/go/encoding/ascii85/ascii85.go
@@ -249,7 +249,6 @@ type decoder struct {
err error
readErr error
r io.Reader
- end bool // saw end of message
buf [1024]byte // leftover input
nbuf int
out []byte // leftover decoded output
@@ -281,6 +280,18 @@ func (d *decoder) Read(p []byte) (n int, err error) {
d.nbuf = copy(d.buf[0:], d.buf[nsrc:d.nbuf])
continue // copy out and return
}
+ if ndst == 0 && d.err == nil {
+ // Special case: input buffer is mostly filled with non-data bytes.
+ // Filter out such bytes to make room for more input.
+ off := 0
+ for i := 0; i < d.nbuf; i++ {
+ if d.buf[i] > ' ' {
+ d.buf[off] = d.buf[i]
+ off++
+ }
+ }
+ d.nbuf = off
+ }
}
// Out of input, out of decoded output. Check errors.
diff --git a/libgo/go/encoding/ascii85/ascii85_test.go b/libgo/go/encoding/ascii85/ascii85_test.go
index 42cf7e80e1..aad199b4fa 100644
--- a/libgo/go/encoding/ascii85/ascii85_test.go
+++ b/libgo/go/encoding/ascii85/ascii85_test.go
@@ -8,6 +8,7 @@ import (
"bytes"
"io"
"io/ioutil"
+ "strings"
"testing"
)
@@ -16,6 +17,11 @@ type testpair struct {
}
var pairs = []testpair{
+ // Encode returns 0 when len(src) is 0
+ {
+ "",
+ "",
+ },
// Wikipedia example
{
"Man is distinguished, not only by his reason, but by this singular passion from " +
@@ -110,7 +116,7 @@ func TestDecode(t *testing.T) {
func TestDecoder(t *testing.T) {
for _, p := range pairs {
- decoder := NewDecoder(bytes.NewBufferString(p.encoded))
+ decoder := NewDecoder(strings.NewReader(p.encoded))
dbuf, err := ioutil.ReadAll(decoder)
if err != nil {
t.Fatal("Read failed", err)
@@ -125,7 +131,7 @@ func TestDecoder(t *testing.T) {
func TestDecoderBuffering(t *testing.T) {
for bs := 1; bs <= 12; bs++ {
- decoder := NewDecoder(bytes.NewBufferString(bigtest.encoded))
+ decoder := NewDecoder(strings.NewReader(bigtest.encoded))
buf := make([]byte, len(bigtest.decoded)+12)
var total int
for total = 0; total < len(bigtest.decoded); {
@@ -191,3 +197,14 @@ func TestBig(t *testing.T) {
t.Errorf("Decode(Encode(%d-byte string)) failed at offset %d", n, i)
}
}
+
+func TestDecoderInternalWhitespace(t *testing.T) {
+ s := strings.Repeat(" ", 2048) + "z"
+ decoded, err := ioutil.ReadAll(NewDecoder(strings.NewReader(s)))
+ if err != nil {
+ t.Errorf("Decode gave error %v", err)
+ }
+ if want := []byte("\000\000\000\000"); !bytes.Equal(want, decoded) {
+ t.Errorf("Decode failed: got %v, want %v", decoded, want)
+ }
+}
diff --git a/libgo/go/encoding/asn1/asn1.go b/libgo/go/encoding/asn1/asn1.go
index 992356c263..8b3d1b3412 100644
--- a/libgo/go/encoding/asn1/asn1.go
+++ b/libgo/go/encoding/asn1/asn1.go
@@ -23,6 +23,7 @@ import (
"fmt"
"math/big"
"reflect"
+ "strconv"
"time"
)
@@ -197,6 +198,19 @@ func (oi ObjectIdentifier) Equal(other ObjectIdentifier) bool {
return true
}
+func (oi ObjectIdentifier) String() string {
+ var s string
+
+ for i, v := range oi {
+ if i > 0 {
+ s += "."
+ }
+ s += strconv.Itoa(v)
+ }
+
+ return s
+}
+
// parseObjectIdentifier parses an OBJECT IDENTIFIER from the given bytes and
// returns it. An object identifier is a sequence of variable length integers
// that are assigned in a hierarchy.
@@ -451,11 +465,17 @@ func parseSequenceOf(bytes []byte, sliceType reflect.Type, elemType reflect.Type
if err != nil {
return
}
- // We pretend that GENERAL STRINGs are PRINTABLE STRINGs so
- // that a sequence of them can be parsed into a []string.
- if t.tag == tagGeneralString {
+ switch t.tag {
+ case tagIA5String, tagGeneralString, tagT61String, tagUTF8String:
+ // We pretend that various other string types are
+ // PRINTABLE STRINGs so that a sequence of them can be
+ // parsed into a []string.
t.tag = tagPrintableString
+ case tagGeneralizedTime, tagUTCTime:
+ // Likewise, both time types are treated the same.
+ t.tag = tagUTCTime
}
+
if t.class != classUniversal || t.isCompound != compoundType || t.tag != expectedTag {
err = StructuralError{"sequence tag mismatch"}
return
@@ -620,18 +640,26 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
// when it sees a string, so if we see a different string type on the
// wire, we change the universal type to match.
if universalTag == tagPrintableString {
- switch t.tag {
- case tagIA5String, tagGeneralString, tagT61String, tagUTF8String:
- universalTag = t.tag
+ if t.class == classUniversal {
+ switch t.tag {
+ case tagIA5String, tagGeneralString, tagT61String, tagUTF8String:
+ universalTag = t.tag
+ }
+ } else if params.stringType != 0 {
+ universalTag = params.stringType
}
}
// Special case for time: UTCTime and GeneralizedTime both map to the
// Go type time.Time.
- if universalTag == tagUTCTime && t.tag == tagGeneralizedTime {
+ if universalTag == tagUTCTime && t.tag == tagGeneralizedTime && t.class == classUniversal {
universalTag = tagGeneralizedTime
}
+ if params.set {
+ universalTag = tagSet
+ }
+
expectedClass := classUniversal
expectedTag := universalTag
@@ -798,8 +826,19 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
return
}
+// canHaveDefaultValue reports whether k is a Kind that we will set a default
+// value for. (A signed integer, essentially.)
+func canHaveDefaultValue(k reflect.Kind) bool {
+ switch k {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return true
+ }
+
+ return false
+}
+
// setDefaultValue is used to install a default value, from a tag string, into
-// a Value. It is successful is the field was optional, even if a default value
+// a Value. It is successful if the field was optional, even if a default value
// wasn't provided or it failed to install it into the Value.
func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
if !params.optional {
@@ -809,9 +848,8 @@ func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
if params.defaultValue == nil {
return
}
- switch val := v; val.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- val.SetInt(*params.defaultValue)
+ if canHaveDefaultValue(v.Kind()) {
+ v.SetInt(*params.defaultValue)
}
return
}
@@ -852,13 +890,20 @@ func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
//
// The following tags on struct fields have special meaning to Unmarshal:
//
-// optional marks the field as ASN.1 OPTIONAL
-// [explicit] tag:x specifies the ASN.1 tag number; implies ASN.1 CONTEXT SPECIFIC
-// default:x sets the default value for optional integer fields
+// application specifies that a APPLICATION tag is used
+// default:x sets the default value for optional integer fields
+// explicit specifies that an additional, explicit tag wraps the implicit one
+// optional marks the field as ASN.1 OPTIONAL
+// set causes a SET, rather than a SEQUENCE type to be expected
+// tag:x specifies the ASN.1 tag number; implies ASN.1 CONTEXT SPECIFIC
//
// If the type of the first field of a structure is RawContent then the raw
// ASN1 contents of the struct will be stored in it.
//
+// If the type name of a slice element ends with "SET" then it's treated as if
+// the "set" tag was set on it. This can be used with nested slices where a
+// struct tag cannot be given.
+//
// Other ASN.1 types are not supported; if it encounters them,
// Unmarshal returns a parse error.
func Unmarshal(b []byte, val interface{}) (rest []byte, err error) {
diff --git a/libgo/go/encoding/asn1/asn1_test.go b/libgo/go/encoding/asn1/asn1_test.go
index f68804ebff..4e864d08ac 100644
--- a/libgo/go/encoding/asn1/asn1_test.go
+++ b/libgo/go/encoding/asn1/asn1_test.go
@@ -6,6 +6,7 @@ package asn1
import (
"bytes"
+ "fmt"
"math/big"
"reflect"
"testing"
@@ -171,6 +172,12 @@ func TestBitStringAt(t *testing.T) {
if bs.At(9) != 1 {
t.Error("#4: Failed")
}
+ if bs.At(-1) != 0 {
+ t.Error("#5: Failed")
+ }
+ if bs.At(17) != 0 {
+ t.Error("#6: Failed")
+ }
}
type bitStringRightAlignTest struct {
@@ -225,6 +232,10 @@ func TestObjectIdentifier(t *testing.T) {
}
}
}
+
+ if s := ObjectIdentifier([]int{1, 2, 3, 4}).String(); s != "1.2.3.4" {
+ t.Errorf("bad ObjectIdentifier.String(). Got %s, want 1.2.3.4", s)
+ }
}
type timeTest struct {
@@ -238,6 +249,7 @@ var utcTestData = []timeTest{
{"910506164540+0730", true, time.Date(1991, 05, 06, 16, 45, 40, 0, time.FixedZone("", 7*60*60+30*60))},
{"910506234540Z", true, time.Date(1991, 05, 06, 23, 45, 40, 0, time.UTC)},
{"9105062345Z", true, time.Date(1991, 05, 06, 23, 45, 0, 0, time.UTC)},
+ {"5105062345Z", true, time.Date(1951, 05, 06, 23, 45, 0, 0, time.UTC)},
{"a10506234540Z", false, time.Time{}},
{"91a506234540Z", false, time.Time{}},
{"9105a6234540Z", false, time.Time{}},
@@ -380,6 +392,10 @@ type TestContextSpecificTags2 struct {
B int
}
+type TestContextSpecificTags3 struct {
+ S string `asn1:"tag:1,utf8"`
+}
+
type TestElementsAfterString struct {
S string
A, B int
@@ -389,6 +405,10 @@ type TestBigInt struct {
X *big.Int
}
+type TestSet struct {
+ Ints []int `asn1:"set"`
+}
+
var unmarshalTestData = []struct {
in []byte
out interface{}
@@ -404,10 +424,12 @@ var unmarshalTestData = []struct {
{[]byte{0x04, 0x04, 1, 2, 3, 4}, &RawValue{0, 4, false, []byte{1, 2, 3, 4}, []byte{4, 4, 1, 2, 3, 4}}},
{[]byte{0x30, 0x03, 0x81, 0x01, 0x01}, &TestContextSpecificTags{1}},
{[]byte{0x30, 0x08, 0xa1, 0x03, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02}, &TestContextSpecificTags2{1, 2}},
+ {[]byte{0x30, 0x03, 0x81, 0x01, '@'}, &TestContextSpecificTags3{"@"}},
{[]byte{0x01, 0x01, 0x00}, newBool(false)},
{[]byte{0x01, 0x01, 0xff}, newBool(true)},
{[]byte{0x30, 0x0b, 0x13, 0x03, 0x66, 0x6f, 0x6f, 0x02, 0x01, 0x22, 0x02, 0x01, 0x33}, &TestElementsAfterString{"foo", 0x22, 0x33}},
{[]byte{0x30, 0x05, 0x02, 0x03, 0x12, 0x34, 0x56}, &TestBigInt{big.NewInt(0x123456)}},
+ {[]byte{0x30, 0x0b, 0x31, 0x09, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02, 0x01, 0x03}, &TestSet{Ints: []int{1, 2, 3}}},
}
func TestUnmarshal(t *testing.T) {
@@ -509,6 +531,38 @@ func TestRawStructs(t *testing.T) {
}
}
+type oiEqualTest struct {
+ first ObjectIdentifier
+ second ObjectIdentifier
+ same bool
+}
+
+var oiEqualTests = []oiEqualTest{
+ {
+ ObjectIdentifier{1, 2, 3},
+ ObjectIdentifier{1, 2, 3},
+ true,
+ },
+ {
+ ObjectIdentifier{1},
+ ObjectIdentifier{1, 2, 3},
+ false,
+ },
+ {
+ ObjectIdentifier{1, 2, 3},
+ ObjectIdentifier{10, 11, 12},
+ false,
+ },
+}
+
+func TestObjectIdentifierEqual(t *testing.T) {
+ for _, o := range oiEqualTests {
+ if s := o.first.Equal(o.second); s != o.same {
+ t.Errorf("ObjectIdentifier.Equal: got: %t want: %t", s, o.same)
+ }
+ }
+}
+
var derEncodedSelfSignedCert = Certificate{
TBSCertificate: TBSCertificate{
Version: 0,
@@ -737,3 +791,77 @@ var derEncodedPaypalNULCertBytes = []byte{
0xc8, 0x64, 0x8c, 0xb5, 0x50, 0x23, 0x82, 0x6f, 0xdb, 0xb8, 0x22, 0x1c, 0x43,
0x96, 0x07, 0xa8, 0xbb,
}
+
+var stringSliceTestData = [][]string{
+ {"foo", "bar"},
+ {"foo", "\\bar"},
+ {"foo", "\"bar\""},
+ {"foo", "åäö"},
+}
+
+func TestStringSlice(t *testing.T) {
+ for _, test := range stringSliceTestData {
+ bs, err := Marshal(test)
+ if err != nil {
+ t.Error(err)
+ }
+
+ var res []string
+ _, err = Unmarshal(bs, &res)
+ if err != nil {
+ t.Error(err)
+ }
+
+ if fmt.Sprintf("%v", res) != fmt.Sprintf("%v", test) {
+ t.Errorf("incorrect marshal/unmarshal; %v != %v", res, test)
+ }
+ }
+}
+
+type explicitTaggedTimeTest struct {
+ Time time.Time `asn1:"explicit,tag:0"`
+}
+
+var explicitTaggedTimeTestData = []struct {
+ in []byte
+ out explicitTaggedTimeTest
+}{
+ {[]byte{0x30, 0x11, 0xa0, 0xf, 0x17, 0xd, '9', '1', '0', '5', '0', '6', '1', '6', '4', '5', '4', '0', 'Z'},
+ explicitTaggedTimeTest{time.Date(1991, 05, 06, 16, 45, 40, 0, time.UTC)}},
+ {[]byte{0x30, 0x17, 0xa0, 0xf, 0x18, 0x13, '2', '0', '1', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '+', '0', '6', '0', '7'},
+ explicitTaggedTimeTest{time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", 6*60*60+7*60))}},
+}
+
+func TestExplicitTaggedTime(t *testing.T) {
+ // Test that a time.Time will match either tagUTCTime or
+ // tagGeneralizedTime.
+ for i, test := range explicitTaggedTimeTestData {
+ var got explicitTaggedTimeTest
+ _, err := Unmarshal(test.in, &got)
+ if err != nil {
+ t.Errorf("Unmarshal failed at index %d %v", i, err)
+ }
+ if !got.Time.Equal(test.out.Time) {
+ t.Errorf("#%d: got %v, want %v", i, got.Time, test.out.Time)
+ }
+ }
+}
+
+type implicitTaggedTimeTest struct {
+ Time time.Time `asn1:"tag:24"`
+}
+
+func TestImplicitTaggedTime(t *testing.T) {
+ // An implicitly tagged time value, that happens to have an implicit
+ // tag equal to a GENERALIZEDTIME, should still be parsed as a UTCTime.
+ // (There's no "timeType" in fieldParameters to determine what type of
+ // time should be expected when implicitly tagged.)
+ der := []byte{0x30, 0x0f, 0x80 | 24, 0xd, '9', '1', '0', '5', '0', '6', '1', '6', '4', '5', '4', '0', 'Z'}
+ var result implicitTaggedTimeTest
+ if _, err := Unmarshal(der, &result); err != nil {
+ t.Fatalf("Error while parsing: %s", err)
+ }
+ if expected := time.Date(1991, 05, 06, 16, 45, 40, 0, time.UTC); !result.Time.Equal(expected) {
+ t.Errorf("Wrong result. Got %v, want %v", result.Time, expected)
+ }
+}
diff --git a/libgo/go/encoding/asn1/marshal.go b/libgo/go/encoding/asn1/marshal.go
index ed17e41a55..b2f104b4cb 100644
--- a/libgo/go/encoding/asn1/marshal.go
+++ b/libgo/go/encoding/asn1/marshal.go
@@ -295,8 +295,23 @@ func marshalTwoDigits(out *forkableWriter, v int) (err error) {
return out.WriteByte(byte('0' + v%10))
}
+func marshalFourDigits(out *forkableWriter, v int) (err error) {
+ var bytes [4]byte
+ for i := range bytes {
+ bytes[3-i] = '0' + byte(v%10)
+ v /= 10
+ }
+ _, err = out.Write(bytes[:])
+ return
+}
+
+func outsideUTCRange(t time.Time) bool {
+ year := t.Year()
+ return year < 1950 || year >= 2050
+}
+
func marshalUTCTime(out *forkableWriter, t time.Time) (err error) {
- year, month, day := t.Date()
+ year := t.Year()
switch {
case 1950 <= year && year < 2000:
@@ -310,6 +325,24 @@ func marshalUTCTime(out *forkableWriter, t time.Time) (err error) {
return
}
+ return marshalTimeCommon(out, t)
+}
+
+func marshalGeneralizedTime(out *forkableWriter, t time.Time) (err error) {
+ year := t.Year()
+ if year < 0 || year > 9999 {
+ return StructuralError{"cannot represent time as GeneralizedTime"}
+ }
+ if err = marshalFourDigits(out, year); err != nil {
+ return
+ }
+
+ return marshalTimeCommon(out, t)
+}
+
+func marshalTimeCommon(out *forkableWriter, t time.Time) (err error) {
+ _, month, day := t.Date()
+
err = marshalTwoDigits(out, int(month))
if err != nil {
return
@@ -378,7 +411,12 @@ func stripTagAndLength(in []byte) []byte {
func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameters) (err error) {
switch value.Type() {
case timeType:
- return marshalUTCTime(out, value.Interface().(time.Time))
+ t := value.Interface().(time.Time)
+ if outsideUTCRange(t) {
+ return marshalGeneralizedTime(out, t)
+ } else {
+ return marshalUTCTime(out, t)
+ }
case bitStringType:
return marshalBitString(out, value.Interface().(BitString))
case objectIdentifierType:
@@ -475,8 +513,22 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
return
}
- if params.optional && reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface()) {
- return
+ if params.optional && params.defaultValue != nil && canHaveDefaultValue(v.Kind()) {
+ defaultValue := reflect.New(v.Type()).Elem()
+ defaultValue.SetInt(*params.defaultValue)
+
+ if reflect.DeepEqual(v.Interface(), defaultValue.Interface()) {
+ return
+ }
+ }
+
+ // If no default value is given then the zero value for the type is
+ // assumed to be the default value. This isn't obviously the correct
+ // behaviour, but it's what Go has traditionally done.
+ if params.optional && params.defaultValue == nil {
+ if reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface()) {
+ return
+ }
}
if v.Type() == rawValueType {
@@ -504,7 +556,8 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
return StructuralError{"explicit string type given to non-string member"}
}
- if tag == tagPrintableString {
+ switch tag {
+ case tagPrintableString:
if params.stringType == 0 {
// This is a string without an explicit string type. We'll use
// a PrintableString if the character set in the string is
@@ -521,6 +574,10 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
} else {
tag = params.stringType
}
+ case tagUTCTime:
+ if outsideUTCRange(v.Interface().(time.Time)) {
+ tag = tagGeneralizedTime
+ }
}
if params.set {
@@ -568,6 +625,14 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
}
// Marshal returns the ASN.1 encoding of val.
+//
+// In addition to the struct tags recognised by Unmarshal, the following can be
+// used:
+//
+// ia5: causes strings to be marshaled as ASN.1, IA5 strings
+// omitempty: causes empty slices to be skipped
+// printable: causes strings to be marshaled as ASN.1, PrintableString strings.
+// utf8: causes strings to be marshaled as ASN.1, UTF8 strings
func Marshal(val interface{}) ([]byte, error) {
var out bytes.Buffer
v := reflect.ValueOf(val)
diff --git a/libgo/go/encoding/asn1/marshal_test.go b/libgo/go/encoding/asn1/marshal_test.go
index 763c86da23..5b0115f28c 100644
--- a/libgo/go/encoding/asn1/marshal_test.go
+++ b/libgo/go/encoding/asn1/marshal_test.go
@@ -58,6 +58,10 @@ type omitEmptyTest struct {
A []string `asn1:"omitempty"`
}
+type defaultTest struct {
+ A int `asn1:"optional,default:1"`
+}
+
type testSET []int
var PST = time.FixedZone("PST", -8*60*60)
@@ -67,6 +71,14 @@ type marshalTest struct {
out string // hex encoded
}
+func farFuture() time.Time {
+ t, err := time.Parse(time.RFC3339, "2100-04-05T12:01:01Z")
+ if err != nil {
+ panic(err)
+ }
+ return t
+}
+
var marshalTests = []marshalTest{
{10, "02010a"},
{127, "02017f"},
@@ -83,6 +95,7 @@ var marshalTests = []marshalTest{
{time.Unix(0, 0).UTC(), "170d3730303130313030303030305a"},
{time.Unix(1258325776, 0).UTC(), "170d3039313131353232353631365a"},
{time.Unix(1258325776, 0).In(PST), "17113039313131353134353631362d30383030"},
+ {farFuture(), "180f32313030303430353132303130315a"},
{BitString{[]byte{0x80}, 1}, "03020780"},
{BitString{[]byte{0x81, 0xf0}, 12}, "03030481f0"},
{ObjectIdentifier([]int{1, 2, 3, 4}), "06032a0304"},
@@ -124,6 +137,9 @@ var marshalTests = []marshalTest{
{omitEmptyTest{[]string{}}, "3000"},
{omitEmptyTest{[]string{"1"}}, "30053003130131"},
{"Σ", "0c02cea3"},
+ {defaultTest{0}, "3003020100"},
+ {defaultTest{1}, "3000"},
+ {defaultTest{2}, "3003020102"},
}
func TestMarshal(t *testing.T) {
diff --git a/libgo/go/encoding/base32/base32.go b/libgo/go/encoding/base32/base32.go
index fe17b73220..5a9e86919d 100644
--- a/libgo/go/encoding/base32/base32.go
+++ b/libgo/go/encoding/base32/base32.go
@@ -73,45 +73,43 @@ func (enc *Encoding) Encode(dst, src []byte) {
}
for len(src) > 0 {
- dst[0] = 0
- dst[1] = 0
- dst[2] = 0
- dst[3] = 0
- dst[4] = 0
- dst[5] = 0
- dst[6] = 0
- dst[7] = 0
+ var b0, b1, b2, b3, b4, b5, b6, b7 byte
// Unpack 8x 5-bit source blocks into a 5 byte
// destination quantum
switch len(src) {
default:
- dst[7] |= src[4] & 0x1F
- dst[6] |= src[4] >> 5
+ b7 = src[4] & 0x1F
+ b6 = src[4] >> 5
fallthrough
case 4:
- dst[6] |= (src[3] << 3) & 0x1F
- dst[5] |= (src[3] >> 2) & 0x1F
- dst[4] |= src[3] >> 7
+ b6 |= (src[3] << 3) & 0x1F
+ b5 = (src[3] >> 2) & 0x1F
+ b4 = src[3] >> 7
fallthrough
case 3:
- dst[4] |= (src[2] << 1) & 0x1F
- dst[3] |= (src[2] >> 4) & 0x1F
+ b4 |= (src[2] << 1) & 0x1F
+ b3 = (src[2] >> 4) & 0x1F
fallthrough
case 2:
- dst[3] |= (src[1] << 4) & 0x1F
- dst[2] |= (src[1] >> 1) & 0x1F
- dst[1] |= (src[1] >> 6) & 0x1F
+ b3 |= (src[1] << 4) & 0x1F
+ b2 = (src[1] >> 1) & 0x1F
+ b1 = (src[1] >> 6) & 0x1F
fallthrough
case 1:
- dst[1] |= (src[0] << 2) & 0x1F
- dst[0] |= src[0] >> 3
+ b1 |= (src[0] << 2) & 0x1F
+ b0 = src[0] >> 3
}
// Encode 5-bit blocks using the base32 alphabet
- for j := 0; j < 8; j++ {
- dst[j] = enc.encode[dst[j]]
- }
+ dst[0] = enc.encode[b0]
+ dst[1] = enc.encode[b1]
+ dst[2] = enc.encode[b2]
+ dst[3] = enc.encode[b3]
+ dst[4] = enc.encode[b4]
+ dst[5] = enc.encode[b5]
+ dst[6] = enc.encode[b6]
+ dst[7] = enc.encode[b7]
// Pad the final quantum
if len(src) < 5 {
@@ -179,13 +177,11 @@ func (e *encoder) Write(p []byte) (n int, err error) {
nn := len(e.out) / 8 * 5
if nn > len(p) {
nn = len(p)
+ nn -= nn % 5
}
- nn -= nn % 5
- if nn > 0 {
- e.enc.Encode(e.out[0:], p[0:nn])
- if _, e.err = e.w.Write(e.out[0 : nn/5*8]); e.err != nil {
- return n, e.err
- }
+ e.enc.Encode(e.out[0:], p[0:nn])
+ if _, e.err = e.w.Write(e.out[0 : nn/5*8]); e.err != nil {
+ return n, e.err
}
n += nn
p = p[nn:]
@@ -268,7 +264,7 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
// 7, 5 and 2 are not valid padding lengths, and so 1, 3 and 6 are not
// valid dlen values. See RFC 4648 Section 6 "Base 32 Encoding" listing
// the five valid padding lengths, and Section 9 "Illustrations and
- // Examples" for an illustration for how the the 1st, 3rd and 6th base32
+ // Examples" for an illustration for how the 1st, 3rd and 6th base32
// src bytes do not yield enough information to decode a dst byte.
if dlen == 1 || dlen == 3 || dlen == 6 {
return n, false, CorruptInputError(olen - len(src) - 1)
@@ -332,7 +328,7 @@ func (enc *Encoding) Decode(dst, src []byte) (n int, err error) {
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))
+ n, _, err := enc.decode(dbuf, []byte(s))
return dbuf[:n], err
}
diff --git a/libgo/go/encoding/base32/base32_test.go b/libgo/go/encoding/base32/base32_test.go
index 63298d1c94..5a68f06e1c 100644
--- a/libgo/go/encoding/base32/base32_test.go
+++ b/libgo/go/encoding/base32/base32_test.go
@@ -108,7 +108,7 @@ func TestDecode(t *testing.T) {
func TestDecoder(t *testing.T) {
for _, p := range pairs {
- decoder := NewDecoder(StdEncoding, bytes.NewBufferString(p.encoded))
+ decoder := NewDecoder(StdEncoding, strings.NewReader(p.encoded))
dbuf := make([]byte, StdEncoding.DecodedLen(len(p.encoded)))
count, err := decoder.Read(dbuf)
if err != nil && err != io.EOF {
@@ -125,7 +125,7 @@ func TestDecoder(t *testing.T) {
func TestDecoderBuffering(t *testing.T) {
for bs := 1; bs <= 12; bs++ {
- decoder := NewDecoder(StdEncoding, bytes.NewBufferString(bigtest.encoded))
+ decoder := NewDecoder(StdEncoding, strings.NewReader(bigtest.encoded))
buf := make([]byte, len(bigtest.decoded)+12)
var total int
for total = 0; total < len(bigtest.decoded); {
@@ -267,13 +267,13 @@ LNEBUWIIDFON2CA3DBMJXXE5LNFY==
====`
encodedShort := strings.Replace(encoded, "\n", "", -1)
- dec := NewDecoder(StdEncoding, bytes.NewBufferString(encoded))
+ dec := NewDecoder(StdEncoding, strings.NewReader(encoded))
res1, err := ioutil.ReadAll(dec)
if err != nil {
t.Errorf("ReadAll failed: %v", err)
}
- dec = NewDecoder(StdEncoding, bytes.NewBufferString(encodedShort))
+ dec = NewDecoder(StdEncoding, strings.NewReader(encodedShort))
var res2 []byte
res2, err = ioutil.ReadAll(dec)
if err != nil {
@@ -284,3 +284,19 @@ LNEBUWIIDFON2CA3DBMJXXE5LNFY==
t.Error("Decoded results not equal")
}
}
+
+func BenchmarkEncodeToString(b *testing.B) {
+ data := make([]byte, 8192)
+ b.SetBytes(int64(len(data)))
+ for i := 0; i < b.N; i++ {
+ StdEncoding.EncodeToString(data)
+ }
+}
+
+func BenchmarkDecodeString(b *testing.B) {
+ data := StdEncoding.EncodeToString(make([]byte, 8192))
+ b.SetBytes(int64(len(data)))
+ for i := 0; i < b.N; i++ {
+ StdEncoding.DecodeString(data)
+ }
+}
diff --git a/libgo/go/encoding/base64/base64.go b/libgo/go/encoding/base64/base64.go
index 85e398fd0b..ad3abe6623 100644
--- a/libgo/go/encoding/base64/base64.go
+++ b/libgo/go/encoding/base64/base64.go
@@ -74,31 +74,29 @@ func (enc *Encoding) Encode(dst, src []byte) {
}
for len(src) > 0 {
- dst[0] = 0
- dst[1] = 0
- dst[2] = 0
- dst[3] = 0
+ var b0, b1, b2, b3 byte
// Unpack 4x 6-bit source blocks into a 4 byte
// destination quantum
switch len(src) {
default:
- dst[3] |= src[2] & 0x3F
- dst[2] |= src[2] >> 6
+ b3 = src[2] & 0x3F
+ b2 = src[2] >> 6
fallthrough
case 2:
- dst[2] |= (src[1] << 2) & 0x3F
- dst[1] |= src[1] >> 4
+ b2 |= (src[1] << 2) & 0x3F
+ b1 = src[1] >> 4
fallthrough
case 1:
- dst[1] |= (src[0] << 4) & 0x3F
- dst[0] |= src[0] >> 2
+ b1 |= (src[0] << 4) & 0x3F
+ b0 = src[0] >> 2
}
// Encode 6-bit blocks using the base64 alphabet
- for j := 0; j < 4; j++ {
- dst[j] = enc.encode[dst[j]]
- }
+ 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 {
@@ -159,13 +157,11 @@ func (e *encoder) Write(p []byte) (n int, err error) {
nn := len(e.out) / 4 * 3
if nn > len(p) {
nn = len(p)
+ nn -= nn % 3
}
- nn -= nn % 3
- if nn > 0 {
- e.enc.Encode(e.out[0:], p[0:nn])
- if _, e.err = e.w.Write(e.out[0 : nn/3*4]); e.err != nil {
- return n, e.err
- }
+ e.enc.Encode(e.out[0:], p[0:nn])
+ if _, e.err = e.w.Write(e.out[0 : nn/3*4]); e.err != nil {
+ return n, e.err
}
n += nn
p = p[nn:]
@@ -226,21 +222,33 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
var dbuf [4]byte
dlen := 4
- for j := 0; j < 4; {
+ for j := range dbuf {
if len(src) == 0 {
return n, false, CorruptInputError(olen - len(src) - j)
}
in := src[0]
src = src[1:]
- if in == '=' && j >= 2 && len(src) < 4 {
+ if in == '=' {
// We've reached the end and there's padding
- if len(src)+j < 4-1 {
- // not enough padding
- return n, false, CorruptInputError(olen)
- }
- if len(src) > 0 && src[0] != '=' {
+ switch j {
+ case 0, 1:
// incorrect padding
return n, false, CorruptInputError(olen - len(src) - 1)
+ case 2:
+ // "==" is expected, the first "=" is already consumed.
+ if len(src) == 0 {
+ // not enough padding
+ return n, false, CorruptInputError(olen)
+ }
+ if src[0] != '=' {
+ // incorrect padding
+ return n, false, CorruptInputError(olen - len(src) - 1)
+ }
+ src = src[1:]
+ }
+ if len(src) > 0 {
+ // trailing garbage
+ err = CorruptInputError(olen - len(src))
}
dlen, end = j, true
break
@@ -249,7 +257,6 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
if dbuf[j] == 0xFF {
return n, false, CorruptInputError(olen - len(src) - 1)
}
- j++
}
// Pack 4x 6-bit source blocks into 3 byte destination
@@ -268,7 +275,7 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
n += dlen - 1
}
- return n, end, nil
+ return n, end, err
}
// Decode decodes src using the encoding enc. It writes at most
@@ -286,7 +293,7 @@ func (enc *Encoding) Decode(dst, src []byte) (n int, err error) {
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))
+ n, _, err := enc.decode(dbuf, []byte(s))
return dbuf[:n], err
}
diff --git a/libgo/go/encoding/base64/base64_test.go b/libgo/go/encoding/base64/base64_test.go
index 579591a88d..7d199bfa08 100644
--- a/libgo/go/encoding/base64/base64_test.go
+++ b/libgo/go/encoding/base64/base64_test.go
@@ -9,6 +9,7 @@ import (
"errors"
"io"
"io/ioutil"
+ "reflect"
"strings"
"testing"
"time"
@@ -113,7 +114,7 @@ func TestDecode(t *testing.T) {
func TestDecoder(t *testing.T) {
for _, p := range pairs {
- decoder := NewDecoder(StdEncoding, bytes.NewBufferString(p.encoded))
+ decoder := NewDecoder(StdEncoding, strings.NewReader(p.encoded))
dbuf := make([]byte, StdEncoding.DecodedLen(len(p.encoded)))
count, err := decoder.Read(dbuf)
if err != nil && err != io.EOF {
@@ -130,7 +131,7 @@ func TestDecoder(t *testing.T) {
func TestDecoderBuffering(t *testing.T) {
for bs := 1; bs <= 12; bs++ {
- decoder := NewDecoder(StdEncoding, bytes.NewBufferString(bigtest.encoded))
+ decoder := NewDecoder(StdEncoding, strings.NewReader(bigtest.encoded))
buf := make([]byte, len(bigtest.decoded)+12)
var total int
for total = 0; total < len(bigtest.decoded); {
@@ -149,9 +150,13 @@ func TestDecodeCorrupt(t *testing.T) {
}{
{"", -1},
{"!!!!", 0},
+ {"====", 0},
{"x===", 1},
+ {"=AAA", 0},
+ {"A=AA", 1},
{"AA=A", 2},
- {"AAA=AAAA", 3},
+ {"AA==A", 4},
+ {"AAA=AAAA", 4},
{"AAAAA", 4},
{"AAAAAA", 4},
{"A=", 1},
@@ -161,6 +166,7 @@ func TestDecodeCorrupt(t *testing.T) {
{"AAA=", -1},
{"AAAA", -1},
{"AAAAAA=", 7},
+ {"YWJjZA=====", 8},
}
for _, tc := range testCases {
dbuf := make([]byte, StdEncoding.DecodedLen(len(tc.input)))
@@ -308,13 +314,13 @@ bqbPb06551Y4
`
encodedShort := strings.Replace(encoded, "\n", "", -1)
- dec := NewDecoder(StdEncoding, bytes.NewBufferString(encoded))
+ dec := NewDecoder(StdEncoding, strings.NewReader(encoded))
res1, err := ioutil.ReadAll(dec)
if err != nil {
t.Errorf("ReadAll failed: %v", err)
}
- dec = NewDecoder(StdEncoding, bytes.NewBufferString(encodedShort))
+ dec = NewDecoder(StdEncoding, strings.NewReader(encodedShort))
var res2 []byte
res2, err = ioutil.ReadAll(dec)
if err != nil {
@@ -325,3 +331,30 @@ bqbPb06551Y4
t.Error("Decoded results not equal")
}
}
+
+func TestDecoderIssue7733(t *testing.T) {
+ s, err := StdEncoding.DecodeString("YWJjZA=====")
+ want := CorruptInputError(8)
+ if !reflect.DeepEqual(want, err) {
+ t.Errorf("Error = %v; want CorruptInputError(8)", err)
+ }
+ if string(s) != "abcd" {
+ t.Errorf("DecodeString = %q; want abcd", s)
+ }
+}
+
+func BenchmarkEncodeToString(b *testing.B) {
+ data := make([]byte, 8192)
+ b.SetBytes(int64(len(data)))
+ for i := 0; i < b.N; i++ {
+ StdEncoding.EncodeToString(data)
+ }
+}
+
+func BenchmarkDecodeString(b *testing.B) {
+ data := StdEncoding.EncodeToString(make([]byte, 8192))
+ b.SetBytes(int64(len(data)))
+ for i := 0; i < b.N; i++ {
+ StdEncoding.DecodeString(data)
+ }
+}
diff --git a/libgo/go/encoding/binary/binary.go b/libgo/go/encoding/binary/binary.go
index f3466b9af0..466bf97c97 100644
--- a/libgo/go/encoding/binary/binary.go
+++ b/libgo/go/encoding/binary/binary.go
@@ -10,9 +10,10 @@
// type (int8, uint8, int16, float32, complex64, ...)
// or an array or struct containing only fixed-size values.
//
-// Varints are a method of encoding integers using one or more bytes;
-// numbers with smaller absolute value take a smaller number of bytes.
-// For a specification, see http://code.google.com/apis/protocolbuffers/docs/encoding.html.
+// The varint functions encode and decode single integer values using
+// a variable-length encoding; smaller values require fewer bytes.
+// For a specification, see
+// http://code.google.com/apis/protocolbuffers/docs/encoding.html.
//
// This package favors simplicity over efficiency. Clients that require
// high-performance serialization, especially for large data structures,
@@ -133,6 +134,7 @@ func (bigEndian) GoString() string { return "binary.BigEndian" }
// When reading into structs, the field data for fields with
// blank (_) field names is skipped; i.e., blank field names
// may be used for padding.
+// When reading into a struct, all non-blank fields must be exported.
func Read(r io.Reader, order ByteOrder, data interface{}) error {
// Fast path for basic types and slices.
if n := intDataSize(data); n != 0 {
@@ -198,18 +200,17 @@ func Read(r io.Reader, order ByteOrder, data interface{}) error {
}
// Fallback to reflect-based decoding.
- var v reflect.Value
- switch d := reflect.ValueOf(data); d.Kind() {
+ v := reflect.ValueOf(data)
+ size := -1
+ switch v.Kind() {
case reflect.Ptr:
- v = d.Elem()
+ v = v.Elem()
+ size = dataSize(v)
case reflect.Slice:
- v = d
- default:
- return errors.New("binary.Read: invalid type " + d.Type().String())
+ size = dataSize(v)
}
- size, err := dataSize(v)
- if err != nil {
- return errors.New("binary.Read: " + err.Error())
+ if size < 0 {
+ return errors.New("binary.Read: invalid type " + reflect.TypeOf(data).String())
}
d := &decoder{order: order, buf: make([]byte, size)}
if _, err := io.ReadFull(r, d.buf); err != nil {
@@ -322,68 +323,64 @@ func Write(w io.Writer, order ByteOrder, data interface{}) error {
// Fallback to reflect-based encoding.
v := reflect.Indirect(reflect.ValueOf(data))
- size, err := dataSize(v)
- if err != nil {
- return errors.New("binary.Write: " + err.Error())
+ size := dataSize(v)
+ if size < 0 {
+ return errors.New("binary.Write: invalid type " + reflect.TypeOf(data).String())
}
buf := make([]byte, size)
e := &encoder{order: order, buf: buf}
e.value(v)
- _, err = w.Write(buf)
+ _, err := w.Write(buf)
return err
}
// Size returns how many bytes Write would generate to encode the value v, which
// must be a fixed-size value or a slice of fixed-size values, or a pointer to such data.
+// If v is neither of these, Size returns -1.
func Size(v interface{}) int {
- n, err := dataSize(reflect.Indirect(reflect.ValueOf(v)))
- if err != nil {
- return -1
- }
- return n
+ return dataSize(reflect.Indirect(reflect.ValueOf(v)))
}
// dataSize returns the number of bytes the actual data represented by v occupies in memory.
// For compound structures, it sums the sizes of the elements. Thus, for instance, for a slice
// it returns the length of the slice times the element size and does not count the memory
-// occupied by the header.
-func dataSize(v reflect.Value) (int, error) {
+// occupied by the header. If the type of v is not acceptable, dataSize returns -1.
+func dataSize(v reflect.Value) int {
if v.Kind() == reflect.Slice {
- elem, err := sizeof(v.Type().Elem())
- if err != nil {
- return 0, err
+ if s := sizeof(v.Type().Elem()); s >= 0 {
+ return s * v.Len()
}
- return v.Len() * elem, nil
+ return -1
}
return sizeof(v.Type())
}
-func sizeof(t reflect.Type) (int, error) {
+// sizeof returns the size >= 0 of variables for the given type or -1 if the type is not acceptable.
+func sizeof(t reflect.Type) int {
switch t.Kind() {
case reflect.Array:
- n, err := sizeof(t.Elem())
- if err != nil {
- return 0, err
+ if s := sizeof(t.Elem()); s >= 0 {
+ return s * t.Len()
}
- return t.Len() * n, nil
case reflect.Struct:
sum := 0
for i, n := 0, t.NumField(); i < n; i++ {
- s, err := sizeof(t.Field(i).Type)
- if err != nil {
- return 0, err
+ s := sizeof(t.Field(i).Type)
+ if s < 0 {
+ return -1
}
sum += s
}
- return sum, nil
+ return sum
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
- return int(t.Size()), nil
+ return int(t.Size())
}
- return 0, errors.New("invalid type " + t.String())
+
+ return -1
}
type coder struct {
@@ -593,12 +590,11 @@ func (e *encoder) value(v reflect.Value) {
}
func (d *decoder) skip(v reflect.Value) {
- n, _ := dataSize(v)
- d.buf = d.buf[n:]
+ d.buf = d.buf[dataSize(v):]
}
func (e *encoder) skip(v reflect.Value) {
- n, _ := dataSize(v)
+ n := dataSize(v)
for i := range e.buf[0:n] {
e.buf[i] = 0
}
diff --git a/libgo/go/encoding/binary/binary_test.go b/libgo/go/encoding/binary/binary_test.go
index fdfee7d871..8ee595fa47 100644
--- a/libgo/go/encoding/binary/binary_test.go
+++ b/libgo/go/encoding/binary/binary_test.go
@@ -111,7 +111,7 @@ func checkResult(t *testing.T, dir string, order ByteOrder, err error, have, wan
func testRead(t *testing.T, order ByteOrder, b []byte, s1 interface{}) {
var s2 Struct
- err := Read(bytes.NewBuffer(b), order, &s2)
+ err := Read(bytes.NewReader(b), order, &s2)
checkResult(t, "Read", order, err, s2, s1)
}
@@ -131,7 +131,7 @@ func TestBigEndianPtrWrite(t *testing.T) { testWrite(t, BigEndian, big, &s) }
func TestReadSlice(t *testing.T) {
slice := make([]int32, 2)
- err := Read(bytes.NewBuffer(src), BigEndian, slice)
+ err := Read(bytes.NewReader(src), BigEndian, slice)
checkResult(t, "ReadSlice", BigEndian, err, slice, res)
}
@@ -265,6 +265,50 @@ func TestBlankFields(t *testing.T) {
}
}
+// An attempt to read into a struct with an unexported field will
+// panic. This is probably not the best choice, but at this point
+// anything else would be an API change.
+
+type Unexported struct {
+ a int32
+}
+
+func TestUnexportedRead(t *testing.T) {
+ var buf bytes.Buffer
+ u1 := Unexported{a: 1}
+ if err := Write(&buf, LittleEndian, &u1); err != nil {
+ t.Fatal(err)
+ }
+
+ defer func() {
+ if recover() == nil {
+ t.Fatal("did not panic")
+ }
+ }()
+ var u2 Unexported
+ Read(&buf, LittleEndian, &u2)
+}
+
+func TestReadErrorMsg(t *testing.T) {
+ var buf bytes.Buffer
+ read := func(data interface{}) {
+ err := Read(&buf, LittleEndian, data)
+ want := "binary.Read: invalid type " + reflect.TypeOf(data).String()
+ if err == nil {
+ t.Errorf("%T: got no error; want %q", data, want)
+ return
+ }
+ if got := err.Error(); got != want {
+ t.Errorf("%T: got %q; want %q", data, got, want)
+ }
+ }
+ read(0)
+ s := new(struct{})
+ read(&s)
+ p := &s
+ read(&p)
+}
+
type byteSliceReader struct {
remain []byte
}
@@ -291,8 +335,7 @@ func BenchmarkReadStruct(b *testing.B) {
bsr := &byteSliceReader{}
var buf bytes.Buffer
Write(&buf, BigEndian, &s)
- n, _ := dataSize(reflect.ValueOf(s))
- b.SetBytes(int64(n))
+ b.SetBytes(int64(dataSize(reflect.ValueOf(s))))
t := s
b.ResetTimer()
for i := 0; i < b.N; i++ {
diff --git a/libgo/go/encoding/binary/varint_test.go b/libgo/go/encoding/binary/varint_test.go
index 9476bd5fb7..ca411ecbd6 100644
--- a/libgo/go/encoding/binary/varint_test.go
+++ b/libgo/go/encoding/binary/varint_test.go
@@ -35,7 +35,7 @@ func testVarint(t *testing.T, x int64) {
t.Errorf("Varint(%d): got n = %d; want %d", x, m, n)
}
- y, err := ReadVarint(bytes.NewBuffer(buf))
+ y, err := ReadVarint(bytes.NewReader(buf))
if err != nil {
t.Errorf("ReadVarint(%d): %s", x, err)
}
@@ -55,7 +55,7 @@ func testUvarint(t *testing.T, x uint64) {
t.Errorf("Uvarint(%d): got n = %d; want %d", x, m, n)
}
- y, err := ReadUvarint(bytes.NewBuffer(buf))
+ y, err := ReadUvarint(bytes.NewReader(buf))
if err != nil {
t.Errorf("ReadUvarint(%d): %s", x, err)
}
@@ -114,7 +114,7 @@ func TestBufferTooSmall(t *testing.T) {
t.Errorf("Uvarint(%v): got x = %d, n = %d", buf, x, n)
}
- x, err := ReadUvarint(bytes.NewBuffer(buf))
+ x, err := ReadUvarint(bytes.NewReader(buf))
if x != 0 || err != io.EOF {
t.Errorf("ReadUvarint(%v): got x = %d, err = %s", buf, x, err)
}
@@ -127,7 +127,7 @@ func testOverflow(t *testing.T, buf []byte, n0 int, err0 error) {
t.Errorf("Uvarint(%v): got x = %d, n = %d; want 0, %d", buf, x, n, n0)
}
- x, err := ReadUvarint(bytes.NewBuffer(buf))
+ x, err := ReadUvarint(bytes.NewReader(buf))
if x != 0 || err != err0 {
t.Errorf("ReadUvarint(%v): got x = %d, err = %s; want 0, %s", buf, x, err, err0)
}
diff --git a/libgo/go/encoding/csv/reader.go b/libgo/go/encoding/csv/reader.go
index b328dcc375..d9432954ac 100644
--- a/libgo/go/encoding/csv/reader.go
+++ b/libgo/go/encoding/csv/reader.go
@@ -193,12 +193,6 @@ func (r *Reader) readRune() (rune, error) {
return r1, err
}
-// unreadRune puts the last rune read from r back.
-func (r *Reader) unreadRune() {
- r.r.UnreadRune()
- r.column--
-}
-
// skip reads runes up to and including the rune delim or until error.
func (r *Reader) skip(delim rune) error {
for {
diff --git a/libgo/go/encoding/csv/writer.go b/libgo/go/encoding/csv/writer.go
index 1faecb6648..17e7bb7f5c 100644
--- a/libgo/go/encoding/csv/writer.go
+++ b/libgo/go/encoding/csv/writer.go
@@ -115,10 +115,22 @@ func (w *Writer) WriteAll(records [][]string) (err error) {
}
// fieldNeedsQuotes returns true if our field must be enclosed in quotes.
-// Empty fields, files with a Comma, fields with a quote or newline, and
+// 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).
+// The two representations should be equivalent, but Postgres distinguishes
+// quoted vs non-quoted empty string during database imports, and it has
+// an option to force the quoted behavior for non-quoted CSV but it has
+// no option to force the non-quoted behavior for quoted CSV, making
+// 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 `\.`.
func (w *Writer) fieldNeedsQuotes(field string) bool {
- if len(field) == 0 || strings.IndexRune(field, w.Comma) >= 0 || strings.IndexAny(field, "\"\r\n") >= 0 {
+ if field == "" {
+ return false
+ }
+ if field == `\.` || strings.IndexRune(field, w.Comma) >= 0 || strings.IndexAny(field, "\"\r\n") >= 0 {
return true
}
diff --git a/libgo/go/encoding/csv/writer_test.go b/libgo/go/encoding/csv/writer_test.go
index 03ca6b093c..8ddca0abe0 100644
--- a/libgo/go/encoding/csv/writer_test.go
+++ b/libgo/go/encoding/csv/writer_test.go
@@ -26,6 +26,19 @@ var writeTests = []struct {
{Input: [][]string{{"abc"}, {"def"}}, Output: "abc\ndef\n"},
{Input: [][]string{{"abc\ndef"}}, Output: "\"abc\ndef\"\n"},
{Input: [][]string{{"abc\ndef"}}, Output: "\"abc\r\ndef\"\r\n", UseCRLF: true},
+ {Input: [][]string{{"abc\rdef"}}, Output: "\"abcdef\"\r\n", UseCRLF: true},
+ {Input: [][]string{{"abc\rdef"}}, Output: "\"abc\rdef\"\n", UseCRLF: false},
+ {Input: [][]string{{""}}, Output: "\n"},
+ {Input: [][]string{{"", ""}}, Output: ",\n"},
+ {Input: [][]string{{"", "", ""}}, Output: ",,\n"},
+ {Input: [][]string{{"", "", "a"}}, Output: ",,a\n"},
+ {Input: [][]string{{"", "a", ""}}, Output: ",a,\n"},
+ {Input: [][]string{{"", "a", "a"}}, Output: ",a,a\n"},
+ {Input: [][]string{{"a", "", ""}}, Output: "a,,\n"},
+ {Input: [][]string{{"a", "", "a"}}, Output: "a,,a\n"},
+ {Input: [][]string{{"a", "a", ""}}, Output: "a,a,\n"},
+ {Input: [][]string{{"a", "a", "a"}}, Output: "a,a,a\n"},
+ {Input: [][]string{{`\.`}}, Output: "\"\\.\"\n"},
}
func TestWrite(t *testing.T) {
diff --git a/libgo/go/encoding/gob/codec_test.go b/libgo/go/encoding/gob/codec_test.go
index b40f78360c..56a7298fa5 100644
--- a/libgo/go/encoding/gob/codec_test.go
+++ b/libgo/go/encoding/gob/codec_test.go
@@ -14,7 +14,6 @@ import (
"strings"
"testing"
"time"
- "unsafe"
)
var doFuzzTests = flag.Bool("gob.fuzz", false, "run the fuzz tests, which are large and very slow")
@@ -51,10 +50,16 @@ func testError(t *testing.T) {
return
}
+func newDecBuffer(data []byte) *decBuffer {
+ return &decBuffer{
+ data: data,
+ }
+}
+
// Test basic encode/decode routines for unsigned integers
func TestUintCodec(t *testing.T) {
defer testError(t)
- b := new(bytes.Buffer)
+ b := new(encBuffer)
encState := newEncoderState(b)
for _, tt := range encodeT {
b.Reset()
@@ -63,10 +68,10 @@ func TestUintCodec(t *testing.T) {
t.Errorf("encodeUint: %#x encode: expected % x got % x", tt.x, tt.b, b.Bytes())
}
}
- decState := newDecodeState(b)
for u := uint64(0); ; u = (u + 1) * 7 {
b.Reset()
encState.encodeUint(u)
+ decState := newDecodeState(newDecBuffer(b.Bytes()))
v := decState.decodeUint()
if u != v {
t.Errorf("Encode/Decode: sent %#x received %#x", u, v)
@@ -79,10 +84,10 @@ func TestUintCodec(t *testing.T) {
func verifyInt(i int64, t *testing.T) {
defer testError(t)
- var b = new(bytes.Buffer)
+ var b = new(encBuffer)
encState := newEncoderState(b)
encState.encodeInt(i)
- decState := newDecodeState(b)
+ decState := newDecodeState(newDecBuffer(b.Bytes()))
decState.buf = make([]byte, 8)
j := decState.decodeInt()
if i != j {
@@ -119,14 +124,14 @@ var complexResult = []byte{0x07, 0xFE, 0x31, 0x40, 0xFE, 0x33, 0x40}
// The result of encoding "hello" with field number 7
var bytesResult = []byte{0x07, 0x05, 'h', 'e', 'l', 'l', 'o'}
-func newDecodeState(buf *bytes.Buffer) *decoderState {
+func newDecodeState(buf *decBuffer) *decoderState {
d := new(decoderState)
d.b = buf
d.buf = make([]byte, uint64Size)
return d
}
-func newEncoderState(b *bytes.Buffer) *encoderState {
+func newEncoderState(b *encBuffer) *encoderState {
b.Reset()
state := &encoderState{enc: nil, b: b}
state.fieldnum = -1
@@ -136,14 +141,14 @@ func newEncoderState(b *bytes.Buffer) *encoderState {
// Test instruction execution for encoding.
// Do not run the machine yet; instead do individual instructions crafted by hand.
func TestScalarEncInstructions(t *testing.T) {
- var b = new(bytes.Buffer)
+ var b = new(encBuffer)
// bool
{
- data := struct{ a bool }{true}
- instr := &encInstr{encBool, 6, 0, 0}
+ var data bool = true
+ instr := &encInstr{encBool, 6, nil, 0}
state := newEncoderState(b)
- instr.op(instr, state, unsafe.Pointer(&data))
+ instr.op(instr, state, reflect.ValueOf(data))
if !bytes.Equal(boolResult, b.Bytes()) {
t.Errorf("bool enc instructions: expected % x got % x", boolResult, b.Bytes())
}
@@ -152,10 +157,10 @@ func TestScalarEncInstructions(t *testing.T) {
// int
{
b.Reset()
- data := struct{ a int }{17}
- instr := &encInstr{encInt, 6, 0, 0}
+ var data int = 17
+ instr := &encInstr{encInt, 6, nil, 0}
state := newEncoderState(b)
- instr.op(instr, state, unsafe.Pointer(&data))
+ instr.op(instr, state, reflect.ValueOf(data))
if !bytes.Equal(signedResult, b.Bytes()) {
t.Errorf("int enc instructions: expected % x got % x", signedResult, b.Bytes())
}
@@ -164,10 +169,10 @@ func TestScalarEncInstructions(t *testing.T) {
// uint
{
b.Reset()
- data := struct{ a uint }{17}
- instr := &encInstr{encUint, 6, 0, 0}
+ var data uint = 17
+ instr := &encInstr{encUint, 6, nil, 0}
state := newEncoderState(b)
- instr.op(instr, state, unsafe.Pointer(&data))
+ instr.op(instr, state, reflect.ValueOf(data))
if !bytes.Equal(unsignedResult, b.Bytes()) {
t.Errorf("uint enc instructions: expected % x got % x", unsignedResult, b.Bytes())
}
@@ -176,10 +181,10 @@ func TestScalarEncInstructions(t *testing.T) {
// int8
{
b.Reset()
- data := struct{ a int8 }{17}
- instr := &encInstr{encInt8, 6, 0, 0}
+ var data int8 = 17
+ instr := &encInstr{encInt, 6, nil, 0}
state := newEncoderState(b)
- instr.op(instr, state, unsafe.Pointer(&data))
+ instr.op(instr, state, reflect.ValueOf(data))
if !bytes.Equal(signedResult, b.Bytes()) {
t.Errorf("int8 enc instructions: expected % x got % x", signedResult, b.Bytes())
}
@@ -188,10 +193,10 @@ func TestScalarEncInstructions(t *testing.T) {
// uint8
{
b.Reset()
- data := struct{ a uint8 }{17}
- instr := &encInstr{encUint8, 6, 0, 0}
+ var data uint8 = 17
+ instr := &encInstr{encUint, 6, nil, 0}
state := newEncoderState(b)
- instr.op(instr, state, unsafe.Pointer(&data))
+ instr.op(instr, state, reflect.ValueOf(data))
if !bytes.Equal(unsignedResult, b.Bytes()) {
t.Errorf("uint8 enc instructions: expected % x got % x", unsignedResult, b.Bytes())
}
@@ -200,10 +205,10 @@ func TestScalarEncInstructions(t *testing.T) {
// int16
{
b.Reset()
- data := struct{ a int16 }{17}
- instr := &encInstr{encInt16, 6, 0, 0}
+ var data int16 = 17
+ instr := &encInstr{encInt, 6, nil, 0}
state := newEncoderState(b)
- instr.op(instr, state, unsafe.Pointer(&data))
+ instr.op(instr, state, reflect.ValueOf(data))
if !bytes.Equal(signedResult, b.Bytes()) {
t.Errorf("int16 enc instructions: expected % x got % x", signedResult, b.Bytes())
}
@@ -212,10 +217,10 @@ func TestScalarEncInstructions(t *testing.T) {
// uint16
{
b.Reset()
- data := struct{ a uint16 }{17}
- instr := &encInstr{encUint16, 6, 0, 0}
+ var data uint16 = 17
+ instr := &encInstr{encUint, 6, nil, 0}
state := newEncoderState(b)
- instr.op(instr, state, unsafe.Pointer(&data))
+ instr.op(instr, state, reflect.ValueOf(data))
if !bytes.Equal(unsignedResult, b.Bytes()) {
t.Errorf("uint16 enc instructions: expected % x got % x", unsignedResult, b.Bytes())
}
@@ -224,10 +229,10 @@ func TestScalarEncInstructions(t *testing.T) {
// int32
{
b.Reset()
- data := struct{ a int32 }{17}
- instr := &encInstr{encInt32, 6, 0, 0}
+ var data int32 = 17
+ instr := &encInstr{encInt, 6, nil, 0}
state := newEncoderState(b)
- instr.op(instr, state, unsafe.Pointer(&data))
+ instr.op(instr, state, reflect.ValueOf(data))
if !bytes.Equal(signedResult, b.Bytes()) {
t.Errorf("int32 enc instructions: expected % x got % x", signedResult, b.Bytes())
}
@@ -236,10 +241,10 @@ func TestScalarEncInstructions(t *testing.T) {
// uint32
{
b.Reset()
- data := struct{ a uint32 }{17}
- instr := &encInstr{encUint32, 6, 0, 0}
+ var data uint32 = 17
+ instr := &encInstr{encUint, 6, nil, 0}
state := newEncoderState(b)
- instr.op(instr, state, unsafe.Pointer(&data))
+ instr.op(instr, state, reflect.ValueOf(data))
if !bytes.Equal(unsignedResult, b.Bytes()) {
t.Errorf("uint32 enc instructions: expected % x got % x", unsignedResult, b.Bytes())
}
@@ -248,10 +253,10 @@ func TestScalarEncInstructions(t *testing.T) {
// int64
{
b.Reset()
- data := struct{ a int64 }{17}
- instr := &encInstr{encInt64, 6, 0, 0}
+ var data int64 = 17
+ instr := &encInstr{encInt, 6, nil, 0}
state := newEncoderState(b)
- instr.op(instr, state, unsafe.Pointer(&data))
+ instr.op(instr, state, reflect.ValueOf(data))
if !bytes.Equal(signedResult, b.Bytes()) {
t.Errorf("int64 enc instructions: expected % x got % x", signedResult, b.Bytes())
}
@@ -260,10 +265,10 @@ func TestScalarEncInstructions(t *testing.T) {
// uint64
{
b.Reset()
- data := struct{ a uint64 }{17}
- instr := &encInstr{encUint64, 6, 0, 0}
+ var data uint64 = 17
+ instr := &encInstr{encUint, 6, nil, 0}
state := newEncoderState(b)
- instr.op(instr, state, unsafe.Pointer(&data))
+ instr.op(instr, state, reflect.ValueOf(data))
if !bytes.Equal(unsignedResult, b.Bytes()) {
t.Errorf("uint64 enc instructions: expected % x got % x", unsignedResult, b.Bytes())
}
@@ -272,10 +277,10 @@ func TestScalarEncInstructions(t *testing.T) {
// float32
{
b.Reset()
- data := struct{ a float32 }{17}
- instr := &encInstr{encFloat32, 6, 0, 0}
+ var data float32 = 17
+ instr := &encInstr{encFloat, 6, nil, 0}
state := newEncoderState(b)
- instr.op(instr, state, unsafe.Pointer(&data))
+ instr.op(instr, state, reflect.ValueOf(data))
if !bytes.Equal(floatResult, b.Bytes()) {
t.Errorf("float32 enc instructions: expected % x got % x", floatResult, b.Bytes())
}
@@ -284,10 +289,10 @@ func TestScalarEncInstructions(t *testing.T) {
// float64
{
b.Reset()
- data := struct{ a float64 }{17}
- instr := &encInstr{encFloat64, 6, 0, 0}
+ var data float64 = 17
+ instr := &encInstr{encFloat, 6, nil, 0}
state := newEncoderState(b)
- instr.op(instr, state, unsafe.Pointer(&data))
+ instr.op(instr, state, reflect.ValueOf(data))
if !bytes.Equal(floatResult, b.Bytes()) {
t.Errorf("float64 enc instructions: expected % x got % x", floatResult, b.Bytes())
}
@@ -296,10 +301,10 @@ func TestScalarEncInstructions(t *testing.T) {
// bytes == []uint8
{
b.Reset()
- data := struct{ a []byte }{[]byte("hello")}
- instr := &encInstr{encUint8Array, 6, 0, 0}
+ data := []byte("hello")
+ instr := &encInstr{encUint8Array, 6, nil, 0}
state := newEncoderState(b)
- instr.op(instr, state, unsafe.Pointer(&data))
+ instr.op(instr, state, reflect.ValueOf(data))
if !bytes.Equal(bytesResult, b.Bytes()) {
t.Errorf("bytes enc instructions: expected % x got % x", bytesResult, b.Bytes())
}
@@ -308,28 +313,28 @@ func TestScalarEncInstructions(t *testing.T) {
// string
{
b.Reset()
- data := struct{ a string }{"hello"}
- instr := &encInstr{encString, 6, 0, 0}
+ var data string = "hello"
+ instr := &encInstr{encString, 6, nil, 0}
state := newEncoderState(b)
- instr.op(instr, state, unsafe.Pointer(&data))
+ instr.op(instr, state, reflect.ValueOf(data))
if !bytes.Equal(bytesResult, b.Bytes()) {
t.Errorf("string enc instructions: expected % x got % x", bytesResult, b.Bytes())
}
}
}
-func execDec(typ string, instr *decInstr, state *decoderState, t *testing.T, p unsafe.Pointer) {
+func execDec(typ string, instr *decInstr, state *decoderState, t *testing.T, value reflect.Value) {
defer testError(t)
v := int(state.decodeUint())
if v+state.fieldnum != 6 {
t.Fatalf("decoding field number %d, got %d", 6, v+state.fieldnum)
}
- instr.op(instr, state, decIndirect(p, instr.indir))
+ instr.op(instr, state, value.Elem())
state.fieldnum = 6
}
func newDecodeStateFromData(data []byte) *decoderState {
- b := bytes.NewBuffer(data)
+ b := newDecBuffer(data)
state := newDecodeState(b)
state.fieldnum = -1
return state
@@ -342,234 +347,198 @@ func TestScalarDecInstructions(t *testing.T) {
// bool
{
- var data struct {
- a bool
- }
- instr := &decInstr{decBool, 6, 0, 0, ovfl}
+ var data bool
+ instr := &decInstr{decBool, 6, nil, ovfl}
state := newDecodeStateFromData(boolResult)
- execDec("bool", instr, state, t, unsafe.Pointer(&data))
- if data.a != true {
- t.Errorf("bool a = %v not true", data.a)
+ execDec("bool", instr, state, t, reflect.ValueOf(&data))
+ if data != true {
+ t.Errorf("bool a = %v not true", data)
}
}
// int
{
- var data struct {
- a int
- }
- instr := &decInstr{decOpTable[reflect.Int], 6, 0, 0, ovfl}
+ var data int
+ instr := &decInstr{decOpTable[reflect.Int], 6, nil, ovfl}
state := newDecodeStateFromData(signedResult)
- execDec("int", instr, state, t, unsafe.Pointer(&data))
- if data.a != 17 {
- t.Errorf("int a = %v not 17", data.a)
+ execDec("int", instr, state, t, reflect.ValueOf(&data))
+ if data != 17 {
+ t.Errorf("int a = %v not 17", data)
}
}
// uint
{
- var data struct {
- a uint
- }
- instr := &decInstr{decOpTable[reflect.Uint], 6, 0, 0, ovfl}
+ var data uint
+ instr := &decInstr{decOpTable[reflect.Uint], 6, nil, ovfl}
state := newDecodeStateFromData(unsignedResult)
- execDec("uint", instr, state, t, unsafe.Pointer(&data))
- if data.a != 17 {
- t.Errorf("uint a = %v not 17", data.a)
+ execDec("uint", instr, state, t, reflect.ValueOf(&data))
+ if data != 17 {
+ t.Errorf("uint a = %v not 17", data)
}
}
// int8
{
- var data struct {
- a int8
- }
- instr := &decInstr{decInt8, 6, 0, 0, ovfl}
+ var data int8
+ instr := &decInstr{decInt8, 6, nil, ovfl}
state := newDecodeStateFromData(signedResult)
- execDec("int8", instr, state, t, unsafe.Pointer(&data))
- if data.a != 17 {
- t.Errorf("int8 a = %v not 17", data.a)
+ execDec("int8", instr, state, t, reflect.ValueOf(&data))
+ if data != 17 {
+ t.Errorf("int8 a = %v not 17", data)
}
}
// uint8
{
- var data struct {
- a uint8
- }
- instr := &decInstr{decUint8, 6, 0, 0, ovfl}
+ var data uint8
+ instr := &decInstr{decUint8, 6, nil, ovfl}
state := newDecodeStateFromData(unsignedResult)
- execDec("uint8", instr, state, t, unsafe.Pointer(&data))
- if data.a != 17 {
- t.Errorf("uint8 a = %v not 17", data.a)
+ execDec("uint8", instr, state, t, reflect.ValueOf(&data))
+ if data != 17 {
+ t.Errorf("uint8 a = %v not 17", data)
}
}
// int16
{
- var data struct {
- a int16
- }
- instr := &decInstr{decInt16, 6, 0, 0, ovfl}
+ var data int16
+ instr := &decInstr{decInt16, 6, nil, ovfl}
state := newDecodeStateFromData(signedResult)
- execDec("int16", instr, state, t, unsafe.Pointer(&data))
- if data.a != 17 {
- t.Errorf("int16 a = %v not 17", data.a)
+ execDec("int16", instr, state, t, reflect.ValueOf(&data))
+ if data != 17 {
+ t.Errorf("int16 a = %v not 17", data)
}
}
// uint16
{
- var data struct {
- a uint16
- }
- instr := &decInstr{decUint16, 6, 0, 0, ovfl}
+ var data uint16
+ instr := &decInstr{decUint16, 6, nil, ovfl}
state := newDecodeStateFromData(unsignedResult)
- execDec("uint16", instr, state, t, unsafe.Pointer(&data))
- if data.a != 17 {
- t.Errorf("uint16 a = %v not 17", data.a)
+ execDec("uint16", instr, state, t, reflect.ValueOf(&data))
+ if data != 17 {
+ t.Errorf("uint16 a = %v not 17", data)
}
}
// int32
{
- var data struct {
- a int32
- }
- instr := &decInstr{decInt32, 6, 0, 0, ovfl}
+ var data int32
+ instr := &decInstr{decInt32, 6, nil, ovfl}
state := newDecodeStateFromData(signedResult)
- execDec("int32", instr, state, t, unsafe.Pointer(&data))
- if data.a != 17 {
- t.Errorf("int32 a = %v not 17", data.a)
+ execDec("int32", instr, state, t, reflect.ValueOf(&data))
+ if data != 17 {
+ t.Errorf("int32 a = %v not 17", data)
}
}
// uint32
{
- var data struct {
- a uint32
- }
- instr := &decInstr{decUint32, 6, 0, 0, ovfl}
+ var data uint32
+ instr := &decInstr{decUint32, 6, nil, ovfl}
state := newDecodeStateFromData(unsignedResult)
- execDec("uint32", instr, state, t, unsafe.Pointer(&data))
- if data.a != 17 {
- t.Errorf("uint32 a = %v not 17", data.a)
+ execDec("uint32", instr, state, t, reflect.ValueOf(&data))
+ if data != 17 {
+ t.Errorf("uint32 a = %v not 17", data)
}
}
// uintptr
{
- var data struct {
- a uintptr
- }
- instr := &decInstr{decOpTable[reflect.Uintptr], 6, 0, 0, ovfl}
+ var data uintptr
+ instr := &decInstr{decOpTable[reflect.Uintptr], 6, nil, ovfl}
state := newDecodeStateFromData(unsignedResult)
- execDec("uintptr", instr, state, t, unsafe.Pointer(&data))
- if data.a != 17 {
- t.Errorf("uintptr a = %v not 17", data.a)
+ execDec("uintptr", instr, state, t, reflect.ValueOf(&data))
+ if data != 17 {
+ t.Errorf("uintptr a = %v not 17", data)
}
}
// int64
{
- var data struct {
- a int64
- }
- instr := &decInstr{decInt64, 6, 0, 0, ovfl}
+ var data int64
+ instr := &decInstr{decInt64, 6, nil, ovfl}
state := newDecodeStateFromData(signedResult)
- execDec("int64", instr, state, t, unsafe.Pointer(&data))
- if data.a != 17 {
- t.Errorf("int64 a = %v not 17", data.a)
+ execDec("int64", instr, state, t, reflect.ValueOf(&data))
+ if data != 17 {
+ t.Errorf("int64 a = %v not 17", data)
}
}
// uint64
{
- var data struct {
- a uint64
- }
- instr := &decInstr{decUint64, 6, 0, 0, ovfl}
+ var data uint64
+ instr := &decInstr{decUint64, 6, nil, ovfl}
state := newDecodeStateFromData(unsignedResult)
- execDec("uint64", instr, state, t, unsafe.Pointer(&data))
- if data.a != 17 {
- t.Errorf("uint64 a = %v not 17", data.a)
+ execDec("uint64", instr, state, t, reflect.ValueOf(&data))
+ if data != 17 {
+ t.Errorf("uint64 a = %v not 17", data)
}
}
// float32
{
- var data struct {
- a float32
- }
- instr := &decInstr{decFloat32, 6, 0, 0, ovfl}
+ var data float32
+ instr := &decInstr{decFloat32, 6, nil, ovfl}
state := newDecodeStateFromData(floatResult)
- execDec("float32", instr, state, t, unsafe.Pointer(&data))
- if data.a != 17 {
- t.Errorf("float32 a = %v not 17", data.a)
+ execDec("float32", instr, state, t, reflect.ValueOf(&data))
+ if data != 17 {
+ t.Errorf("float32 a = %v not 17", data)
}
}
// float64
{
- var data struct {
- a float64
- }
- instr := &decInstr{decFloat64, 6, 0, 0, ovfl}
+ var data float64
+ instr := &decInstr{decFloat64, 6, nil, ovfl}
state := newDecodeStateFromData(floatResult)
- execDec("float64", instr, state, t, unsafe.Pointer(&data))
- if data.a != 17 {
- t.Errorf("float64 a = %v not 17", data.a)
+ execDec("float64", instr, state, t, reflect.ValueOf(&data))
+ if data != 17 {
+ t.Errorf("float64 a = %v not 17", data)
}
}
// complex64
{
- var data struct {
- a complex64
- }
- instr := &decInstr{decOpTable[reflect.Complex64], 6, 0, 0, ovfl}
+ var data complex64
+ instr := &decInstr{decOpTable[reflect.Complex64], 6, nil, ovfl}
state := newDecodeStateFromData(complexResult)
- execDec("complex", instr, state, t, unsafe.Pointer(&data))
- if data.a != 17+19i {
- t.Errorf("complex a = %v not 17+19i", data.a)
+ execDec("complex", instr, state, t, reflect.ValueOf(&data))
+ if data != 17+19i {
+ t.Errorf("complex a = %v not 17+19i", data)
}
}
// complex128
{
- var data struct {
- a complex128
- }
- instr := &decInstr{decOpTable[reflect.Complex128], 6, 0, 0, ovfl}
+ var data complex128
+ instr := &decInstr{decOpTable[reflect.Complex128], 6, nil, ovfl}
state := newDecodeStateFromData(complexResult)
- execDec("complex", instr, state, t, unsafe.Pointer(&data))
- if data.a != 17+19i {
- t.Errorf("complex a = %v not 17+19i", data.a)
+ execDec("complex", instr, state, t, reflect.ValueOf(&data))
+ if data != 17+19i {
+ t.Errorf("complex a = %v not 17+19i", data)
}
}
// bytes == []uint8
{
- var data struct {
- a []byte
- }
- instr := &decInstr{decUint8Slice, 6, 0, 0, ovfl}
+ var data []byte
+ instr := &decInstr{decUint8Slice, 6, nil, ovfl}
state := newDecodeStateFromData(bytesResult)
- execDec("bytes", instr, state, t, unsafe.Pointer(&data))
- if string(data.a) != "hello" {
- t.Errorf(`bytes a = %q not "hello"`, string(data.a))
+ execDec("bytes", instr, state, t, reflect.ValueOf(&data))
+ if string(data) != "hello" {
+ t.Errorf(`bytes a = %q not "hello"`, string(data))
}
}
// string
{
- var data struct {
- a string
- }
- instr := &decInstr{decString, 6, 0, 0, ovfl}
+ var data string
+ instr := &decInstr{decString, 6, nil, ovfl}
state := newDecodeStateFromData(bytesResult)
- execDec("bytes", instr, state, t, unsafe.Pointer(&data))
- if data.a != "hello" {
- t.Errorf(`bytes a = %q not "hello"`, data.a)
+ execDec("bytes", instr, state, t, reflect.ValueOf(&data))
+ if data != "hello" {
+ t.Errorf(`bytes a = %q not "hello"`, data)
}
}
}
@@ -1364,11 +1333,7 @@ type DT struct {
S []string
}
-func TestDebugStruct(t *testing.T) {
- if debugFunc == nil {
- return
- }
- Register(OnTheFly{})
+func newDT() DT {
var dt DT
dt.A = 17
dt.B = "hello"
@@ -1379,6 +1344,15 @@ func TestDebugStruct(t *testing.T) {
dt.M = map[string]int{"one": 1, "two": 2}
dt.T = [3]int{11, 22, 33}
dt.S = []string{"hi", "joe"}
+ return dt
+}
+
+func TestDebugStruct(t *testing.T) {
+ if debugFunc == nil {
+ return
+ }
+ Register(OnTheFly{})
+ dt := newDT()
b := new(bytes.Buffer)
err := NewEncoder(b).Encode(dt)
if err != nil {
@@ -1458,3 +1432,44 @@ func testFuzz(t *testing.T, seed int64, n int, input ...interface{}) {
}
}
}
+
+// TestFuzzOneByte tries to decode corrupted input sequences
+// and checks that no panic occurs.
+func TestFuzzOneByte(t *testing.T) {
+ buf := new(bytes.Buffer)
+ Register(OnTheFly{})
+ dt := newDT()
+ if err := NewEncoder(buf).Encode(dt); err != nil {
+ t.Fatal(err)
+ }
+ s := buf.String()
+
+ indices := make([]int, 0, len(s))
+ for i := 0; i < len(s); i++ {
+ switch i {
+ case 14, 167, 231, 265: // a slice length, corruptions are not handled yet.
+ continue
+ }
+ indices = append(indices, i)
+ }
+ if testing.Short() {
+ indices = []int{1, 111, 178} // known fixed panics
+ }
+ for _, i := range indices {
+ for j := 0; j < 256; j += 3 {
+ b := []byte(s)
+ b[i] ^= byte(j)
+ var e DT
+ func() {
+ defer func() {
+ if p := recover(); p != nil {
+ t.Errorf("crash for b[%d] ^= 0x%x", i, j)
+ panic(p)
+ }
+ }()
+ err := NewDecoder(bytes.NewReader(b)).Decode(&e)
+ _ = err
+ }()
+ }
+ }
+}
diff --git a/libgo/go/encoding/gob/debug.go b/libgo/go/encoding/gob/debug.go
index 6117eb0837..536bbdb5ac 100644
--- a/libgo/go/encoding/gob/debug.go
+++ b/libgo/go/encoding/gob/debug.go
@@ -306,7 +306,7 @@ func (deb *debugger) common() CommonType {
// Id typeId
id = deb.typeId()
default:
- errorf("corrupted CommonType")
+ errorf("corrupted CommonType, delta is %d fieldNum is %d", delta, fieldNum)
}
}
return CommonType{name, id}
@@ -598,11 +598,11 @@ func (deb *debugger) printBuiltin(indent tab, id typeId) {
fmt.Fprintf(os.Stderr, "%s%d\n", indent, x)
case tFloat:
x := deb.uint64()
- fmt.Fprintf(os.Stderr, "%s%g\n", indent, floatFromBits(x))
+ fmt.Fprintf(os.Stderr, "%s%g\n", indent, float64FromBits(x))
case tComplex:
r := deb.uint64()
i := deb.uint64()
- fmt.Fprintf(os.Stderr, "%s%g+%gi\n", indent, floatFromBits(r), floatFromBits(i))
+ fmt.Fprintf(os.Stderr, "%s%g+%gi\n", indent, float64FromBits(r), float64FromBits(i))
case tBytes:
x := int(deb.uint64())
b := make([]byte, x)
diff --git a/libgo/go/encoding/gob/dec_helpers.go b/libgo/go/encoding/gob/dec_helpers.go
new file mode 100644
index 0000000000..a1b67661d8
--- /dev/null
+++ b/libgo/go/encoding/gob/dec_helpers.go
@@ -0,0 +1,468 @@
+// Created by decgen --output dec_helpers.go; DO NOT EDIT
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+ "math"
+ "reflect"
+)
+
+var decArrayHelper = map[reflect.Kind]decHelper{
+ reflect.Bool: decBoolArray,
+ reflect.Complex64: decComplex64Array,
+ reflect.Complex128: decComplex128Array,
+ reflect.Float32: decFloat32Array,
+ reflect.Float64: decFloat64Array,
+ reflect.Int: decIntArray,
+ reflect.Int16: decInt16Array,
+ reflect.Int32: decInt32Array,
+ reflect.Int64: decInt64Array,
+ reflect.Int8: decInt8Array,
+ reflect.String: decStringArray,
+ reflect.Uint: decUintArray,
+ reflect.Uint16: decUint16Array,
+ reflect.Uint32: decUint32Array,
+ reflect.Uint64: decUint64Array,
+ reflect.Uintptr: decUintptrArray,
+}
+
+var decSliceHelper = map[reflect.Kind]decHelper{
+ reflect.Bool: decBoolSlice,
+ reflect.Complex64: decComplex64Slice,
+ reflect.Complex128: decComplex128Slice,
+ reflect.Float32: decFloat32Slice,
+ reflect.Float64: decFloat64Slice,
+ reflect.Int: decIntSlice,
+ reflect.Int16: decInt16Slice,
+ reflect.Int32: decInt32Slice,
+ reflect.Int64: decInt64Slice,
+ reflect.Int8: decInt8Slice,
+ reflect.String: decStringSlice,
+ reflect.Uint: decUintSlice,
+ reflect.Uint16: decUint16Slice,
+ reflect.Uint32: decUint32Slice,
+ reflect.Uint64: decUint64Slice,
+ reflect.Uintptr: decUintptrSlice,
+}
+
+func decBoolArray(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return decBoolSlice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decBoolSlice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ slice, ok := v.Interface().([]bool)
+ if !ok {
+ // It is kind bool but not type bool. TODO: We can handle this unsafely.
+ return false
+ }
+ for i := 0; i < length; i++ {
+ if state.b.Len() == 0 {
+ errorf("decoding bool array or slice: length exceeds input size (%d elements)", length)
+ }
+ slice[i] = state.decodeUint() != 0
+ }
+ return true
+}
+
+func decComplex64Array(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return decComplex64Slice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decComplex64Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ slice, ok := v.Interface().([]complex64)
+ if !ok {
+ // It is kind complex64 but not type complex64. TODO: We can handle this unsafely.
+ return false
+ }
+ for i := 0; i < length; i++ {
+ if state.b.Len() == 0 {
+ errorf("decoding complex64 array or slice: length exceeds input size (%d elements)", length)
+ }
+ real := float32FromBits(state.decodeUint(), ovfl)
+ imag := float32FromBits(state.decodeUint(), ovfl)
+ slice[i] = complex(float32(real), float32(imag))
+ }
+ return true
+}
+
+func decComplex128Array(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return decComplex128Slice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decComplex128Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ slice, ok := v.Interface().([]complex128)
+ if !ok {
+ // It is kind complex128 but not type complex128. TODO: We can handle this unsafely.
+ return false
+ }
+ for i := 0; i < length; i++ {
+ if state.b.Len() == 0 {
+ errorf("decoding complex128 array or slice: length exceeds input size (%d elements)", length)
+ }
+ real := float64FromBits(state.decodeUint())
+ imag := float64FromBits(state.decodeUint())
+ slice[i] = complex(real, imag)
+ }
+ return true
+}
+
+func decFloat32Array(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return decFloat32Slice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decFloat32Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ slice, ok := v.Interface().([]float32)
+ if !ok {
+ // It is kind float32 but not type float32. TODO: We can handle this unsafely.
+ return false
+ }
+ for i := 0; i < length; i++ {
+ if state.b.Len() == 0 {
+ errorf("decoding float32 array or slice: length exceeds input size (%d elements)", length)
+ }
+ slice[i] = float32(float32FromBits(state.decodeUint(), ovfl))
+ }
+ return true
+}
+
+func decFloat64Array(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return decFloat64Slice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decFloat64Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ slice, ok := v.Interface().([]float64)
+ if !ok {
+ // It is kind float64 but not type float64. TODO: We can handle this unsafely.
+ return false
+ }
+ for i := 0; i < length; i++ {
+ if state.b.Len() == 0 {
+ errorf("decoding float64 array or slice: length exceeds input size (%d elements)", length)
+ }
+ slice[i] = float64FromBits(state.decodeUint())
+ }
+ return true
+}
+
+func decIntArray(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return decIntSlice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decIntSlice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ slice, ok := v.Interface().([]int)
+ if !ok {
+ // It is kind int but not type int. TODO: We can handle this unsafely.
+ return false
+ }
+ for i := 0; i < length; i++ {
+ if state.b.Len() == 0 {
+ errorf("decoding int array or slice: length exceeds input size (%d elements)", length)
+ }
+ x := state.decodeInt()
+ // MinInt and MaxInt
+ if x < ^int64(^uint(0)>>1) || int64(^uint(0)>>1) < x {
+ error_(ovfl)
+ }
+ slice[i] = int(x)
+ }
+ return true
+}
+
+func decInt16Array(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return decInt16Slice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decInt16Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ slice, ok := v.Interface().([]int16)
+ if !ok {
+ // It is kind int16 but not type int16. TODO: We can handle this unsafely.
+ return false
+ }
+ for i := 0; i < length; i++ {
+ if state.b.Len() == 0 {
+ errorf("decoding int16 array or slice: length exceeds input size (%d elements)", length)
+ }
+ x := state.decodeInt()
+ if x < math.MinInt16 || math.MaxInt16 < x {
+ error_(ovfl)
+ }
+ slice[i] = int16(x)
+ }
+ return true
+}
+
+func decInt32Array(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return decInt32Slice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decInt32Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ slice, ok := v.Interface().([]int32)
+ if !ok {
+ // It is kind int32 but not type int32. TODO: We can handle this unsafely.
+ return false
+ }
+ for i := 0; i < length; i++ {
+ if state.b.Len() == 0 {
+ errorf("decoding int32 array or slice: length exceeds input size (%d elements)", length)
+ }
+ x := state.decodeInt()
+ if x < math.MinInt32 || math.MaxInt32 < x {
+ error_(ovfl)
+ }
+ slice[i] = int32(x)
+ }
+ return true
+}
+
+func decInt64Array(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return decInt64Slice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decInt64Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ slice, ok := v.Interface().([]int64)
+ if !ok {
+ // It is kind int64 but not type int64. TODO: We can handle this unsafely.
+ return false
+ }
+ for i := 0; i < length; i++ {
+ if state.b.Len() == 0 {
+ errorf("decoding int64 array or slice: length exceeds input size (%d elements)", length)
+ }
+ slice[i] = state.decodeInt()
+ }
+ return true
+}
+
+func decInt8Array(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return decInt8Slice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decInt8Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ slice, ok := v.Interface().([]int8)
+ if !ok {
+ // It is kind int8 but not type int8. TODO: We can handle this unsafely.
+ return false
+ }
+ for i := 0; i < length; i++ {
+ if state.b.Len() == 0 {
+ errorf("decoding int8 array or slice: length exceeds input size (%d elements)", length)
+ }
+ x := state.decodeInt()
+ if x < math.MinInt8 || math.MaxInt8 < x {
+ error_(ovfl)
+ }
+ slice[i] = int8(x)
+ }
+ return true
+}
+
+func decStringArray(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return decStringSlice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decStringSlice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ slice, ok := v.Interface().([]string)
+ if !ok {
+ // It is kind string but not type string. TODO: We can handle this unsafely.
+ return false
+ }
+ for i := 0; i < length; i++ {
+ if state.b.Len() == 0 {
+ errorf("decoding string array or slice: length exceeds input size (%d elements)", length)
+ }
+ u := state.decodeUint()
+ n := int(u)
+ if n < 0 || uint64(n) != u || n > state.b.Len() {
+ errorf("length of string exceeds input size (%d bytes)", u)
+ }
+ if n > state.b.Len() {
+ errorf("string data too long for buffer: %d", n)
+ }
+ // Read the data.
+ data := make([]byte, n)
+ if _, err := state.b.Read(data); err != nil {
+ errorf("error decoding string: %s", err)
+ }
+ slice[i] = string(data)
+ }
+ return true
+}
+
+func decUintArray(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return decUintSlice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decUintSlice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ slice, ok := v.Interface().([]uint)
+ if !ok {
+ // It is kind uint but not type uint. TODO: We can handle this unsafely.
+ return false
+ }
+ for i := 0; i < length; i++ {
+ if state.b.Len() == 0 {
+ errorf("decoding uint array or slice: length exceeds input size (%d elements)", length)
+ }
+ x := state.decodeUint()
+ /*TODO if math.MaxUint32 < x {
+ error_(ovfl)
+ }*/
+ slice[i] = uint(x)
+ }
+ return true
+}
+
+func decUint16Array(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return decUint16Slice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decUint16Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ slice, ok := v.Interface().([]uint16)
+ if !ok {
+ // It is kind uint16 but not type uint16. TODO: We can handle this unsafely.
+ return false
+ }
+ for i := 0; i < length; i++ {
+ if state.b.Len() == 0 {
+ errorf("decoding uint16 array or slice: length exceeds input size (%d elements)", length)
+ }
+ x := state.decodeUint()
+ if math.MaxUint16 < x {
+ error_(ovfl)
+ }
+ slice[i] = uint16(x)
+ }
+ return true
+}
+
+func decUint32Array(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return decUint32Slice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decUint32Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ slice, ok := v.Interface().([]uint32)
+ if !ok {
+ // It is kind uint32 but not type uint32. TODO: We can handle this unsafely.
+ return false
+ }
+ for i := 0; i < length; i++ {
+ if state.b.Len() == 0 {
+ errorf("decoding uint32 array or slice: length exceeds input size (%d elements)", length)
+ }
+ x := state.decodeUint()
+ if math.MaxUint32 < x {
+ error_(ovfl)
+ }
+ slice[i] = uint32(x)
+ }
+ return true
+}
+
+func decUint64Array(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return decUint64Slice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decUint64Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ slice, ok := v.Interface().([]uint64)
+ if !ok {
+ // It is kind uint64 but not type uint64. TODO: We can handle this unsafely.
+ return false
+ }
+ for i := 0; i < length; i++ {
+ if state.b.Len() == 0 {
+ errorf("decoding uint64 array or slice: length exceeds input size (%d elements)", length)
+ }
+ slice[i] = state.decodeUint()
+ }
+ return true
+}
+
+func decUintptrArray(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return decUintptrSlice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decUintptrSlice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ slice, ok := v.Interface().([]uintptr)
+ if !ok {
+ // It is kind uintptr but not type uintptr. TODO: We can handle this unsafely.
+ return false
+ }
+ for i := 0; i < length; i++ {
+ if state.b.Len() == 0 {
+ errorf("decoding uintptr array or slice: length exceeds input size (%d elements)", length)
+ }
+ x := state.decodeUint()
+ if uint64(^uintptr(0)) < x {
+ error_(ovfl)
+ }
+ slice[i] = uintptr(x)
+ }
+ return true
+}
diff --git a/libgo/go/encoding/gob/decgen.go b/libgo/go/encoding/gob/decgen.go
new file mode 100644
index 0000000000..da41a899ed
--- /dev/null
+++ b/libgo/go/encoding/gob/decgen.go
@@ -0,0 +1,240 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+// encgen writes the helper functions for encoding. Intended to be
+// used with go generate; see the invocation in encode.go.
+
+// TODO: We could do more by being unsafe. Add a -unsafe flag?
+
+package main
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "go/format"
+ "log"
+ "os"
+)
+
+var output = flag.String("output", "dec_helpers.go", "file name to write")
+
+type Type struct {
+ lower string
+ upper string
+ decoder string
+}
+
+var types = []Type{
+ {
+ "bool",
+ "Bool",
+ `slice[i] = state.decodeUint() != 0`,
+ },
+ {
+ "complex64",
+ "Complex64",
+ `real := float32FromBits(state.decodeUint(), ovfl)
+ imag := float32FromBits(state.decodeUint(), ovfl)
+ slice[i] = complex(float32(real), float32(imag))`,
+ },
+ {
+ "complex128",
+ "Complex128",
+ `real := float64FromBits(state.decodeUint())
+ imag := float64FromBits(state.decodeUint())
+ slice[i] = complex(real, imag)`,
+ },
+ {
+ "float32",
+ "Float32",
+ `slice[i] = float32(float32FromBits(state.decodeUint(), ovfl))`,
+ },
+ {
+ "float64",
+ "Float64",
+ `slice[i] = float64FromBits(state.decodeUint())`,
+ },
+ {
+ "int",
+ "Int",
+ `x := state.decodeInt()
+ // MinInt and MaxInt
+ if x < ^int64(^uint(0)>>1) || int64(^uint(0)>>1) < x {
+ error_(ovfl)
+ }
+ slice[i] = int(x)`,
+ },
+ {
+ "int16",
+ "Int16",
+ `x := state.decodeInt()
+ if x < math.MinInt16 || math.MaxInt16 < x {
+ error_(ovfl)
+ }
+ slice[i] = int16(x)`,
+ },
+ {
+ "int32",
+ "Int32",
+ `x := state.decodeInt()
+ if x < math.MinInt32 || math.MaxInt32 < x {
+ error_(ovfl)
+ }
+ slice[i] = int32(x)`,
+ },
+ {
+ "int64",
+ "Int64",
+ `slice[i] = state.decodeInt()`,
+ },
+ {
+ "int8",
+ "Int8",
+ `x := state.decodeInt()
+ if x < math.MinInt8 || math.MaxInt8 < x {
+ error_(ovfl)
+ }
+ slice[i] = int8(x)`,
+ },
+ {
+ "string",
+ "String",
+ `u := state.decodeUint()
+ n := int(u)
+ if n < 0 || uint64(n) != u || n > state.b.Len() {
+ errorf("length of string exceeds input size (%d bytes)", u)
+ }
+ if n > state.b.Len() {
+ errorf("string data too long for buffer: %d", n)
+ }
+ // Read the data.
+ data := make([]byte, n)
+ if _, err := state.b.Read(data); err != nil {
+ errorf("error decoding string: %s", err)
+ }
+ slice[i] = string(data)`,
+ },
+ {
+ "uint",
+ "Uint",
+ `x := state.decodeUint()
+ /*TODO if math.MaxUint32 < x {
+ error_(ovfl)
+ }*/
+ slice[i] = uint(x)`,
+ },
+ {
+ "uint16",
+ "Uint16",
+ `x := state.decodeUint()
+ if math.MaxUint16 < x {
+ error_(ovfl)
+ }
+ slice[i] = uint16(x)`,
+ },
+ {
+ "uint32",
+ "Uint32",
+ `x := state.decodeUint()
+ if math.MaxUint32 < x {
+ error_(ovfl)
+ }
+ slice[i] = uint32(x)`,
+ },
+ {
+ "uint64",
+ "Uint64",
+ `slice[i] = state.decodeUint()`,
+ },
+ {
+ "uintptr",
+ "Uintptr",
+ `x := state.decodeUint()
+ if uint64(^uintptr(0)) < x {
+ error_(ovfl)
+ }
+ slice[i] = uintptr(x)`,
+ },
+ // uint8 Handled separately.
+}
+
+func main() {
+ log.SetFlags(0)
+ log.SetPrefix("decgen: ")
+ flag.Parse()
+ if flag.NArg() != 0 {
+ log.Fatal("usage: decgen [--output filename]")
+ }
+ var b bytes.Buffer
+ fmt.Fprintf(&b, "// Created by decgen --output %s; DO NOT EDIT\n", *output)
+ fmt.Fprint(&b, header)
+ printMaps(&b, "Array")
+ fmt.Fprint(&b, "\n")
+ printMaps(&b, "Slice")
+ for _, t := range types {
+ fmt.Fprintf(&b, arrayHelper, t.lower, t.upper)
+ fmt.Fprintf(&b, sliceHelper, t.lower, t.upper, t.decoder)
+ }
+ source, err := format.Source(b.Bytes())
+ if err != nil {
+ log.Fatal("source format error:", err)
+ }
+ fd, err := os.Create(*output)
+ _, err = fd.Write(source)
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+func printMaps(b *bytes.Buffer, upperClass string) {
+ fmt.Fprintf(b, "var dec%sHelper = map[reflect.Kind]decHelper{\n", upperClass)
+ for _, t := range types {
+ fmt.Fprintf(b, "reflect.%s: dec%s%s,\n", t.upper, t.upper, upperClass)
+ }
+ fmt.Fprintf(b, "}\n")
+}
+
+const header = `
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+ "math"
+ "reflect"
+)
+
+`
+
+const arrayHelper = `
+func dec%[2]sArray(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return dec%[2]sSlice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+`
+
+const sliceHelper = `
+func dec%[2]sSlice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+ slice, ok := v.Interface().([]%[1]s)
+ if !ok {
+ // It is kind %[1]s but not type %[1]s. TODO: We can handle this unsafely.
+ return false
+ }
+ for i := 0; i < length; i++ {
+ if state.b.Len() == 0 {
+ errorf("decoding %[1]s array or slice: length exceeds input size (%%d elements)", length)
+ }
+ %[3]s
+ }
+ return true
+}
+`
diff --git a/libgo/go/encoding/gob/decode.go b/libgo/go/encoding/gob/decode.go
index 3e76f4c906..a5bef93141 100644
--- a/libgo/go/encoding/gob/decode.go
+++ b/libgo/go/encoding/gob/decode.go
@@ -2,19 +2,16 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package gob
+//go:generate go run decgen.go -output dec_helpers.go
-// TODO(rsc): When garbage collector changes, revisit
-// the allocations in this file that use unsafe.Pointer.
+package gob
import (
- "bytes"
"encoding"
"errors"
"io"
"math"
"reflect"
- "unsafe"
)
var (
@@ -23,21 +20,79 @@ var (
errRange = errors.New("gob: bad data: field numbers out of bounds")
)
+type decHelper func(state *decoderState, v reflect.Value, length int, ovfl error) bool
+
// decoderState is the execution state of an instance of the decoder. A new state
// is created for nested objects.
type decoderState struct {
dec *Decoder
// The buffer is stored with an extra indirection because it may be replaced
// if we load a type during decode (when reading an interface value).
- b *bytes.Buffer
+ b *decBuffer
fieldnum int // the last field number read.
buf []byte
next *decoderState // for free list
}
+// decBuffer is an extremely simple, fast implementation of a read-only byte buffer.
+// It is initialized by calling Size and then copying the data into the slice returned by Bytes().
+type decBuffer struct {
+ data []byte
+ offset int // Read offset.
+}
+
+func (d *decBuffer) Read(p []byte) (int, error) {
+ n := copy(p, d.data[d.offset:])
+ if n == 0 && len(p) != 0 {
+ return 0, io.EOF
+ }
+ d.offset += n
+ return n, nil
+}
+
+func (d *decBuffer) Drop(n int) {
+ if n > d.Len() {
+ panic("drop")
+ }
+ d.offset += n
+}
+
+// Size grows the buffer to exactly n bytes, so d.Bytes() will
+// return a slice of length n. Existing data is first discarded.
+func (d *decBuffer) Size(n int) {
+ d.Reset()
+ if cap(d.data) < n {
+ d.data = make([]byte, n)
+ } else {
+ d.data = d.data[0:n]
+ }
+}
+
+func (d *decBuffer) ReadByte() (byte, error) {
+ if d.offset >= len(d.data) {
+ return 0, io.EOF
+ }
+ c := d.data[d.offset]
+ d.offset++
+ return c, nil
+}
+
+func (d *decBuffer) Len() int {
+ return len(d.data) - d.offset
+}
+
+func (d *decBuffer) Bytes() []byte {
+ return d.data[d.offset:]
+}
+
+func (d *decBuffer) Reset() {
+ d.data = d.data[0:0]
+ d.offset = 0
+}
+
// We pass the bytes.Buffer separately for easier testing of the infrastructure
// without requiring a full Decoder.
-func (dec *Decoder) newDecoderState(buf *bytes.Buffer) *decoderState {
+func (dec *Decoder) newDecoderState(buf *decBuffer) *decoderState {
d := dec.freeList
if d == nil {
d = new(decoderState)
@@ -128,175 +183,118 @@ func (state *decoderState) decodeInt() int64 {
}
// decOp is the signature of a decoding operator for a given type.
-type decOp func(i *decInstr, state *decoderState, p unsafe.Pointer)
+type decOp func(i *decInstr, state *decoderState, v reflect.Value)
// The 'instructions' of the decoding machine
type decInstr struct {
- op decOp
- field int // field number of the wire type
- indir int // how many pointer indirections to reach the value in the struct
- offset uintptr // offset in the structure of the field to encode
- ovfl error // error message for overflow/underflow (for arrays, of the elements)
-}
-
-// Since the encoder writes no zeros, if we arrive at a decoder we have
-// a value to extract and store. The field number has already been read
-// (it's how we knew to call this decoder).
-// Each decoder is responsible for handling any indirections associated
-// with the data structure. If any pointer so reached is nil, allocation must
-// be done.
-
-// Walk the pointer hierarchy, allocating if we find a nil. Stop one before the end.
-func decIndirect(p unsafe.Pointer, indir int) unsafe.Pointer {
- for ; indir > 1; indir-- {
- if *(*unsafe.Pointer)(p) == nil {
- // Allocation required
- *(*unsafe.Pointer)(p) = unsafe.Pointer(new(unsafe.Pointer))
- }
- p = *(*unsafe.Pointer)(p)
- }
- return p
+ op decOp
+ field int // field number of the wire type
+ index []int // field access indices for destination type
+ ovfl error // error message for overflow/underflow (for arrays, of the elements)
}
// ignoreUint discards a uint value with no destination.
-func ignoreUint(i *decInstr, state *decoderState, p unsafe.Pointer) {
+func ignoreUint(i *decInstr, state *decoderState, v reflect.Value) {
state.decodeUint()
}
// ignoreTwoUints discards a uint value with no destination. It's used to skip
// complex values.
-func ignoreTwoUints(i *decInstr, state *decoderState, p unsafe.Pointer) {
+func ignoreTwoUints(i *decInstr, state *decoderState, v reflect.Value) {
state.decodeUint()
state.decodeUint()
}
-// decBool decodes a uint and stores it as a boolean through p.
-func decBool(i *decInstr, state *decoderState, p unsafe.Pointer) {
- if i.indir > 0 {
- if *(*unsafe.Pointer)(p) == nil {
- *(*unsafe.Pointer)(p) = unsafe.Pointer(new(bool))
+// Since the encoder writes no zeros, if we arrive at a decoder we have
+// a value to extract and store. The field number has already been read
+// (it's how we knew to call this decoder).
+// Each decoder is responsible for handling any indirections associated
+// with the data structure. If any pointer so reached is nil, allocation must
+// be done.
+
+// decAlloc takes a value and returns a settable value that can
+// be assigned to. If the value is a pointer, decAlloc guarantees it points to storage.
+// The callers to the individual decoders are expected to have used decAlloc.
+// The individual decoders don't need to it.
+func decAlloc(v reflect.Value) reflect.Value {
+ for v.Kind() == reflect.Ptr {
+ if v.IsNil() {
+ v.Set(reflect.New(v.Type().Elem()))
}
- p = *(*unsafe.Pointer)(p)
+ v = v.Elem()
}
- *(*bool)(p) = state.decodeUint() != 0
+ return v
}
-// decInt8 decodes an integer and stores it as an int8 through p.
-func decInt8(i *decInstr, state *decoderState, p unsafe.Pointer) {
- if i.indir > 0 {
- if *(*unsafe.Pointer)(p) == nil {
- *(*unsafe.Pointer)(p) = unsafe.Pointer(new(int8))
- }
- p = *(*unsafe.Pointer)(p)
- }
+// decBool decodes a uint and stores it as a boolean in value.
+func decBool(i *decInstr, state *decoderState, value reflect.Value) {
+ value.SetBool(state.decodeUint() != 0)
+}
+
+// decInt8 decodes an integer and stores it as an int8 in value.
+func decInt8(i *decInstr, state *decoderState, value reflect.Value) {
v := state.decodeInt()
if v < math.MinInt8 || math.MaxInt8 < v {
error_(i.ovfl)
- } else {
- *(*int8)(p) = int8(v)
}
+ value.SetInt(v)
}
-// decUint8 decodes an unsigned integer and stores it as a uint8 through p.
-func decUint8(i *decInstr, state *decoderState, p unsafe.Pointer) {
- if i.indir > 0 {
- if *(*unsafe.Pointer)(p) == nil {
- *(*unsafe.Pointer)(p) = unsafe.Pointer(new(uint8))
- }
- p = *(*unsafe.Pointer)(p)
- }
+// decUint8 decodes an unsigned integer and stores it as a uint8 in value.
+func decUint8(i *decInstr, state *decoderState, value reflect.Value) {
v := state.decodeUint()
if math.MaxUint8 < v {
error_(i.ovfl)
- } else {
- *(*uint8)(p) = uint8(v)
}
+ value.SetUint(v)
}
-// decInt16 decodes an integer and stores it as an int16 through p.
-func decInt16(i *decInstr, state *decoderState, p unsafe.Pointer) {
- if i.indir > 0 {
- if *(*unsafe.Pointer)(p) == nil {
- *(*unsafe.Pointer)(p) = unsafe.Pointer(new(int16))
- }
- p = *(*unsafe.Pointer)(p)
- }
+// decInt16 decodes an integer and stores it as an int16 in value.
+func decInt16(i *decInstr, state *decoderState, value reflect.Value) {
v := state.decodeInt()
if v < math.MinInt16 || math.MaxInt16 < v {
error_(i.ovfl)
- } else {
- *(*int16)(p) = int16(v)
}
+ value.SetInt(v)
}
-// decUint16 decodes an unsigned integer and stores it as a uint16 through p.
-func decUint16(i *decInstr, state *decoderState, p unsafe.Pointer) {
- if i.indir > 0 {
- if *(*unsafe.Pointer)(p) == nil {
- *(*unsafe.Pointer)(p) = unsafe.Pointer(new(uint16))
- }
- p = *(*unsafe.Pointer)(p)
- }
+// decUint16 decodes an unsigned integer and stores it as a uint16 in value.
+func decUint16(i *decInstr, state *decoderState, value reflect.Value) {
v := state.decodeUint()
if math.MaxUint16 < v {
error_(i.ovfl)
- } else {
- *(*uint16)(p) = uint16(v)
}
+ value.SetUint(v)
}
-// decInt32 decodes an integer and stores it as an int32 through p.
-func decInt32(i *decInstr, state *decoderState, p unsafe.Pointer) {
- if i.indir > 0 {
- if *(*unsafe.Pointer)(p) == nil {
- *(*unsafe.Pointer)(p) = unsafe.Pointer(new(int32))
- }
- p = *(*unsafe.Pointer)(p)
- }
+// decInt32 decodes an integer and stores it as an int32 in value.
+func decInt32(i *decInstr, state *decoderState, value reflect.Value) {
v := state.decodeInt()
if v < math.MinInt32 || math.MaxInt32 < v {
error_(i.ovfl)
- } else {
- *(*int32)(p) = int32(v)
}
+ value.SetInt(v)
}
-// decUint32 decodes an unsigned integer and stores it as a uint32 through p.
-func decUint32(i *decInstr, state *decoderState, p unsafe.Pointer) {
- if i.indir > 0 {
- if *(*unsafe.Pointer)(p) == nil {
- *(*unsafe.Pointer)(p) = unsafe.Pointer(new(uint32))
- }
- p = *(*unsafe.Pointer)(p)
- }
+// decUint32 decodes an unsigned integer and stores it as a uint32 in value.
+func decUint32(i *decInstr, state *decoderState, value reflect.Value) {
v := state.decodeUint()
if math.MaxUint32 < v {
error_(i.ovfl)
- } else {
- *(*uint32)(p) = uint32(v)
}
+ value.SetUint(v)
}
-// decInt64 decodes an integer and stores it as an int64 through p.
-func decInt64(i *decInstr, state *decoderState, p unsafe.Pointer) {
- if i.indir > 0 {
- if *(*unsafe.Pointer)(p) == nil {
- *(*unsafe.Pointer)(p) = unsafe.Pointer(new(int64))
- }
- p = *(*unsafe.Pointer)(p)
- }
- *(*int64)(p) = int64(state.decodeInt())
+// decInt64 decodes an integer and stores it as an int64 in value.
+func decInt64(i *decInstr, state *decoderState, value reflect.Value) {
+ v := state.decodeInt()
+ value.SetInt(v)
}
-// decUint64 decodes an unsigned integer and stores it as a uint64 through p.
-func decUint64(i *decInstr, state *decoderState, p unsafe.Pointer) {
- if i.indir > 0 {
- if *(*unsafe.Pointer)(p) == nil {
- *(*unsafe.Pointer)(p) = unsafe.Pointer(new(uint64))
- }
- p = *(*unsafe.Pointer)(p)
- }
- *(*uint64)(p) = uint64(state.decodeUint())
+// decUint64 decodes an unsigned integer and stores it as a uint64 in value.
+func decUint64(i *decInstr, state *decoderState, value reflect.Value) {
+ v := state.decodeUint()
+ value.SetUint(v)
}
// Floating-point numbers are transmitted as uint64s holding the bits
@@ -304,7 +302,7 @@ func decUint64(i *decInstr, state *decoderState, p unsafe.Pointer) {
// the exponent end coming out first, so integer floating point numbers
// (for example) transmit more compactly. This routine does the
// unswizzling.
-func floatFromBits(u uint64) float64 {
+func float64FromBits(u uint64) float64 {
var v uint64
for i := 0; i < 8; i++ {
v <<= 8
@@ -314,128 +312,100 @@ func floatFromBits(u uint64) float64 {
return math.Float64frombits(v)
}
-// storeFloat32 decodes an unsigned integer, treats it as a 32-bit floating-point
-// number, and stores it through p. It's a helper function for float32 and complex64.
-func storeFloat32(i *decInstr, state *decoderState, p unsafe.Pointer) {
- v := floatFromBits(state.decodeUint())
+// float32FromBits decodes an unsigned integer, treats it as a 32-bit floating-point
+// number, and returns it. It's a helper function for float32 and complex64.
+// It returns a float64 because that's what reflection needs, but its return
+// value is known to be accurately representable in a float32.
+func float32FromBits(u uint64, ovfl error) float64 {
+ v := float64FromBits(u)
av := v
if av < 0 {
av = -av
}
// +Inf is OK in both 32- and 64-bit floats. Underflow is always OK.
if math.MaxFloat32 < av && av <= math.MaxFloat64 {
- error_(i.ovfl)
- } else {
- *(*float32)(p) = float32(v)
+ error_(ovfl)
}
+ return v
}
// decFloat32 decodes an unsigned integer, treats it as a 32-bit floating-point
-// number, and stores it through p.
-func decFloat32(i *decInstr, state *decoderState, p unsafe.Pointer) {
- if i.indir > 0 {
- if *(*unsafe.Pointer)(p) == nil {
- *(*unsafe.Pointer)(p) = unsafe.Pointer(new(float32))
- }
- p = *(*unsafe.Pointer)(p)
- }
- storeFloat32(i, state, p)
+// number, and stores it in value.
+func decFloat32(i *decInstr, state *decoderState, value reflect.Value) {
+ value.SetFloat(float32FromBits(state.decodeUint(), i.ovfl))
}
// decFloat64 decodes an unsigned integer, treats it as a 64-bit floating-point
-// number, and stores it through p.
-func decFloat64(i *decInstr, state *decoderState, p unsafe.Pointer) {
- if i.indir > 0 {
- if *(*unsafe.Pointer)(p) == nil {
- *(*unsafe.Pointer)(p) = unsafe.Pointer(new(float64))
- }
- p = *(*unsafe.Pointer)(p)
- }
- *(*float64)(p) = floatFromBits(uint64(state.decodeUint()))
+// number, and stores it in value.
+func decFloat64(i *decInstr, state *decoderState, value reflect.Value) {
+ value.SetFloat(float64FromBits(state.decodeUint()))
}
// decComplex64 decodes a pair of unsigned integers, treats them as a
-// pair of floating point numbers, and stores them as a complex64 through p.
+// pair of floating point numbers, and stores them as a complex64 in value.
// The real part comes first.
-func decComplex64(i *decInstr, state *decoderState, p unsafe.Pointer) {
- if i.indir > 0 {
- if *(*unsafe.Pointer)(p) == nil {
- *(*unsafe.Pointer)(p) = unsafe.Pointer(new(complex64))
- }
- p = *(*unsafe.Pointer)(p)
- }
- storeFloat32(i, state, p)
- storeFloat32(i, state, unsafe.Pointer(uintptr(p)+unsafe.Sizeof(float32(0))))
+func decComplex64(i *decInstr, state *decoderState, value reflect.Value) {
+ real := float32FromBits(state.decodeUint(), i.ovfl)
+ imag := float32FromBits(state.decodeUint(), i.ovfl)
+ value.SetComplex(complex(real, imag))
}
// decComplex128 decodes a pair of unsigned integers, treats them as a
-// pair of floating point numbers, and stores them as a complex128 through p.
+// pair of floating point numbers, and stores them as a complex128 in value.
// The real part comes first.
-func decComplex128(i *decInstr, state *decoderState, p unsafe.Pointer) {
- if i.indir > 0 {
- if *(*unsafe.Pointer)(p) == nil {
- *(*unsafe.Pointer)(p) = unsafe.Pointer(new(complex128))
- }
- p = *(*unsafe.Pointer)(p)
- }
- real := floatFromBits(uint64(state.decodeUint()))
- imag := floatFromBits(uint64(state.decodeUint()))
- *(*complex128)(p) = complex(real, imag)
+func decComplex128(i *decInstr, state *decoderState, value reflect.Value) {
+ real := float64FromBits(state.decodeUint())
+ imag := float64FromBits(state.decodeUint())
+ value.SetComplex(complex(real, imag))
}
-// decUint8Slice decodes a byte slice and stores through p a slice header
+// decUint8Slice decodes a byte slice and stores in value a slice header
// describing the data.
// uint8 slices are encoded as an unsigned count followed by the raw bytes.
-func decUint8Slice(i *decInstr, state *decoderState, p unsafe.Pointer) {
- if i.indir > 0 {
- if *(*unsafe.Pointer)(p) == nil {
- *(*unsafe.Pointer)(p) = unsafe.Pointer(new([]uint8))
- }
- p = *(*unsafe.Pointer)(p)
+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)
}
- n := state.decodeUint()
- if n > uint64(state.b.Len()) {
- errorf("length of []byte exceeds input size (%d bytes)", n)
+ if n > state.b.Len() {
+ errorf("%s data too long for buffer: %d", value.Type(), n)
}
- slice := (*[]uint8)(p)
- if uint64(cap(*slice)) < n {
- *slice = make([]uint8, n)
+ if n > tooBig {
+ errorf("byte slice too big: %d", n)
+ }
+ if value.Cap() < n {
+ value.Set(reflect.MakeSlice(value.Type(), n, n))
} else {
- *slice = (*slice)[0:n]
+ value.Set(value.Slice(0, n))
}
- if _, err := state.b.Read(*slice); err != nil {
+ if _, err := state.b.Read(value.Bytes()); err != nil {
errorf("error decoding []byte: %s", err)
}
}
-// decString decodes byte array and stores through p a string header
+// decString decodes byte array and stores in value a string header
// describing the data.
// Strings are encoded as an unsigned count followed by the raw bytes.
-func decString(i *decInstr, state *decoderState, p unsafe.Pointer) {
- if i.indir > 0 {
- if *(*unsafe.Pointer)(p) == nil {
- *(*unsafe.Pointer)(p) = unsafe.Pointer(new(string))
- }
- p = *(*unsafe.Pointer)(p)
+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)
}
- n := state.decodeUint()
- if n > uint64(state.b.Len()) {
- errorf("string length exceeds input size (%d bytes)", n)
+ if n > state.b.Len() {
+ errorf("%s data too long for buffer: %d", value.Type(), n)
}
- b := make([]byte, n)
- state.b.Read(b)
- // It would be a shame to do the obvious thing here,
- // *(*string)(p) = string(b)
- // because we've already allocated the storage and this would
- // allocate again and copy. So we do this ugly hack, which is even
- // even more unsafe than it looks as it depends the memory
- // representation of a string matching the beginning of the memory
- // representation of a byte slice (a byte slice is longer).
- *(*string)(p) = *(*string)(unsafe.Pointer(&b))
+ // Read the data.
+ data := make([]byte, n)
+ if _, err := state.b.Read(data); err != nil {
+ errorf("error decoding string: %s", err)
+ }
+ value.SetString(string(data))
}
// ignoreUint8Array skips over the data for a byte slice value with no destination.
-func ignoreUint8Array(i *decInstr, state *decoderState, p unsafe.Pointer) {
+func ignoreUint8Array(i *decInstr, state *decoderState, value reflect.Value) {
b := make([]byte, state.decodeUint())
state.b.Read(b)
}
@@ -449,55 +419,29 @@ type decEngine struct {
numInstr int // the number of active instructions
}
-// allocate makes sure storage is available for an object of underlying type rtyp
-// that is indir levels of indirection through p.
-func allocate(rtyp reflect.Type, p unsafe.Pointer, indir int) unsafe.Pointer {
- if indir == 0 {
- return p
- }
- up := p
- if indir > 1 {
- up = decIndirect(up, indir)
- }
- if *(*unsafe.Pointer)(up) == nil {
- // Allocate object.
- *(*unsafe.Pointer)(up) = unsafe.Pointer(reflect.New(rtyp).Pointer())
- }
- return *(*unsafe.Pointer)(up)
-}
-
-// decodeSingle decodes a top-level value that is not a struct and stores it through p.
+// decodeSingle decodes a top-level value that is not a struct and stores it in value.
// Such values are preceded by a zero, making them have the memory layout of a
// struct field (although with an illegal field number).
-func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, basep unsafe.Pointer) {
+func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, value reflect.Value) {
state := dec.newDecoderState(&dec.buf)
+ defer dec.freeDecoderState(state)
state.fieldnum = singletonField
- delta := int(state.decodeUint())
- if delta != 0 {
+ if state.decodeUint() != 0 {
errorf("decode: corrupted data: non-zero delta for singleton")
}
instr := &engine.instr[singletonField]
- if instr.indir != ut.indir {
- errorf("internal error: inconsistent indirection instr %d ut %d", instr.indir, ut.indir)
- }
- ptr := basep // offset will be zero
- if instr.indir > 1 {
- ptr = decIndirect(ptr, instr.indir)
- }
- instr.op(instr, state, ptr)
- dec.freeDecoderState(state)
+ instr.op(instr, state, value)
}
-// decodeStruct decodes a top-level struct and stores it through p.
+// decodeStruct decodes a top-level struct and stores it in value.
// Indir is for the value, not the type. At the time of the call it may
// differ from ut.indir, which was computed when the engine was built.
// This state cannot arise for decodeSingle, which is called directly
// from the user's value, not from the innards of an engine.
-func (dec *Decoder) decodeStruct(engine *decEngine, ut *userTypeInfo, p unsafe.Pointer, indir int) {
- p = allocate(ut.base, p, indir)
+func (dec *Decoder) decodeStruct(engine *decEngine, ut *userTypeInfo, value reflect.Value) {
state := dec.newDecoderState(&dec.buf)
+ defer dec.freeDecoderState(state)
state.fieldnum = -1
- basep := p
for state.b.Len() > 0 {
delta := int(state.decodeUint())
if delta < 0 {
@@ -512,19 +456,25 @@ func (dec *Decoder) decodeStruct(engine *decEngine, ut *userTypeInfo, p unsafe.P
break
}
instr := &engine.instr[fieldnum]
- p := unsafe.Pointer(uintptr(basep) + instr.offset)
- if instr.indir > 1 {
- p = decIndirect(p, instr.indir)
+ var field reflect.Value
+ if instr.index != nil {
+ // Otherwise the field is unknown to us and instr.op is an ignore op.
+ field = value.FieldByIndex(instr.index)
+ if field.Kind() == reflect.Ptr {
+ field = decAlloc(field)
+ }
}
- instr.op(instr, state, p)
+ instr.op(instr, state, field)
state.fieldnum = fieldnum
}
- dec.freeDecoderState(state)
}
+var noValue reflect.Value
+
// ignoreStruct discards the data for a struct with no destination.
func (dec *Decoder) ignoreStruct(engine *decEngine) {
state := dec.newDecoderState(&dec.buf)
+ defer dec.freeDecoderState(state)
state.fieldnum = -1
for state.b.Len() > 0 {
delta := int(state.decodeUint())
@@ -539,97 +489,89 @@ func (dec *Decoder) ignoreStruct(engine *decEngine) {
error_(errRange)
}
instr := &engine.instr[fieldnum]
- instr.op(instr, state, unsafe.Pointer(nil))
+ instr.op(instr, state, noValue)
state.fieldnum = fieldnum
}
- dec.freeDecoderState(state)
}
// ignoreSingle discards the data for a top-level non-struct value with no
// destination. It's used when calling Decode with a nil value.
func (dec *Decoder) ignoreSingle(engine *decEngine) {
state := dec.newDecoderState(&dec.buf)
+ defer dec.freeDecoderState(state)
state.fieldnum = singletonField
delta := int(state.decodeUint())
if delta != 0 {
errorf("decode: corrupted data: non-zero delta for singleton")
}
instr := &engine.instr[singletonField]
- instr.op(instr, state, unsafe.Pointer(nil))
- dec.freeDecoderState(state)
+ instr.op(instr, state, noValue)
}
// decodeArrayHelper does the work for decoding arrays and slices.
-func (dec *Decoder) decodeArrayHelper(state *decoderState, p unsafe.Pointer, elemOp decOp, elemWid uintptr, length, elemIndir int, ovfl error) {
- instr := &decInstr{elemOp, 0, elemIndir, 0, ovfl}
+func (dec *Decoder) decodeArrayHelper(state *decoderState, value reflect.Value, elemOp decOp, length int, ovfl error, helper decHelper) {
+ if helper != nil && helper(state, value, length, ovfl) {
+ return
+ }
+ instr := &decInstr{elemOp, 0, nil, ovfl}
+ isPtr := value.Type().Elem().Kind() == reflect.Ptr
for i := 0; i < length; i++ {
if state.b.Len() == 0 {
errorf("decoding array or slice: length exceeds input size (%d elements)", length)
}
- up := p
- if elemIndir > 1 {
- up = decIndirect(up, elemIndir)
+ v := value.Index(i)
+ if isPtr {
+ v = decAlloc(v)
}
- elemOp(instr, state, up)
- p = unsafe.Pointer(uintptr(p) + elemWid)
+ elemOp(instr, state, v)
}
}
-// decodeArray decodes an array and stores it through p, that is, p points to the zeroth element.
+// decodeArray decodes an array and stores it in value.
// The length is an unsigned integer preceding the elements. Even though the length is redundant
// (it's part of the type), it's a useful check and is included in the encoding.
-func (dec *Decoder) decodeArray(atyp reflect.Type, state *decoderState, p unsafe.Pointer, elemOp decOp, elemWid uintptr, length, indir, elemIndir int, ovfl error) {
- if indir > 0 {
- p = allocate(atyp, p, 1) // All but the last level has been allocated by dec.Indirect
- }
+func (dec *Decoder) decodeArray(atyp reflect.Type, state *decoderState, value reflect.Value, elemOp decOp, length int, ovfl error, helper decHelper) {
if n := state.decodeUint(); n != uint64(length) {
errorf("length mismatch in decodeArray")
}
- dec.decodeArrayHelper(state, p, elemOp, elemWid, length, elemIndir, ovfl)
+ dec.decodeArrayHelper(state, value, elemOp, length, ovfl, helper)
}
-// decodeIntoValue is a helper for map decoding. Since maps are decoded using reflection,
-// unlike the other items we can't use a pointer directly.
-func decodeIntoValue(state *decoderState, op decOp, indir int, v reflect.Value, ovfl error) reflect.Value {
- instr := &decInstr{op, 0, indir, 0, ovfl}
- up := unsafeAddr(v)
- if indir > 1 {
- up = decIndirect(up, indir)
+// decodeIntoValue is a helper for map decoding.
+func decodeIntoValue(state *decoderState, op decOp, isPtr bool, value reflect.Value, ovfl error) reflect.Value {
+ instr := &decInstr{op, 0, nil, ovfl}
+ v := value
+ if isPtr {
+ v = decAlloc(value)
}
- op(instr, state, up)
- return v
+ op(instr, state, v)
+ return value
}
-// decodeMap decodes a map and stores its header through p.
+// decodeMap decodes a map and stores it in value.
// Maps are encoded as a length followed by key:value pairs.
// Because the internals of maps are not visible to us, we must
// use reflection rather than pointer magic.
-func (dec *Decoder) decodeMap(mtyp reflect.Type, state *decoderState, p unsafe.Pointer, keyOp, elemOp decOp, indir, keyIndir, elemIndir int, ovfl error) {
- if indir > 0 {
- p = allocate(mtyp, p, 1) // All but the last level has been allocated by dec.Indirect
- }
- up := unsafe.Pointer(p)
- if *(*unsafe.Pointer)(up) == nil { // maps are represented as a pointer in the runtime
+func (dec *Decoder) decodeMap(mtyp reflect.Type, state *decoderState, value reflect.Value, keyOp, elemOp decOp, ovfl error) {
+ if value.IsNil() {
// Allocate map.
- *(*unsafe.Pointer)(up) = unsafe.Pointer(reflect.MakeMap(mtyp).Pointer())
+ value.Set(reflect.MakeMap(mtyp))
}
- // Maps cannot be accessed by moving addresses around the way
- // that slices etc. can. We must recover a full reflection value for
- // the iteration.
- v := reflect.NewAt(mtyp, unsafe.Pointer(p)).Elem()
n := int(state.decodeUint())
+ keyIsPtr := mtyp.Key().Kind() == reflect.Ptr
+ elemIsPtr := mtyp.Elem().Kind() == reflect.Ptr
for i := 0; i < n; i++ {
- key := decodeIntoValue(state, keyOp, keyIndir, allocValue(mtyp.Key()), ovfl)
- elem := decodeIntoValue(state, elemOp, elemIndir, allocValue(mtyp.Elem()), ovfl)
- v.SetMapIndex(key, elem)
+ key := decodeIntoValue(state, keyOp, keyIsPtr, allocValue(mtyp.Key()), ovfl)
+ elem := decodeIntoValue(state, elemOp, elemIsPtr, allocValue(mtyp.Elem()), ovfl)
+ value.SetMapIndex(key, elem)
}
}
// ignoreArrayHelper does the work for discarding arrays and slices.
func (dec *Decoder) ignoreArrayHelper(state *decoderState, elemOp decOp, length int) {
- instr := &decInstr{elemOp, 0, 0, 0, errors.New("no error")}
+ instr := &decInstr{elemOp, 0, nil, errors.New("no error")}
for i := 0; i < length; i++ {
- elemOp(instr, state, nil)
+ elemOp(instr, state, noValue)
}
}
@@ -644,37 +586,34 @@ func (dec *Decoder) ignoreArray(state *decoderState, elemOp decOp, length int) {
// ignoreMap discards the data for a map value with no destination.
func (dec *Decoder) ignoreMap(state *decoderState, keyOp, elemOp decOp) {
n := int(state.decodeUint())
- keyInstr := &decInstr{keyOp, 0, 0, 0, errors.New("no error")}
- elemInstr := &decInstr{elemOp, 0, 0, 0, errors.New("no error")}
+ keyInstr := &decInstr{keyOp, 0, nil, errors.New("no error")}
+ elemInstr := &decInstr{elemOp, 0, nil, errors.New("no error")}
for i := 0; i < n; i++ {
- keyOp(keyInstr, state, nil)
- elemOp(elemInstr, state, nil)
+ keyOp(keyInstr, state, noValue)
+ elemOp(elemInstr, state, noValue)
}
}
-// decodeSlice decodes a slice and stores the slice header through p.
+// decodeSlice decodes a slice and stores it in value.
// Slices are encoded as an unsigned length followed by the elements.
-func (dec *Decoder) decodeSlice(atyp reflect.Type, state *decoderState, p uintptr, elemOp decOp, elemWid uintptr, indir, elemIndir int, ovfl error) {
- nr := state.decodeUint()
- n := int(nr)
- if indir > 0 {
- up := unsafe.Pointer(p)
- if *(*unsafe.Pointer)(up) == nil {
- // Allocate the slice header.
- *(*unsafe.Pointer)(up) = unsafe.Pointer(new([]unsafe.Pointer))
- }
- p = *(*uintptr)(up)
- }
- // Allocate storage for the slice elements, that is, the underlying array,
- // if the existing slice does not have the capacity.
- // Always write a header at p.
- hdrp := (*reflect.SliceHeader)(unsafe.Pointer(p))
- if hdrp.Cap < n {
- hdrp.Data = reflect.MakeSlice(atyp, n, n).Pointer()
- hdrp.Cap = n
+func (dec *Decoder) decodeSlice(state *decoderState, value reflect.Value, elemOp decOp, ovfl error, helper decHelper) {
+ u := state.decodeUint()
+ typ := value.Type()
+ size := uint64(typ.Elem().Size())
+ nBytes := u * size
+ n := int(u)
+ // Take care with overflow in this calculation.
+ if n < 0 || uint64(n) != u || nBytes > tooBig || (size > 0 && nBytes/size != u) {
+ // We don't check n against buffer length here because if it's a slice
+ // of interfaces, there will be buffer reloads.
+ errorf("%s slice too big: %d elements of %d bytes", typ.Elem(), u, size)
+ }
+ if value.Cap() < n {
+ value.Set(reflect.MakeSlice(typ, n, n))
+ } else {
+ value.Set(value.Slice(0, n))
}
- hdrp.Len = n
- dec.decodeArrayHelper(state, unsafe.Pointer(hdrp.Data), elemOp, elemWid, n, elemIndir, ovfl)
+ dec.decodeArrayHelper(state, value, elemOp, n, ovfl, helper)
}
// ignoreSlice skips over the data for a slice value with no destination.
@@ -682,36 +621,25 @@ func (dec *Decoder) ignoreSlice(state *decoderState, elemOp decOp) {
dec.ignoreArrayHelper(state, elemOp, int(state.decodeUint()))
}
-// setInterfaceValue sets an interface value to a concrete value,
-// but first it checks that the assignment will succeed.
-func setInterfaceValue(ivalue reflect.Value, value reflect.Value) {
- if !value.Type().AssignableTo(ivalue.Type()) {
- errorf("cannot assign value of type %s to %s", value.Type(), ivalue.Type())
- }
- ivalue.Set(value)
-}
-
-// decodeInterface decodes an interface value and stores it through p.
+// decodeInterface decodes an interface value and stores it in value.
// Interfaces are encoded as the name of a concrete type followed by a value.
// If the name is empty, the value is nil and no value is sent.
-func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, p unsafe.Pointer, indir int) {
- // Create a writable interface reflect.Value. We need one even for the nil case.
- ivalue := allocValue(ityp)
+func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, value reflect.Value) {
// Read the name of the concrete type.
nr := state.decodeUint()
if nr < 0 || nr > 1<<31 { // zero is permissible for anonymous types
errorf("invalid type name length %d", nr)
}
+ if nr > uint64(state.b.Len()) {
+ errorf("invalid type name length %d: exceeds input size", nr)
+ }
b := make([]byte, nr)
state.b.Read(b)
name := string(b)
+ // Allocate the destination interface value.
if name == "" {
- // Copy the representation of the nil interface value to the target.
- // This is horribly unsafe and special.
- if indir > 0 {
- p = allocate(ityp, p, 1) // All but the last level has been allocated by dec.Indirect
- }
- *(*[2]uintptr)(unsafe.Pointer(p)) = ivalue.InterfaceData()
+ // Copy the nil interface value to the target.
+ value.Set(reflect.Zero(value.Type()))
return
}
if len(name) > 1024 {
@@ -733,21 +661,18 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, p un
// in case we want to ignore the value by skipping it completely).
state.decodeUint()
// Read the concrete value.
- value := allocValue(typ)
- dec.decodeValue(concreteId, value)
+ v := allocValue(typ)
+ dec.decodeValue(concreteId, v)
if dec.err != nil {
error_(dec.err)
}
- // Allocate the destination interface value.
- if indir > 0 {
- p = allocate(ityp, p, 1) // All but the last level has been allocated by dec.Indirect
- }
// Assign the concrete value to the interface.
// Tread carefully; it might not satisfy the interface.
- setInterfaceValue(ivalue, value)
- // Copy the representation of the interface value to the target.
- // This is horribly unsafe and special.
- *(*[2]uintptr)(unsafe.Pointer(p)) = ivalue.InterfaceData()
+ if !typ.AssignableTo(ityp) {
+ errorf("%s is not assignable to type %s", typ, ityp)
+ }
+ // Copy the interface value to the target.
+ value.Set(v)
}
// ignoreInterface discards the data for an interface value with no destination.
@@ -763,12 +688,12 @@ func (dec *Decoder) ignoreInterface(state *decoderState) {
error_(dec.err)
}
// At this point, the decoder buffer contains a delimited value. Just toss it.
- state.b.Next(int(state.decodeUint()))
+ state.b.Drop(int(state.decodeUint()))
}
// decodeGobDecoder decodes something implementing the GobDecoder interface.
// The data is encoded as a byte slice.
-func (dec *Decoder) decodeGobDecoder(ut *userTypeInfo, state *decoderState, v reflect.Value) {
+func (dec *Decoder) decodeGobDecoder(ut *userTypeInfo, state *decoderState, value reflect.Value) {
// Read the bytes for the value.
b := make([]byte, state.decodeUint())
_, err := state.b.Read(b)
@@ -778,11 +703,11 @@ func (dec *Decoder) decodeGobDecoder(ut *userTypeInfo, state *decoderState, v re
// We know it's one of these.
switch ut.externalDec {
case xGob:
- err = v.Interface().(GobDecoder).GobDecode(b)
+ err = value.Interface().(GobDecoder).GobDecode(b)
case xBinary:
- err = v.Interface().(encoding.BinaryUnmarshaler).UnmarshalBinary(b)
+ err = value.Interface().(encoding.BinaryUnmarshaler).UnmarshalBinary(b)
case xText:
- err = v.Interface().(encoding.TextUnmarshaler).UnmarshalText(b)
+ err = value.Interface().(encoding.TextUnmarshaler).UnmarshalText(b)
}
if err != nil {
error_(err)
@@ -830,7 +755,7 @@ var decIgnoreOpMap = map[typeId]decOp{
// decOpFor returns the decoding op for the base type under rt and
// the indirection count to reach it.
-func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProgress map[reflect.Type]*decOp) (*decOp, int) {
+func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProgress map[reflect.Type]*decOp) *decOp {
ut := userType(rt)
// If the type implements GobEncoder, we handle it without further processing.
if ut.externalDec != 0 {
@@ -840,10 +765,9 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg
// 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[rt]; opPtr != nil {
- return opPtr, ut.indir
+ return opPtr
}
typ := ut.base
- indir := ut.indir
var op decOp
k := typ.Kind()
if int(k) < len(decOpTable) {
@@ -856,20 +780,21 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg
case reflect.Array:
name = "element of " + name
elemId := dec.wireType[wireId].ArrayT.Elem
- elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), name, inProgress)
+ elemOp := dec.decOpFor(elemId, t.Elem(), name, inProgress)
ovfl := overflow(name)
- op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
- state.dec.decodeArray(t, state, p, *elemOp, t.Elem().Size(), t.Len(), i.indir, elemIndir, ovfl)
+ helper := decArrayHelper[t.Elem().Kind()]
+ op = func(i *decInstr, state *decoderState, value reflect.Value) {
+ state.dec.decodeArray(t, state, value, *elemOp, t.Len(), ovfl, helper)
}
case reflect.Map:
keyId := dec.wireType[wireId].MapT.Key
elemId := dec.wireType[wireId].MapT.Elem
- keyOp, keyIndir := dec.decOpFor(keyId, t.Key(), "key of "+name, inProgress)
- elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), "element of "+name, inProgress)
+ keyOp := dec.decOpFor(keyId, t.Key(), "key of "+name, inProgress)
+ elemOp := dec.decOpFor(elemId, t.Elem(), "element of "+name, inProgress)
ovfl := overflow(name)
- op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
- state.dec.decodeMap(t, state, p, *keyOp, *elemOp, i.indir, keyIndir, elemIndir, ovfl)
+ op = func(i *decInstr, state *decoderState, value reflect.Value) {
+ state.dec.decodeMap(t, state, value, *keyOp, *elemOp, ovfl)
}
case reflect.Slice:
@@ -884,32 +809,34 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg
} else {
elemId = dec.wireType[wireId].SliceT.Elem
}
- elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), name, inProgress)
+ elemOp := dec.decOpFor(elemId, t.Elem(), name, inProgress)
ovfl := overflow(name)
- op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
- state.dec.decodeSlice(t, state, uintptr(p), *elemOp, t.Elem().Size(), i.indir, elemIndir, ovfl)
+ helper := decSliceHelper[t.Elem().Kind()]
+ op = func(i *decInstr, state *decoderState, value reflect.Value) {
+ state.dec.decodeSlice(state, value, *elemOp, ovfl, helper)
}
case reflect.Struct:
// Generate a closure that calls out to the engine for the nested type.
- enginePtr, err := dec.getDecEnginePtr(wireId, userType(typ))
+ ut := userType(typ)
+ enginePtr, err := dec.getDecEnginePtr(wireId, ut)
if err != nil {
error_(err)
}
- op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ op = func(i *decInstr, state *decoderState, value reflect.Value) {
// indirect through enginePtr to delay evaluation for recursive structs.
- dec.decodeStruct(*enginePtr, userType(typ), p, i.indir)
+ dec.decodeStruct(*enginePtr, ut, value)
}
case reflect.Interface:
- op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
- state.dec.decodeInterface(t, state, p, i.indir)
+ op = func(i *decInstr, state *decoderState, value reflect.Value) {
+ state.dec.decodeInterface(t, state, value)
}
}
}
if op == nil {
errorf("decode can't handle type %s", rt)
}
- return &op, indir
+ return &op
}
// decIgnoreOpFor returns the decoding op for a field that has no destination.
@@ -919,7 +846,7 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp {
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, p unsafe.Pointer) {
+ op = func(i *decInstr, state *decoderState, value reflect.Value) {
state.dec.ignoreInterface(state)
}
return op
@@ -932,7 +859,7 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp {
case wire.ArrayT != nil:
elemId := wire.ArrayT.Elem
elemOp := dec.decIgnoreOpFor(elemId)
- op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ op = func(i *decInstr, state *decoderState, value reflect.Value) {
state.dec.ignoreArray(state, elemOp, wire.ArrayT.Len)
}
@@ -941,14 +868,14 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp {
elemId := dec.wireType[wireId].MapT.Elem
keyOp := dec.decIgnoreOpFor(keyId)
elemOp := dec.decIgnoreOpFor(elemId)
- op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ op = func(i *decInstr, state *decoderState, value reflect.Value) {
state.dec.ignoreMap(state, keyOp, elemOp)
}
case wire.SliceT != nil:
elemId := wire.SliceT.Elem
elemOp := dec.decIgnoreOpFor(elemId)
- op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ op = func(i *decInstr, state *decoderState, value reflect.Value) {
state.dec.ignoreSlice(state, elemOp)
}
@@ -958,13 +885,13 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp {
if err != nil {
error_(err)
}
- op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ op = func(i *decInstr, state *decoderState, value reflect.Value) {
// indirect through enginePtr to delay evaluation for recursive structs
state.dec.ignoreStruct(*enginePtr)
}
case wire.GobEncoderT != nil, wire.BinaryMarshalerT != nil, wire.TextMarshalerT != nil:
- op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ op = func(i *decInstr, state *decoderState, value reflect.Value) {
state.dec.ignoreGobDecoder(state)
}
}
@@ -977,7 +904,7 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp {
// gobDecodeOpFor returns the op for a type that is known to implement
// GobDecoder.
-func (dec *Decoder) gobDecodeOpFor(ut *userTypeInfo) (*decOp, int) {
+func (dec *Decoder) gobDecodeOpFor(ut *userTypeInfo) *decOp {
rcvrType := ut.user
if ut.decIndir == -1 {
rcvrType = reflect.PtrTo(rcvrType)
@@ -987,25 +914,14 @@ func (dec *Decoder) gobDecodeOpFor(ut *userTypeInfo) (*decOp, int) {
}
}
var op decOp
- op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
- // Caller has gotten us to within one indirection of our value.
- if i.indir > 0 {
- if *(*unsafe.Pointer)(p) == nil {
- *(*unsafe.Pointer)(p) = unsafe.Pointer(reflect.New(ut.base).Pointer())
- }
+ op = func(i *decInstr, state *decoderState, value reflect.Value) {
+ // We now have the base type. We need its address if the receiver is a pointer.
+ if value.Kind() != reflect.Ptr && rcvrType.Kind() == reflect.Ptr {
+ value = value.Addr()
}
- // Now p is a pointer to the base type. Do we need to climb out to
- // get to the receiver type?
- var v reflect.Value
- if ut.decIndir == -1 {
- v = reflect.NewAt(rcvrType, unsafe.Pointer(&p)).Elem()
- } else {
- v = reflect.NewAt(rcvrType, p).Elem()
- }
- state.dec.decodeGobDecoder(ut, state, v)
+ state.dec.decodeGobDecoder(ut, state, value)
}
- return &op, int(ut.indir)
-
+ return &op
}
// compatibleType asks: Are these two gob Types compatible?
@@ -1106,9 +1022,9 @@ func (dec *Decoder) compileSingle(remoteId typeId, ut *userTypeInfo) (engine *de
}
return nil, errors.New("gob: decoding into local type " + name + ", received remote type " + remoteType)
}
- op, indir := dec.decOpFor(remoteId, rt, name, make(map[reflect.Type]*decOp))
+ op := dec.decOpFor(remoteId, rt, name, make(map[reflect.Type]*decOp))
ovfl := errors.New(`value for "` + name + `" out of range`)
- engine.instr[singletonField] = decInstr{*op, singletonField, indir, 0, ovfl}
+ engine.instr[singletonField] = decInstr{*op, singletonField, nil, ovfl}
engine.numInstr = 1
return
}
@@ -1119,7 +1035,7 @@ func (dec *Decoder) compileIgnoreSingle(remoteId typeId) (engine *decEngine, err
engine.instr = make([]decInstr, 1) // one item
op := dec.decIgnoreOpFor(remoteId)
ovfl := overflow(dec.typeString(remoteId))
- engine.instr[0] = decInstr{op, 0, 0, 0, ovfl}
+ engine.instr[0] = decInstr{op, 0, nil, ovfl}
engine.numInstr = 1
return
}
@@ -1162,14 +1078,14 @@ func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEn
// TODO(r): anonymous names
if !present || !isExported(wireField.Name) {
op := dec.decIgnoreOpFor(wireField.Id)
- engine.instr[fieldnum] = decInstr{op, fieldnum, 0, 0, ovfl}
+ engine.instr[fieldnum] = decInstr{op, fieldnum, nil, ovfl}
continue
}
if !dec.compatibleType(localField.Type, wireField.Id, make(map[reflect.Type]typeId)) {
errorf("wrong type (%s) for received field %s.%s", localField.Type, wireStruct.Name, wireField.Name)
}
- op, indir := dec.decOpFor(wireField.Id, localField.Type, localField.Name, seen)
- engine.instr[fieldnum] = decInstr{*op, fieldnum, indir, uintptr(localField.Offset), ovfl}
+ op := dec.decOpFor(wireField.Id, localField.Type, localField.Name, seen)
+ engine.instr[fieldnum] = decInstr{*op, fieldnum, localField.Index, ovfl}
engine.numInstr++
}
return
@@ -1220,31 +1136,33 @@ func (dec *Decoder) getIgnoreEnginePtr(wireId typeId) (enginePtr **decEngine, er
return
}
-// decodeValue decodes the data stream representing a value and stores it in val.
-func (dec *Decoder) decodeValue(wireId typeId, val reflect.Value) {
+// decodeValue decodes the data stream representing a value and stores it in value.
+func (dec *Decoder) decodeValue(wireId typeId, value reflect.Value) {
defer catchError(&dec.err)
// If the value is nil, it means we should just ignore this item.
- if !val.IsValid() {
+ if !value.IsValid() {
dec.decodeIgnoredValue(wireId)
return
}
// Dereference down to the underlying type.
- ut := userType(val.Type())
+ ut := userType(value.Type())
base := ut.base
var enginePtr **decEngine
enginePtr, dec.err = dec.getDecEnginePtr(wireId, ut)
if dec.err != nil {
return
}
+ value = decAlloc(value)
engine := *enginePtr
if st := base; st.Kind() == reflect.Struct && ut.externalDec == 0 {
- if engine.numInstr == 0 && st.NumField() > 0 && len(dec.wireType[wireId].StructT.Field) > 0 {
+ if engine.numInstr == 0 && st.NumField() > 0 &&
+ dec.wireType[wireId] != nil && len(dec.wireType[wireId].StructT.Field) > 0 {
name := base.Name()
errorf("type mismatch: no fields matched compiling decoder for %s", name)
}
- dec.decodeStruct(engine, ut, unsafeAddr(val), ut.indir)
+ dec.decodeStruct(engine, ut, value)
} else {
- dec.decodeSingle(engine, ut, unsafeAddr(val))
+ dec.decodeSingle(engine, ut, value)
}
}
@@ -1290,21 +1208,6 @@ func init() {
decOpTable[reflect.Uintptr] = uop
}
-// Gob assumes it can call UnsafeAddr on any Value
-// in order to get a pointer it can copy data from.
-// Values that have just been created and do not point
-// into existing structs or slices cannot be addressed,
-// so simulate it by returning a pointer to a copy.
-// Each call allocates once.
-func unsafeAddr(v reflect.Value) unsafe.Pointer {
- if v.CanAddr() {
- return unsafe.Pointer(v.UnsafeAddr())
- }
- x := reflect.New(v.Type()).Elem()
- x.Set(v)
- return unsafe.Pointer(x.UnsafeAddr())
-}
-
// Gob depends on being able to take the address
// of zeroed Values it creates, so use this wrapper instead
// of the standard reflect.Zero.
diff --git a/libgo/go/encoding/gob/decoder.go b/libgo/go/encoding/gob/decoder.go
index 04f706ca54..c453e9ba39 100644
--- a/libgo/go/encoding/gob/decoder.go
+++ b/libgo/go/encoding/gob/decoder.go
@@ -6,25 +6,28 @@ package gob
import (
"bufio"
- "bytes"
"errors"
"io"
"reflect"
"sync"
)
+// tooBig provides a sanity check for sizes; used in several places.
+// Upper limit of 1GB, allowing room to grow a little without overflow.
+// TODO: make this adjustable?
+const tooBig = 1 << 30
+
// A Decoder manages the receipt of type and data information read from the
// remote side of a connection.
type Decoder struct {
mutex sync.Mutex // each item must be received atomically
r io.Reader // source of the data
- buf bytes.Buffer // buffer for more efficient i/o from r
+ buf decBuffer // buffer for more efficient i/o from r
wireType map[typeId]*wireType // map from remote ID to local description
decoderCache map[reflect.Type]map[typeId]**decEngine // cache of compiled engines
ignorerCache map[typeId]**decEngine // ditto for ignored objects
freeList *decoderState // list of free decoderStates; avoids reallocation
countBuf []byte // used for decoding integers while parsing messages
- tmp []byte // temporary storage for i/o; saves reallocating
err error
}
@@ -75,9 +78,7 @@ func (dec *Decoder) recvMessage() bool {
dec.err = err
return false
}
- // Upper limit of 1GB, allowing room to grow a little without overflow.
- // TODO: We might want more control over this limit.
- if nbytes >= 1<<30 {
+ if nbytes >= tooBig {
dec.err = errBadCount
return false
}
@@ -87,37 +88,17 @@ func (dec *Decoder) recvMessage() bool {
// readMessage reads the next nbytes bytes from the input.
func (dec *Decoder) readMessage(nbytes int) {
- // Allocate the dec.tmp buffer, up to 10KB.
- const maxBuf = 10 * 1024
- nTmp := nbytes
- if nTmp > maxBuf {
- nTmp = maxBuf
- }
- if cap(dec.tmp) < nTmp {
- nAlloc := nTmp + 100 // A little extra for growth.
- if nAlloc > maxBuf {
- nAlloc = maxBuf
- }
- dec.tmp = make([]byte, nAlloc)
+ if dec.buf.Len() != 0 {
+ // The buffer should always be empty now.
+ panic("non-empty decoder buffer")
}
- dec.tmp = dec.tmp[:nTmp]
-
// Read the data
- dec.buf.Grow(nbytes)
- for nbytes > 0 {
- if nbytes < nTmp {
- dec.tmp = dec.tmp[:nbytes]
- }
- var nRead int
- nRead, dec.err = io.ReadFull(dec.r, dec.tmp)
- if dec.err != nil {
- if dec.err == io.EOF {
- dec.err = io.ErrUnexpectedEOF
- }
- return
+ dec.buf.Size(nbytes)
+ _, dec.err = io.ReadFull(dec.r, dec.buf.Bytes())
+ if dec.err != nil {
+ if dec.err == io.EOF {
+ dec.err = io.ErrUnexpectedEOF
}
- dec.buf.Write(dec.tmp)
- nbytes -= nRead
}
}
@@ -183,11 +164,13 @@ func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId {
return -1
}
-// Decode reads the next value from the connection and stores
+// Decode reads the next value from the input stream and stores
// it in the data represented by the empty interface value.
// If e is nil, the value will be discarded. Otherwise,
// the value underlying e must be a pointer to the
// correct type for the next data item received.
+// If the input is at EOF, Decode returns io.EOF and
+// does not modify e.
func (dec *Decoder) Decode(e interface{}) error {
if e == nil {
return dec.DecodeValue(reflect.Value{})
@@ -202,10 +185,12 @@ func (dec *Decoder) Decode(e interface{}) error {
return dec.DecodeValue(value)
}
-// DecodeValue reads the next value from the connection.
+// DecodeValue reads the next value from the input stream.
// If v is the zero reflect.Value (v.Kind() == Invalid), DecodeValue discards the value.
// Otherwise, it stores the value into v. In that case, v must represent
// a non-nil pointer to data or be an assignable reflect.Value (v.CanSet())
+// If the input is at EOF, DecodeValue returns io.EOF and
+// does not modify v.
func (dec *Decoder) DecodeValue(v reflect.Value) error {
if v.IsValid() {
if v.Kind() == reflect.Ptr && !v.IsNil() {
diff --git a/libgo/go/encoding/gob/enc_helpers.go b/libgo/go/encoding/gob/enc_helpers.go
new file mode 100644
index 0000000000..804e539d84
--- /dev/null
+++ b/libgo/go/encoding/gob/enc_helpers.go
@@ -0,0 +1,414 @@
+// Created by encgen --output enc_helpers.go; DO NOT EDIT
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+ "reflect"
+)
+
+var encArrayHelper = map[reflect.Kind]encHelper{
+ reflect.Bool: encBoolArray,
+ reflect.Complex64: encComplex64Array,
+ reflect.Complex128: encComplex128Array,
+ reflect.Float32: encFloat32Array,
+ reflect.Float64: encFloat64Array,
+ reflect.Int: encIntArray,
+ reflect.Int16: encInt16Array,
+ reflect.Int32: encInt32Array,
+ reflect.Int64: encInt64Array,
+ reflect.Int8: encInt8Array,
+ reflect.String: encStringArray,
+ reflect.Uint: encUintArray,
+ reflect.Uint16: encUint16Array,
+ reflect.Uint32: encUint32Array,
+ reflect.Uint64: encUint64Array,
+ reflect.Uintptr: encUintptrArray,
+}
+
+var encSliceHelper = map[reflect.Kind]encHelper{
+ reflect.Bool: encBoolSlice,
+ reflect.Complex64: encComplex64Slice,
+ reflect.Complex128: encComplex128Slice,
+ reflect.Float32: encFloat32Slice,
+ reflect.Float64: encFloat64Slice,
+ reflect.Int: encIntSlice,
+ reflect.Int16: encInt16Slice,
+ reflect.Int32: encInt32Slice,
+ reflect.Int64: encInt64Slice,
+ reflect.Int8: encInt8Slice,
+ reflect.String: encStringSlice,
+ reflect.Uint: encUintSlice,
+ reflect.Uint16: encUint16Slice,
+ reflect.Uint32: encUint32Slice,
+ reflect.Uint64: encUint64Slice,
+ reflect.Uintptr: encUintptrSlice,
+}
+
+func encBoolArray(state *encoderState, v reflect.Value) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return encBoolSlice(state, v.Slice(0, v.Len()))
+}
+
+func encBoolSlice(state *encoderState, v reflect.Value) bool {
+ slice, ok := v.Interface().([]bool)
+ if !ok {
+ // It is kind bool but not type bool. TODO: We can handle this unsafely.
+ return false
+ }
+ for _, x := range slice {
+ if x != false || state.sendZero {
+ if x {
+ state.encodeUint(1)
+ } else {
+ state.encodeUint(0)
+ }
+ }
+ }
+ return true
+}
+
+func encComplex64Array(state *encoderState, v reflect.Value) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return encComplex64Slice(state, v.Slice(0, v.Len()))
+}
+
+func encComplex64Slice(state *encoderState, v reflect.Value) bool {
+ slice, ok := v.Interface().([]complex64)
+ if !ok {
+ // It is kind complex64 but not type complex64. TODO: We can handle this unsafely.
+ return false
+ }
+ for _, x := range slice {
+ if x != 0+0i || state.sendZero {
+ rpart := floatBits(float64(real(x)))
+ ipart := floatBits(float64(imag(x)))
+ state.encodeUint(rpart)
+ state.encodeUint(ipart)
+ }
+ }
+ return true
+}
+
+func encComplex128Array(state *encoderState, v reflect.Value) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return encComplex128Slice(state, v.Slice(0, v.Len()))
+}
+
+func encComplex128Slice(state *encoderState, v reflect.Value) bool {
+ slice, ok := v.Interface().([]complex128)
+ if !ok {
+ // It is kind complex128 but not type complex128. TODO: We can handle this unsafely.
+ return false
+ }
+ for _, x := range slice {
+ if x != 0+0i || state.sendZero {
+ rpart := floatBits(real(x))
+ ipart := floatBits(imag(x))
+ state.encodeUint(rpart)
+ state.encodeUint(ipart)
+ }
+ }
+ return true
+}
+
+func encFloat32Array(state *encoderState, v reflect.Value) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return encFloat32Slice(state, v.Slice(0, v.Len()))
+}
+
+func encFloat32Slice(state *encoderState, v reflect.Value) bool {
+ slice, ok := v.Interface().([]float32)
+ if !ok {
+ // It is kind float32 but not type float32. TODO: We can handle this unsafely.
+ return false
+ }
+ for _, x := range slice {
+ if x != 0 || state.sendZero {
+ bits := floatBits(float64(x))
+ state.encodeUint(bits)
+ }
+ }
+ return true
+}
+
+func encFloat64Array(state *encoderState, v reflect.Value) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return encFloat64Slice(state, v.Slice(0, v.Len()))
+}
+
+func encFloat64Slice(state *encoderState, v reflect.Value) bool {
+ slice, ok := v.Interface().([]float64)
+ if !ok {
+ // It is kind float64 but not type float64. TODO: We can handle this unsafely.
+ return false
+ }
+ for _, x := range slice {
+ if x != 0 || state.sendZero {
+ bits := floatBits(x)
+ state.encodeUint(bits)
+ }
+ }
+ return true
+}
+
+func encIntArray(state *encoderState, v reflect.Value) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return encIntSlice(state, v.Slice(0, v.Len()))
+}
+
+func encIntSlice(state *encoderState, v reflect.Value) bool {
+ slice, ok := v.Interface().([]int)
+ if !ok {
+ // It is kind int but not type int. TODO: We can handle this unsafely.
+ return false
+ }
+ for _, x := range slice {
+ if x != 0 || state.sendZero {
+ state.encodeInt(int64(x))
+ }
+ }
+ return true
+}
+
+func encInt16Array(state *encoderState, v reflect.Value) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return encInt16Slice(state, v.Slice(0, v.Len()))
+}
+
+func encInt16Slice(state *encoderState, v reflect.Value) bool {
+ slice, ok := v.Interface().([]int16)
+ if !ok {
+ // It is kind int16 but not type int16. TODO: We can handle this unsafely.
+ return false
+ }
+ for _, x := range slice {
+ if x != 0 || state.sendZero {
+ state.encodeInt(int64(x))
+ }
+ }
+ return true
+}
+
+func encInt32Array(state *encoderState, v reflect.Value) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return encInt32Slice(state, v.Slice(0, v.Len()))
+}
+
+func encInt32Slice(state *encoderState, v reflect.Value) bool {
+ slice, ok := v.Interface().([]int32)
+ if !ok {
+ // It is kind int32 but not type int32. TODO: We can handle this unsafely.
+ return false
+ }
+ for _, x := range slice {
+ if x != 0 || state.sendZero {
+ state.encodeInt(int64(x))
+ }
+ }
+ return true
+}
+
+func encInt64Array(state *encoderState, v reflect.Value) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return encInt64Slice(state, v.Slice(0, v.Len()))
+}
+
+func encInt64Slice(state *encoderState, v reflect.Value) bool {
+ slice, ok := v.Interface().([]int64)
+ if !ok {
+ // It is kind int64 but not type int64. TODO: We can handle this unsafely.
+ return false
+ }
+ for _, x := range slice {
+ if x != 0 || state.sendZero {
+ state.encodeInt(x)
+ }
+ }
+ return true
+}
+
+func encInt8Array(state *encoderState, v reflect.Value) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return encInt8Slice(state, v.Slice(0, v.Len()))
+}
+
+func encInt8Slice(state *encoderState, v reflect.Value) bool {
+ slice, ok := v.Interface().([]int8)
+ if !ok {
+ // It is kind int8 but not type int8. TODO: We can handle this unsafely.
+ return false
+ }
+ for _, x := range slice {
+ if x != 0 || state.sendZero {
+ state.encodeInt(int64(x))
+ }
+ }
+ return true
+}
+
+func encStringArray(state *encoderState, v reflect.Value) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return encStringSlice(state, v.Slice(0, v.Len()))
+}
+
+func encStringSlice(state *encoderState, v reflect.Value) bool {
+ slice, ok := v.Interface().([]string)
+ if !ok {
+ // It is kind string but not type string. TODO: We can handle this unsafely.
+ return false
+ }
+ for _, x := range slice {
+ if x != "" || state.sendZero {
+ state.encodeUint(uint64(len(x)))
+ state.b.WriteString(x)
+ }
+ }
+ return true
+}
+
+func encUintArray(state *encoderState, v reflect.Value) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return encUintSlice(state, v.Slice(0, v.Len()))
+}
+
+func encUintSlice(state *encoderState, v reflect.Value) bool {
+ slice, ok := v.Interface().([]uint)
+ if !ok {
+ // It is kind uint but not type uint. TODO: We can handle this unsafely.
+ return false
+ }
+ for _, x := range slice {
+ if x != 0 || state.sendZero {
+ state.encodeUint(uint64(x))
+ }
+ }
+ return true
+}
+
+func encUint16Array(state *encoderState, v reflect.Value) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return encUint16Slice(state, v.Slice(0, v.Len()))
+}
+
+func encUint16Slice(state *encoderState, v reflect.Value) bool {
+ slice, ok := v.Interface().([]uint16)
+ if !ok {
+ // It is kind uint16 but not type uint16. TODO: We can handle this unsafely.
+ return false
+ }
+ for _, x := range slice {
+ if x != 0 || state.sendZero {
+ state.encodeUint(uint64(x))
+ }
+ }
+ return true
+}
+
+func encUint32Array(state *encoderState, v reflect.Value) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return encUint32Slice(state, v.Slice(0, v.Len()))
+}
+
+func encUint32Slice(state *encoderState, v reflect.Value) bool {
+ slice, ok := v.Interface().([]uint32)
+ if !ok {
+ // It is kind uint32 but not type uint32. TODO: We can handle this unsafely.
+ return false
+ }
+ for _, x := range slice {
+ if x != 0 || state.sendZero {
+ state.encodeUint(uint64(x))
+ }
+ }
+ return true
+}
+
+func encUint64Array(state *encoderState, v reflect.Value) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return encUint64Slice(state, v.Slice(0, v.Len()))
+}
+
+func encUint64Slice(state *encoderState, v reflect.Value) bool {
+ slice, ok := v.Interface().([]uint64)
+ if !ok {
+ // It is kind uint64 but not type uint64. TODO: We can handle this unsafely.
+ return false
+ }
+ for _, x := range slice {
+ if x != 0 || state.sendZero {
+ state.encodeUint(x)
+ }
+ }
+ return true
+}
+
+func encUintptrArray(state *encoderState, v reflect.Value) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return encUintptrSlice(state, v.Slice(0, v.Len()))
+}
+
+func encUintptrSlice(state *encoderState, v reflect.Value) bool {
+ slice, ok := v.Interface().([]uintptr)
+ if !ok {
+ // It is kind uintptr but not type uintptr. TODO: We can handle this unsafely.
+ return false
+ }
+ for _, x := range slice {
+ if x != 0 || state.sendZero {
+ state.encodeUint(uint64(x))
+ }
+ }
+ return true
+}
diff --git a/libgo/go/encoding/gob/encgen.go b/libgo/go/encoding/gob/encgen.go
new file mode 100644
index 0000000000..efdd928292
--- /dev/null
+++ b/libgo/go/encoding/gob/encgen.go
@@ -0,0 +1,218 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+// encgen writes the helper functions for encoding. Intended to be
+// used with go generate; see the invocation in encode.go.
+
+// TODO: We could do more by being unsafe. Add a -unsafe flag?
+
+package main
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "go/format"
+ "log"
+ "os"
+)
+
+var output = flag.String("output", "enc_helpers.go", "file name to write")
+
+type Type struct {
+ lower string
+ upper string
+ zero string
+ encoder string
+}
+
+var types = []Type{
+ {
+ "bool",
+ "Bool",
+ "false",
+ `if x {
+ state.encodeUint(1)
+ } else {
+ state.encodeUint(0)
+ }`,
+ },
+ {
+ "complex64",
+ "Complex64",
+ "0+0i",
+ `rpart := floatBits(float64(real(x)))
+ ipart := floatBits(float64(imag(x)))
+ state.encodeUint(rpart)
+ state.encodeUint(ipart)`,
+ },
+ {
+ "complex128",
+ "Complex128",
+ "0+0i",
+ `rpart := floatBits(real(x))
+ ipart := floatBits(imag(x))
+ state.encodeUint(rpart)
+ state.encodeUint(ipart)`,
+ },
+ {
+ "float32",
+ "Float32",
+ "0",
+ `bits := floatBits(float64(x))
+ state.encodeUint(bits)`,
+ },
+ {
+ "float64",
+ "Float64",
+ "0",
+ `bits := floatBits(x)
+ state.encodeUint(bits)`,
+ },
+ {
+ "int",
+ "Int",
+ "0",
+ `state.encodeInt(int64(x))`,
+ },
+ {
+ "int16",
+ "Int16",
+ "0",
+ `state.encodeInt(int64(x))`,
+ },
+ {
+ "int32",
+ "Int32",
+ "0",
+ `state.encodeInt(int64(x))`,
+ },
+ {
+ "int64",
+ "Int64",
+ "0",
+ `state.encodeInt(x)`,
+ },
+ {
+ "int8",
+ "Int8",
+ "0",
+ `state.encodeInt(int64(x))`,
+ },
+ {
+ "string",
+ "String",
+ `""`,
+ `state.encodeUint(uint64(len(x)))
+ state.b.WriteString(x)`,
+ },
+ {
+ "uint",
+ "Uint",
+ "0",
+ `state.encodeUint(uint64(x))`,
+ },
+ {
+ "uint16",
+ "Uint16",
+ "0",
+ `state.encodeUint(uint64(x))`,
+ },
+ {
+ "uint32",
+ "Uint32",
+ "0",
+ `state.encodeUint(uint64(x))`,
+ },
+ {
+ "uint64",
+ "Uint64",
+ "0",
+ `state.encodeUint(x)`,
+ },
+ {
+ "uintptr",
+ "Uintptr",
+ "0",
+ `state.encodeUint(uint64(x))`,
+ },
+ // uint8 Handled separately.
+}
+
+func main() {
+ log.SetFlags(0)
+ log.SetPrefix("encgen: ")
+ flag.Parse()
+ if flag.NArg() != 0 {
+ log.Fatal("usage: encgen [--output filename]")
+ }
+ var b bytes.Buffer
+ fmt.Fprintf(&b, "// Created by encgen --output %s; DO NOT EDIT\n", *output)
+ fmt.Fprint(&b, header)
+ printMaps(&b, "Array")
+ fmt.Fprint(&b, "\n")
+ printMaps(&b, "Slice")
+ for _, t := range types {
+ fmt.Fprintf(&b, arrayHelper, t.lower, t.upper)
+ fmt.Fprintf(&b, sliceHelper, t.lower, t.upper, t.zero, t.encoder)
+ }
+ source, err := format.Source(b.Bytes())
+ if err != nil {
+ log.Fatal("source format error:", err)
+ }
+ fd, err := os.Create(*output)
+ _, err = fd.Write(source)
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+func printMaps(b *bytes.Buffer, upperClass string) {
+ fmt.Fprintf(b, "var enc%sHelper = map[reflect.Kind]encHelper{\n", upperClass)
+ for _, t := range types {
+ fmt.Fprintf(b, "reflect.%s: enc%s%s,\n", t.upper, t.upper, upperClass)
+ }
+ fmt.Fprintf(b, "}\n")
+}
+
+const header = `
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+ "reflect"
+)
+
+`
+
+const arrayHelper = `
+func enc%[2]sArray(state *encoderState, v reflect.Value) bool {
+ // Can only slice if it is addressable.
+ if !v.CanAddr() {
+ return false
+ }
+ return enc%[2]sSlice(state, v.Slice(0, v.Len()))
+}
+`
+
+const sliceHelper = `
+func enc%[2]sSlice(state *encoderState, v reflect.Value) bool {
+ slice, ok := v.Interface().([]%[1]s)
+ if !ok {
+ // It is kind %[1]s but not type %[1]s. TODO: We can handle this unsafely.
+ return false
+ }
+ for _, x := range slice {
+ if x != %[3]s || state.sendZero {
+ %[4]s
+ }
+ }
+ return true
+}
+`
diff --git a/libgo/go/encoding/gob/encode.go b/libgo/go/encoding/gob/encode.go
index d158b6442a..f66279f141 100644
--- a/libgo/go/encoding/gob/encode.go
+++ b/libgo/go/encoding/gob/encode.go
@@ -2,17 +2,19 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:generate go run encgen.go -output enc_helpers.go
+
package gob
import (
- "bytes"
"encoding"
"math"
"reflect"
- "unsafe"
)
-const uint64Size = int(unsafe.Sizeof(uint64(0)))
+const uint64Size = 8
+
+type encHelper func(state *encoderState, v reflect.Value) bool
// encoderState is the global execution state of an instance of the encoder.
// Field numbers are delta encoded and always increase. The field
@@ -20,14 +22,46 @@ const uint64Size = int(unsafe.Sizeof(uint64(0)))
// 0 terminates the structure.
type encoderState struct {
enc *Encoder
- b *bytes.Buffer
+ b *encBuffer
sendZero bool // encoding an array element or map key/value pair; send zero values
fieldnum int // the last field number written.
buf [1 + uint64Size]byte // buffer used by the encoder; here to avoid allocation.
next *encoderState // for free list
}
-func (enc *Encoder) newEncoderState(b *bytes.Buffer) *encoderState {
+// encBuffer is an extremely simple, fast implementation of a write-only byte buffer.
+// It never returns a non-nil error, but Write returns an error value so it matches io.Writer.
+type encBuffer struct {
+ data []byte
+ scratch [64]byte
+}
+
+func (e *encBuffer) WriteByte(c byte) {
+ e.data = append(e.data, c)
+}
+
+func (e *encBuffer) Write(p []byte) (int, error) {
+ e.data = append(e.data, p...)
+ return len(p), nil
+}
+
+func (e *encBuffer) WriteString(s string) {
+ e.data = append(e.data, s...)
+}
+
+func (e *encBuffer) Len() int {
+ return len(e.data)
+}
+
+func (e *encBuffer) Bytes() []byte {
+ return e.data
+}
+
+func (e *encBuffer) Reset() {
+ e.data = e.data[0:0]
+}
+
+func (enc *Encoder) newEncoderState(b *encBuffer) *encoderState {
e := enc.freeList
if e == nil {
e = new(encoderState)
@@ -38,6 +72,9 @@ func (enc *Encoder) newEncoderState(b *bytes.Buffer) *encoderState {
e.sendZero = false
e.fieldnum = 0
e.b = b
+ if len(b.data) == 0 {
+ b.data = b.scratch[0:0]
+ }
return e
}
@@ -54,10 +91,7 @@ func (enc *Encoder) freeEncoderState(e *encoderState) {
// encodeUint writes an encoded unsigned integer to state.b.
func (state *encoderState) encodeUint(x uint64) {
if x <= 0x7F {
- err := state.b.WriteByte(uint8(x))
- if err != nil {
- error_(err)
- }
+ state.b.WriteByte(uint8(x))
return
}
i := uint64Size
@@ -67,10 +101,7 @@ func (state *encoderState) encodeUint(x uint64) {
i--
}
state.buf[i] = uint8(i - uint64Size) // = loop count, negated
- _, err := state.b.Write(state.buf[i : uint64Size+1])
- if err != nil {
- error_(err)
- }
+ state.b.Write(state.buf[i : uint64Size+1])
}
// encodeInt writes an encoded signed integer to state.w.
@@ -87,14 +118,14 @@ func (state *encoderState) encodeInt(i int64) {
}
// encOp is the signature of an encoding operator for a given type.
-type encOp func(i *encInstr, state *encoderState, p unsafe.Pointer)
+type encOp func(i *encInstr, state *encoderState, v reflect.Value)
// The 'instructions' of the encoding machine
type encInstr struct {
- op encOp
- field int // field number
- indir int // how many pointer indirections to reach the value in the struct
- offset uintptr // offset in the structure of the field to encode
+ op encOp
+ field int // field number in input
+ index []int // struct index
+ indir int // how many pointer indirections to reach the value in the struct
}
// update emits a field number and updates the state to record its value for delta encoding.
@@ -115,20 +146,20 @@ func (state *encoderState) update(instr *encInstr) {
// encoded integer, followed by the field data in its appropriate
// format.
-// encIndirect dereferences p indir times and returns the result.
-func encIndirect(p unsafe.Pointer, indir int) unsafe.Pointer {
+// encIndirect dereferences pv indir times and returns the result.
+func encIndirect(pv reflect.Value, indir int) reflect.Value {
for ; indir > 0; indir-- {
- p = *(*unsafe.Pointer)(p)
- if p == nil {
- return unsafe.Pointer(nil)
+ if pv.IsNil() {
+ break
}
+ pv = pv.Elem()
}
- return p
+ return pv
}
-// encBool encodes the bool with address p as an unsigned 0 or 1.
-func encBool(i *encInstr, state *encoderState, p unsafe.Pointer) {
- b := *(*bool)(p)
+// encBool encodes the bool referenced by v as an unsigned 0 or 1.
+func encBool(i *encInstr, state *encoderState, v reflect.Value) {
+ b := v.Bool()
if b || state.sendZero {
state.update(i)
if b {
@@ -139,102 +170,21 @@ func encBool(i *encInstr, state *encoderState, p unsafe.Pointer) {
}
}
-// encInt encodes the int with address p.
-func encInt(i *encInstr, state *encoderState, p unsafe.Pointer) {
- v := int64(*(*int)(p))
- if v != 0 || state.sendZero {
- state.update(i)
- state.encodeInt(v)
- }
-}
-
-// encUint encodes the uint with address p.
-func encUint(i *encInstr, state *encoderState, p unsafe.Pointer) {
- v := uint64(*(*uint)(p))
- if v != 0 || state.sendZero {
+// encInt encodes the signed integer (int int8 int16 int32 int64) referenced by v.
+func encInt(i *encInstr, state *encoderState, v reflect.Value) {
+ value := v.Int()
+ if value != 0 || state.sendZero {
state.update(i)
- state.encodeUint(v)
+ state.encodeInt(value)
}
}
-// encInt8 encodes the int8 with address p.
-func encInt8(i *encInstr, state *encoderState, p unsafe.Pointer) {
- v := int64(*(*int8)(p))
- if v != 0 || state.sendZero {
+// encUint encodes the unsigned integer (uint uint8 uint16 uint32 uint64 uintptr) referenced by v.
+func encUint(i *encInstr, state *encoderState, v reflect.Value) {
+ value := v.Uint()
+ if value != 0 || state.sendZero {
state.update(i)
- state.encodeInt(v)
- }
-}
-
-// encUint8 encodes the uint8 with address p.
-func encUint8(i *encInstr, state *encoderState, p unsafe.Pointer) {
- v := uint64(*(*uint8)(p))
- if v != 0 || state.sendZero {
- state.update(i)
- state.encodeUint(v)
- }
-}
-
-// encInt16 encodes the int16 with address p.
-func encInt16(i *encInstr, state *encoderState, p unsafe.Pointer) {
- v := int64(*(*int16)(p))
- if v != 0 || state.sendZero {
- state.update(i)
- state.encodeInt(v)
- }
-}
-
-// encUint16 encodes the uint16 with address p.
-func encUint16(i *encInstr, state *encoderState, p unsafe.Pointer) {
- v := uint64(*(*uint16)(p))
- if v != 0 || state.sendZero {
- state.update(i)
- state.encodeUint(v)
- }
-}
-
-// encInt32 encodes the int32 with address p.
-func encInt32(i *encInstr, state *encoderState, p unsafe.Pointer) {
- v := int64(*(*int32)(p))
- if v != 0 || state.sendZero {
- state.update(i)
- state.encodeInt(v)
- }
-}
-
-// encUint encodes the uint32 with address p.
-func encUint32(i *encInstr, state *encoderState, p unsafe.Pointer) {
- v := uint64(*(*uint32)(p))
- if v != 0 || state.sendZero {
- state.update(i)
- state.encodeUint(v)
- }
-}
-
-// encInt64 encodes the int64 with address p.
-func encInt64(i *encInstr, state *encoderState, p unsafe.Pointer) {
- v := *(*int64)(p)
- if v != 0 || state.sendZero {
- state.update(i)
- state.encodeInt(v)
- }
-}
-
-// encInt64 encodes the uint64 with address p.
-func encUint64(i *encInstr, state *encoderState, p unsafe.Pointer) {
- v := *(*uint64)(p)
- if v != 0 || state.sendZero {
- state.update(i)
- state.encodeUint(v)
- }
-}
-
-// encUintptr encodes the uintptr with address p.
-func encUintptr(i *encInstr, state *encoderState, p unsafe.Pointer) {
- v := uint64(*(*uintptr)(p))
- if v != 0 || state.sendZero {
- state.update(i)
- state.encodeUint(v)
+ state.encodeUint(value)
}
}
@@ -255,42 +205,20 @@ func floatBits(f float64) uint64 {
return v
}
-// encFloat32 encodes the float32 with address p.
-func encFloat32(i *encInstr, state *encoderState, p unsafe.Pointer) {
- f := *(*float32)(p)
+// encFloat encodes the floating point value (float32 float64) referenced by v.
+func encFloat(i *encInstr, state *encoderState, v reflect.Value) {
+ f := v.Float()
if f != 0 || state.sendZero {
- v := floatBits(float64(f))
+ bits := floatBits(f)
state.update(i)
- state.encodeUint(v)
+ state.encodeUint(bits)
}
}
-// encFloat64 encodes the float64 with address p.
-func encFloat64(i *encInstr, state *encoderState, p unsafe.Pointer) {
- f := *(*float64)(p)
- if f != 0 || state.sendZero {
- state.update(i)
- v := floatBits(f)
- state.encodeUint(v)
- }
-}
-
-// encComplex64 encodes the complex64 with address p.
+// encComplex encodes the complex value (complex64 complex128) referenced by v.
// Complex numbers are just a pair of floating-point numbers, real part first.
-func encComplex64(i *encInstr, state *encoderState, p unsafe.Pointer) {
- c := *(*complex64)(p)
- if c != 0+0i || state.sendZero {
- rpart := floatBits(float64(real(c)))
- ipart := floatBits(float64(imag(c)))
- state.update(i)
- state.encodeUint(rpart)
- state.encodeUint(ipart)
- }
-}
-
-// encComplex128 encodes the complex128 with address p.
-func encComplex128(i *encInstr, state *encoderState, p unsafe.Pointer) {
- c := *(*complex128)(p)
+func encComplex(i *encInstr, state *encoderState, v reflect.Value) {
+ c := v.Complex()
if c != 0+0i || state.sendZero {
rpart := floatBits(real(c))
ipart := floatBits(imag(c))
@@ -300,10 +228,10 @@ func encComplex128(i *encInstr, state *encoderState, p unsafe.Pointer) {
}
}
-// encUint8Array encodes the byte slice whose header has address p.
+// encUint8Array encodes the byte array referenced by v.
// Byte arrays are encoded as an unsigned count followed by the raw bytes.
-func encUint8Array(i *encInstr, state *encoderState, p unsafe.Pointer) {
- b := *(*[]byte)(p)
+func encUint8Array(i *encInstr, state *encoderState, v reflect.Value) {
+ b := v.Bytes()
if len(b) > 0 || state.sendZero {
state.update(i)
state.encodeUint(uint64(len(b)))
@@ -311,10 +239,10 @@ func encUint8Array(i *encInstr, state *encoderState, p unsafe.Pointer) {
}
}
-// encString encodes the string whose header has address p.
+// encString encodes the string referenced by v.
// Strings are encoded as an unsigned count followed by the raw bytes.
-func encString(i *encInstr, state *encoderState, p unsafe.Pointer) {
- s := *(*string)(p)
+func encString(i *encInstr, state *encoderState, v reflect.Value) {
+ s := v.String()
if len(s) > 0 || state.sendZero {
state.update(i)
state.encodeUint(uint64(len(s)))
@@ -324,7 +252,7 @@ func encString(i *encInstr, state *encoderState, p unsafe.Pointer) {
// encStructTerminator encodes the end of an encoded struct
// as delta field number of 0.
-func encStructTerminator(i *encInstr, state *encoderState, p unsafe.Pointer) {
+func encStructTerminator(i *encInstr, state *encoderState, v reflect.Value) {
state.encodeUint(0)
}
@@ -338,60 +266,83 @@ type encEngine struct {
const singletonField = 0
+// valid reports whether the value is valid and a non-nil pointer.
+// (Slices, maps, and chans take care of themselves.)
+func valid(v reflect.Value) bool {
+ switch v.Kind() {
+ case reflect.Invalid:
+ return false
+ case reflect.Ptr:
+ return !v.IsNil()
+ }
+ return true
+}
+
// encodeSingle encodes a single top-level non-struct value.
-func (enc *Encoder) encodeSingle(b *bytes.Buffer, engine *encEngine, basep unsafe.Pointer) {
+func (enc *Encoder) encodeSingle(b *encBuffer, engine *encEngine, value reflect.Value) {
state := enc.newEncoderState(b)
+ defer enc.freeEncoderState(state)
state.fieldnum = singletonField
// There is no surrounding struct to frame the transmission, so we must
// generate data even if the item is zero. To do this, set sendZero.
state.sendZero = true
instr := &engine.instr[singletonField]
- p := basep // offset will be zero
if instr.indir > 0 {
- if p = encIndirect(p, instr.indir); p == nil {
- return
- }
+ value = encIndirect(value, instr.indir)
+ }
+ if valid(value) {
+ instr.op(instr, state, value)
}
- instr.op(instr, state, p)
- enc.freeEncoderState(state)
}
// encodeStruct encodes a single struct value.
-func (enc *Encoder) encodeStruct(b *bytes.Buffer, engine *encEngine, basep unsafe.Pointer) {
+func (enc *Encoder) encodeStruct(b *encBuffer, engine *encEngine, value reflect.Value) {
+ if !valid(value) {
+ return
+ }
state := enc.newEncoderState(b)
+ defer enc.freeEncoderState(state)
state.fieldnum = -1
for i := 0; i < len(engine.instr); i++ {
instr := &engine.instr[i]
- p := unsafe.Pointer(uintptr(basep) + instr.offset)
+ if i >= value.NumField() {
+ // encStructTerminator
+ instr.op(instr, state, reflect.Value{})
+ break
+ }
+ field := value.FieldByIndex(instr.index)
if instr.indir > 0 {
- if p = encIndirect(p, instr.indir); p == nil {
+ field = encIndirect(field, instr.indir)
+ // TODO: Is field guaranteed valid? If so we could avoid this check.
+ if !valid(field) {
continue
}
}
- instr.op(instr, state, p)
+ instr.op(instr, state, field)
}
- enc.freeEncoderState(state)
}
-// encodeArray encodes the array whose 0th element is at p.
-func (enc *Encoder) encodeArray(b *bytes.Buffer, p unsafe.Pointer, op encOp, elemWid uintptr, elemIndir int, length int) {
+// encodeArray encodes an array.
+func (enc *Encoder) encodeArray(b *encBuffer, value reflect.Value, op encOp, elemIndir int, length int, helper encHelper) {
state := enc.newEncoderState(b)
+ defer enc.freeEncoderState(state)
state.fieldnum = -1
state.sendZero = true
state.encodeUint(uint64(length))
+ if helper != nil && helper(state, value) {
+ return
+ }
for i := 0; i < length; i++ {
- elemp := p
+ elem := value.Index(i)
if elemIndir > 0 {
- up := encIndirect(elemp, elemIndir)
- if up == nil {
+ elem = encIndirect(elem, elemIndir)
+ // TODO: Is elem guaranteed valid? If so we could avoid this check.
+ if !valid(elem) {
errorf("encodeArray: nil element")
}
- elemp = up
}
- op(nil, state, elemp)
- p = unsafe.Pointer(uintptr(p) + elemWid)
+ op(nil, state, elem)
}
- enc.freeEncoderState(state)
}
// encodeReflectValue is a helper for maps. It encodes the value v.
@@ -402,13 +353,11 @@ func encodeReflectValue(state *encoderState, v reflect.Value, op encOp, indir in
if !v.IsValid() {
errorf("encodeReflectValue: nil element")
}
- op(nil, state, unsafeAddr(v))
+ op(nil, state, v)
}
// encodeMap encodes a map as unsigned count followed by key:value pairs.
-// Because map internals are not exposed, we must use reflection rather than
-// addresses.
-func (enc *Encoder) encodeMap(b *bytes.Buffer, mv reflect.Value, keyOp, elemOp encOp, keyIndir, elemIndir int) {
+func (enc *Encoder) encodeMap(b *encBuffer, mv reflect.Value, keyOp, elemOp encOp, keyIndir, elemIndir int) {
state := enc.newEncoderState(b)
state.fieldnum = -1
state.sendZero = true
@@ -426,7 +375,7 @@ func (enc *Encoder) encodeMap(b *bytes.Buffer, mv reflect.Value, keyOp, elemOp e
// by the type identifier (which might require defining that type right now), followed
// by the concrete value. A nil value gets sent as the empty string for the name,
// followed by no value.
-func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv reflect.Value) {
+func (enc *Encoder) encodeInterface(b *encBuffer, iv reflect.Value) {
// Gobs can encode nil interface values but not typed interface
// values holding nil pointers, since nil pointers point to no value.
elem := iv.Elem()
@@ -450,10 +399,7 @@ func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv reflect.Value) {
}
// Send the name.
state.encodeUint(uint64(len(name)))
- _, err := state.b.WriteString(name)
- if err != nil {
- error_(err)
- }
+ state.b.WriteString(name)
// Define the type id if necessary.
enc.sendTypeDescriptor(enc.writer(), state, ut)
// Send the type id.
@@ -461,7 +407,7 @@ func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv reflect.Value) {
// Encode the value into a new buffer. Any nested type definitions
// should be written to b, before the encoded value.
enc.pushWriter(b)
- data := new(bytes.Buffer)
+ data := new(encBuffer)
data.Write(spaceForLength)
enc.encode(data, elem, ut)
if enc.err != nil {
@@ -470,7 +416,7 @@ func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv reflect.Value) {
enc.popWriter()
enc.writeMessage(b, data)
if enc.err != nil {
- error_(err)
+ error_(enc.err)
}
enc.freeEncoderState(state)
}
@@ -491,7 +437,7 @@ func isZero(val reflect.Value) bool {
return !val.Bool()
case reflect.Complex64, reflect.Complex128:
return val.Complex() == 0
- case reflect.Chan, reflect.Func, reflect.Ptr:
+ case reflect.Chan, reflect.Func, reflect.Interface, reflect.Ptr:
return val.IsNil()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return val.Int() == 0
@@ -512,7 +458,7 @@ func isZero(val reflect.Value) bool {
// encGobEncoder encodes a value that implements the GobEncoder interface.
// The data is sent as a byte array.
-func (enc *Encoder) encodeGobEncoder(b *bytes.Buffer, ut *userTypeInfo, v reflect.Value) {
+func (enc *Encoder) encodeGobEncoder(b *encBuffer, ut *userTypeInfo, v reflect.Value) {
// TODO: should we catch panics from the called method?
var data []byte
@@ -539,30 +485,30 @@ func (enc *Encoder) encodeGobEncoder(b *bytes.Buffer, ut *userTypeInfo, v reflec
var encOpTable = [...]encOp{
reflect.Bool: encBool,
reflect.Int: encInt,
- reflect.Int8: encInt8,
- reflect.Int16: encInt16,
- reflect.Int32: encInt32,
- reflect.Int64: encInt64,
+ reflect.Int8: encInt,
+ reflect.Int16: encInt,
+ reflect.Int32: encInt,
+ reflect.Int64: encInt,
reflect.Uint: encUint,
- reflect.Uint8: encUint8,
- reflect.Uint16: encUint16,
- reflect.Uint32: encUint32,
- reflect.Uint64: encUint64,
- reflect.Uintptr: encUintptr,
- reflect.Float32: encFloat32,
- reflect.Float64: encFloat64,
- reflect.Complex64: encComplex64,
- reflect.Complex128: encComplex128,
+ reflect.Uint8: encUint,
+ reflect.Uint16: encUint,
+ reflect.Uint32: encUint,
+ reflect.Uint64: encUint,
+ reflect.Uintptr: encUint,
+ reflect.Float32: encFloat,
+ reflect.Float64: encFloat,
+ reflect.Complex64: encComplex,
+ reflect.Complex128: encComplex,
reflect.String: encString,
}
// encOpFor returns (a pointer to) the encoding op for the base type under rt and
// the indirection count to reach it.
-func (enc *Encoder) encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp) (*encOp, int) {
+func encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp, building map[*typeInfo]bool) (*encOp, int) {
ut := userType(rt)
// If the type implements GobEncoder, we handle it without further processing.
if ut.externalEnc != 0 {
- return enc.gobEncodeOpFor(ut)
+ return gobEncodeOpFor(ut)
}
// 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.
@@ -586,31 +532,27 @@ func (enc *Encoder) encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp
break
}
// Slices have a header; we decode it to find the underlying array.
- elemOp, elemIndir := enc.encOpFor(t.Elem(), inProgress)
- op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
- slice := (*reflect.SliceHeader)(p)
- if !state.sendZero && slice.Len == 0 {
+ elemOp, elemIndir := encOpFor(t.Elem(), inProgress, building)
+ helper := encSliceHelper[t.Elem().Kind()]
+ op = func(i *encInstr, state *encoderState, slice reflect.Value) {
+ if !state.sendZero && slice.Len() == 0 {
return
}
state.update(i)
- state.enc.encodeArray(state.b, unsafe.Pointer(slice.Data), *elemOp, t.Elem().Size(), elemIndir, int(slice.Len))
+ state.enc.encodeArray(state.b, slice, *elemOp, elemIndir, slice.Len(), helper)
}
case reflect.Array:
// True arrays have size in the type.
- elemOp, elemIndir := enc.encOpFor(t.Elem(), inProgress)
- op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ elemOp, elemIndir := encOpFor(t.Elem(), inProgress, building)
+ helper := encArrayHelper[t.Elem().Kind()]
+ op = func(i *encInstr, state *encoderState, array reflect.Value) {
state.update(i)
- state.enc.encodeArray(state.b, p, *elemOp, t.Elem().Size(), elemIndir, t.Len())
+ state.enc.encodeArray(state.b, array, *elemOp, elemIndir, array.Len(), helper)
}
case reflect.Map:
- keyOp, keyIndir := enc.encOpFor(t.Key(), inProgress)
- elemOp, elemIndir := enc.encOpFor(t.Elem(), inProgress)
- op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
- // Maps cannot be accessed by moving addresses around the way
- // that slices etc. can. We must recover a full reflection value for
- // the iteration.
- v := reflect.NewAt(t, unsafe.Pointer(p)).Elem()
- mv := reflect.Indirect(v)
+ keyOp, keyIndir := encOpFor(t.Key(), inProgress, building)
+ elemOp, elemIndir := encOpFor(t.Elem(), inProgress, building)
+ op = func(i *encInstr, state *encoderState, mv reflect.Value) {
// We send zero-length (but non-nil) maps because the
// receiver might want to use the map. (Maps don't use append.)
if !state.sendZero && mv.IsNil() {
@@ -621,19 +563,16 @@ func (enc *Encoder) encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp
}
case reflect.Struct:
// Generate a closure that calls out to the engine for the nested type.
- enc.getEncEngine(userType(typ))
+ getEncEngine(userType(typ), building)
info := mustGetTypeInfo(typ)
- op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ op = func(i *encInstr, state *encoderState, sv reflect.Value) {
state.update(i)
// indirect through info to delay evaluation for recursive structs
- state.enc.encodeStruct(state.b, info.encoder, p)
+ enc := info.encoder.Load().(*encEngine)
+ state.enc.encodeStruct(state.b, enc, sv)
}
case reflect.Interface:
- op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
- // Interfaces transmit the name and contents of the concrete
- // value they contain.
- v := reflect.NewAt(t, unsafe.Pointer(p)).Elem()
- iv := reflect.Indirect(v)
+ op = func(i *encInstr, state *encoderState, iv reflect.Value) {
if !state.sendZero && (!iv.IsValid() || iv.IsNil()) {
return
}
@@ -648,9 +587,8 @@ func (enc *Encoder) encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp
return &op, indir
}
-// gobEncodeOpFor returns the op for a type that is known to implement
-// GobEncoder.
-func (enc *Encoder) gobEncodeOpFor(ut *userTypeInfo) (*encOp, int) {
+// gobEncodeOpFor returns the op for a type that is known to implement GobEncoder.
+func gobEncodeOpFor(ut *userTypeInfo) (*encOp, int) {
rt := ut.user
if ut.encIndir == -1 {
rt = reflect.PtrTo(rt)
@@ -660,13 +598,13 @@ func (enc *Encoder) gobEncodeOpFor(ut *userTypeInfo) (*encOp, int) {
}
}
var op encOp
- op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
- var v reflect.Value
+ op = func(i *encInstr, state *encoderState, v reflect.Value) {
if ut.encIndir == -1 {
// Need to climb up one level to turn value into pointer.
- v = reflect.NewAt(rt, unsafe.Pointer(&p)).Elem()
- } else {
- v = reflect.NewAt(rt, p).Elem()
+ if !v.CanAddr() {
+ errorf("unaddressable value of type %s", rt)
+ }
+ v = v.Addr()
}
if !state.sendZero && isZero(v) {
return
@@ -678,7 +616,7 @@ func (enc *Encoder) gobEncodeOpFor(ut *userTypeInfo) (*encOp, int) {
}
// compileEnc returns the engine to compile the type.
-func (enc *Encoder) compileEnc(ut *userTypeInfo) *encEngine {
+func compileEnc(ut *userTypeInfo, building map[*typeInfo]bool) *encEngine {
srt := ut.base
engine := new(encEngine)
seen := make(map[reflect.Type]*encOp)
@@ -692,59 +630,57 @@ func (enc *Encoder) compileEnc(ut *userTypeInfo) *encEngine {
if !isSent(&f) {
continue
}
- op, indir := enc.encOpFor(f.Type, seen)
- engine.instr = append(engine.instr, encInstr{*op, wireFieldNum, indir, uintptr(f.Offset)})
+ op, indir := encOpFor(f.Type, seen, building)
+ engine.instr = append(engine.instr, encInstr{*op, wireFieldNum, f.Index, indir})
wireFieldNum++
}
if srt.NumField() > 0 && len(engine.instr) == 0 {
errorf("type %s has no exported fields", rt)
}
- engine.instr = append(engine.instr, encInstr{encStructTerminator, 0, 0, 0})
+ engine.instr = append(engine.instr, encInstr{encStructTerminator, 0, nil, 0})
} else {
engine.instr = make([]encInstr, 1)
- op, indir := enc.encOpFor(rt, seen)
- engine.instr[0] = encInstr{*op, singletonField, indir, 0} // offset is zero
+ op, indir := encOpFor(rt, seen, building)
+ engine.instr[0] = encInstr{*op, singletonField, nil, indir}
}
return engine
}
// getEncEngine returns the engine to compile the type.
-// typeLock must be held (or we're in initialization and guaranteed single-threaded).
-func (enc *Encoder) getEncEngine(ut *userTypeInfo) *encEngine {
- info, err1 := getTypeInfo(ut)
- if err1 != nil {
- error_(err1)
- }
- if info.encoder == nil {
- // Assign the encEngine now, so recursive types work correctly. But...
- info.encoder = new(encEngine)
- // ... if we fail to complete building the engine, don't cache the half-built machine.
- // Doing this here means we won't cache a type that is itself OK but
- // that contains a nested type that won't compile. The result is consistent
- // error behavior when Encode is called multiple times on the top-level type.
- ok := false
- defer func() {
- if !ok {
- info.encoder = nil
- }
- }()
- info.encoder = enc.compileEnc(ut)
- ok = true
+func getEncEngine(ut *userTypeInfo, building map[*typeInfo]bool) *encEngine {
+ info, err := getTypeInfo(ut)
+ if err != nil {
+ error_(err)
}
- return info.encoder
+ enc, ok := info.encoder.Load().(*encEngine)
+ if !ok {
+ enc = buildEncEngine(info, ut, building)
+ }
+ return enc
}
-// lockAndGetEncEngine is a function that locks and compiles.
-// This lets us hold the lock only while compiling, not when encoding.
-func (enc *Encoder) lockAndGetEncEngine(ut *userTypeInfo) *encEngine {
- typeLock.Lock()
- defer typeLock.Unlock()
- return enc.getEncEngine(ut)
+func buildEncEngine(info *typeInfo, ut *userTypeInfo, building map[*typeInfo]bool) *encEngine {
+ // Check for recursive types.
+ if building != nil && building[info] {
+ return nil
+ }
+ info.encInit.Lock()
+ defer info.encInit.Unlock()
+ enc, ok := info.encoder.Load().(*encEngine)
+ if !ok {
+ if building == nil {
+ building = make(map[*typeInfo]bool)
+ }
+ building[info] = true
+ enc = compileEnc(ut, building)
+ info.encoder.Store(enc)
+ }
+ return enc
}
-func (enc *Encoder) encode(b *bytes.Buffer, value reflect.Value, ut *userTypeInfo) {
+func (enc *Encoder) encode(b *encBuffer, value reflect.Value, ut *userTypeInfo) {
defer catchError(&enc.err)
- engine := enc.lockAndGetEncEngine(ut)
+ engine := getEncEngine(ut, nil)
indir := ut.indir
if ut.externalEnc != 0 {
indir = int(ut.encIndir)
@@ -753,8 +689,8 @@ func (enc *Encoder) encode(b *bytes.Buffer, value reflect.Value, ut *userTypeInf
value = reflect.Indirect(value)
}
if ut.externalEnc == 0 && value.Type().Kind() == reflect.Struct {
- enc.encodeStruct(b, engine, unsafeAddr(value))
+ enc.encodeStruct(b, engine, value)
} else {
- enc.encodeSingle(b, engine, unsafeAddr(value))
+ enc.encodeSingle(b, engine, value)
}
}
diff --git a/libgo/go/encoding/gob/encoder.go b/libgo/go/encoding/gob/encoder.go
index a3301c3bd3..a340e47b5e 100644
--- a/libgo/go/encoding/gob/encoder.go
+++ b/libgo/go/encoding/gob/encoder.go
@@ -5,7 +5,6 @@
package gob
import (
- "bytes"
"io"
"reflect"
"sync"
@@ -19,7 +18,7 @@ type Encoder struct {
sent map[reflect.Type]typeId // which types we've already sent
countState *encoderState // stage for writing counts
freeList *encoderState // list of free encoderStates; avoids reallocation
- byteBuf bytes.Buffer // buffer for top-level encoderState
+ byteBuf encBuffer // buffer for top-level encoderState
err error
}
@@ -34,7 +33,7 @@ func NewEncoder(w io.Writer) *Encoder {
enc := new(Encoder)
enc.w = []io.Writer{w}
enc.sent = make(map[reflect.Type]typeId)
- enc.countState = enc.newEncoderState(new(bytes.Buffer))
+ enc.countState = enc.newEncoderState(new(encBuffer))
return enc
}
@@ -60,7 +59,7 @@ func (enc *Encoder) setError(err error) {
}
// writeMessage sends the data item preceded by a unsigned count of its length.
-func (enc *Encoder) writeMessage(w io.Writer, b *bytes.Buffer) {
+func (enc *Encoder) writeMessage(w io.Writer, b *encBuffer) {
// Space has been reserved for the length at the head of the message.
// This is a little dirty: we grab the slice from the bytes.Buffer and massage
// it by hand.
@@ -88,9 +87,7 @@ func (enc *Encoder) sendActualType(w io.Writer, state *encoderState, ut *userTyp
if _, alreadySent := enc.sent[actual]; alreadySent {
return false
}
- typeLock.Lock()
info, err := getTypeInfo(ut)
- typeLock.Unlock()
if err != nil {
enc.setError(err)
return
@@ -191,9 +188,7 @@ func (enc *Encoder) sendTypeDescriptor(w io.Writer, state *encoderState, ut *use
// a singleton basic type (int, []byte etc.) at top level. We don't
// need to send the type info but we do need to update enc.sent.
if !sent {
- typeLock.Lock()
info, err := getTypeInfo(ut)
- typeLock.Unlock()
if err != nil {
enc.setError(err)
return
diff --git a/libgo/go/encoding/gob/encoder_test.go b/libgo/go/encoding/gob/encoder_test.go
index 4ecf51d122..0ea4c0ec8e 100644
--- a/libgo/go/encoding/gob/encoder_test.go
+++ b/libgo/go/encoding/gob/encoder_test.go
@@ -13,6 +13,52 @@ import (
"testing"
)
+// Test basic operations in a safe manner.
+func TestBasicEncoderDecoder(t *testing.T) {
+ var values = []interface{}{
+ true,
+ int(123),
+ int8(123),
+ int16(-12345),
+ int32(123456),
+ int64(-1234567),
+ uint(123),
+ uint8(123),
+ uint16(12345),
+ uint32(123456),
+ uint64(1234567),
+ uintptr(12345678),
+ float32(1.2345),
+ float64(1.2345678),
+ complex64(1.2345 + 2.3456i),
+ complex128(1.2345678 + 2.3456789i),
+ []byte("hello"),
+ string("hello"),
+ }
+ for _, value := range values {
+ b := new(bytes.Buffer)
+ enc := NewEncoder(b)
+ err := enc.Encode(value)
+ if err != nil {
+ t.Error("encoder fail:", err)
+ }
+ dec := NewDecoder(b)
+ result := reflect.New(reflect.TypeOf(value))
+ err = dec.Decode(result.Interface())
+ if err != nil {
+ t.Fatalf("error decoding %T: %v:", reflect.TypeOf(value), err)
+ }
+ if !reflect.DeepEqual(value, result.Elem().Interface()) {
+ t.Fatalf("%T: expected %v got %v", value, value, result.Elem().Interface())
+ }
+ }
+}
+
+type ET0 struct {
+ A int
+ B string
+}
+
type ET2 struct {
X string
}
@@ -40,14 +86,40 @@ type ET4 struct {
func TestEncoderDecoder(t *testing.T) {
b := new(bytes.Buffer)
enc := NewEncoder(b)
+ et0 := new(ET0)
+ et0.A = 7
+ et0.B = "gobs of fun"
+ err := enc.Encode(et0)
+ if err != nil {
+ t.Error("encoder fail:", err)
+ }
+ //fmt.Printf("% x %q\n", b, b)
+ //Debug(b)
+ dec := NewDecoder(b)
+ newEt0 := new(ET0)
+ err = dec.Decode(newEt0)
+ if err != nil {
+ t.Fatal("error decoding ET0:", err)
+ }
+
+ if !reflect.DeepEqual(et0, newEt0) {
+ t.Fatalf("invalid data for et0: expected %+v; got %+v", *et0, *newEt0)
+ }
+ if b.Len() != 0 {
+ t.Error("not at eof;", b.Len(), "bytes left")
+ }
+ // t.FailNow()
+
+ b = new(bytes.Buffer)
+ enc = NewEncoder(b)
et1 := new(ET1)
et1.A = 7
et1.Et2 = new(ET2)
- err := enc.Encode(et1)
+ err = enc.Encode(et1)
if err != nil {
t.Error("encoder fail:", err)
}
- dec := NewDecoder(b)
+ dec = NewDecoder(b)
newEt1 := new(ET1)
err = dec.Decode(newEt1)
if err != nil {
@@ -129,6 +201,8 @@ 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.
@@ -630,7 +704,7 @@ func TestSliceReusesMemory(t *testing.T) {
// Used to crash: negative count in recvMessage.
func TestBadCount(t *testing.T) {
b := []byte{0xfb, 0xa5, 0x82, 0x2f, 0xca, 0x1}
- if err := NewDecoder(bytes.NewBuffer(b)).Decode(nil); err == nil {
+ if err := NewDecoder(bytes.NewReader(b)).Decode(nil); err == nil {
t.Error("expected error from bad count")
} else if err.Error() != errBadCount.Error() {
t.Error("expected bad count error; got", err)
@@ -858,3 +932,25 @@ func Test29ElementSlice(t *testing.T) {
return
}
}
+
+// Don't crash, just give error when allocating a huge slice.
+// Issue 8084.
+func TestErrorForHugeSlice(t *testing.T) {
+ // Encode an int slice.
+ buf := new(bytes.Buffer)
+ slice := []int{1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
+ err := NewEncoder(buf).Encode(slice)
+ if err != nil {
+ t.Fatal("encode:", err)
+ }
+ // Reach into the buffer and smash the count to make the encoded slice very long.
+ buf.Bytes()[buf.Len()-len(slice)-1] = 0xfa
+ // Decode and see error.
+ err = NewDecoder(buf).Decode(&slice)
+ if err == nil {
+ t.Fatal("decode: no error")
+ }
+ if !strings.Contains(err.Error(), "slice too big") {
+ t.Fatal("decode: expected slice too big error, got %s", err.Error())
+ }
+}
diff --git a/libgo/go/encoding/gob/gobencdec_test.go b/libgo/go/encoding/gob/gobencdec_test.go
index 0193e2b67d..eb76b481d1 100644
--- a/libgo/go/encoding/gob/gobencdec_test.go
+++ b/libgo/go/encoding/gob/gobencdec_test.go
@@ -279,7 +279,7 @@ func TestGobEncoderValueField(t *testing.T) {
b := new(bytes.Buffer)
// First a field that's a structure.
enc := NewEncoder(b)
- err := enc.Encode(GobTestValueEncDec{17, StringStruct{"HIJKL"}})
+ err := enc.Encode(&GobTestValueEncDec{17, StringStruct{"HIJKL"}})
if err != nil {
t.Fatal("encode error:", err)
}
@@ -326,7 +326,7 @@ func TestGobEncoderArrayField(t *testing.T) {
for i := range a.A.a {
a.A.a[i] = byte(i)
}
- err := enc.Encode(a)
+ err := enc.Encode(&a)
if err != nil {
t.Fatal("encode error:", err)
}
@@ -589,7 +589,8 @@ func TestGobEncoderStructSingleton(t *testing.T) {
func TestGobEncoderNonStructSingleton(t *testing.T) {
b := new(bytes.Buffer)
enc := NewEncoder(b)
- err := enc.Encode(Gobber(1234))
+ var g Gobber = 1234
+ err := enc.Encode(&g)
if err != nil {
t.Fatal("encode error:", err)
}
@@ -705,13 +706,14 @@ func TestGobEncoderExtraIndirect(t *testing.T) {
}
// Another bug: this caused a crash with the new Go1 Time type.
-// We throw in a gob-encoding array, to test another case of isZero
-
+// We throw in a gob-encoding array, to test another case of isZero,
+// and a struct containing an nil interface, to test a third.
type isZeroBug struct {
T time.Time
S string
I int
A isZeroBugArray
+ F isZeroBugInterface
}
type isZeroBugArray [2]uint8
@@ -731,8 +733,20 @@ func (a *isZeroBugArray) GobDecode(data []byte) error {
return nil
}
+type isZeroBugInterface struct {
+ I interface{}
+}
+
+func (i isZeroBugInterface) GobEncode() (b []byte, e error) {
+ return []byte{}, nil
+}
+
+func (i *isZeroBugInterface) GobDecode(data []byte) error {
+ return nil
+}
+
func TestGobEncodeIsZero(t *testing.T) {
- x := isZeroBug{time.Now(), "hello", -55, isZeroBugArray{1, 2}}
+ x := isZeroBug{time.Now(), "hello", -55, isZeroBugArray{1, 2}, isZeroBugInterface{}}
b := new(bytes.Buffer)
enc := NewEncoder(b)
err := enc.Encode(x)
diff --git a/libgo/go/encoding/gob/timing_test.go b/libgo/go/encoding/gob/timing_test.go
index 9fbb0ac6d5..940e5ad412 100644
--- a/libgo/go/encoding/gob/timing_test.go
+++ b/libgo/go/encoding/gob/timing_test.go
@@ -19,33 +19,57 @@ type Bench struct {
D []byte
}
-func benchmarkEndToEnd(r io.Reader, w io.Writer, b *testing.B) {
- b.StopTimer()
- enc := NewEncoder(w)
- dec := NewDecoder(r)
- bench := &Bench{7, 3.2, "now is the time", []byte("for all good men")}
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- if enc.Encode(bench) != nil {
- panic("encode error")
+func benchmarkEndToEnd(b *testing.B, ctor func() interface{}, pipe func() (r io.Reader, w io.Writer, err error)) {
+ b.RunParallel(func(pb *testing.PB) {
+ r, w, err := pipe()
+ if err != nil {
+ b.Fatal("can't get pipe:", err)
}
- if dec.Decode(bench) != nil {
- panic("decode error")
+ v := ctor()
+ enc := NewEncoder(w)
+ dec := NewDecoder(r)
+ for pb.Next() {
+ if err := enc.Encode(v); err != nil {
+ b.Fatal("encode error:", err)
+ }
+ if err := dec.Decode(v); err != nil {
+ b.Fatal("decode error:", err)
+ }
}
- }
+ })
}
func BenchmarkEndToEndPipe(b *testing.B) {
- r, w, err := os.Pipe()
- if err != nil {
- b.Fatal("can't get pipe:", err)
- }
- benchmarkEndToEnd(r, w, b)
+ benchmarkEndToEnd(b, func() interface{} {
+ return &Bench{7, 3.2, "now is the time", bytes.Repeat([]byte("for all good men"), 100)}
+ }, func() (r io.Reader, w io.Writer, err error) {
+ r, w, err = os.Pipe()
+ return
+ })
}
func BenchmarkEndToEndByteBuffer(b *testing.B) {
- var buf bytes.Buffer
- benchmarkEndToEnd(&buf, &buf, b)
+ benchmarkEndToEnd(b, func() interface{} {
+ return &Bench{7, 3.2, "now is the time", bytes.Repeat([]byte("for all good men"), 100)}
+ }, func() (r io.Reader, w io.Writer, err error) {
+ var buf bytes.Buffer
+ return &buf, &buf, nil
+ })
+}
+
+func BenchmarkEndToEndSliceByteBuffer(b *testing.B) {
+ benchmarkEndToEnd(b, func() interface{} {
+ v := &Bench{7, 3.2, "now is the time", nil}
+ Register(v)
+ arr := make([]interface{}, 100)
+ for i := range arr {
+ arr[i] = v
+ }
+ return &arr
+ }, func() (r io.Reader, w io.Writer, err error) {
+ var buf bytes.Buffer
+ return &buf, &buf, nil
+ })
}
func TestCountEncodeMallocs(t *testing.T) {
@@ -103,7 +127,199 @@ func TestCountDecodeMallocs(t *testing.T) {
t.Fatal("decode:", err)
}
})
- if allocs != 3 {
- t.Fatalf("mallocs per decode of type Bench: %v; wanted 3\n", allocs)
+ if allocs != 4 {
+ t.Fatalf("mallocs per decode of type Bench: %v; wanted 4\n", allocs)
+ }
+}
+
+func BenchmarkEncodeComplex128Slice(b *testing.B) {
+ var buf bytes.Buffer
+ enc := NewEncoder(&buf)
+ a := make([]complex128, 1000)
+ for i := range a {
+ a[i] = 1.2 + 3.4i
+ }
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ buf.Reset()
+ err := enc.Encode(a)
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+}
+
+func BenchmarkEncodeFloat64Slice(b *testing.B) {
+ var buf bytes.Buffer
+ enc := NewEncoder(&buf)
+ a := make([]float64, 1000)
+ for i := range a {
+ a[i] = 1.23e4
+ }
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ buf.Reset()
+ err := enc.Encode(a)
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+}
+
+func BenchmarkEncodeInt32Slice(b *testing.B) {
+ var buf bytes.Buffer
+ enc := NewEncoder(&buf)
+ a := make([]int32, 1000)
+ for i := range a {
+ a[i] = 1234
+ }
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ buf.Reset()
+ err := enc.Encode(a)
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+}
+
+func BenchmarkEncodeStringSlice(b *testing.B) {
+ var buf bytes.Buffer
+ enc := NewEncoder(&buf)
+ a := make([]string, 1000)
+ for i := range a {
+ a[i] = "now is the time"
+ }
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ buf.Reset()
+ err := enc.Encode(a)
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+}
+
+// benchmarkBuf is a read buffer we can reset
+type benchmarkBuf struct {
+ offset int
+ data []byte
+}
+
+func (b *benchmarkBuf) Read(p []byte) (n int, err error) {
+ n = copy(p, b.data[b.offset:])
+ if n == 0 {
+ return 0, io.EOF
+ }
+ b.offset += n
+ return
+}
+
+func (b *benchmarkBuf) ReadByte() (c byte, err error) {
+ if b.offset >= len(b.data) {
+ return 0, io.EOF
+ }
+ c = b.data[b.offset]
+ b.offset++
+ return
+}
+
+func (b *benchmarkBuf) reset() {
+ b.offset = 0
+}
+
+func BenchmarkDecodeComplex128Slice(b *testing.B) {
+ var buf bytes.Buffer
+ enc := NewEncoder(&buf)
+ a := make([]complex128, 1000)
+ for i := range a {
+ a[i] = 1.2 + 3.4i
+ }
+ err := enc.Encode(a)
+ if err != nil {
+ b.Fatal(err)
+ }
+ x := make([]complex128, 1000)
+ bbuf := benchmarkBuf{data: buf.Bytes()}
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ bbuf.reset()
+ dec := NewDecoder(&bbuf)
+ err := dec.Decode(&x)
+ if err != nil {
+ b.Fatal(i, err)
+ }
+ }
+}
+
+func BenchmarkDecodeFloat64Slice(b *testing.B) {
+ var buf bytes.Buffer
+ enc := NewEncoder(&buf)
+ a := make([]float64, 1000)
+ for i := range a {
+ a[i] = 1.23e4
+ }
+ err := enc.Encode(a)
+ if err != nil {
+ b.Fatal(err)
+ }
+ x := make([]float64, 1000)
+ bbuf := benchmarkBuf{data: buf.Bytes()}
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ bbuf.reset()
+ dec := NewDecoder(&bbuf)
+ err := dec.Decode(&x)
+ if err != nil {
+ b.Fatal(i, err)
+ }
+ }
+}
+
+func BenchmarkDecodeInt32Slice(b *testing.B) {
+ var buf bytes.Buffer
+ enc := NewEncoder(&buf)
+ a := make([]int32, 1000)
+ for i := range a {
+ a[i] = 1234
+ }
+ err := enc.Encode(a)
+ if err != nil {
+ b.Fatal(err)
+ }
+ x := make([]int32, 1000)
+ bbuf := benchmarkBuf{data: buf.Bytes()}
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ bbuf.reset()
+ dec := NewDecoder(&bbuf)
+ err := dec.Decode(&x)
+ if err != nil {
+ b.Fatal(i, err)
+ }
+ }
+}
+
+func BenchmarkDecodeStringSlice(b *testing.B) {
+ var buf bytes.Buffer
+ enc := NewEncoder(&buf)
+ a := make([]string, 1000)
+ for i := range a {
+ a[i] = "now is the time"
+ }
+ err := enc.Encode(a)
+ if err != nil {
+ b.Fatal(err)
+ }
+ x := make([]string, 1000)
+ bbuf := benchmarkBuf{data: buf.Bytes()}
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ bbuf.reset()
+ dec := NewDecoder(&bbuf)
+ err := dec.Decode(&x)
+ if err != nil {
+ b.Fatal(i, err)
+ }
}
}
diff --git a/libgo/go/encoding/gob/type.go b/libgo/go/encoding/gob/type.go
index cad1452795..a49b71a867 100644
--- a/libgo/go/encoding/gob/type.go
+++ b/libgo/go/encoding/gob/type.go
@@ -11,6 +11,7 @@ import (
"os"
"reflect"
"sync"
+ "sync/atomic"
"unicode"
"unicode/utf8"
)
@@ -681,29 +682,51 @@ func (w *wireType) string() string {
type typeInfo struct {
id typeId
- encoder *encEngine
+ encInit sync.Mutex // protects creation of encoder
+ encoder atomic.Value // *encEngine
wire *wireType
}
-var typeInfoMap = make(map[reflect.Type]*typeInfo) // protected by typeLock
+// typeInfoMap is an atomic pointer to map[reflect.Type]*typeInfo.
+// It's updated copy-on-write. Readers just do an atomic load
+// to get the current version of the map. Writers make a full copy of
+// the map and atomically update the pointer to point to the new map.
+// Under heavy read contention, this is significantly faster than a map
+// protected by a mutex.
+var typeInfoMap atomic.Value
+
+func lookupTypeInfo(rt reflect.Type) *typeInfo {
+ m, _ := typeInfoMap.Load().(map[reflect.Type]*typeInfo)
+ return m[rt]
+}
-// typeLock must be held.
func getTypeInfo(ut *userTypeInfo) (*typeInfo, error) {
rt := ut.base
if ut.externalEnc != 0 {
// We want the user type, not the base type.
rt = ut.user
}
- info, ok := typeInfoMap[rt]
- if ok {
+ if info := lookupTypeInfo(rt); info != nil {
return info, nil
}
- info = new(typeInfo)
+ return buildTypeInfo(ut, rt)
+}
+
+// buildTypeInfo constructs the type information for the type
+// and stores it in the type info map.
+func buildTypeInfo(ut *userTypeInfo, rt reflect.Type) (*typeInfo, error) {
+ typeLock.Lock()
+ defer typeLock.Unlock()
+
+ if info := lookupTypeInfo(rt); info != nil {
+ return info, nil
+ }
+
gt, err := getBaseType(rt.Name(), rt)
if err != nil {
return nil, err
}
- info.id = gt.id()
+ info := &typeInfo{id: gt.id()}
if ut.externalEnc != 0 {
userType, err := getType(rt.Name(), ut, rt)
@@ -719,25 +742,32 @@ func getTypeInfo(ut *userTypeInfo) (*typeInfo, error) {
case xText:
info.wire = &wireType{TextMarshalerT: gt}
}
- typeInfoMap[ut.user] = info
- return info, nil
+ rt = ut.user
+ } else {
+ t := info.id.gobType()
+ switch typ := rt; typ.Kind() {
+ case reflect.Array:
+ info.wire = &wireType{ArrayT: t.(*arrayType)}
+ case reflect.Map:
+ info.wire = &wireType{MapT: t.(*mapType)}
+ case reflect.Slice:
+ // []byte == []uint8 is a special case handled separately
+ if typ.Elem().Kind() != reflect.Uint8 {
+ info.wire = &wireType{SliceT: t.(*sliceType)}
+ }
+ case reflect.Struct:
+ info.wire = &wireType{StructT: t.(*structType)}
+ }
}
- t := info.id.gobType()
- switch typ := rt; typ.Kind() {
- case reflect.Array:
- info.wire = &wireType{ArrayT: t.(*arrayType)}
- case reflect.Map:
- info.wire = &wireType{MapT: t.(*mapType)}
- case reflect.Slice:
- // []byte == []uint8 is a special case handled separately
- if typ.Elem().Kind() != reflect.Uint8 {
- info.wire = &wireType{SliceT: t.(*sliceType)}
- }
- case reflect.Struct:
- info.wire = &wireType{StructT: t.(*structType)}
+ // Create new map with old contents plus new entry.
+ newm := make(map[reflect.Type]*typeInfo)
+ m, _ := typeInfoMap.Load().(map[reflect.Type]*typeInfo)
+ for k, v := range m {
+ newm[k] = v
}
- typeInfoMap[rt] = info
+ newm[rt] = info
+ typeInfoMap.Store(newm)
return info, nil
}
diff --git a/libgo/go/encoding/hex/hex.go b/libgo/go/encoding/hex/hex.go
index 167d00e032..d1fc7024a9 100644
--- a/libgo/go/encoding/hex/hex.go
+++ b/libgo/go/encoding/hex/hex.go
@@ -146,6 +146,9 @@ func (h *dumper) Write(data []byte) (n int, err error) {
h.buf[12] = ' '
h.buf[13] = ' '
_, err = h.w.Write(h.buf[4:])
+ if err != nil {
+ return
+ }
}
Encode(h.buf[:], data[i:i+1])
h.buf[2] = ' '
diff --git a/libgo/go/encoding/hex/hex_test.go b/libgo/go/encoding/hex/hex_test.go
index 356f590f02..b969636cd5 100644
--- a/libgo/go/encoding/hex/hex_test.go
+++ b/libgo/go/encoding/hex/hex_test.go
@@ -38,7 +38,10 @@ func TestEncode(t *testing.T) {
}
func TestDecode(t *testing.T) {
- for i, test := range encDecTests {
+ // Case for decoding uppercase hex characters, since
+ // Encode always uses lowercase.
+ decTests := append(encDecTests, encDecTest{"F8F9FAFBFCFDFEFF", []byte{0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff}})
+ for i, test := range decTests {
dst := make([]byte, DecodedLen(len(test.enc)))
n, err := Decode(dst, []byte(test.enc))
if err != nil {
@@ -79,6 +82,7 @@ type errTest struct {
var errTests = []errTest{
{"0", "encoding/hex: odd length hex string"},
{"0g", "encoding/hex: invalid byte: U+0067 'g'"},
+ {"00gg", "encoding/hex: invalid byte: U+0067 'g'"},
{"0\x01", "encoding/hex: invalid byte: U+0001"},
}
diff --git a/libgo/go/encoding/json/decode.go b/libgo/go/encoding/json/decode.go
index 458fb39ec0..705bc2e17a 100644
--- a/libgo/go/encoding/json/decode.go
+++ b/libgo/go/encoding/json/decode.go
@@ -8,6 +8,7 @@
package json
import (
+ "bytes"
"encoding"
"encoding/base64"
"errors"
@@ -15,7 +16,6 @@ import (
"reflect"
"runtime"
"strconv"
- "strings"
"unicode"
"unicode/utf16"
"unicode/utf8"
@@ -54,6 +54,11 @@ import (
// If no more serious errors are encountered, Unmarshal returns
// an UnmarshalTypeError describing the earliest such error.
//
+// The JSON null value unmarshals into an interface, map, pointer, or slice
+// by setting that Go value to nil. Because null is often used in JSON to mean
+// ``not present,'' unmarshaling a JSON null into any other Go type has no effect
+// on the value and produces no error.
+//
// When unmarshaling quoted strings, invalid UTF-8 or
// invalid UTF-16 surrogate pairs are not treated as an error.
// Instead, they are replaced by the Unicode replacement
@@ -168,7 +173,6 @@ type decodeState struct {
scan scanner
nextscan scanner // for calls to nextValue
savedError error
- tempstr string // scratch space to avoid some allocations
useNumber bool
}
@@ -288,6 +292,32 @@ func (d *decodeState) value(v reflect.Value) {
}
}
+type unquotedValue struct{}
+
+// valueQuoted is like value but decodes a
+// quoted string literal or literal null into an interface value.
+// If it finds anything other than a quoted string literal or null,
+// valueQuoted returns unquotedValue{}.
+func (d *decodeState) valueQuoted() interface{} {
+ switch op := d.scanWhile(scanSkipSpace); op {
+ default:
+ d.error(errPhase)
+
+ case scanBeginArray:
+ d.array(reflect.Value{})
+
+ case scanBeginObject:
+ d.object(reflect.Value{})
+
+ case scanBeginLiteral:
+ switch v := d.literalInterface().(type) {
+ case nil, string:
+ return v
+ }
+ }
+ return unquotedValue{}
+}
+
// indirect walks down v allocating pointers as needed,
// until it gets to a non-pointer.
// if it encounters an Unmarshaler, indirect stops and returns that.
@@ -439,8 +469,10 @@ func (d *decodeState) array(v reflect.Value) {
}
}
+var nullLiteral = []byte("null")
+
// object consumes an object from d.data[d.off-1:], decoding into the value v.
-// the first byte of the object ('{') has been read already.
+// the first byte ('{') of the object has been read already.
func (d *decodeState) object(v reflect.Value) {
// Check for unmarshaler.
u, ut, pv := d.indirect(v, false)
@@ -473,7 +505,9 @@ func (d *decodeState) object(v reflect.Value) {
t := v.Type()
if t.Key().Kind() != reflect.String {
d.saveError(&UnmarshalTypeError{"object", v.Type()})
- break
+ d.off--
+ d.next() // skip over { } in input
+ return
}
if v.IsNil() {
v.Set(reflect.MakeMap(t))
@@ -500,11 +534,11 @@ func (d *decodeState) object(v reflect.Value) {
d.error(errPhase)
}
- // Read string key.
+ // Read key.
start := d.off - 1
op = d.scanWhile(scanContinue)
item := d.data[start : d.off-1]
- key, ok := unquote(item)
+ key, ok := unquoteBytes(item)
if !ok {
d.error(errPhase)
}
@@ -526,11 +560,11 @@ func (d *decodeState) object(v reflect.Value) {
fields := cachedTypeFields(v.Type())
for i := range fields {
ff := &fields[i]
- if ff.name == key {
+ if bytes.Equal(ff.nameBytes, key) {
f = ff
break
}
- if f == nil && strings.EqualFold(ff.name, key) {
+ if f == nil && ff.equalFold(ff.nameBytes, key) {
f = ff
}
}
@@ -559,8 +593,14 @@ func (d *decodeState) object(v reflect.Value) {
// Read value.
if destring {
- d.value(reflect.ValueOf(&d.tempstr))
- d.literalStore([]byte(d.tempstr), subv, true)
+ switch qv := d.valueQuoted().(type) {
+ case nil:
+ d.literalStore(nullLiteral, subv, false)
+ case string:
+ d.literalStore([]byte(qv), subv, true)
+ default:
+ d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", item, v.Type()))
+ }
} else {
d.value(subv)
}
diff --git a/libgo/go/encoding/json/decode_test.go b/libgo/go/encoding/json/decode_test.go
index 22c5f89f79..7235969b9f 100644
--- a/libgo/go/encoding/json/decode_test.go
+++ b/libgo/go/encoding/json/decode_test.go
@@ -406,6 +406,13 @@ var unmarshalTests = []unmarshalTest{
ptr: new(string),
out: "hello\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdworld",
},
+
+ // issue 8305
+ {
+ in: `{"2009-11-10T23:00:00Z": "hello world"}`,
+ ptr: &map[time.Time]string{},
+ err: &UnmarshalTypeError{"object", reflect.TypeOf(map[time.Time]string{})},
+ },
}
func TestMarshal(t *testing.T) {
@@ -514,6 +521,7 @@ func TestUnmarshal(t *testing.T) {
if tt.ptr == nil {
continue
}
+
// v = new(right-type)
v := reflect.New(reflect.TypeOf(tt.ptr).Elem())
dec := NewDecoder(bytes.NewReader(in))
@@ -521,7 +529,9 @@ func TestUnmarshal(t *testing.T) {
dec.UseNumber()
}
if err := dec.Decode(v.Interface()); !reflect.DeepEqual(err, tt.err) {
- t.Errorf("#%d: %v want %v", i, err, tt.err)
+ t.Errorf("#%d: %v, want %v", i, err, tt.err)
+ continue
+ } else if err != nil {
continue
}
if !reflect.DeepEqual(v.Elem().Interface(), tt.out) {
@@ -1060,6 +1070,28 @@ func TestEmptyString(t *testing.T) {
}
}
+// Test that a null for ,string is not replaced with the previous quoted string (issue 7046).
+// It should also not be an error (issue 2540, issue 8587).
+func TestNullString(t *testing.T) {
+ type T struct {
+ A int `json:",string"`
+ B int `json:",string"`
+ C *int `json:",string"`
+ }
+ data := []byte(`{"A": "1", "B": null, "C": null}`)
+ var s T
+ s.B = 1
+ s.C = new(int)
+ *s.C = 2
+ err := Unmarshal(data, &s)
+ if err != nil {
+ t.Fatalf("Unmarshal: %v")
+ }
+ if s.B != 1 || s.C != nil {
+ t.Fatalf("after Unmarshal, s.B=%d, s.C=%p, want 1, nil", s.B, s.C)
+ }
+}
+
func intp(x int) *int {
p := new(int)
*p = x
@@ -1110,8 +1142,8 @@ func TestInterfaceSet(t *testing.T) {
// Issue 2540
func TestUnmarshalNulls(t *testing.T) {
jsonData := []byte(`{
- "Bool" : null,
- "Int" : null,
+ "Bool" : null,
+ "Int" : null,
"Int8" : null,
"Int16" : null,
"Int32" : null,
@@ -1316,3 +1348,26 @@ func TestPrefilled(t *testing.T) {
}
}
}
+
+var invalidUnmarshalTests = []struct {
+ v interface{}
+ want string
+}{
+ {nil, "json: Unmarshal(nil)"},
+ {struct{}{}, "json: Unmarshal(non-pointer struct {})"},
+ {(*int)(nil), "json: Unmarshal(nil *int)"},
+}
+
+func TestInvalidUnmarshal(t *testing.T) {
+ buf := []byte(`{"a":"1"}`)
+ for _, tt := range invalidUnmarshalTests {
+ 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)
+ }
+ }
+}
diff --git a/libgo/go/encoding/json/encode.go b/libgo/go/encoding/json/encode.go
index 7d6c71d7a9..fca2a0980b 100644
--- a/libgo/go/encoding/json/encode.go
+++ b/libgo/go/encoding/json/encode.go
@@ -40,10 +40,11 @@ import (
//
// Floating point, integer, and Number values encode as JSON numbers.
//
-// String values encode as JSON strings. InvalidUTF8Error will be returned
-// if an invalid UTF-8 sequence is encountered.
+// String values encode as JSON strings coerced to valid UTF-8,
+// replacing invalid bytes with the Unicode replacement rune.
// The angle brackets "<" and ">" are escaped to "\u003c" and "\u003e"
// to keep some browsers from misinterpreting JSON output as HTML.
+// Ampersand "&" is also escaped to "\u0026" for the same reason.
//
// Array and slice values encode as JSON arrays, except that
// []byte encodes as a base64-encoded string, and a nil slice
@@ -92,6 +93,8 @@ import (
// as described in the next paragraph.
// An anonymous struct field with a name given in its JSON tag is treated as
// having that name, rather than being anonymous.
+// An anonymous struct field of interface type is treated the same as having
+// that type as its name, rather than being anonymous.
//
// The Go visibility rules for struct fields are amended for JSON when
// deciding which field to marshal or unmarshal. If there are
@@ -241,24 +244,15 @@ type encodeState struct {
scratch [64]byte
}
-// TODO(bradfitz): use a sync.Cache here
-var encodeStatePool = make(chan *encodeState, 8)
+var encodeStatePool sync.Pool
func newEncodeState() *encodeState {
- select {
- case e := <-encodeStatePool:
+ if v := encodeStatePool.Get(); v != nil {
+ e := v.(*encodeState)
e.Reset()
return e
- default:
- return new(encodeState)
- }
-}
-
-func putEncodeState(e *encodeState) {
- select {
- case encodeStatePool <- e:
- default:
}
+ return new(encodeState)
}
func (e *encodeState) marshal(v interface{}) (err error) {
@@ -704,12 +698,12 @@ type ptrEncoder struct {
elemEnc encoderFunc
}
-func (pe *ptrEncoder) encode(e *encodeState, v reflect.Value, _ bool) {
+func (pe *ptrEncoder) encode(e *encodeState, v reflect.Value, quoted bool) {
if v.IsNil() {
e.WriteString("null")
return
}
- pe.elemEnc(e, v.Elem(), false)
+ pe.elemEnc(e, v.Elem(), quoted)
}
func newPtrEncoder(t reflect.Type) encoderFunc {
@@ -811,9 +805,12 @@ func (e *encodeState) string(s string) (int, error) {
case '\r':
e.WriteByte('\\')
e.WriteByte('r')
+ case '\t':
+ e.WriteByte('\\')
+ e.WriteByte('t')
default:
// This encodes bytes < 0x20 except for \n and \r,
- // as well as < and >. The latter are escaped because they
+ // as well as <, > and &. The latter are escaped because they
// can lead to security holes when user-controlled strings
// are rendered into JSON and served to some browsers.
e.WriteString(`\u00`)
@@ -884,9 +881,12 @@ func (e *encodeState) stringBytes(s []byte) (int, error) {
case '\r':
e.WriteByte('\\')
e.WriteByte('r')
+ case '\t':
+ e.WriteByte('\\')
+ e.WriteByte('t')
default:
// This encodes bytes < 0x20 except for \n and \r,
- // as well as < and >. The latter are escaped because they
+ // as well as <, >, and &. The latter are escaped because they
// can lead to security holes when user-controlled strings
// are rendered into JSON and served to some browsers.
e.WriteString(`\u00`)
@@ -936,6 +936,9 @@ func (e *encodeState) stringBytes(s []byte) (int, error) {
// A field represents a single field found in a struct.
type field struct {
name string
+ nameBytes []byte // []byte(name)
+ equalFold func(s, t []byte) bool // bytes.EqualFold or equivalent
+
tag bool
index []int
typ reflect.Type
@@ -943,6 +946,12 @@ type field struct {
quoted bool
}
+func fillField(f field) field {
+ f.nameBytes = []byte(f.name)
+ f.equalFold = foldFunc(f.nameBytes)
+ return f
+}
+
// byName sorts field by name, breaking ties with depth,
// then breaking ties with "name came from json tag", then
// breaking ties with index sequence.
@@ -1042,8 +1051,14 @@ func typeFields(t reflect.Type) []field {
if name == "" {
name = sf.Name
}
- fields = append(fields, field{name, tagged, index, ft,
- opts.Contains("omitempty"), opts.Contains("string")})
+ fields = append(fields, fillField(field{
+ name: name,
+ tag: tagged,
+ index: index,
+ typ: ft,
+ omitEmpty: opts.Contains("omitempty"),
+ quoted: opts.Contains("string"),
+ }))
if count[f.typ] > 1 {
// If there were multiple instances, add a second,
// so that the annihilation code will see a duplicate.
@@ -1057,7 +1072,7 @@ func typeFields(t reflect.Type) []field {
// Record new anonymous struct to explore in next round.
nextCount[ft]++
if nextCount[ft] == 1 {
- next = append(next, field{name: ft.Name(), index: index, typ: ft})
+ next = append(next, fillField(field{name: ft.Name(), index: index, typ: ft}))
}
}
}
diff --git a/libgo/go/encoding/json/encode_test.go b/libgo/go/encoding/json/encode_test.go
index 9395db7cb6..7abfa85db7 100644
--- a/libgo/go/encoding/json/encode_test.go
+++ b/libgo/go/encoding/json/encode_test.go
@@ -25,13 +25,30 @@ type Optionals struct {
Mr map[string]interface{} `json:"mr"`
Mo map[string]interface{} `json:",omitempty"`
+
+ Fr float64 `json:"fr"`
+ Fo float64 `json:"fo,omitempty"`
+
+ Br bool `json:"br"`
+ Bo bool `json:"bo,omitempty"`
+
+ Ur uint `json:"ur"`
+ Uo uint `json:"uo,omitempty"`
+
+ Str struct{} `json:"str"`
+ Sto struct{} `json:"sto,omitempty"`
}
var optionalsExpected = `{
"sr": "",
"omitempty": 0,
"slr": null,
- "mr": {}
+ "mr": {},
+ "fr": 0,
+ "br": false,
+ "ur": 0,
+ "str": {},
+ "sto": {}
}`
func TestOmitEmpty(t *testing.T) {
@@ -76,7 +93,7 @@ func TestStringTag(t *testing.T) {
// Verify that it round-trips.
var s2 StringTag
- err = NewDecoder(bytes.NewBuffer(got)).Decode(&s2)
+ err = NewDecoder(bytes.NewReader(got)).Decode(&s2)
if err != nil {
t.Fatalf("Decode: %v", err)
}
@@ -425,3 +442,91 @@ func TestIssue6458(t *testing.T) {
t.Errorf("Marshal(x) = %#q; want %#q", b, want)
}
}
+
+func TestHTMLEscape(t *testing.T) {
+ var b, want bytes.Buffer
+ m := `{"M":"<html>foo &` + "\xe2\x80\xa8 \xe2\x80\xa9" + `</html>"}`
+ want.Write([]byte(`{"M":"\u003chtml\u003efoo \u0026\u2028 \u2029\u003c/html\u003e"}`))
+ HTMLEscape(&b, []byte(m))
+ if !bytes.Equal(b.Bytes(), want.Bytes()) {
+ t.Errorf("HTMLEscape(&b, []byte(m)) = %s; want %s", b.Bytes(), want.Bytes())
+ }
+}
+
+// golang.org/issue/8582
+func TestEncodePointerString(t *testing.T) {
+ type stringPointer struct {
+ N *int64 `json:"n,string"`
+ }
+ var n int64 = 42
+ b, err := Marshal(stringPointer{N: &n})
+ if err != nil {
+ t.Fatalf("Marshal: %v", err)
+ }
+ if got, want := string(b), `{"n":"42"}`; got != want {
+ t.Errorf("Marshal = %s, want %s", got, want)
+ }
+ var back stringPointer
+ err = Unmarshal(b, &back)
+ if err != nil {
+ t.Fatalf("Unmarshal: %v", err)
+ }
+ if back.N == nil {
+ t.Fatalf("Unmarshalled nil N field")
+ }
+ if *back.N != 42 {
+ t.Fatalf("*N = %d; want 42", *back.N)
+ }
+}
+
+var encodeStringTests = []struct {
+ in string
+ out string
+}{
+ {"\x00", `"\u0000"`},
+ {"\x01", `"\u0001"`},
+ {"\x02", `"\u0002"`},
+ {"\x03", `"\u0003"`},
+ {"\x04", `"\u0004"`},
+ {"\x05", `"\u0005"`},
+ {"\x06", `"\u0006"`},
+ {"\x07", `"\u0007"`},
+ {"\x08", `"\u0008"`},
+ {"\x09", `"\t"`},
+ {"\x0a", `"\n"`},
+ {"\x0b", `"\u000b"`},
+ {"\x0c", `"\u000c"`},
+ {"\x0d", `"\r"`},
+ {"\x0e", `"\u000e"`},
+ {"\x0f", `"\u000f"`},
+ {"\x10", `"\u0010"`},
+ {"\x11", `"\u0011"`},
+ {"\x12", `"\u0012"`},
+ {"\x13", `"\u0013"`},
+ {"\x14", `"\u0014"`},
+ {"\x15", `"\u0015"`},
+ {"\x16", `"\u0016"`},
+ {"\x17", `"\u0017"`},
+ {"\x18", `"\u0018"`},
+ {"\x19", `"\u0019"`},
+ {"\x1a", `"\u001a"`},
+ {"\x1b", `"\u001b"`},
+ {"\x1c", `"\u001c"`},
+ {"\x1d", `"\u001d"`},
+ {"\x1e", `"\u001e"`},
+ {"\x1f", `"\u001f"`},
+}
+
+func TestEncodeString(t *testing.T) {
+ for _, tt := range encodeStringTests {
+ b, err := Marshal(tt.in)
+ if err != nil {
+ t.Errorf("Marshal(%q): %v", tt.in, err)
+ continue
+ }
+ out := string(b)
+ if out != tt.out {
+ t.Errorf("Marshal(%q) = %#q, want %#q", tt.in, out, tt.out)
+ }
+ }
+}
diff --git a/libgo/go/encoding/json/fold.go b/libgo/go/encoding/json/fold.go
new file mode 100644
index 0000000000..d6f77c93e5
--- /dev/null
+++ b/libgo/go/encoding/json/fold.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.
+
+package json
+
+import (
+ "bytes"
+ "unicode/utf8"
+)
+
+const (
+ caseMask = ^byte(0x20) // Mask to ignore case in ASCII.
+ kelvin = '\u212a'
+ smallLongEss = '\u017f'
+)
+
+// foldFunc returns one of four different case folding equivalence
+// functions, from most general (and slow) to fastest:
+//
+// 1) bytes.EqualFold, if the key s contains any non-ASCII UTF-8
+// 2) equalFoldRight, if s contains special folding ASCII ('k', 'K', 's', 'S')
+// 3) asciiEqualFold, no special, but includes non-letters (including _)
+// 4) simpleLetterEqualFold, no specials, no non-letters.
+//
+// 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
+//
+// The returned function is specialized for matching against s and
+// should only be given s. It's not curried for performance reasons.
+func foldFunc(s []byte) func(s, t []byte) bool {
+ nonLetter := false
+ special := false // special letter
+ for _, b := range s {
+ if b >= utf8.RuneSelf {
+ return bytes.EqualFold
+ }
+ upper := b & caseMask
+ if upper < 'A' || upper > 'Z' {
+ nonLetter = true
+ } else if upper == 'K' || upper == 'S' {
+ // See above for why these letters are special.
+ special = true
+ }
+ }
+ if special {
+ return equalFoldRight
+ }
+ if nonLetter {
+ return asciiEqualFold
+ }
+ return simpleLetterEqualFold
+}
+
+// equalFoldRight is a specialization of bytes.EqualFold when s is
+// known to be all ASCII (including punctuation), but contains an 's',
+// 'S', 'k', or 'K', requiring a Unicode fold on the bytes in t.
+// See comments on foldFunc.
+func equalFoldRight(s, t []byte) bool {
+ for _, sb := range s {
+ if len(t) == 0 {
+ return false
+ }
+ tb := t[0]
+ if tb < utf8.RuneSelf {
+ if sb != tb {
+ sbUpper := sb & caseMask
+ if 'A' <= sbUpper && sbUpper <= 'Z' {
+ if sbUpper != tb&caseMask {
+ return false
+ }
+ } else {
+ return false
+ }
+ }
+ t = t[1:]
+ continue
+ }
+ // sb is ASCII and t is not. t must be either kelvin
+ // sign or long s; sb must be s, S, k, or K.
+ tr, size := utf8.DecodeRune(t)
+ switch sb {
+ case 's', 'S':
+ if tr != smallLongEss {
+ return false
+ }
+ case 'k', 'K':
+ if tr != kelvin {
+ return false
+ }
+ default:
+ return false
+ }
+ t = t[size:]
+
+ }
+ if len(t) > 0 {
+ return false
+ }
+ return true
+}
+
+// asciiEqualFold is a specialization of bytes.EqualFold for use when
+// s is all ASCII (but may contain non-letters) and contains no
+// special-folding letters.
+// See comments on foldFunc.
+func asciiEqualFold(s, t []byte) bool {
+ if len(s) != len(t) {
+ return false
+ }
+ for i, sb := range s {
+ tb := t[i]
+ if sb == tb {
+ continue
+ }
+ if ('a' <= sb && sb <= 'z') || ('A' <= sb && sb <= 'Z') {
+ if sb&caseMask != tb&caseMask {
+ return false
+ }
+ } else {
+ return false
+ }
+ }
+ return true
+}
+
+// simpleLetterEqualFold is a specialization of bytes.EqualFold for
+// use when s is all ASCII letters (no underscores, etc) and also
+// doesn't contain 'k', 'K', 's', or 'S'.
+// See comments on foldFunc.
+func simpleLetterEqualFold(s, t []byte) bool {
+ if len(s) != len(t) {
+ return false
+ }
+ for i, b := range s {
+ if b&caseMask != t[i]&caseMask {
+ return false
+ }
+ }
+ return true
+}
diff --git a/libgo/go/encoding/json/fold_test.go b/libgo/go/encoding/json/fold_test.go
new file mode 100644
index 0000000000..9fb94646a8
--- /dev/null
+++ b/libgo/go/encoding/json/fold_test.go
@@ -0,0 +1,116 @@
+// 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 json
+
+import (
+ "bytes"
+ "strings"
+ "testing"
+ "unicode/utf8"
+)
+
+var foldTests = []struct {
+ fn func(s, t []byte) bool
+ s, t string
+ want bool
+}{
+ {equalFoldRight, "", "", true},
+ {equalFoldRight, "a", "a", true},
+ {equalFoldRight, "", "a", false},
+ {equalFoldRight, "a", "", false},
+ {equalFoldRight, "a", "A", true},
+ {equalFoldRight, "AB", "ab", true},
+ {equalFoldRight, "AB", "ac", false},
+ {equalFoldRight, "sbkKc", "ſbKKc", true},
+ {equalFoldRight, "SbKkc", "ſbKKc", true},
+ {equalFoldRight, "SbKkc", "ſbKK", false},
+ {equalFoldRight, "e", "é", false},
+ {equalFoldRight, "s", "S", true},
+
+ {simpleLetterEqualFold, "", "", true},
+ {simpleLetterEqualFold, "abc", "abc", true},
+ {simpleLetterEqualFold, "abc", "ABC", true},
+ {simpleLetterEqualFold, "abc", "ABCD", false},
+ {simpleLetterEqualFold, "abc", "xxx", false},
+
+ {asciiEqualFold, "a_B", "A_b", true},
+ {asciiEqualFold, "aa@", "aa`", false}, // verify 0x40 and 0x60 aren't case-equivalent
+}
+
+func TestFold(t *testing.T) {
+ for i, tt := range foldTests {
+ if got := tt.fn([]byte(tt.s), []byte(tt.t)); got != tt.want {
+ t.Errorf("%d. %q, %q = %v; want %v", i, tt.s, tt.t, got, tt.want)
+ }
+ truth := strings.EqualFold(tt.s, tt.t)
+ if truth != tt.want {
+ t.Errorf("strings.EqualFold doesn't agree with case %d", i)
+ }
+ }
+}
+
+func TestFoldAgainstUnicode(t *testing.T) {
+ const bufSize = 5
+ buf1 := make([]byte, 0, bufSize)
+ buf2 := make([]byte, 0, bufSize)
+ var runes []rune
+ for i := 0x20; i <= 0x7f; i++ {
+ runes = append(runes, rune(i))
+ }
+ runes = append(runes, kelvin, smallLongEss)
+
+ funcs := []struct {
+ name string
+ fold func(s, t []byte) bool
+ letter bool // must be ASCII letter
+ simple bool // must be simple ASCII letter (not 'S' or 'K')
+ }{
+ {
+ name: "equalFoldRight",
+ fold: equalFoldRight,
+ },
+ {
+ name: "asciiEqualFold",
+ fold: asciiEqualFold,
+ simple: true,
+ },
+ {
+ name: "simpleLetterEqualFold",
+ fold: simpleLetterEqualFold,
+ simple: true,
+ letter: true,
+ },
+ }
+
+ for _, ff := range funcs {
+ for _, r := range runes {
+ if r >= utf8.RuneSelf {
+ continue
+ }
+ if ff.letter && !isASCIILetter(byte(r)) {
+ continue
+ }
+ if ff.simple && (r == 's' || r == 'S' || r == 'k' || r == 'K') {
+ continue
+ }
+ for _, r2 := range runes {
+ buf1 := append(buf1[:0], 'x')
+ buf2 := append(buf2[:0], 'x')
+ buf1 = buf1[:1+utf8.EncodeRune(buf1[1:bufSize], r)]
+ buf2 = buf2[:1+utf8.EncodeRune(buf2[1:bufSize], r2)]
+ buf1 = append(buf1, 'x')
+ buf2 = append(buf2, 'x')
+ want := bytes.EqualFold(buf1, buf2)
+ if got := ff.fold(buf1, buf2); got != want {
+ t.Errorf("%s(%q, %q) = %v; want %v", ff.name, buf1, buf2, got, want)
+ }
+ }
+ }
+ }
+}
+
+func isASCIILetter(b byte) bool {
+ return ('A' <= b && b <= 'Z') || ('a' <= b && b <= 'z')
+}
diff --git a/libgo/go/encoding/json/indent.go b/libgo/go/encoding/json/indent.go
index 11ef709cce..e1bacafd6b 100644
--- a/libgo/go/encoding/json/indent.go
+++ b/libgo/go/encoding/json/indent.go
@@ -69,8 +69,9 @@ func newline(dst *bytes.Buffer, prefix, indent string, depth int) {
// Each element in a JSON object or array begins on a new,
// indented line beginning with prefix followed by one or more
// copies of indent according to the indentation nesting.
-// The data appended to dst has no trailing newline, to make it easier
-// to embed inside other formatted JSON data.
+// The data appended to dst does not begin with the prefix nor
+// any indentation, and has no trailing newline, to make it
+// easier to embed inside other formatted JSON data.
func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error {
origLen := dst.Len()
var scan scanner
diff --git a/libgo/go/encoding/json/scanner_test.go b/libgo/go/encoding/json/scanner_test.go
index 90e45ff036..7880342902 100644
--- a/libgo/go/encoding/json/scanner_test.go
+++ b/libgo/go/encoding/json/scanner_test.go
@@ -239,23 +239,16 @@ func trim(b []byte) []byte {
var jsonBig []byte
-const (
- big = 10000
- small = 100
-)
-
func initBig() {
- n := big
+ n := 10000
if testing.Short() {
- n = small
+ n = 100
}
- if len(jsonBig) != n {
- b, err := Marshal(genValue(n))
- if err != nil {
- panic(err)
- }
- jsonBig = b
+ b, err := Marshal(genValue(n))
+ if err != nil {
+ panic(err)
}
+ jsonBig = b
}
func genValue(n int) interface{} {
@@ -296,6 +289,9 @@ func genArray(n int) []interface{} {
if f > n {
f = n
}
+ if f < 1 {
+ f = 1
+ }
x := make([]interface{}, f)
for i := range x {
x[i] = genValue(((i+1)*n)/f - (i*n)/f)
diff --git a/libgo/go/encoding/json/stream.go b/libgo/go/encoding/json/stream.go
index 1928abadb7..9566ecadcb 100644
--- a/libgo/go/encoding/json/stream.go
+++ b/libgo/go/encoding/json/stream.go
@@ -139,7 +139,6 @@ func nonSpace(b []byte) bool {
// An Encoder writes JSON objects to an output stream.
type Encoder struct {
w io.Writer
- e encodeState
err error
}
@@ -148,7 +147,8 @@ func NewEncoder(w io.Writer) *Encoder {
return &Encoder{w: w}
}
-// Encode writes the JSON encoding of v to the stream.
+// Encode writes the JSON encoding of v to the stream,
+// followed by a newline character.
//
// See the documentation for Marshal for details about the
// conversion of Go values to JSON.
@@ -173,7 +173,7 @@ func (enc *Encoder) Encode(v interface{}) error {
if _, err = enc.w.Write(e.Bytes()); err != nil {
enc.err = err
}
- putEncodeState(e)
+ encodeStatePool.Put(e)
return err
}
diff --git a/libgo/go/encoding/xml/marshal.go b/libgo/go/encoding/xml/marshal.go
index d9522e0b39..8c6342013d 100644
--- a/libgo/go/encoding/xml/marshal.go
+++ b/libgo/go/encoding/xml/marshal.go
@@ -184,10 +184,12 @@ var (
// EncodeToken does not call Flush, because usually it is part of a larger operation
// such as Encode or EncodeElement (or a custom Marshaler's MarshalXML invoked
// during those), and those will call Flush when finished.
-//
// Callers that create an Encoder and then invoke EncodeToken directly, without
// using Encode or EncodeElement, need to call Flush when finished to ensure
// that the XML is written to the underlying writer.
+//
+// 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) {
@@ -210,7 +212,12 @@ func (enc *Encoder) EncodeToken(t Token) error {
p.WriteString("-->")
return p.cachedWriteError()
case ProcInst:
- if t.Target == "xml" || !isNameString(t.Target) {
+ // First token to be encoded which is also a ProcInst with target of xml
+ // is the xml declaration. The only ProcInst where target of xml is allowed.
+ if t.Target == "xml" && p.Buffered() != 0 {
+ return fmt.Errorf("xml: EncodeToken of ProcInst xml target only valid for xml declaration, first token encoded")
+ }
+ if !isNameString(t.Target) {
return fmt.Errorf("xml: EncodeToken of ProcInst with invalid Target")
}
if bytes.Contains(t.Inst, endProcInst) {
diff --git a/libgo/go/encoding/xml/marshal_test.go b/libgo/go/encoding/xml/marshal_test.go
index d34118a3d8..14f73a75d5 100644
--- a/libgo/go/encoding/xml/marshal_test.go
+++ b/libgo/go/encoding/xml/marshal_test.go
@@ -314,6 +314,31 @@ type MarshalerStruct struct {
Foo MyMarshalerAttrTest `xml:",attr"`
}
+type InnerStruct struct {
+ XMLName Name `xml:"testns outer"`
+}
+
+type OuterStruct struct {
+ InnerStruct
+ IntAttr int `xml:"int,attr"`
+}
+
+type OuterNamedStruct struct {
+ InnerStruct
+ XMLName Name `xml:"outerns test"`
+ IntAttr int `xml:"int,attr"`
+}
+
+type OuterNamedOrderedStruct struct {
+ XMLName Name `xml:"outerns test"`
+ InnerStruct
+ IntAttr int `xml:"int,attr"`
+}
+
+type OuterOuterStruct struct {
+ OuterStruct
+}
+
func ifaceptr(x interface{}) interface{} {
return &x
}
@@ -883,6 +908,22 @@ var marshalTests = []struct {
ExpectXML: `<MarshalerStruct Foo="hello world"></MarshalerStruct>`,
Value: &MarshalerStruct{},
},
+ {
+ ExpectXML: `<outer xmlns="testns" int="10"></outer>`,
+ Value: &OuterStruct{IntAttr: 10},
+ },
+ {
+ ExpectXML: `<test xmlns="outerns" int="10"></test>`,
+ Value: &OuterNamedStruct{XMLName: Name{Space: "outerns", Local: "test"}, IntAttr: 10},
+ },
+ {
+ ExpectXML: `<test xmlns="outerns" int="10"></test>`,
+ Value: &OuterNamedOrderedStruct{XMLName: Name{Space: "outerns", Local: "test"}, IntAttr: 10},
+ },
+ {
+ ExpectXML: `<outer xmlns="testns" int="10"></outer>`,
+ Value: &OuterOuterStruct{OuterStruct{IntAttr: 10}},
+ },
}
func TestMarshal(t *testing.T) {
@@ -1149,3 +1190,77 @@ func TestStructPointerMarshal(t *testing.T) {
t.Fatal(err)
}
}
+
+var encodeTokenTests = []struct {
+ tok Token
+ want string
+ ok bool
+}{
+ {StartElement{Name{"space", "local"}, nil}, "<local xmlns=\"space\">", true},
+ {StartElement{Name{"space", ""}, nil}, "", false},
+ {EndElement{Name{"space", ""}}, "", false},
+ {CharData("foo"), "foo", true},
+ {Comment("foo"), "<!--foo-->", true},
+ {Comment("foo-->"), "", false},
+ {ProcInst{"Target", []byte("Instruction")}, "<?Target Instruction?>", true},
+ {ProcInst{"", []byte("Instruction")}, "", false},
+ {ProcInst{"Target", []byte("Instruction?>")}, "", false},
+ {Directive("foo"), "<!foo>", true},
+ {Directive("foo>"), "", false},
+}
+
+func TestEncodeToken(t *testing.T) {
+ for _, tt := range encodeTokenTests {
+ var buf bytes.Buffer
+ enc := NewEncoder(&buf)
+ err := enc.EncodeToken(tt.tok)
+ 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
+ }
+ if err := enc.Flush(); err != nil {
+ t.Fatalf("enc.EncodeToken: %v", err)
+ }
+ if got := buf.String(); got != tt.want {
+ t.Errorf("enc.EncodeToken = %s; want: %s", got, tt.want)
+ }
+ }
+}
+
+func TestProcInstEncodeToken(t *testing.T) {
+ var buf bytes.Buffer
+ enc := NewEncoder(&buf)
+
+ if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err != nil {
+ t.Fatalf("enc.EncodeToken: expected to be able to encode xml target ProcInst as first token, %s", err)
+ }
+
+ if err := enc.EncodeToken(ProcInst{"Target", []byte("Instruction")}); err != nil {
+ t.Fatalf("enc.EncodeToken: expected to be able to add non-xml target ProcInst")
+ }
+
+ if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err == nil {
+ t.Fatalf("enc.EncodeToken: expected to not be allowed to encode xml target ProcInst when not first token")
+ }
+}
+
+func TestDecodeEncode(t *testing.T) {
+ var in, out bytes.Buffer
+ in.WriteString(`<?xml version="1.0" encoding="UTF-8"?>
+<?Target Instruction?>
+<root>
+</root>
+`)
+ dec := NewDecoder(&in)
+ enc := NewEncoder(&out)
+ for tok, err := dec.Token(); err == nil; tok, err = dec.Token() {
+ err = enc.EncodeToken(tok)
+ if err != nil {
+ t.Fatalf("enc.EncodeToken: Unable to encode token (%#v), %v", tok, err)
+ }
+ }
+}
diff --git a/libgo/go/encoding/xml/read.go b/libgo/go/encoding/xml/read.go
index 8890508f85..75b9f2ba1b 100644
--- a/libgo/go/encoding/xml/read.go
+++ b/libgo/go/encoding/xml/read.go
@@ -112,7 +112,7 @@ import (
// to a freshly allocated value and then mapping the element to that value.
//
func Unmarshal(data []byte, v interface{}) error {
- return NewDecoder(bytes.NewBuffer(data)).Decode(v)
+ return NewDecoder(bytes.NewReader(data)).Decode(v)
}
// Decode works like xml.Unmarshal, except it reads the decoder
@@ -284,6 +284,15 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
}
}
+ // Load value from interface, but only if the result will be
+ // usefully addressable.
+ if val.Kind() == reflect.Interface && !val.IsNil() {
+ e := val.Elem()
+ if e.Kind() == reflect.Ptr && !e.IsNil() {
+ val = e
+ }
+ }
+
if val.Kind() == reflect.Ptr {
if val.IsNil() {
val.Set(reflect.New(val.Type().Elem()))
diff --git a/libgo/go/encoding/xml/read_test.go b/libgo/go/encoding/xml/read_test.go
index 1404c900f5..01f55d0dd0 100644
--- a/libgo/go/encoding/xml/read_test.go
+++ b/libgo/go/encoding/xml/read_test.go
@@ -685,3 +685,30 @@ func TestUnmarshaler(t *testing.T) {
t.Errorf("m=%#+v\n", m)
}
}
+
+type Pea struct {
+ Cotelydon string
+}
+
+type Pod struct {
+ Pea interface{} `xml:"Pea"`
+}
+
+// https://code.google.com/p/go/issues/detail?id=6836
+func TestUnmarshalIntoInterface(t *testing.T) {
+ pod := new(Pod)
+ pod.Pea = new(Pea)
+ xml := `<Pod><Pea><Cotelydon>Green stuff</Cotelydon></Pea></Pod>`
+ err := Unmarshal([]byte(xml), pod)
+ if err != nil {
+ t.Fatalf("failed to unmarshal %q: %v", xml, err)
+ }
+ pea, ok := pod.Pea.(*Pea)
+ if !ok {
+ t.Fatalf("unmarshalled into wrong type: have %T want *Pea", pod.Pea)
+ }
+ have, want := pea.Cotelydon, "Green stuff"
+ if have != want {
+ t.Errorf("failed to unmarshal into interface, have %q want %q", have, want)
+ }
+}
diff --git a/libgo/go/encoding/xml/typeinfo.go b/libgo/go/encoding/xml/typeinfo.go
index 83e65402c0..22248d20a6 100644
--- a/libgo/go/encoding/xml/typeinfo.go
+++ b/libgo/go/encoding/xml/typeinfo.go
@@ -75,6 +75,9 @@ func getTypeInfo(typ reflect.Type) (*typeInfo, error) {
if err != nil {
return nil, err
}
+ if tinfo.xmlname == nil {
+ tinfo.xmlname = inner.xmlname
+ }
for _, finfo := range inner.fields {
finfo.idx = append([]int{i}, finfo.idx...)
if err := addFieldInfo(typ, tinfo, &finfo); err != nil {
diff --git a/libgo/go/encoding/xml/xml.go b/libgo/go/encoding/xml/xml.go
index 5b9d670024..8c15b98c3a 100644
--- a/libgo/go/encoding/xml/xml.go
+++ b/libgo/go/encoding/xml/xml.go
@@ -196,10 +196,13 @@ type Decoder struct {
ns map[string]string
err error
line int
+ offset int64
unmarshalDepth int
}
// NewDecoder creates a new XML parser reading from r.
+// If r does not implement io.ByteReader, NewDecoder will
+// do its own buffering.
func NewDecoder(r io.Reader) *Decoder {
d := &Decoder{
ns: make(map[string]string),
@@ -857,9 +860,17 @@ func (d *Decoder) getc() (b byte, ok bool) {
if b == '\n' {
d.line++
}
+ d.offset++
return b, true
}
+// InputOffset returns the input stream byte offset of the current decoder position.
+// The offset gives the location of the end of the most recently returned token
+// and the beginning of the next token.
+func (d *Decoder) InputOffset() int64 {
+ return d.offset
+}
+
// Return saved offset.
// If we did ungetc (nextByte >= 0), have to back up one.
func (d *Decoder) savedOffset() int {
@@ -889,6 +900,7 @@ func (d *Decoder) ungetc(b byte) {
d.line--
}
d.nextByte = int(b)
+ d.offset--
}
var entity = map[string]int{
diff --git a/libgo/go/encoding/xml/xml_test.go b/libgo/go/encoding/xml/xml_test.go
index 7723ab1c9f..be995c0d52 100644
--- a/libgo/go/encoding/xml/xml_test.go
+++ b/libgo/go/encoding/xml/xml_test.go
@@ -170,7 +170,7 @@ var xmlInput = []string{
func TestRawToken(t *testing.T) {
d := NewDecoder(strings.NewReader(testInput))
d.Entity = testEntity
- testRawToken(t, d, rawTokens)
+ testRawToken(t, d, testInput, rawTokens)
}
const nonStrictInput = `
@@ -225,7 +225,7 @@ var nonStrictTokens = []Token{
func TestNonStrictRawToken(t *testing.T) {
d := NewDecoder(strings.NewReader(nonStrictInput))
d.Strict = false
- testRawToken(t, d, nonStrictTokens)
+ testRawToken(t, d, nonStrictInput, nonStrictTokens)
}
type downCaser struct {
@@ -254,7 +254,7 @@ func TestRawTokenAltEncoding(t *testing.T) {
}
return &downCaser{t, input.(io.ByteReader)}, nil
}
- testRawToken(t, d, rawTokensAltEncoding)
+ testRawToken(t, d, testInputAltEncoding, rawTokensAltEncoding)
}
func TestRawTokenAltEncodingNoConverter(t *testing.T) {
@@ -280,9 +280,12 @@ func TestRawTokenAltEncodingNoConverter(t *testing.T) {
}
}
-func testRawToken(t *testing.T, d *Decoder, rawTokens []Token) {
+func testRawToken(t *testing.T, d *Decoder, raw string, rawTokens []Token) {
+ lastEnd := int64(0)
for i, want := range rawTokens {
+ start := d.InputOffset()
have, err := d.RawToken()
+ end := d.InputOffset()
if err != nil {
t.Fatalf("token %d: unexpected error: %s", i, err)
}
@@ -300,6 +303,26 @@ func testRawToken(t *testing.T, d *Decoder, rawTokens []Token) {
}
t.Errorf("token %d = %s, want %s", i, shave, swant)
}
+
+ // Check that InputOffset returned actual token.
+ switch {
+ case start < lastEnd:
+ t.Errorf("token %d: position [%d,%d) for %T is before previous token", i, start, end, have)
+ case start >= end:
+ // Special case: EndElement can be synthesized.
+ if start == end && end == lastEnd {
+ break
+ }
+ t.Errorf("token %d: position [%d,%d) for %T is empty", i, start, end, have)
+ case end > int64(len(raw)):
+ t.Errorf("token %d: position [%d,%d) for %T extends beyond input", i, start, end, have)
+ default:
+ text := raw[start:end]
+ if strings.ContainsAny(text, "<>") && (!strings.HasPrefix(text, "<") || !strings.HasSuffix(text, ">")) {
+ t.Errorf("token %d: misaligned raw token %#q for %T", i, text, have)
+ }
+ }
+ lastEnd = end
}
}
diff --git a/libgo/go/expvar/expvar.go b/libgo/go/expvar/expvar.go
index b06599505f..9b6dab487c 100644
--- a/libgo/go/expvar/expvar.go
+++ b/libgo/go/expvar/expvar.go
@@ -29,6 +29,7 @@ import (
"net/http"
"os"
"runtime"
+ "sort"
"strconv"
"sync"
)
@@ -40,8 +41,8 @@ type Var interface {
// Int is a 64-bit integer variable that satisfies the Var interface.
type Int struct {
- i int64
mu sync.RWMutex
+ i int64
}
func (v *Int) String() string {
@@ -64,8 +65,8 @@ func (v *Int) Set(value int64) {
// Float is a 64-bit float variable that satisfies the Var interface.
type Float struct {
- f float64
mu sync.RWMutex
+ f float64
}
func (v *Float) String() string {
@@ -90,8 +91,9 @@ func (v *Float) Set(value float64) {
// Map is a string-to-Var map variable that satisfies the Var interface.
type Map struct {
- m map[string]Var
- mu sync.RWMutex
+ mu sync.RWMutex
+ m map[string]Var
+ keys []string // sorted
}
// KeyValue represents a single entry in a Map.
@@ -106,13 +108,13 @@ func (v *Map) String() string {
var b bytes.Buffer
fmt.Fprintf(&b, "{")
first := true
- for key, val := range v.m {
+ v.doLocked(func(kv KeyValue) {
if !first {
fmt.Fprintf(&b, ", ")
}
- fmt.Fprintf(&b, "\"%s\": %v", key, val)
+ fmt.Fprintf(&b, "%q: %v", kv.Key, kv.Value)
first = false
- }
+ })
fmt.Fprintf(&b, "}")
return b.String()
}
@@ -122,6 +124,20 @@ func (v *Map) Init() *Map {
return v
}
+// updateKeys updates the sorted list of keys in v.keys.
+// must be called with v.mu held.
+func (v *Map) updateKeys() {
+ if len(v.m) == len(v.keys) {
+ // No new key.
+ return
+ }
+ v.keys = v.keys[:0]
+ for k := range v.m {
+ v.keys = append(v.keys, k)
+ }
+ sort.Strings(v.keys)
+}
+
func (v *Map) Get(key string) Var {
v.mu.RLock()
defer v.mu.RUnlock()
@@ -132,6 +148,7 @@ func (v *Map) Set(key string, av Var) {
v.mu.Lock()
defer v.mu.Unlock()
v.m[key] = av
+ v.updateKeys()
}
func (v *Map) Add(key string, delta int64) {
@@ -141,9 +158,11 @@ func (v *Map) Add(key string, delta int64) {
if !ok {
// check again under the write lock
v.mu.Lock()
- if _, ok = v.m[key]; !ok {
+ av, ok = v.m[key]
+ if !ok {
av = new(Int)
v.m[key] = av
+ v.updateKeys()
}
v.mu.Unlock()
}
@@ -162,9 +181,11 @@ func (v *Map) AddFloat(key string, delta float64) {
if !ok {
// check again under the write lock
v.mu.Lock()
- if _, ok = v.m[key]; !ok {
+ av, ok = v.m[key]
+ if !ok {
av = new(Float)
v.m[key] = av
+ v.updateKeys()
}
v.mu.Unlock()
}
@@ -181,15 +202,21 @@ func (v *Map) AddFloat(key string, delta float64) {
func (v *Map) Do(f func(KeyValue)) {
v.mu.RLock()
defer v.mu.RUnlock()
- for k, v := range v.m {
- f(KeyValue{k, v})
+ v.doLocked(f)
+}
+
+// doLocked calls f for each entry in the map.
+// v.mu must be held for reads.
+func (v *Map) doLocked(f func(KeyValue)) {
+ for _, k := range v.keys {
+ f(KeyValue{k, v.m[k]})
}
}
// String is a string variable, and satisfies the Var interface.
type String struct {
- s string
mu sync.RWMutex
+ s string
}
func (v *String) String() string {
@@ -215,8 +242,9 @@ func (f Func) String() string {
// All published variables.
var (
- mutex sync.RWMutex
- vars map[string]Var = make(map[string]Var)
+ mutex sync.RWMutex
+ vars = make(map[string]Var)
+ varKeys []string // sorted
)
// Publish declares a named exported variable. This should be called from a
@@ -229,6 +257,8 @@ func Publish(name string, v Var) {
log.Panicln("Reuse of exported var name:", name)
}
vars[name] = v
+ varKeys = append(varKeys, name)
+ sort.Strings(varKeys)
}
// Get retrieves a named exported variable.
@@ -270,8 +300,8 @@ func NewString(name string) *String {
func Do(f func(KeyValue)) {
mutex.RLock()
defer mutex.RUnlock()
- for k, v := range vars {
- f(KeyValue{k, v})
+ for _, k := range varKeys {
+ f(KeyValue{k, vars[k]})
}
}
diff --git a/libgo/go/expvar/expvar_test.go b/libgo/go/expvar/expvar_test.go
index 572c62beed..765e3b757e 100644
--- a/libgo/go/expvar/expvar_test.go
+++ b/libgo/go/expvar/expvar_test.go
@@ -5,7 +5,10 @@
package expvar
import (
+ "bytes"
"encoding/json"
+ "net/http/httptest"
+ "strconv"
"testing"
)
@@ -15,6 +18,7 @@ func RemoveAll() {
mutex.Lock()
defer mutex.Unlock()
vars = make(map[string]Var)
+ varKeys = nil
}
func TestInt(t *testing.T) {
@@ -93,15 +97,15 @@ func TestMapCounter(t *testing.T) {
colors.Add("red", 1)
colors.Add("red", 2)
colors.Add("blue", 4)
- colors.AddFloat("green", 4.125)
+ colors.AddFloat(`green "midori"`, 4.125)
if x := colors.m["red"].(*Int).i; x != 3 {
t.Errorf("colors.m[\"red\"] = %v, want 3", x)
}
if x := colors.m["blue"].(*Int).i; x != 4 {
t.Errorf("colors.m[\"blue\"] = %v, want 4", x)
}
- if x := colors.m["green"].(*Float).f; x != 4.125 {
- t.Errorf("colors.m[\"green\"] = %v, want 3.14", x)
+ if x := colors.m[`green "midori"`].(*Float).f; x != 4.125 {
+ t.Errorf("colors.m[`green \"midori\"] = %v, want 3.14", x)
}
// colors.String() should be '{"red":3, "blue":4}',
@@ -139,3 +143,25 @@ func TestFunc(t *testing.T) {
t.Errorf(`f.String() = %q, want %q`, s, exp)
}
}
+
+func TestHandler(t *testing.T) {
+ RemoveAll()
+ m := NewMap("map1")
+ m.Add("a", 1)
+ m.Add("z", 2)
+ m2 := NewMap("map2")
+ for i := 0; i < 9; i++ {
+ m2.Add(strconv.Itoa(i), int64(i))
+ }
+ rr := httptest.NewRecorder()
+ rr.Body = new(bytes.Buffer)
+ expvarHandler(rr, nil)
+ want := `{
+"map1": {"a": 1, "z": 2},
+"map2": {"0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8}
+}
+`
+ if got := rr.Body.String(); got != want {
+ t.Errorf("HTTP handler wrote:\n%s\nWant:\n%s", got, want)
+ }
+}
diff --git a/libgo/go/flag/flag.go b/libgo/go/flag/flag.go
index e7c863ee92..60aef5d806 100644
--- a/libgo/go/flag/flag.go
+++ b/libgo/go/flag/flag.go
@@ -50,7 +50,8 @@
("-" is a non-flag argument) or after the terminator "--".
Integer flags accept 1234, 0664, 0x1234 and may be negative.
- Boolean flags may be 1, 0, t, f, true, false, TRUE, FALSE, True, False.
+ Boolean flags may be:
+ 1, 0, t, f, T, F, true, false, TRUE, FALSE, True, False
Duration flags accept any input valid for time.ParseDuration.
The default set of command-line flags is controlled by
@@ -72,7 +73,8 @@ import (
"time"
)
-// ErrHelp is the error returned if the flag -help is invoked but no such flag is defined.
+// ErrHelp is the error returned if the -help or -h flag is invoked
+// but no such flag is defined.
var ErrHelp = errors.New("flag: help requested")
// -- bool Value
@@ -269,7 +271,6 @@ type FlagSet struct {
actual map[string]*Flag
formal map[string]*Flag
args []string // arguments after flags
- exitOnError bool // does the program exit if there's an error?
errorHandling ErrorHandling
output io.Writer // nil means stderr; use out() accessor
}
@@ -405,6 +406,7 @@ func defaultUsage(f *FlagSet) {
// for how to write your own usage function.
// Usage prints to standard error a usage message documenting all defined command-line flags.
+// It is called when an error occurs while parsing flags.
// The function is a variable that may be changed to point to a custom function.
var Usage = func() {
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
@@ -628,18 +630,21 @@ func Float64(name string, value float64, usage string) *float64 {
// DurationVar defines a time.Duration flag with specified name, default value, and usage string.
// The argument p points to a time.Duration variable in which to store the value of the flag.
+// The flag accepts a value acceptable to time.ParseDuration.
func (f *FlagSet) DurationVar(p *time.Duration, name string, value time.Duration, usage string) {
f.Var(newDurationValue(value, p), name, usage)
}
// DurationVar defines a time.Duration flag with specified name, default value, and usage string.
// The argument p points to a time.Duration variable in which to store the value of the flag.
+// The flag accepts a value acceptable to time.ParseDuration.
func DurationVar(p *time.Duration, name string, value time.Duration, usage string) {
CommandLine.Var(newDurationValue(value, p), name, usage)
}
// Duration defines a time.Duration flag with specified name, default value, and usage string.
// The return value is the address of a time.Duration variable that stores the value of the flag.
+// The flag accepts a value acceptable to time.ParseDuration.
func (f *FlagSet) Duration(name string, value time.Duration, usage string) *time.Duration {
p := new(time.Duration)
f.DurationVar(p, name, value, usage)
@@ -648,6 +653,7 @@ func (f *FlagSet) Duration(name string, value time.Duration, usage string) *time
// Duration defines a time.Duration flag with specified name, default value, and usage string.
// The return value is the address of a time.Duration variable that stores the value of the flag.
+// The flag accepts a value acceptable to time.ParseDuration.
func Duration(name string, value time.Duration, usage string) *time.Duration {
return CommandLine.Duration(name, value, usage)
}
@@ -697,13 +703,15 @@ func (f *FlagSet) failf(format string, a ...interface{}) error {
return err
}
-// usage calls the Usage method for the flag set, or the usage function if
-// the flag set is CommandLine.
+// usage calls the Usage method for the flag set if one is specified,
+// or the appropriate default usage function otherwise.
func (f *FlagSet) usage() {
- if f == CommandLine {
- Usage()
- } else if f.Usage == nil {
- defaultUsage(f)
+ if f.Usage == nil {
+ if f == CommandLine {
+ Usage()
+ } else {
+ defaultUsage(f)
+ }
} else {
f.Usage()
}
@@ -752,10 +760,11 @@ func (f *FlagSet) parseOne() (bool, error) {
}
return false, f.failf("flag provided but not defined: -%s", name)
}
+
if fv, ok := flag.Value.(boolFlag); ok && fv.IsBoolFlag() { // special case: doesn't need an arg
if has_value {
if err := fv.Set(value); err != nil {
- return false, f.failf("invalid boolean value %q for -%s: %v", value, name, err)
+ return false, f.failf("invalid boolean value %q for -%s: %v", value, name, err)
}
} else {
fv.Set("true")
@@ -784,7 +793,7 @@ func (f *FlagSet) parseOne() (bool, error) {
// Parse parses flag definitions from the argument list, which should not
// include the command name. Must be called after all flags in the FlagSet
// are defined and before flags are accessed by the program.
-// The return value will be ErrHelp if -help was set but not defined.
+// The return value will be ErrHelp if -help or -h were set but not defined.
func (f *FlagSet) Parse(arguments []string) error {
f.parsed = true
f.args = arguments
@@ -826,7 +835,7 @@ func Parsed() bool {
}
// CommandLine is the default set of command-line flags, parsed from os.Args.
-// The top-level functions such as BoolVar, Arg, and on are wrappers for the
+// The top-level functions such as BoolVar, Arg, and so on are wrappers for the
// methods of CommandLine.
var CommandLine = NewFlagSet(os.Args[0], ExitOnError)
diff --git a/libgo/go/flag/flag_test.go b/libgo/go/flag/flag_test.go
index 2c03872697..8c88c8c274 100644
--- a/libgo/go/flag/flag_test.go
+++ b/libgo/go/flag/flag_test.go
@@ -251,6 +251,16 @@ func TestUserDefined(t *testing.T) {
}
}
+func TestUserDefinedForCommandLine(t *testing.T) {
+ const help = "HELP"
+ var result string
+ ResetForTesting(func() { result = help })
+ Usage()
+ if result != help {
+ t.Fatalf("got %q; expected %q", result, help)
+ }
+}
+
// Declare a user-defined boolean flag type.
type boolFlagVar struct {
count int
diff --git a/libgo/go/fmt/doc.go b/libgo/go/fmt/doc.go
index 095fd03b23..ee54463e27 100644
--- a/libgo/go/fmt/doc.go
+++ b/libgo/go/fmt/doc.go
@@ -13,7 +13,7 @@
The verbs:
General:
- %v the value in a default format.
+ %v the value in a default format
when printing structs, the plus flag (%+v) adds field names
%#v a Go-syntax representation of the value
%T a Go-syntax representation of the type of the value
@@ -37,8 +37,9 @@
%e scientific notation, e.g. -1234.456e+78
%E scientific notation, e.g. -1234.456E+78
%f decimal point but no exponent, e.g. 123.456
- %g whichever of %e or %f produces more compact output
- %G whichever of %E or %f produces more compact output
+ %F synonym for %f
+ %g %e for large exponents, %f otherwise
+ %G %E for large exponents, %F otherwise
String and slice of bytes:
%s the uninterpreted bytes of the string or slice
%q a double-quoted string safely escaped with Go syntax
@@ -50,23 +51,58 @@
There is no 'u' flag. Integers are printed unsigned if they have unsigned type.
Similarly, there is no need to specify the size of the operand (int8, int64).
- The width and precision control formatting and are in units of Unicode
- code points. (This differs from C's printf where the units are numbers
- of bytes.) Either or both of the flags may be replaced with the
- character '*', causing their values to be obtained from the next
- operand, which must be of type int.
+ The default format for %v is:
+ bool: %t
+ int, int8 etc.: %d
+ uint, uint8 etc.: %d, %x if printed with %#v
+ float32, complex64, etc: %g
+ string: %s
+ chan: %p
+ pointer: %p
+ For compound objects, the elements are printed using these rules, recursively,
+ laid out like this:
+ struct: {field0 field1 ...}
+ array, slice: [elem0 elem1 ...]
+ maps: map[key1:value1 key2:value2]
+ pointer to above: &{}, &[], &map[]
+
+ Width is specified by an optional decimal number immediately following the verb.
+ If absent, the width is whatever is necessary to represent the value.
+ Precision is specified after the (optional) width by a period followed by a
+ 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
+ %9f width 9, default precision
+ %.2f default width, precision 2
+ %9.2f width 9, precision 2
+ %9.f width 9, precision 0
+
+ Width and precision are measured in units of Unicode code points,
+ that is, runes. (This differs from C's printf where the
+ units are always measured in bytes.) Either or both of the flags
+ may be replaced with the character '*', causing their values to be
+ obtained from the next operand, which must be of type int.
+
+ For most values, width is the minimum number of runes to output,
+ padding the formatted form with spaces if necessary.
+
+ For strings, byte slices and byte arrays, however, precision
+ limits the length of the input to be formatted (not the size of
+ the output), truncating if necessary. Normally it is measured in
+ runes, but for these types when formatted with the %x or %X format
+ it is measured in bytes.
- For numeric values, width sets the minimum width of the field and
+ For floating-point values, width sets the minimum width of the field and
precision sets the number of places after the decimal, if appropriate,
except that for %g/%G it sets the total number of digits. For example,
given 123.45 the format %6.2f prints 123.45 while %.4g prints 123.5.
The default precision for %e and %f is 6; for %g it is the smallest
number of digits necessary to identify the value uniquely.
- For most values, width is the minimum number of characters to output,
- padding the formatted form with spaces if necessary.
- For strings, precision is the maximum number of characters to output,
- truncating if necessary.
+ For complex numbers, the width and precision apply to the two
+ components independently and the result is parenthesized, so %f applied
+ to 1.2+3.4i produces (1.200000+3.400000i).
Other flags:
+ always print a sign for numeric values;
@@ -98,25 +134,42 @@
fmt.Printf("%v\n", i)
will print 23.
- If an operand implements interface Formatter, that interface
- can be used for fine control of formatting.
+ Except when printed using the verbs %T and %p, special
+ formatting considerations apply for operands that implement
+ certain interfaces. In order of application:
+
+ 1. 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
+ 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 also apply:
+ for a string (%s %q %v %x %X), the following two rules apply:
- 1. If an operand implements the error interface, the Error method
- will be used to convert the object to a string, which will then
+ 3. 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).
- 2. If an operand implements method String() string, that method
- will be used to convert the object to a string, which will then
+ 4. 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).
+ For compound operands such as slices and structs, the format
+ applies to the elements of each operand, recursively, not to the
+ operand as a whole. Thus %q will quote each element of a slice
+ of strings, and %6.2f will control formatting for each element
+ of a floating-point array.
+
To avoid recursion in cases such as
type X string
func (x X) String() string { return Sprintf("<%s>", x) }
convert the value before recurring:
func (x X) String() string { return Sprintf("<%s>", string(x)) }
+ Infinite recursion can also be triggered by self-referential data
+ structures, such as a slice that contains itself as an element, if
+ that type has a String method. Such pathologies are rare, however,
+ and the package does not protect against them.
Explicit argument indexes:
@@ -130,7 +183,7 @@
For example,
fmt.Sprintf("%[2]d %[1]d\n", 11, 22)
- will yield "22, 11", while
+ will yield "22 11", while
fmt.Sprintf("%[3]*.[2]*[1]f", 12.0, 2, 6),
equivalent to
fmt.Sprintf("%6.2f", 12.0),
diff --git a/libgo/go/fmt/fmt_test.go b/libgo/go/fmt/fmt_test.go
index bbca2c574b..ccd8090477 100644
--- a/libgo/go/fmt/fmt_test.go
+++ b/libgo/go/fmt/fmt_test.go
@@ -108,6 +108,20 @@ func (p *P) String() string {
var barray = [5]renamedUint8{1, 2, 3, 4, 5}
var bslice = barray[:]
+type byteStringer byte
+
+func (byteStringer) String() string { return "X" }
+
+var byteStringerSlice = []byteStringer{97, 98, 99, 100}
+
+type byteFormatter byte
+
+func (byteFormatter) Format(f State, _ rune) {
+ Fprint(f, "X")
+}
+
+var byteFormatterSlice = []byteFormatter{97, 98, 99, 100}
+
var b byte
var fmtTests = []struct {
@@ -125,13 +139,17 @@ var fmtTests = []struct {
{"%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"},
// basic bytes
{"%s", []byte("abc"), "abc"},
{"%x", []byte("abc"), "616263"},
{"% x", []byte("abc\xff"), "61 62 63 ff"},
- {"%#x", []byte("abc\xff"), "0x610x620x630xff"},
- {"%#X", []byte("abc\xff"), "0X610X620X630XFF"},
+ {"%#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"},
@@ -176,9 +194,18 @@ var fmtTests = []struct {
{"%.5s", "日本語日本語", "日本語日本"},
{"%.5s", []byte("日本語日本語"), "日本語日本"},
{"%.5q", "abcdefghijklmnopqrstuvwxyz", `"abcde"`},
+ {"%.5x", "abcdefghijklmnopqrstuvwxyz", `6162636465`},
+ {"%.5q", []byte("abcdefghijklmnopqrstuvwxyz"), `"abcde"`},
+ {"%.5x", []byte("abcdefghijklmnopqrstuvwxyz"), `6162636465`},
{"%.3q", "日本語日本語", `"日本語"`},
{"%.3q", []byte("日本語日本語"), `"日本語"`},
+ {"%.1q", "日本語", `"日"`},
+ {"%.1q", []byte("日本語"), `"日"`},
+ {"%.1x", "日本語", `e6`},
+ {"%.1X", []byte("日本語"), `E6`},
{"%10.1q", "日本語日本語", ` "日"`},
+ {"%3c", '⌘', " ⌘"},
+ {"%5q", '\u2026', ` '…'`},
{"%10v", nil, " <nil>"},
{"%-10v", nil, "<nil> "},
@@ -220,6 +247,12 @@ var fmtTests = []struct {
{"%+.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"},
@@ -239,6 +272,8 @@ var fmtTests = []struct {
{"%+.3g", 1 + 2i, "(+1+2i)"},
{"%.3e", 0i, "(0.000e+00+0.000e+00i)"},
{"%.3f", 0i, "(0.000+0.000i)"},
+ {"%.3F", 0i, "(0.000+0.000i)"},
+ {"%.3F", complex64(0i), "(0.000+0.000i)"},
{"%.3g", 0i, "(0+0i)"},
{"%.3e", 1 + 2i, "(1.000e+00+2.000e+00i)"},
{"%.3f", 1 + 2i, "(1.000+2.000i)"},
@@ -371,7 +406,7 @@ var fmtTests = []struct {
{"%s", I(23), `<23>`},
{"%q", I(23), `"<23>"`},
{"%x", I(23), `3c32333e`},
- {"%#x", I(23), `0x3c0x320x330x3e`},
+ {"%#x", I(23), `0x3c32333e`},
{"%# x", I(23), `0x3c 0x32 0x33 0x3e`},
{"%d", I(23), `23`}, // Stringer applies only to string formats.
@@ -397,6 +432,8 @@ var fmtTests = []struct {
{"%#v", "foo", `"foo"`},
{"%#v", barray, `[5]fmt_test.renamedUint8{0x1, 0x2, 0x3, 0x4, 0x5}`},
{"%#v", bslice, `[]fmt_test.renamedUint8{0x1, 0x2, 0x3, 0x4, 0x5}`},
+ {"%#v", []byte(nil), "[]byte(nil)"},
+ {"%#v", []int32(nil), "[]int32(nil)"},
// slices with other formats
{"%#x", []int{1, 2, 15}, `[0x1 0x2 0xf]`},
@@ -495,18 +532,85 @@ var fmtTests = []struct {
{"%v", map[float64]int{math.NaN(): 1, math.NaN(): 2}, "map[NaN:<nil> NaN:<nil>]"},
// Used to crash because nByte didn't allow for a sign.
- {"%b", int64(-1 << 63), "-1000000000000000000000000000000000000000000000000000000000000000"},
+ {"%b", int64(-1 << 63), zeroFill("-1", 63, "")},
// Used to panic.
- {"%0100d", 1, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"},
- {"%0100d", -1, "-000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"},
- {"%0.100f", 1.0, "1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},
- {"%0.100f", -1.0, "-1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},
+ {"%0100d", 1, zeroFill("", 100, "1")},
+ {"%0100d", -1, zeroFill("-", 99, "1")},
+ {"%0.100f", 1.0, zeroFill("1.", 100, "")},
+ {"%0.100f", -1.0, zeroFill("-1.", 100, "")},
+
+ // Comparison of padding rules with C printf.
+ /*
+ C program:
+ #include <stdio.h>
+
+ char *format[] = {
+ "[%.2f]",
+ "[% .2f]",
+ "[%+.2f]",
+ "[%7.2f]",
+ "[% 7.2f]",
+ "[%+7.2f]",
+ "[%07.2f]",
+ "[% 07.2f]",
+ "[%+07.2f]",
+ };
+
+ int main(void) {
+ int i;
+ for(i = 0; i < 9; i++) {
+ printf("%s: ", format[i]);
+ printf(format[i], 1.0);
+ printf(" ");
+ printf(format[i], -1.0);
+ printf("\n");
+ }
+ }
- // Zero padding floats used to put the minus sign in the middle.
- {"%020f", -1.0, "-000000000001.000000"},
+ Output:
+ [%.2f]: [1.00] [-1.00]
+ [% .2f]: [ 1.00] [-1.00]
+ [%+.2f]: [+1.00] [-1.00]
+ [%7.2f]: [ 1.00] [ -1.00]
+ [% 7.2f]: [ 1.00] [ -1.00]
+ [%+7.2f]: [ +1.00] [ -1.00]
+ [%07.2f]: [0001.00] [-001.00]
+ [% 07.2f]: [ 001.00] [-001.00]
+ [%+07.2f]: [+001.00] [-001.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"},
+ {"%+.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"},
+
+ // Complex numbers: exhaustively tested in TestComplexFormatting.
+ {"%7.2f", 1 + 2i, "( 1.00 +2.00i)"},
+ {"%+07.2f", -1 - 2i, "(-001.00-002.00i)"},
+ // 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"},
- {"%0100f", -1.0, "-00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.000000"},
+ // Make sure we can handle very large widths.
+ {"%0100f", -1.0, zeroFill("-", 99, "1.000000")},
// Complex fmt used to leave the plus flag set for future entries in the array
// causing +2+0i and +3+0i instead of 2+0i and 3+0i.
@@ -515,6 +619,58 @@ var fmtTests = []struct {
// Incomplete format specification caused crash.
{"%.", 3, "%!.(int=3)"},
+
+ // Used to panic with out-of-bounds for very large numeric representations.
+ // nByte is set to handle one bit per uint64 in %b format, with a negative number.
+ // See issue 6777.
+ {"%#064x", 1, zeroFill("0x", 64, "1")},
+ {"%#064x", -1, zeroFill("-0x", 63, "1")},
+ {"%#064b", 1, zeroFill("", 64, "1")},
+ {"%#064b", -1, zeroFill("-", 63, "1")},
+ {"%#064o", 1, zeroFill("", 64, "1")},
+ {"%#064o", -1, zeroFill("-", 63, "1")},
+ {"%#064d", 1, zeroFill("", 64, "1")},
+ {"%#064d", -1, zeroFill("-", 63, "1")},
+ // Test that we handle the crossover above the size of uint64
+ {"%#072x", 1, zeroFill("0x", 72, "1")},
+ {"%#072x", -1, zeroFill("-0x", 71, "1")},
+ {"%#072b", 1, zeroFill("", 72, "1")},
+ {"%#072b", -1, zeroFill("-", 71, "1")},
+ {"%#072o", 1, zeroFill("", 72, "1")},
+ {"%#072o", -1, zeroFill("-", 71, "1")},
+ {"%#072d", 1, zeroFill("", 72, "1")},
+ {"%#072d", -1, zeroFill("-", 71, "1")},
+
+ // Padding for complex numbers. Has been bad, then fixed, then bad again.
+ {"%+10.2f", +104.66 + 440.51i, "( +104.66 +440.51i)"},
+ {"%+10.2f", -104.66 + 440.51i, "( -104.66 +440.51i)"},
+ {"%+10.2f", +104.66 - 440.51i, "( +104.66 -440.51i)"},
+ {"%+10.2f", -104.66 - 440.51i, "( -104.66 -440.51i)"},
+ {"%+010.2f", +104.66 + 440.51i, "(+000104.66+000440.51i)"},
+ {"%+010.2f", -104.66 + 440.51i, "(-000104.66+000440.51i)"},
+ {"%+010.2f", +104.66 - 440.51i, "(+000104.66-000440.51i)"},
+ {"%+010.2f", -104.66 - 440.51i, "(-000104.66-000440.51i)"},
+
+ // []T where type T is a byte with a Stringer method.
+ {"%v", byteStringerSlice, "[X X X X]"},
+ {"%s", byteStringerSlice, "abcd"},
+ {"%q", byteStringerSlice, "\"abcd\""},
+ {"%x", byteStringerSlice, "61626364"},
+ {"%#v", byteStringerSlice, "[]fmt_test.byteStringer{0x61, 0x62, 0x63, 0x64}"},
+
+ // And the same for Formatter.
+ {"%v", byteFormatterSlice, "[X X X X]"},
+ {"%s", byteFormatterSlice, "abcd"},
+ {"%q", byteFormatterSlice, "\"abcd\""},
+ {"%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}"},
+}
+
+// zeroFill generates zero-filled strings of the specified width. The length
+// of the suffix (but not the prefix) is compensated for in the width calculation.
+func zeroFill(prefix string, width int, suffix string) string {
+ return prefix + strings.Repeat("0", width-len(suffix)) + suffix
}
func TestSprintf(t *testing.T) {
@@ -554,6 +710,50 @@ func TestSprintf(t *testing.T) {
}
}
+// TestComplexFormatting checks that a complex always formats to the same
+// thing as if done by hand with two singleton prints.
+func TestComplexFormatting(t *testing.T) {
+ var yesNo = []bool{true, false}
+ var values = []float64{1, 0, -1, math.Inf(1), math.Inf(-1), math.NaN()}
+ for _, plus := range yesNo {
+ for _, zero := range yesNo {
+ for _, space := range yesNo {
+ for _, char := range "fFeEgG" {
+ realFmt := "%"
+ if zero {
+ realFmt += "0"
+ }
+ if space {
+ realFmt += " "
+ }
+ if plus {
+ realFmt += "+"
+ }
+ realFmt += "10.2"
+ realFmt += string(char)
+ // Imaginary part always has a sign, so force + and ignore space.
+ imagFmt := "%"
+ if zero {
+ imagFmt += "0"
+ }
+ imagFmt += "+"
+ imagFmt += "10.2"
+ imagFmt += string(char)
+ for _, realValue := range values {
+ for _, imagValue := range values {
+ one := Sprintf(realFmt, complex(realValue, imagValue))
+ two := Sprintf("("+realFmt+imagFmt+"i)", realValue, imagValue)
+ if one != two {
+ t.Error(f, one, two)
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
type SE []interface{} // slice of empty; notational compactness.
var reorderTests = []struct {
@@ -604,50 +804,82 @@ func TestReorder(t *testing.T) {
}
func BenchmarkSprintfEmpty(b *testing.B) {
- for i := 0; i < b.N; i++ {
- Sprintf("")
- }
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("")
+ }
+ })
}
func BenchmarkSprintfString(b *testing.B) {
- for i := 0; i < b.N; i++ {
- Sprintf("%s", "hello")
- }
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("%s", "hello")
+ }
+ })
}
func BenchmarkSprintfInt(b *testing.B) {
- for i := 0; i < b.N; i++ {
- Sprintf("%d", 5)
- }
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("%d", 5)
+ }
+ })
}
func BenchmarkSprintfIntInt(b *testing.B) {
- for i := 0; i < b.N; i++ {
- Sprintf("%d %d", 5, 6)
- }
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("%d %d", 5, 6)
+ }
+ })
}
func BenchmarkSprintfPrefixedInt(b *testing.B) {
- for i := 0; i < b.N; i++ {
- Sprintf("This is some meaningless prefix text that needs to be scanned %d", 6)
- }
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("This is some meaningless prefix text that needs to be scanned %d", 6)
+ }
+ })
}
func BenchmarkSprintfFloat(b *testing.B) {
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("%g", 5.23184)
+ }
+ })
+}
+
+func BenchmarkManyArgs(b *testing.B) {
+ b.RunParallel(func(pb *testing.PB) {
+ var buf bytes.Buffer
+ for pb.Next() {
+ buf.Reset()
+ Fprintf(&buf, "%2d/%2d/%2d %d:%d:%d %s %s\n", 3, 4, 5, 11, 12, 13, "hello", "world")
+ }
+ })
+}
+
+func BenchmarkFprintInt(b *testing.B) {
+ var buf bytes.Buffer
for i := 0; i < b.N; i++ {
- Sprintf("%g", 5.23184)
+ buf.Reset()
+ Fprint(&buf, 123456)
}
}
-func BenchmarkManyArgs(b *testing.B) {
+func BenchmarkFprintIntNoAlloc(b *testing.B) {
+ var x interface{} = 123456
var buf bytes.Buffer
for i := 0; i < b.N; i++ {
buf.Reset()
- Fprintf(&buf, "%2d/%2d/%2d %d:%d:%d %s %s\n", 3, 4, 5, 11, 12, 13, "hello", "world")
+ Fprint(&buf, x)
}
}
var mallocBuf bytes.Buffer
+var mallocPointer *int // A pointer so we know the interface value won't allocate.
// gccgo numbers are different because gccgo does not have escape
// analysis yet.
@@ -661,11 +893,13 @@ var mallocTest = []struct {
{5, `Sprintf("%x")`, func() { Sprintf("%x", 7) }},
{5, `Sprintf("%s")`, func() { Sprintf("%s", "hello") }},
{5, `Sprintf("%x %x")`, func() { Sprintf("%x %x", 7, 112) }},
- // For %g we use a float32, not float64, to guarantee passing the argument
- // does not need to allocate memory to store the result in a pointer-sized word.
- {20, `Sprintf("%g")`, func() { Sprintf("%g", float32(3.14159)) }},
- {5, `Fprintf(buf, "%x %x %x")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%x %x %x", 7, 8, 9) }},
+ {20, `Sprintf("%g")`, func() { Sprintf("%g", float32(3.14159)) }}, // TODO: Can this be 1?
{5, `Fprintf(buf, "%s")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%s", "hello") }},
+ // If the interface value doesn't need to allocate, amortized allocation overhead should be zero.
+ {5, `Fprintf(buf, "%x %x %x")`, func() {
+ mallocBuf.Reset()
+ Fprintf(&mallocBuf, "%x %x %x", mallocPointer, mallocPointer, mallocPointer)
+ }},
}
var _ bytes.Buffer
@@ -687,7 +921,7 @@ func TestCountMallocs(t *testing.T) {
type flagPrinter struct{}
-func (*flagPrinter) Format(f State, c rune) {
+func (flagPrinter) Format(f State, c rune) {
s := "%"
for i := 0; i < 128; i++ {
if f.Flag(i) {
@@ -733,11 +967,12 @@ func TestFlagParser(t *testing.T) {
}
func TestStructPrinter(t *testing.T) {
- var s struct {
+ type T struct {
a string
b string
c int
}
+ var s T
s.a = "abc"
s.b = "def"
s.c = 123
@@ -747,15 +982,38 @@ func TestStructPrinter(t *testing.T) {
}{
{"%v", "{abc def 123}"},
{"%+v", "{a:abc b:def c:123}"},
+ {"%#v", `fmt_test.T{a:"abc", b:"def", c:123}`},
}
for _, tt := range tests {
out := Sprintf(tt.fmt, s)
if out != tt.out {
- t.Errorf("Sprintf(%q, &s) = %q, want %q", tt.fmt, out, tt.out)
+ t.Errorf("Sprintf(%q, s) = %#q, want %#q", tt.fmt, out, tt.out)
+ }
+ // The same but with a pointer.
+ out = Sprintf(tt.fmt, &s)
+ if out != "&"+tt.out {
+ t.Errorf("Sprintf(%q, &s) = %#q, want %#q", tt.fmt, out, "&"+tt.out)
}
}
}
+func TestSlicePrinter(t *testing.T) {
+ slice := []int{}
+ s := Sprint(slice)
+ if s != "[]" {
+ t.Errorf("empty slice printed as %q not %q", s, "[]")
+ }
+ slice = []int{1, 2, 3}
+ s = Sprint(slice)
+ if s != "[1 2 3]" {
+ t.Errorf("slice: got %q expected %q", s, "[1 2 3]")
+ }
+ s = Sprint(&slice)
+ if s != "&[1 2 3]" {
+ t.Errorf("&slice: got %q expected %q", s, "&[1 2 3]")
+ }
+}
+
// presentInMap checks map printing using substrings so we don't depend on the
// print order.
func presentInMap(s string, a []string, t *testing.T) {
@@ -782,6 +1040,12 @@ func TestMapPrinter(t *testing.T) {
a := []string{"1:one", "2:two", "3:three"}
presentInMap(Sprintf("%v", m1), a, t)
presentInMap(Sprint(m1), a, t)
+ // Pointer to map prints the same but with initial &.
+ if !strings.HasPrefix(Sprint(&m1), "&") {
+ t.Errorf("no initial & for address of map")
+ }
+ presentInMap(Sprintf("%v", &m1), a, t)
+ presentInMap(Sprint(&m1), a, t)
}
func TestEmptyMap(t *testing.T) {
@@ -912,10 +1176,10 @@ var panictests = []struct {
}
func TestPanics(t *testing.T) {
- for _, tt := range panictests {
+ for i, tt := range panictests {
s := Sprintf(tt.fmt, tt.in)
if s != tt.out {
- t.Errorf("%q: got %q expected %q", tt.fmt, s, tt.out)
+ t.Errorf("%d: %q: got %q expected %q", i, tt.fmt, s, tt.out)
}
}
}
@@ -975,3 +1239,74 @@ func TestNilDoesNotBecomeTyped(t *testing.T) {
t.Errorf("expected:\n\t%q\ngot:\n\t%q", expect, got)
}
}
+
+var formatterFlagTests = []struct {
+ in string
+ val interface{}
+ out string
+}{
+ // scalar values with the (unused by fmt) 'a' verb.
+ {"%a", flagPrinter{}, "[%a]"},
+ {"%-a", flagPrinter{}, "[%-a]"},
+ {"%+a", flagPrinter{}, "[%+a]"},
+ {"%#a", flagPrinter{}, "[%#a]"},
+ {"% a", flagPrinter{}, "[% a]"},
+ {"%0a", flagPrinter{}, "[%0a]"},
+ {"%1.2a", flagPrinter{}, "[%1.2a]"},
+ {"%-1.2a", flagPrinter{}, "[%-1.2a]"},
+ {"%+1.2a", flagPrinter{}, "[%+1.2a]"},
+ {"%-+1.2a", flagPrinter{}, "[%+-1.2a]"},
+ {"%-+1.2abc", flagPrinter{}, "[%+-1.2a]bc"},
+ {"%-1.2abc", flagPrinter{}, "[%-1.2a]bc"},
+
+ // composite values with the 'a' verb
+ {"%a", [1]flagPrinter{}, "[[%a]]"},
+ {"%-a", [1]flagPrinter{}, "[[%-a]]"},
+ {"%+a", [1]flagPrinter{}, "[[%+a]]"},
+ {"%#a", [1]flagPrinter{}, "[[%#a]]"},
+ {"% a", [1]flagPrinter{}, "[[% a]]"},
+ {"%0a", [1]flagPrinter{}, "[[%0a]]"},
+ {"%1.2a", [1]flagPrinter{}, "[[%1.2a]]"},
+ {"%-1.2a", [1]flagPrinter{}, "[[%-1.2a]]"},
+ {"%+1.2a", [1]flagPrinter{}, "[[%+1.2a]]"},
+ {"%-+1.2a", [1]flagPrinter{}, "[[%+-1.2a]]"},
+ {"%-+1.2abc", [1]flagPrinter{}, "[[%+-1.2a]]bc"},
+ {"%-1.2abc", [1]flagPrinter{}, "[[%-1.2a]]bc"},
+
+ // simple values with the 'v' verb
+ {"%v", flagPrinter{}, "[%v]"},
+ {"%-v", flagPrinter{}, "[%-v]"},
+ {"%+v", flagPrinter{}, "[%+v]"},
+ {"%#v", flagPrinter{}, "[%#v]"},
+ {"% v", flagPrinter{}, "[% v]"},
+ {"%0v", flagPrinter{}, "[%0v]"},
+ {"%1.2v", flagPrinter{}, "[%1.2v]"},
+ {"%-1.2v", flagPrinter{}, "[%-1.2v]"},
+ {"%+1.2v", flagPrinter{}, "[%+1.2v]"},
+ {"%-+1.2v", flagPrinter{}, "[%+-1.2v]"},
+ {"%-+1.2vbc", flagPrinter{}, "[%+-1.2v]bc"},
+ {"%-1.2vbc", flagPrinter{}, "[%-1.2v]bc"},
+
+ // composite values with the 'v' verb.
+ {"%v", [1]flagPrinter{}, "[[%v]]"},
+ {"%-v", [1]flagPrinter{}, "[[%-v]]"},
+ {"%+v", [1]flagPrinter{}, "[[%+v]]"},
+ {"%#v", [1]flagPrinter{}, "[1]fmt_test.flagPrinter{[%#v]}"},
+ {"% v", [1]flagPrinter{}, "[[% v]]"},
+ {"%0v", [1]flagPrinter{}, "[[%0v]]"},
+ {"%1.2v", [1]flagPrinter{}, "[[%1.2v]]"},
+ {"%-1.2v", [1]flagPrinter{}, "[[%-1.2v]]"},
+ {"%+1.2v", [1]flagPrinter{}, "[[%+1.2v]]"},
+ {"%-+1.2v", [1]flagPrinter{}, "[[%+-1.2v]]"},
+ {"%-+1.2vbc", [1]flagPrinter{}, "[[%+-1.2v]]bc"},
+ {"%-1.2vbc", [1]flagPrinter{}, "[[%-1.2v]]bc"},
+}
+
+func TestFormatterFlags(t *testing.T) {
+ for _, tt := range formatterFlagTests {
+ s := Sprintf(tt.in, tt.val)
+ if s != tt.out {
+ t.Errorf("Sprintf(%q, %T) = %q, want %q", tt.in, tt.val, s, tt.out)
+ }
+ }
+}
diff --git a/libgo/go/fmt/format.go b/libgo/go/fmt/format.go
index 2e2b0716ed..4d97d1443e 100644
--- a/libgo/go/fmt/format.go
+++ b/libgo/go/fmt/format.go
@@ -5,12 +5,15 @@
package fmt
import (
+ "math"
"strconv"
"unicode/utf8"
)
const (
- nByte = 65 // %b of an int64, plus a sign.
+ // %b of an int64, plus a sign.
+ // Hex can add 0x and we handle it specially.
+ nByte = 65
ldigits = "0123456789abcdef"
udigits = "0123456789ABCDEF"
@@ -31,15 +34,8 @@ func init() {
}
}
-// A fmt is the raw formatter used by Printf etc.
-// It prints into a buffer that must be set up separately.
-type fmt struct {
- intbuf [nByte]byte
- buf *buffer
- // width, precision
- wid int
- prec int
- // flags
+// flags placed in a separate struct for easy clearing.
+type fmtFlags struct {
widPresent bool
precPresent bool
minus bool
@@ -49,20 +45,27 @@ type fmt struct {
unicode bool
uniQuote bool // Use 'x'= prefix for %U if printable.
zero bool
+
+ // For the formats %+v %#v, we set the plusV/sharpV flags
+ // and clear the plus/sharp flags since %+v and %#v are in effect
+ // different, flagless formats set at the top level.
+ plusV bool
+ sharpV bool
+}
+
+// A fmt is the raw formatter used by Printf etc.
+// It prints into a buffer that must be set up separately.
+type fmt struct {
+ intbuf [nByte]byte
+ buf *buffer
+ // width, precision
+ wid int
+ prec int
+ fmtFlags
}
func (f *fmt) clearflags() {
- f.wid = 0
- f.widPresent = false
- f.prec = 0
- f.precPresent = false
- f.minus = false
- f.plus = false
- f.sharp = false
- f.space = false
- f.unicode = false
- f.uniQuote = false
- f.zero = false
+ f.fmtFlags = fmtFlags{}
}
func (f *fmt) init(buf *buffer) {
@@ -111,7 +114,7 @@ func (f *fmt) pad(b []byte) {
f.buf.Write(b)
return
}
- padding, left, right := f.computePadding(len(b))
+ padding, left, right := f.computePadding(utf8.RuneCount(b))
if left > 0 {
f.writePadding(left, padding)
}
@@ -160,9 +163,16 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
}
var buf []byte = f.intbuf[0:]
- if f.widPresent && f.wid > nByte {
- // We're going to need a bigger boat.
- buf = make([]byte, f.wid)
+ if f.widPresent {
+ width := f.wid
+ if base == 16 && f.sharp {
+ // Also adds "0x".
+ width += 2
+ }
+ if width > nByte {
+ // We're going to need a bigger boat.
+ buf = make([]byte, width)
+ }
}
negative := signedness == signed && a < 0
@@ -189,10 +199,36 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
// block but it's not worth the duplication, so ua has 64 bits.
i := len(buf)
ua := uint64(a)
- for ua >= base {
- i--
- buf[i] = digits[ua%base]
- ua /= base
+ // use constants for the division and modulo for more efficient code.
+ // switch cases ordered by popularity.
+ switch base {
+ case 10:
+ for ua >= 10 {
+ i--
+ next := ua / 10
+ buf[i] = byte('0' + ua - next*10)
+ ua = next
+ }
+ case 16:
+ for ua >= 16 {
+ i--
+ buf[i] = digits[ua&0xF]
+ ua >>= 4
+ }
+ case 8:
+ for ua >= 8 {
+ i--
+ buf[i] = byte('0' + ua&7)
+ ua >>= 3
+ }
+ case 2:
+ for ua >= 2 {
+ i--
+ buf[i] = byte('0' + ua&1)
+ ua >>= 1
+ }
+ default:
+ panic("fmt: unknown base; can't happen")
}
i--
buf[i] = digits[ua]
@@ -288,7 +324,7 @@ func (f *fmt) fmt_sbx(s string, b []byte, digits string) {
if i > 0 && f.space {
buf = append(buf, ' ')
}
- if f.sharp {
+ if f.sharp && (f.space || i == 0) {
buf = append(buf, '0', x)
}
var c byte
@@ -304,11 +340,17 @@ func (f *fmt) fmt_sbx(s string, b []byte, digits string) {
// fmt_sx formats a string as a hexadecimal encoding of its bytes.
func (f *fmt) fmt_sx(s, digits string) {
+ if f.precPresent && f.prec < len(s) {
+ s = s[:f.prec]
+ }
f.fmt_sbx(s, nil, digits)
}
// fmt_bx formats a byte slice as a hexadecimal encoding of its bytes.
func (f *fmt) fmt_bx(b []byte, digits string) {
+ if f.precPresent && f.prec < len(b) {
+ b = b[:f.prec]
+ }
f.fmt_sbx("", b, digits)
}
@@ -351,35 +393,48 @@ func doPrec(f *fmt, def int) int {
// formatFloat formats a float64; it is an efficient equivalent to f.pad(strconv.FormatFloat()...).
func (f *fmt) formatFloat(v float64, verb byte, prec, n int) {
- // We leave one byte at the beginning of f.intbuf for a sign if needed,
- // and make it a space, which we might be able to use.
- f.intbuf[0] = ' '
- slice := strconv.AppendFloat(f.intbuf[0:1], v, verb, prec, n)
- // Add a plus sign or space to the floating-point string representation if missing and required.
- // The formatted number starts at slice[1].
- switch slice[1] {
- case '-', '+':
- // If we're zero padding, want the sign before the leading zeros.
- // Achieve this by writing the sign out and padding the postive number.
- if f.zero && f.widPresent && f.wid > len(slice) {
- f.buf.WriteByte(slice[1])
- f.wid--
- f.pad(slice[2:])
- return
+ // Format number, reserving space for leading + sign if needed.
+ num := strconv.AppendFloat(f.intbuf[0:1], v, verb, prec, n)
+ if num[1] == '-' || num[1] == '+' {
+ num = num[1:]
+ } else {
+ num[0] = '+'
+ }
+ // Special handling for infinity, which doesn't look like a number so shouldn't be padded with zeros.
+ if math.IsInf(v, 0) {
+ if f.zero {
+ defer func() { f.zero = true }()
+ f.zero = false
}
- // We're set; drop the leading space.
- slice = slice[1:]
- default:
- // There's no sign, but we might need one.
- if f.plus {
- slice[0] = '+'
- } else if f.space {
- // space is already there
- } else {
- slice = slice[1:]
+ }
+ // num is now a signed version of the number.
+ // If we're zero padding, want the sign before the leading zeros.
+ // Achieve this by writing the sign out and then padding the unsigned number.
+ if f.zero && f.widPresent && f.wid > len(num) {
+ if f.space && v >= 0 {
+ f.buf.WriteByte(' ') // This is what C does: even with zero, f.space means space.
+ f.wid--
+ } else if f.plus || v < 0 {
+ f.buf.WriteByte(num[0])
+ f.wid--
}
+ f.pad(num[1:])
+ return
+ }
+ // f.space says to replace a leading + with a space.
+ if f.space && num[0] == '+' {
+ num[0] = ' '
+ f.pad(num)
+ return
+ }
+ // Now we know the sign is attached directly to the number, if present at all.
+ // We want a sign if asked for, if it's negative, or if it's infinity (+Inf vs. -Inf).
+ if f.plus || num[0] == '-' || math.IsInf(v, 0) {
+ f.pad(num)
+ return
}
- f.pad(slice)
+ // No sign to show and the number is positive; just print the unsigned number.
+ f.pad(num[1:])
}
// fmt_e64 formats a float64 in the form -1.23e+12.
@@ -424,60 +479,46 @@ func (f *fmt) fmt_fb32(v float32) { f.formatFloat(float64(v), 'b', 0, 32) }
// fmt_c64 formats a complex64 according to the verb.
func (f *fmt) fmt_c64(v complex64, verb rune) {
- f.buf.WriteByte('(')
- r := real(v)
- oldPlus := f.plus
- for i := 0; ; i++ {
- switch verb {
- case 'b':
- f.fmt_fb32(r)
- case 'e':
- f.fmt_e32(r)
- case 'E':
- f.fmt_E32(r)
- case 'f':
- f.fmt_f32(r)
- case 'g':
- f.fmt_g32(r)
- case 'G':
- f.fmt_G32(r)
- }
- if i != 0 {
- break
- }
- f.plus = true
- r = imag(v)
- }
- f.plus = oldPlus
- f.buf.Write(irparenBytes)
+ f.fmt_complex(float64(real(v)), float64(imag(v)), 32, verb)
}
// fmt_c128 formats a complex128 according to the verb.
func (f *fmt) fmt_c128(v complex128, verb rune) {
+ f.fmt_complex(real(v), imag(v), 64, verb)
+}
+
+// fmt_complex formats a complex number as (r+ji).
+func (f *fmt) fmt_complex(r, j float64, size int, verb rune) {
f.buf.WriteByte('(')
- r := real(v)
oldPlus := f.plus
+ oldSpace := f.space
+ oldWid := f.wid
for i := 0; ; i++ {
switch verb {
case 'b':
- f.fmt_fb64(r)
+ f.formatFloat(r, 'b', 0, size)
case 'e':
- f.fmt_e64(r)
+ f.formatFloat(r, 'e', doPrec(f, 6), size)
case 'E':
- f.fmt_E64(r)
- case 'f':
- f.fmt_f64(r)
+ f.formatFloat(r, 'E', doPrec(f, 6), size)
+ case 'f', 'F':
+ f.formatFloat(r, 'f', doPrec(f, 6), size)
case 'g':
- f.fmt_g64(r)
+ f.formatFloat(r, 'g', doPrec(f, -1), size)
case 'G':
- f.fmt_G64(r)
+ f.formatFloat(r, 'G', doPrec(f, -1), size)
}
if i != 0 {
break
}
+ // Imaginary part always has a sign.
f.plus = true
- r = imag(v)
+ f.space = false
+ f.wid = oldWid
+ r = j
}
+ f.space = oldSpace
f.plus = oldPlus
+ f.wid = oldWid
f.buf.Write(irparenBytes)
}
diff --git a/libgo/go/fmt/print.go b/libgo/go/fmt/print.go
index 1ea816d6d5..59a30d221e 100644
--- a/libgo/go/fmt/print.go
+++ b/libgo/go/fmt/print.go
@@ -124,45 +124,13 @@ type pp struct {
fmt fmt
}
-// A cache holds a set of reusable objects.
-// The slice is a stack (LIFO).
-// If more are needed, the cache creates them by calling new.
-type cache struct {
- mu sync.Mutex
- saved []interface{}
- new func() interface{}
+var ppFree = sync.Pool{
+ New: func() interface{} { return new(pp) },
}
-func (c *cache) put(x interface{}) {
- c.mu.Lock()
- if len(c.saved) < cap(c.saved) {
- c.saved = append(c.saved, x)
- }
- c.mu.Unlock()
-}
-
-func (c *cache) get() interface{} {
- c.mu.Lock()
- n := len(c.saved)
- if n == 0 {
- c.mu.Unlock()
- return c.new()
- }
- x := c.saved[n-1]
- c.saved = c.saved[0 : n-1]
- c.mu.Unlock()
- return x
-}
-
-func newCache(f func() interface{}) *cache {
- return &cache{saved: make([]interface{}, 0, 100), new: f}
-}
-
-var ppFree = newCache(func() interface{} { return new(pp) })
-
-// newPrinter allocates a new pp struct or grab a cached one.
+// newPrinter allocates a new pp struct or grabs a cached one.
func newPrinter() *pp {
- p := ppFree.get().(*pp)
+ p := ppFree.Get().(*pp)
p.panicking = false
p.erroring = false
p.fmt.init(&p.buf)
@@ -178,7 +146,7 @@ func (p *pp) free() {
p.buf = p.buf[:0]
p.arg = nil
p.value = reflect.Value{}
- ppFree.put(p)
+ ppFree.Put(p)
}
func (p *pp) Width() (wid int, ok bool) { return p.fmt.wid, p.fmt.widPresent }
@@ -329,13 +297,13 @@ func parsenum(s string, start, end int) (num int, isnum bool, newi int) {
return
}
-func (p *pp) unknownType(v interface{}) {
- if v == nil {
+func (p *pp) unknownType(v reflect.Value) {
+ if !v.IsValid() {
p.buf.Write(nilAngleBytes)
return
}
p.buf.WriteByte('?')
- p.buf.WriteString(reflect.TypeOf(v).String())
+ p.buf.WriteString(v.Type().String())
p.buf.WriteByte('?')
}
@@ -349,11 +317,11 @@ func (p *pp) badVerb(verb rune) {
case p.arg != nil:
p.buf.WriteString(reflect.TypeOf(p.arg).String())
p.add('=')
- p.printArg(p.arg, 'v', false, false, 0)
+ p.printArg(p.arg, 'v', 0)
case p.value.IsValid():
p.buf.WriteString(p.value.Type().String())
p.add('=')
- p.printValue(p.value, 'v', false, false, 0)
+ p.printValue(p.value, 'v', 0)
default:
p.buf.Write(nilAngleBytes)
}
@@ -438,7 +406,7 @@ func (p *pp) fmtUnicode(v int64) {
p.fmt.sharp = sharp
}
-func (p *pp) fmtUint64(v uint64, verb rune, goSyntax bool) {
+func (p *pp) fmtUint64(v uint64, verb rune) {
switch verb {
case 'b':
p.fmt.integer(int64(v), 2, unsigned, ldigits)
@@ -447,7 +415,7 @@ func (p *pp) fmtUint64(v uint64, verb rune, goSyntax bool) {
case 'd':
p.fmt.integer(int64(v), 10, unsigned, ldigits)
case 'v':
- if goSyntax {
+ if p.fmt.sharpV {
p.fmt0x64(v, true)
} else {
p.fmt.integer(int64(v), 10, unsigned, ldigits)
@@ -479,7 +447,7 @@ func (p *pp) fmtFloat32(v float32, verb rune) {
p.fmt.fmt_e32(v)
case 'E':
p.fmt.fmt_E32(v)
- case 'f':
+ case 'f', 'F':
p.fmt.fmt_f32(v)
case 'g', 'v':
p.fmt.fmt_g32(v)
@@ -498,7 +466,7 @@ func (p *pp) fmtFloat64(v float64, verb rune) {
p.fmt.fmt_e64(v)
case 'E':
p.fmt.fmt_E64(v)
- case 'f':
+ case 'f', 'F':
p.fmt.fmt_f64(v)
case 'g', 'v':
p.fmt.fmt_g64(v)
@@ -531,10 +499,10 @@ func (p *pp) fmtComplex128(v complex128, verb rune) {
}
}
-func (p *pp) fmtString(v string, verb rune, goSyntax bool) {
+func (p *pp) fmtString(v string, verb rune) {
switch verb {
case 'v':
- if goSyntax {
+ if p.fmt.sharpV {
p.fmt.fmt_q(v)
} else {
p.fmt.fmt_s(v)
@@ -552,9 +520,18 @@ func (p *pp) fmtString(v string, verb rune, goSyntax bool) {
}
}
-func (p *pp) fmtBytes(v []byte, verb rune, goSyntax bool, typ reflect.Type, depth int) {
+func (p *pp) fmtBytes(v []byte, verb rune, typ reflect.Type, depth int) {
if verb == 'v' || verb == 'd' {
- if goSyntax {
+ if p.fmt.sharpV {
+ if v == nil {
+ if typ == nil {
+ p.buf.WriteString("[]byte(nil)")
+ } else {
+ p.buf.WriteString(typ.String())
+ p.buf.Write(nilParenBytes)
+ }
+ return
+ }
if typ == nil {
p.buf.Write(bytesBytes)
} else {
@@ -566,15 +543,15 @@ func (p *pp) fmtBytes(v []byte, verb rune, goSyntax bool, typ reflect.Type, dept
}
for i, c := range v {
if i > 0 {
- if goSyntax {
+ if p.fmt.sharpV {
p.buf.Write(commaSpaceBytes)
} else {
p.buf.WriteByte(' ')
}
}
- p.printArg(c, 'v', p.fmt.plus, goSyntax, depth+1)
+ p.printArg(c, 'v', depth+1)
}
- if goSyntax {
+ if p.fmt.sharpV {
p.buf.WriteByte('}')
} else {
p.buf.WriteByte(']')
@@ -595,7 +572,7 @@ func (p *pp) fmtBytes(v []byte, verb rune, goSyntax bool, typ reflect.Type, dept
}
}
-func (p *pp) fmtPointer(value reflect.Value, verb rune, goSyntax bool) {
+func (p *pp) fmtPointer(value reflect.Value, verb rune) {
use0x64 := true
switch verb {
case 'p', 'v':
@@ -617,7 +594,7 @@ func (p *pp) fmtPointer(value reflect.Value, verb rune, goSyntax bool) {
return
}
- if goSyntax {
+ if p.fmt.sharpV {
p.add('(')
p.buf.WriteString(value.Type().String())
p.add(')')
@@ -634,7 +611,7 @@ func (p *pp) fmtPointer(value reflect.Value, verb rune, goSyntax bool) {
if use0x64 {
p.fmt0x64(uint64(u), !p.fmt.sharp)
} else {
- p.fmtUint64(uint64(u), verb, false)
+ p.fmtUint64(uint64(u), verb)
}
}
}
@@ -659,42 +636,65 @@ func (p *pp) catchPanic(arg interface{}, verb rune) {
// Nested panics; the recursion in printArg cannot succeed.
panic(err)
}
+ p.fmt.clearflags() // We are done, and for this output we want default behavior.
p.buf.Write(percentBangBytes)
p.add(verb)
p.buf.Write(panicBytes)
p.panicking = true
- p.printArg(err, 'v', false, false, 0)
+ p.printArg(err, 'v', 0)
p.panicking = false
p.buf.WriteByte(')')
}
}
-func (p *pp) handleMethods(verb rune, plus, goSyntax bool, depth int) (wasString, handled bool) {
+// clearSpecialFlags pushes %#v back into the regular flags and returns their old state.
+func (p *pp) clearSpecialFlags() (plusV, sharpV bool) {
+ plusV = p.fmt.plusV
+ if plusV {
+ p.fmt.plus = true
+ p.fmt.plusV = false
+ }
+ sharpV = p.fmt.sharpV
+ if sharpV {
+ p.fmt.sharp = true
+ p.fmt.sharpV = false
+ }
+ return
+}
+
+// restoreSpecialFlags, whose argument should be a call to clearSpecialFlags,
+// restores the setting of the plusV and sharpV flags.
+func (p *pp) restoreSpecialFlags(plusV, sharpV bool) {
+ if plusV {
+ p.fmt.plus = false
+ p.fmt.plusV = true
+ }
+ if sharpV {
+ p.fmt.sharp = false
+ p.fmt.sharpV = true
+ }
+}
+
+func (p *pp) handleMethods(verb rune, depth int) (handled bool) {
if p.erroring {
return
}
// Is it a Formatter?
if formatter, ok := p.arg.(Formatter); ok {
handled = true
- wasString = false
+ defer p.restoreSpecialFlags(p.clearSpecialFlags())
defer p.catchPanic(p.arg, verb)
formatter.Format(p, verb)
return
}
- // Must not touch flags before Formatter looks at them.
- if plus {
- p.fmt.plus = false
- }
// If we're doing Go syntax and the argument knows how to supply it, take care of it now.
- if goSyntax {
- p.fmt.sharp = false
+ if p.fmt.sharpV {
if stringer, ok := p.arg.(GoStringer); ok {
- wasString = false
handled = true
defer p.catchPanic(p.arg, verb)
// Print the result of GoString unadorned.
- p.fmtString(stringer.GoString(), 's', false)
+ p.fmt.fmt_s(stringer.GoString())
return
}
} else {
@@ -705,30 +705,27 @@ func (p *pp) handleMethods(verb rune, plus, goSyntax bool, depth int) (wasString
case 'v', 's', 'x', 'X', 'q':
// Is it an error or Stringer?
// The duplication in the bodies is necessary:
- // setting wasString and handled, and deferring catchPanic,
+ // setting handled and deferring catchPanic
// must happen before calling the method.
switch v := p.arg.(type) {
case error:
- wasString = false
handled = true
defer p.catchPanic(p.arg, verb)
- p.printArg(v.Error(), verb, plus, false, depth)
+ p.printArg(v.Error(), verb, depth)
return
case Stringer:
- wasString = false
handled = true
defer p.catchPanic(p.arg, verb)
- p.printArg(v.String(), verb, plus, false, depth)
+ p.printArg(v.String(), verb, depth)
return
}
}
}
- handled = false
- return
+ return false
}
-func (p *pp) printArg(arg interface{}, verb rune, plus, goSyntax bool, depth int) (wasString bool) {
+func (p *pp) printArg(arg interface{}, verb rune, depth int) (wasString bool) {
p.arg = arg
p.value = reflect.Value{}
@@ -745,26 +742,13 @@ func (p *pp) printArg(arg interface{}, verb rune, plus, goSyntax bool, depth int
// %T (the value's type) and %p (its address) are special; we always do them first.
switch verb {
case 'T':
- p.printArg(reflect.TypeOf(arg).String(), 's', false, false, 0)
+ p.printArg(reflect.TypeOf(arg).String(), 's', 0)
return false
case 'p':
- p.fmtPointer(reflect.ValueOf(arg), verb, goSyntax)
+ p.fmtPointer(reflect.ValueOf(arg), verb)
return false
}
- // Clear flags for base formatters.
- // handleMethods needs them, so we must restore them later.
- // We could call handleMethods here and avoid this work, but
- // handleMethods is expensive enough to be worth delaying.
- oldPlus := p.fmt.plus
- oldSharp := p.fmt.sharp
- if plus {
- p.fmt.plus = false
- }
- if goSyntax {
- p.fmt.sharp = false
- }
-
// Some types can be done without reflection.
switch f := arg.(type) {
case bool:
@@ -788,40 +772,37 @@ func (p *pp) printArg(arg interface{}, verb rune, plus, goSyntax bool, depth int
case int64:
p.fmtInt64(f, verb)
case uint:
- p.fmtUint64(uint64(f), verb, goSyntax)
+ p.fmtUint64(uint64(f), verb)
case uint8:
- p.fmtUint64(uint64(f), verb, goSyntax)
+ p.fmtUint64(uint64(f), verb)
case uint16:
- p.fmtUint64(uint64(f), verb, goSyntax)
+ p.fmtUint64(uint64(f), verb)
case uint32:
- p.fmtUint64(uint64(f), verb, goSyntax)
+ p.fmtUint64(uint64(f), verb)
case uint64:
- p.fmtUint64(f, verb, goSyntax)
+ p.fmtUint64(f, verb)
case uintptr:
- p.fmtUint64(uint64(f), verb, goSyntax)
+ p.fmtUint64(uint64(f), verb)
case string:
- p.fmtString(f, verb, goSyntax)
+ p.fmtString(f, verb)
wasString = verb == 's' || verb == 'v'
case []byte:
- p.fmtBytes(f, verb, goSyntax, nil, depth)
+ p.fmtBytes(f, verb, nil, depth)
wasString = verb == 's'
default:
- // Restore flags in case handleMethods finds a Formatter.
- p.fmt.plus = oldPlus
- p.fmt.sharp = oldSharp
// If the type is not simple, it might have methods.
- if isString, handled := p.handleMethods(verb, plus, goSyntax, depth); handled {
- return isString
+ if handled := p.handleMethods(verb, depth); handled {
+ return false
}
// Need to use reflection
- return p.printReflectValue(reflect.ValueOf(arg), verb, plus, goSyntax, depth)
+ return p.printReflectValue(reflect.ValueOf(arg), verb, depth)
}
p.arg = nil
return
}
// printValue is like printArg but starts with a reflect value, not an interface{} value.
-func (p *pp) printValue(value reflect.Value, verb rune, plus, goSyntax bool, depth int) (wasString bool) {
+func (p *pp) printValue(value reflect.Value, verb rune, depth int) (wasString bool) {
if !value.IsValid() {
if verb == 'T' || verb == 'v' {
p.buf.Write(nilAngleBytes)
@@ -835,10 +816,10 @@ func (p *pp) printValue(value reflect.Value, verb rune, plus, goSyntax bool, dep
// %T (the value's type) and %p (its address) are special; we always do them first.
switch verb {
case 'T':
- p.printArg(value.Type().String(), 's', false, false, 0)
+ p.printArg(value.Type().String(), 's', 0)
return false
case 'p':
- p.fmtPointer(value, verb, goSyntax)
+ p.fmtPointer(value, verb)
return false
}
@@ -848,16 +829,18 @@ func (p *pp) printValue(value reflect.Value, verb rune, plus, goSyntax bool, dep
if value.CanInterface() {
p.arg = value.Interface()
}
- if isString, handled := p.handleMethods(verb, plus, goSyntax, depth); handled {
- return isString
+ if handled := p.handleMethods(verb, depth); handled {
+ return false
}
- return p.printReflectValue(value, verb, plus, goSyntax, depth)
+ return p.printReflectValue(value, verb, depth)
}
+var byteType = reflect.TypeOf(byte(0))
+
// printReflectValue is the fallback for both printArg and printValue.
// It uses reflect to print the value.
-func (p *pp) printReflectValue(value reflect.Value, verb rune, plus, goSyntax bool, depth int) (wasString bool) {
+func (p *pp) printReflectValue(value reflect.Value, verb rune, depth int) (wasString bool) {
oldValue := p.value
p.value = value
BigSwitch:
@@ -867,7 +850,7 @@ BigSwitch:
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
p.fmtInt64(f.Int(), verb)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- p.fmtUint64(f.Uint(), verb, goSyntax)
+ p.fmtUint64(f.Uint(), verb)
case reflect.Float32, reflect.Float64:
if f.Type().Size() == 4 {
p.fmtFloat32(float32(f.Float()), verb)
@@ -881,9 +864,9 @@ BigSwitch:
p.fmtComplex128(f.Complex(), verb)
}
case reflect.String:
- p.fmtString(f.String(), verb, goSyntax)
+ p.fmtString(f.String(), verb)
case reflect.Map:
- if goSyntax {
+ if p.fmt.sharpV {
p.buf.WriteString(f.Type().String())
if f.IsNil() {
p.buf.WriteString("(nil)")
@@ -896,23 +879,23 @@ BigSwitch:
keys := f.MapKeys()
for i, key := range keys {
if i > 0 {
- if goSyntax {
+ if p.fmt.sharpV {
p.buf.Write(commaSpaceBytes)
} else {
p.buf.WriteByte(' ')
}
}
- p.printValue(key, verb, plus, goSyntax, depth+1)
+ p.printValue(key, verb, depth+1)
p.buf.WriteByte(':')
- p.printValue(f.MapIndex(key), verb, plus, goSyntax, depth+1)
+ p.printValue(f.MapIndex(key), verb, depth+1)
}
- if goSyntax {
+ if p.fmt.sharpV {
p.buf.WriteByte('}')
} else {
p.buf.WriteByte(']')
}
case reflect.Struct:
- if goSyntax {
+ if p.fmt.sharpV {
p.buf.WriteString(value.Type().String())
}
p.add('{')
@@ -920,36 +903,40 @@ BigSwitch:
t := v.Type()
for i := 0; i < v.NumField(); i++ {
if i > 0 {
- if goSyntax {
+ if p.fmt.sharpV {
p.buf.Write(commaSpaceBytes)
} else {
p.buf.WriteByte(' ')
}
}
- if plus || goSyntax {
+ if p.fmt.plusV || p.fmt.sharpV {
if f := t.Field(i); f.Name != "" {
p.buf.WriteString(f.Name)
p.buf.WriteByte(':')
}
}
- p.printValue(getField(v, i), verb, plus, goSyntax, depth+1)
+ p.printValue(getField(v, i), verb, depth+1)
}
p.buf.WriteByte('}')
case reflect.Interface:
value := f.Elem()
if !value.IsValid() {
- if goSyntax {
+ if p.fmt.sharpV {
p.buf.WriteString(f.Type().String())
p.buf.Write(nilParenBytes)
} else {
p.buf.Write(nilAngleBytes)
}
} else {
- wasString = p.printValue(value, verb, plus, goSyntax, depth+1)
+ wasString = p.printValue(value, verb, depth+1)
}
case reflect.Array, reflect.Slice:
- // Byte slices are special.
- if typ := f.Type(); typ.Elem().Kind() == reflect.Uint8 {
+ // Byte slices are special:
+ // - Handle []byte (== []uint8) with fmtBytes.
+ // - Handle []T, where T is a named byte type, with fmtBytes only
+ // for the s, q, an x verbs. For other verbs, T might be a
+ // Stringer, so we use printValue to print each element.
+ if typ := f.Type(); typ.Elem().Kind() == reflect.Uint8 && (typ.Elem() == byteType || verb == 's' || verb == 'q' || verb == 'x') {
var bytes []byte
if f.Kind() == reflect.Slice {
bytes = f.Bytes()
@@ -964,11 +951,11 @@ BigSwitch:
bytes[i] = byte(f.Index(i).Uint())
}
}
- p.fmtBytes(bytes, verb, goSyntax, typ, depth)
+ p.fmtBytes(bytes, verb, typ, depth)
wasString = verb == 's'
break
}
- if goSyntax {
+ if p.fmt.sharpV {
p.buf.WriteString(value.Type().String())
if f.Kind() == reflect.Slice && f.IsNil() {
p.buf.WriteString("(nil)")
@@ -980,15 +967,15 @@ BigSwitch:
}
for i := 0; i < f.Len(); i++ {
if i > 0 {
- if goSyntax {
+ if p.fmt.sharpV {
p.buf.Write(commaSpaceBytes)
} else {
p.buf.WriteByte(' ')
}
}
- p.printValue(f.Index(i), verb, plus, goSyntax, depth+1)
+ p.printValue(f.Index(i), verb, depth+1)
}
- if goSyntax {
+ if p.fmt.sharpV {
p.buf.WriteByte('}')
} else {
p.buf.WriteByte(']')
@@ -1001,17 +988,21 @@ BigSwitch:
switch a := f.Elem(); a.Kind() {
case reflect.Array, reflect.Slice:
p.buf.WriteByte('&')
- p.printValue(a, verb, plus, goSyntax, depth+1)
+ p.printValue(a, verb, depth+1)
break BigSwitch
case reflect.Struct:
p.buf.WriteByte('&')
- p.printValue(a, verb, plus, goSyntax, depth+1)
+ p.printValue(a, verb, depth+1)
+ break BigSwitch
+ case reflect.Map:
+ p.buf.WriteByte('&')
+ p.printValue(a, verb, depth+1)
break BigSwitch
}
}
fallthrough
case reflect.Chan, reflect.Func, reflect.UnsafePointer:
- p.fmtPointer(value, verb, goSyntax)
+ p.fmtPointer(value, verb)
default:
p.unknownType(f)
}
@@ -1177,9 +1168,19 @@ func (p *pp) doPrintf(format string, a []interface{}) {
arg := a[argNum]
argNum++
- goSyntax := c == 'v' && p.fmt.sharp
- plus := c == 'v' && p.fmt.plus
- p.printArg(arg, c, plus, goSyntax, 0)
+ if c == 'v' {
+ if p.fmt.sharp {
+ // Go syntax. Set the flag in the fmt and clear the sharp flag.
+ p.fmt.sharp = false
+ p.fmt.sharpV = true
+ }
+ if p.fmt.plus {
+ // Struct-field syntax. Set the flag in the fmt and clear the plus flag.
+ p.fmt.plus = false
+ p.fmt.plusV = true
+ }
+ }
+ p.printArg(arg, c, 0)
}
// Check for extra arguments unless the call accessed the arguments
@@ -1193,7 +1194,7 @@ func (p *pp) doPrintf(format string, a []interface{}) {
p.buf.WriteString(reflect.TypeOf(arg).String())
p.buf.WriteByte('=')
}
- p.printArg(arg, 'v', false, false, 0)
+ p.printArg(arg, 'v', 0)
if argNum+1 < len(a) {
p.buf.Write(commaSpaceBytes)
}
@@ -1214,7 +1215,7 @@ func (p *pp) doPrint(a []interface{}, addspace, addnewline bool) {
p.buf.WriteByte(' ')
}
}
- prevString = p.printArg(arg, 'v', false, false, 0)
+ prevString = p.printArg(arg, 'v', 0)
}
if addnewline {
p.buf.WriteByte('\n')
diff --git a/libgo/go/fmt/scan.go b/libgo/go/fmt/scan.go
index 5b1be5891b..d7befeae43 100644
--- a/libgo/go/fmt/scan.go
+++ b/libgo/go/fmt/scan.go
@@ -11,6 +11,7 @@ import (
"os"
"reflect"
"strconv"
+ "sync"
"unicode/utf8"
)
@@ -283,7 +284,6 @@ var space = [][2]uint16{
{0x0085, 0x0085},
{0x00a0, 0x00a0},
{0x1680, 0x1680},
- {0x180e, 0x180e},
{0x2000, 0x200a},
{0x2028, 0x2029},
{0x202f, 0x202f},
@@ -360,6 +360,7 @@ func (r *readRune) ReadRune() (rr rune, size int, err error) {
}
if r.buf[0] < utf8.RuneSelf { // fast check for common ASCII case
rr = rune(r.buf[0])
+ size = 1 // Known to be 1.
return
}
var n int
@@ -380,7 +381,9 @@ func (r *readRune) ReadRune() (rr rune, size int, err error) {
return
}
-var ssFree = newCache(func() interface{} { return new(ss) })
+var ssFree = sync.Pool{
+ New: func() interface{} { return new(ss) },
+}
// newScanState allocates a new ss struct or grab a cached one.
func newScanState(r io.Reader, nlIsSpace, nlIsEnd bool) (s *ss, old ssave) {
@@ -395,7 +398,7 @@ func newScanState(r io.Reader, nlIsSpace, nlIsEnd bool) (s *ss, old ssave) {
return
}
- s = ssFree.get().(*ss)
+ s = ssFree.Get().(*ss)
if rr, ok := r.(io.RuneReader); ok {
s.rr = rr
} else {
@@ -427,7 +430,7 @@ func (s *ss) free(old ssave) {
}
s.buf = s.buf[:0]
s.rr = nil
- ssFree.put(s)
+ ssFree.Put(s)
}
// skipSpace skips spaces and maybe newlines.
diff --git a/libgo/go/fmt/scan_test.go b/libgo/go/fmt/scan_test.go
index d903f0c3ff..541e12df21 100644
--- a/libgo/go/fmt/scan_test.go
+++ b/libgo/go/fmt/scan_test.go
@@ -842,6 +842,38 @@ func TestLineByLineFscanf(t *testing.T) {
}
}
+// TestScanStateCount verifies the correct byte count is returned. Issue 8512.
+
+// runeScanner implements the Scanner interface for TestScanStateCount.
+type runeScanner struct {
+ rune rune
+ size int
+}
+
+func (rs *runeScanner) Scan(state ScanState, verb rune) error {
+ r, size, err := state.ReadRune()
+ rs.rune = r
+ rs.size = size
+ return err
+}
+
+func TestScanStateCount(t *testing.T) {
+ var a, b, c runeScanner
+ n, err := Sscanf("12➂", "%c%c%c", &a, &b, &c)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if n != 3 {
+ t.Fatalf("expected 3 items consumed, got %d")
+ }
+ 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)
+ }
+ if a.size != 1 || b.size != 1 || c.size != 3 {
+ t.Errorf("bad scan size: %q %q %q should be 1 1 3", a.size, b.size, c.size)
+ }
+}
+
// RecursiveInt accepts a string matching %d.%d.%d....
// and parses it into a linked list.
// It allows us to benchmark recursive descent style scanners.
diff --git a/libgo/go/go/ast/ast.go b/libgo/go/go/ast/ast.go
index 6e635cd016..312e3d1b98 100644
--- a/libgo/go/go/ast/ast.go
+++ b/libgo/go/go/ast/ast.go
@@ -699,9 +699,9 @@ type (
// A RangeStmt represents a for statement with a range clause.
RangeStmt struct {
For token.Pos // position of "for" keyword
- Key, Value Expr // Value may be nil
- TokPos token.Pos // position of Tok
- Tok token.Token // ASSIGN, DEFINE
+ Key, Value Expr // Key, Value may be nil
+ TokPos token.Pos // position of Tok; invalid if Key == nil
+ Tok token.Token // ILLEGAL if Key == nil, ASSIGN, DEFINE
X Expr // value to range over
Body *BlockStmt
}
diff --git a/libgo/go/go/ast/commentmap.go b/libgo/go/go/ast/commentmap.go
index 1fb4867dd2..ac999d627c 100644
--- a/libgo/go/go/ast/commentmap.go
+++ b/libgo/go/go/ast/commentmap.go
@@ -149,7 +149,7 @@ func NewCommentMap(fset *token.FileSet, node Node, comments []*CommentGroup) Com
// set up comment reader r
tmp := make([]*CommentGroup, len(comments))
- copy(tmp, comments) // don't change incomming comments
+ copy(tmp, comments) // don't change incoming comments
sortComments(tmp)
r := commentListReader{fset: fset, list: tmp} // !r.eol() because len(comments) > 0
r.next()
diff --git a/libgo/go/go/ast/scope.go b/libgo/go/go/ast/scope.go
index 8df5b2c656..df1529d181 100644
--- a/libgo/go/go/ast/scope.go
+++ b/libgo/go/go/ast/scope.go
@@ -80,7 +80,7 @@ type Object struct {
Name string // declared name
Decl interface{} // corresponding Field, XxxSpec, FuncDecl, LabeledStmt, AssignStmt, Scope; or nil
Data interface{} // object-specific data; or nil
- Type interface{} // place holder for type information; may be nil
+ Type interface{} // placeholder for type information; may be nil
}
// NewObj creates a new object of a given kind and name.
diff --git a/libgo/go/go/ast/walk.go b/libgo/go/go/ast/walk.go
index fedffb3f22..73ac38647a 100644
--- a/libgo/go/go/ast/walk.go
+++ b/libgo/go/go/ast/walk.go
@@ -275,7 +275,9 @@ func Walk(v Visitor, node Node) {
Walk(v, n.Body)
case *RangeStmt:
- Walk(v, n.Key)
+ if n.Key != nil {
+ Walk(v, n.Key)
+ }
if n.Value != nil {
Walk(v, n.Value)
}
diff --git a/libgo/go/go/build/build.go b/libgo/go/go/build/build.go
index d06a9be531..e9247274b6 100644
--- a/libgo/go/go/build/build.go
+++ b/libgo/go/go/build/build.go
@@ -23,6 +23,7 @@ import (
"strconv"
"strings"
"unicode"
+ "unicode/utf8"
)
// A Context specifies the supporting context for a build.
@@ -206,9 +207,7 @@ func (ctxt *Context) gopath() []string {
if p == "" || p == ctxt.GOROOT {
// Empty paths are uninteresting.
// If the path is the GOROOT, ignore it.
- // People sometimes set GOPATH=$GOROOT, which is useless
- // but would cause us to find packages with import paths
- // like "pkg/math".
+ // People sometimes set GOPATH=$GOROOT.
// Do not get confused by this common mistake.
continue
}
@@ -238,7 +237,7 @@ func (ctxt *Context) gopath() []string {
func (ctxt *Context) SrcDirs() []string {
var all []string
if ctxt.GOROOT != "" {
- dir := ctxt.joinPath(ctxt.GOROOT, "src", "pkg")
+ dir := ctxt.joinPath(ctxt.GOROOT, "src")
if ctxt.isDir(dir) {
all = append(all, dir)
}
@@ -266,8 +265,18 @@ var cgoEnabled = map[string]bool{
"freebsd/amd64": true,
"freebsd/arm": true,
"linux/386": true,
+ "linux/alpha": true,
"linux/amd64": true,
"linux/arm": true,
+ "linux/arm64": true,
+ "linux/ppc": true,
+ "linux/ppc64": true,
+ "linux/ppc64le": true,
+ "linux/s390": true,
+ "linux/s390x": true,
+ "android/386": true,
+ "android/amd64": true,
+ "android/arm": true,
"netbsd/386": true,
"netbsd/amd64": true,
"netbsd/arm": true,
@@ -292,10 +301,10 @@ func defaultContext() Context {
// say "+build go1.x", and code that should only be built before Go 1.x
// (perhaps it is the stub to use in that case) should say "+build !go1.x".
//
- // When we reach Go 1.3 the line will read
- // c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3"}
+ // 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"}
+ c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4"}
switch os.Getenv("CGO_ENABLED") {
case "1":
@@ -303,8 +312,7 @@ func defaultContext() Context {
case "0":
c.CgoEnabled = false
default:
- // golang.org/issue/5141
- // cgo should be disabled for cross compilation builds
+ // cgo must be explicitly enabled for cross compilation builds
if runtime.GOARCH == c.GOARCH && runtime.GOOS == c.GOOS {
c.CgoEnabled = cgoEnabled[c.GOOS+"/"+c.GOARCH]
break
@@ -335,22 +343,29 @@ const (
// If AllowBinary is set, Import can be satisfied by a compiled
// package object without corresponding sources.
AllowBinary
+
+ // If ImportComment is set, parse import comments on package statements.
+ // Import returns an error if it finds a comment it cannot understand
+ // or finds conflicting comments in multiple source files.
+ // See golang.org/s/go14customimport for more information.
+ ImportComment
)
// A Package describes the Go package found in a directory.
type Package struct {
- Dir string // directory containing package sources
- Name string // package name
- Doc string // documentation synopsis
- ImportPath string // import path of package ("" if unknown)
- 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)
- BinDir string // command install directory ("" if unknown)
- Goroot bool // package found in Go root
- PkgObj string // installed .a file
- AllTags []string // tags that can influence file selection in this directory
- ConflictDir string // this directory shadows Dir in $GOPATH
+ Dir string // directory containing package sources
+ Name string // package name
+ ImportComment string // path in import comment on package statement
+ Doc string // documentation synopsis
+ ImportPath string // import path of package ("" if unknown)
+ 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)
+ BinDir string // command install directory ("" if unknown)
+ Goroot bool // package found in Go root
+ PkgObj string // installed .a file
+ AllTags []string // tags that can influence file selection in this directory
+ ConflictDir string // this directory shadows Dir in $GOPATH
// Source files
GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
@@ -358,6 +373,7 @@ type Package struct {
IgnoredGoFiles []string // .go source files ignored for this build
CFiles []string // .c source files
CXXFiles []string // .cc, .cpp and .cxx source files
+ MFiles []string // .m (Objective-C) source files
HFiles []string // .h, .hh, .hpp and .hxx source files
SFiles []string // .s source files
SwigFiles []string // .swig files
@@ -408,6 +424,19 @@ func (e *NoGoError) Error() string {
return "no buildable Go source files in " + e.Dir
}
+// MultiplePackageError describes a directory containing
+// multiple buildable Go source files for multiple packages.
+type MultiplePackageError struct {
+ Dir string // directory containing files
+ Packages []string // package names found
+ Files []string // corresponding files: Files[i] declares package Packages[i]
+}
+
+func (e *MultiplePackageError) Error() string {
+ // Error string limited to two entries for compatibility.
+ return fmt.Sprintf("found packages %s (%s) and %s (%s) in %s", e.Packages[0], e.Files[0], e.Packages[1], e.Files[1], e.Dir)
+}
+
func nameExt(name string) string {
i := strings.LastIndex(name, ".")
if i < 0 {
@@ -468,7 +497,7 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
}
// Determine canonical import path, if any.
if ctxt.GOROOT != "" {
- root := ctxt.joinPath(ctxt.GOROOT, "src", "pkg")
+ root := ctxt.joinPath(ctxt.GOROOT, "src")
if sub, ok := ctxt.hasSubdir(root, p.Dir); ok {
p.Goroot = true
p.ImportPath = sub
@@ -484,7 +513,7 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
// but check that using it wouldn't find something
// else first.
if ctxt.GOROOT != "" {
- if dir := ctxt.joinPath(ctxt.GOROOT, "src", "pkg", sub); ctxt.isDir(dir) {
+ if dir := ctxt.joinPath(ctxt.GOROOT, "src", sub); ctxt.isDir(dir) {
p.ConflictDir = dir
goto Found
}
@@ -518,7 +547,7 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
// Determine directory from import path.
if ctxt.GOROOT != "" {
- dir := ctxt.joinPath(ctxt.GOROOT, "src", "pkg", path)
+ dir := ctxt.joinPath(ctxt.GOROOT, "src", path)
isDir := ctxt.isDir(dir)
binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(ctxt.GOROOT, pkga))
if isDir || binaryOnly {
@@ -564,11 +593,7 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
Found:
if p.Root != "" {
- if p.Goroot {
- p.SrcRoot = ctxt.joinPath(p.Root, "src", "pkg")
- } else {
- p.SrcRoot = ctxt.joinPath(p.Root, "src")
- }
+ p.SrcRoot = ctxt.joinPath(p.Root, "src")
p.PkgRoot = ctxt.joinPath(p.Root, "pkg")
p.BinDir = ctxt.joinPath(p.Root, "bin")
if pkga != "" {
@@ -589,7 +614,7 @@ Found:
}
var Sfiles []string // files with ".S" (capital S)
- var firstFile string
+ var firstFile, firstCommentFile string
imported := make(map[string][]token.Position)
testImported := make(map[string][]token.Position)
xTestImported := make(map[string][]token.Position)
@@ -622,6 +647,9 @@ Found:
case ".cc", ".cpp", ".cxx":
p.CXXFiles = append(p.CXXFiles, name)
continue
+ case ".m":
+ p.MFiles = append(p.MFiles, name)
+ continue
case ".h", ".hh", ".hpp", ".hxx":
p.HFiles = append(p.HFiles, name)
continue
@@ -667,12 +695,28 @@ Found:
p.Name = pkg
firstFile = name
} else if pkg != p.Name {
- return p, fmt.Errorf("found packages %s (%s) and %s (%s) in %s", p.Name, firstFile, pkg, name, p.Dir)
+ return p, &MultiplePackageError{p.Dir, []string{firstFile, name}, []string{p.Name, pkg}}
}
if pf.Doc != nil && p.Doc == "" {
p.Doc = doc.Synopsis(pf.Doc.Text())
}
+ if mode&ImportComment != 0 {
+ qcom, line := findImportComment(data)
+ if line != 0 {
+ com, err := strconv.Unquote(qcom)
+ if err != nil {
+ return p, fmt.Errorf("%s:%d: cannot parse import comment", filename, line)
+ }
+ if p.ImportComment == "" {
+ p.ImportComment = com
+ firstCommentFile = name
+ } else if p.ImportComment != com {
+ return p, fmt.Errorf("found import comments %q (%s) and %q (%s) in %s", p.ImportComment, firstCommentFile, com, name, p.Dir)
+ }
+ }
+ }
+
// Record imports and information about cgo.
isCgo := false
for _, decl := range pf.Decls {
@@ -753,6 +797,117 @@ Found:
return p, pkgerr
}
+func findImportComment(data []byte) (s string, line int) {
+ // expect keyword package
+ word, data := parseWord(data)
+ if string(word) != "package" {
+ return "", 0
+ }
+
+ // expect package name
+ _, data = parseWord(data)
+
+ // now ready for import comment, a // or /* */ comment
+ // beginning and ending on the current line.
+ for len(data) > 0 && (data[0] == ' ' || data[0] == '\t' || data[0] == '\r') {
+ data = data[1:]
+ }
+
+ var comment []byte
+ switch {
+ case bytes.HasPrefix(data, slashSlash):
+ i := bytes.Index(data, newline)
+ if i < 0 {
+ i = len(data)
+ }
+ comment = data[2:i]
+ case bytes.HasPrefix(data, slashStar):
+ data = data[2:]
+ i := bytes.Index(data, starSlash)
+ if i < 0 {
+ // malformed comment
+ return "", 0
+ }
+ comment = data[:i]
+ if bytes.Contains(comment, newline) {
+ return "", 0
+ }
+ }
+ comment = bytes.TrimSpace(comment)
+
+ // split comment into `import`, `"pkg"`
+ word, arg := parseWord(comment)
+ if string(word) != "import" {
+ return "", 0
+ }
+
+ line = 1 + bytes.Count(data[:cap(data)-cap(arg)], newline)
+ return strings.TrimSpace(string(arg)), line
+}
+
+var (
+ slashSlash = []byte("//")
+ slashStar = []byte("/*")
+ starSlash = []byte("*/")
+ newline = []byte("\n")
+)
+
+// skipSpaceOrComment returns data with any leading spaces or comments removed.
+func skipSpaceOrComment(data []byte) []byte {
+ for len(data) > 0 {
+ switch data[0] {
+ case ' ', '\t', '\r', '\n':
+ data = data[1:]
+ continue
+ case '/':
+ if bytes.HasPrefix(data, slashSlash) {
+ i := bytes.Index(data, newline)
+ if i < 0 {
+ return nil
+ }
+ data = data[i+1:]
+ continue
+ }
+ if bytes.HasPrefix(data, slashStar) {
+ data = data[2:]
+ i := bytes.Index(data, starSlash)
+ if i < 0 {
+ return nil
+ }
+ data = data[i+2:]
+ continue
+ }
+ }
+ break
+ }
+ return data
+}
+
+// parseWord skips any leading spaces or comments in data
+// and then parses the beginning of data as an identifier or keyword,
+// returning that word and what remains after the word.
+func parseWord(data []byte) (word, rest []byte) {
+ data = skipSpaceOrComment(data)
+
+ // Parse past leading word characters.
+ rest = data
+ for {
+ r, size := utf8.DecodeRune(rest)
+ if unicode.IsLetter(r) || '0' <= r && r <= '9' || r == '_' {
+ rest = rest[size:]
+ continue
+ }
+ break
+ }
+
+ word = data[:len(data)-len(rest)]
+ if len(word) == 0 {
+ return nil, nil
+ }
+
+ return word, rest
+}
+
// MatchFile reports whether the file with the given name in the given directory
// matches the context and would be included in a Package created by ImportDir
// of that directory.
@@ -789,7 +944,7 @@ func (ctxt *Context) matchFile(dir, name string, returnImports bool, allTags map
}
switch ext {
- case ".go", ".c", ".cc", ".cxx", ".cpp", ".s", ".h", ".hh", ".hpp", ".hxx", ".S", ".swig", ".swigcxx":
+ case ".go", ".c", ".cc", ".cxx", ".cpp", ".m", ".s", ".h", ".hh", ".hpp", ".hxx", ".S", ".swig", ".swigcxx":
// tentatively okay - read to make sure
case ".syso":
// binary, no reading
@@ -1121,6 +1276,9 @@ func (ctxt *Context) match(name string, allTags map[string]bool) bool {
if name == ctxt.GOOS || name == ctxt.GOARCH || name == ctxt.Compiler {
return true
}
+ if ctxt.GOOS == "android" && name == "linux" {
+ return true
+ }
// other tags
for _, tag := range ctxt.BuildTags {
@@ -1148,10 +1306,25 @@ func (ctxt *Context) match(name string, allTags map[string]bool) bool {
// name_$(GOARCH)_test.*
// name_$(GOOS)_$(GOARCH)_test.*
//
+// An exception: if GOOS=android, then files with GOOS=linux are also matched.
func (ctxt *Context) goodOSArchFile(name string, allTags map[string]bool) bool {
if dot := strings.Index(name, "."); dot != -1 {
name = name[:dot]
}
+
+ // Before Go 1.4, a file called "linux.go" would be equivalent to having a
+ // build tag "linux" in that file. For Go 1.4 and beyond, we require this
+ // auto-tagging to apply only to files with a non-empty prefix, so
+ // "foo_linux.go" is tagged but "linux.go" is not. This allows new operating
+ // sytems, such as android, to arrive without breaking existing code with
+ // innocuous source code in "android.go". The easiest fix: cut everything
+ // in the name before the initial _.
+ i := strings.Index(name, "_")
+ if i < 0 {
+ return true
+ }
+ name = name[i:] // ignore everything before first _
+
l := strings.Split(name, "_")
if n := len(l); n > 0 && l[n-1] == "test" {
l = l[:n-1]
@@ -1162,12 +1335,21 @@ func (ctxt *Context) goodOSArchFile(name string, allTags map[string]bool) bool {
allTags[l[n-2]] = true
allTags[l[n-1]] = true
}
- return l[n-2] == ctxt.GOOS && l[n-1] == ctxt.GOARCH
+ if l[n-1] != ctxt.GOARCH {
+ return false
+ }
+ if ctxt.GOOS == "android" && l[n-2] == "linux" {
+ return true
+ }
+ return l[n-2] == ctxt.GOOS
}
if n >= 1 && knownOS[l[n-1]] {
if allTags != nil {
allTags[l[n-1]] = true
}
+ if ctxt.GOOS == "android" && l[n-1] == "linux" {
+ return true
+ }
return l[n-1] == ctxt.GOOS
}
if n >= 1 && knownArch[l[n-1]] {
@@ -1191,8 +1373,15 @@ func init() {
}
}
-// ToolDir is the directory containing build tools.
-var ToolDir = filepath.Join(runtime.GOROOT(), "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH)
+func getToolDir() string {
+ if runtime.Compiler == "gccgo" {
+ return runtime.GCCGOTOOLDIR
+ } else {
+ return filepath.Join(runtime.GOROOT(), "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH)
+ }
+}
+
+var ToolDir = getToolDir()
// IsLocalImport reports whether the import path is
// a local import path, like ".", "..", "./foo", or "../foo".
@@ -1207,12 +1396,14 @@ func ArchChar(goarch string) (string, error) {
switch goarch {
case "386":
return "8", nil
- case "amd64":
+ 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)
}
diff --git a/libgo/go/go/build/build_test.go b/libgo/go/go/build/build_test.go
index fca8d4bdb2..a40def0fa0 100644
--- a/libgo/go/go/build/build_test.go
+++ b/libgo/go/go/build/build_test.go
@@ -85,6 +85,20 @@ func TestEmptyImport(t *testing.T) {
}
}
+func TestEmptyFolderImport(t *testing.T) {
+ _, err := Import(".", "testdata/empty", 0)
+ if _, ok := err.(*NoGoError); !ok {
+ t.Fatal(`Import("testdata/empty") did not return NoGoError.`)
+ }
+}
+
+func TestMultiplePackageImport(t *testing.T) {
+ _, err := Import(".", "testdata/multi", 0)
+ if _, ok := err.(*MultiplePackageError); !ok {
+ t.Fatal(`Import("testdata/multi") did not return MultiplePackageError.`)
+ }
+}
+
func TestLocalDirectory(t *testing.T) {
cwd, err := os.Getwd()
if err != nil {
@@ -153,22 +167,36 @@ func (r readNopCloser) Close() error {
return nil
}
+var (
+ ctxtP9 = Context{GOARCH: "arm", GOOS: "plan9"}
+ ctxtAndroid = Context{GOARCH: "arm", GOOS: "android"}
+)
+
var matchFileTests = []struct {
+ ctxt Context
name string
data string
match bool
}{
- {"foo_arm.go", "", true},
- {"foo1_arm.go", "// +build linux\n\npackage main\n", false},
- {"foo_darwin.go", "", false},
- {"foo.go", "", true},
- {"foo1.go", "// +build linux\n\npackage main\n", false},
- {"foo.badsuffix", "", false},
+ {ctxtP9, "foo_arm.go", "", true},
+ {ctxtP9, "foo1_arm.go", "// +build linux\n\npackage main\n", false},
+ {ctxtP9, "foo_darwin.go", "", false},
+ {ctxtP9, "foo.go", "", true},
+ {ctxtP9, "foo1.go", "// +build linux\n\npackage main\n", false},
+ {ctxtP9, "foo.badsuffix", "", false},
+ {ctxtAndroid, "foo_linux.go", "", true},
+ {ctxtAndroid, "foo_android.go", "", true},
+ {ctxtAndroid, "foo_plan9.go", "", false},
+ {ctxtAndroid, "android.go", "", true},
+ {ctxtAndroid, "plan9.go", "", true},
+ {ctxtAndroid, "plan9_test.go", "", true},
+ {ctxtAndroid, "arm.s", "", true},
+ {ctxtAndroid, "amd64.s", "", true},
}
func TestMatchFile(t *testing.T) {
for _, tt := range matchFileTests {
- ctxt := Context{GOARCH: "arm", GOOS: "plan9"}
+ ctxt := tt.ctxt
ctxt.OpenFile = func(path string) (r io.ReadCloser, err error) {
if path != "x+"+tt.name {
t.Fatalf("OpenFile asked for %q, expected %q", path, "x+"+tt.name)
@@ -184,3 +212,13 @@ func TestMatchFile(t *testing.T) {
}
}
}
+
+func TestImportCmd(t *testing.T) {
+ p, err := Import("cmd/internal/objfile", "", 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !strings.HasSuffix(filepath.ToSlash(p.Dir), "src/cmd/internal/objfile") {
+ t.Fatalf("Import cmd/internal/objfile returned Dir=%q, want %q", filepath.ToSlash(p.Dir), ".../src/cmd/internal/objfile")
+ }
+}
diff --git a/libgo/go/go/build/deps_test.go b/libgo/go/go/build/deps_test.go
index 88f3eca4ed..a335effec3 100644
--- a/libgo/go/go/build/deps_test.go
+++ b/libgo/go/go/build/deps_test.go
@@ -8,6 +8,7 @@
package build
import (
+ "runtime"
"sort"
"testing"
)
@@ -29,7 +30,7 @@ var pkgDeps = map[string][]string{
"errors": {},
"io": {"errors", "sync"},
"runtime": {"unsafe"},
- "sync": {"sync/atomic", "unsafe"},
+ "sync": {"runtime", "sync/atomic", "unsafe"},
"sync/atomic": {"unsafe"},
"unsafe": {},
@@ -125,7 +126,7 @@ var pkgDeps = map[string][]string{
"os": {"L1", "os", "syscall", "time"},
"path/filepath": {"L2", "os", "syscall"},
"io/ioutil": {"L2", "os", "path/filepath", "time"},
- "os/exec": {"L2", "os", "syscall"},
+ "os/exec": {"L2", "os", "path/filepath", "syscall"},
"os/signal": {"L2", "os", "syscall"},
// OS enables basic operating system functionality,
@@ -278,12 +279,12 @@ 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"},
+ "crypto/rand": {"L4", "CRYPTO", "OS", "math/big", "syscall", "internal/syscall"},
// Mathematical crypto: dependencies on fmt (L4) and math/big.
// We could avoid some of the fmt, but math/big imports fmt anyway.
"crypto/dsa": {"L4", "CRYPTO", "math/big"},
- "crypto/ecdsa": {"L4", "CRYPTO", "crypto/elliptic", "math/big"},
+ "crypto/ecdsa": {"L4", "CRYPTO", "crypto/elliptic", "math/big", "encoding/asn1"},
"crypto/elliptic": {"L4", "CRYPTO", "math/big"},
"crypto/rsa": {"L4", "CRYPTO", "crypto/rand", "math/big"},
@@ -301,7 +302,7 @@ var pkgDeps = map[string][]string{
// SSL/TLS.
"crypto/tls": {
"L4", "CRYPTO-MATH", "CGO", "OS",
- "crypto/x509", "encoding/pem", "net", "syscall",
+ "container/list", "crypto/x509", "encoding/pem", "net", "syscall",
},
"crypto/x509": {
"L4", "CRYPTO-MATH", "OS", "CGO",
@@ -317,6 +318,7 @@ var pkgDeps = map[string][]string{
"net/http": {
"L4", "NET", "OS",
"compress/gzip", "crypto/tls", "mime/multipart", "runtime/debug",
+ "net/http/internal",
},
// HTTP-using packages.
@@ -324,9 +326,9 @@ var pkgDeps = map[string][]string{
"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/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", "net/http", "text/template"},
+ "net/rpc": {"L4", "NET", "encoding/gob", "html/template", "net/http"},
"net/rpc/jsonrpc": {"L4", "NET", "encoding/json", "net/rpc"},
}
@@ -359,7 +361,7 @@ func allowed(pkg string) map[string]bool {
}
var bools = []bool{false, true}
-var geese = []string{"darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "plan9", "windows"}
+var geese = []string{"android", "darwin", "dragonfly", "freebsd", "linux", "nacl", "netbsd", "openbsd", "plan9", "solaris", "windows"}
var goarches = []string{"386", "amd64", "arm", "arm64"}
type osPkg struct {
@@ -374,6 +376,11 @@ var allowedErrors = map[osPkg]bool{
}
func TestDependencies(t *testing.T) {
+ if runtime.GOOS == "nacl" {
+ // NaCl tests run in a limited file system and we do not
+ // provide access to every source file.
+ t.Skip("skipping on NaCl")
+ }
var all []string
for k := range pkgDeps {
@@ -387,6 +394,9 @@ func TestDependencies(t *testing.T) {
if isMacro(pkg) {
continue
}
+ if pkg == "runtime/cgo" && !ctxt.CgoEnabled {
+ continue
+ }
p, err := ctxt.Import(pkg, "", 0)
if err != nil {
if allowedErrors[osPkg{ctxt.GOOS, pkg}] {
diff --git a/libgo/go/go/build/doc.go b/libgo/go/go/build/doc.go
index b2f04ea45c..75a827bb91 100644
--- a/libgo/go/go/build/doc.go
+++ b/libgo/go/go/build/doc.go
@@ -57,11 +57,15 @@
//
// Build Constraints
//
-// A build constraint is a line comment beginning with the directive +build
+// A build constraint, also known as a build tag, is a line comment that begins
+//
+// // +build
+//
// that lists the conditions under which a file should be included in the package.
// Constraints may appear in any kind of source file (not just Go), but
// they must appear near the top of the file, preceded
-// only by blank lines and other line comments.
+// only by blank lines and other line comments. These rules mean that in Go
+// files a build constraint must appear before the package clause.
//
// To distinguish build constraints from package documentation, a series of
// build constraints must be followed by a blank line.
@@ -95,6 +99,8 @@
// - "cgo", if ctxt.CgoEnabled is true
// - "go1.1", from Go version 1.1 onward
// - "go1.2", from Go version 1.2 onward
+// - "go1.3", from Go version 1.3 onward
+// - "go1.4", from Go version 1.4 onward
// - any additional words listed in ctxt.BuildTags
//
// If a file's name, after stripping the extension and a possible _test suffix,
@@ -102,12 +108,10 @@
// *_GOOS
// *_GOARCH
// *_GOOS_GOARCH
-// (example: source_windows_amd64.go) or the literals:
-// GOOS
-// GOARCH
-// (example: windows.go) where GOOS and GOARCH represent any known operating
-// system and architecture values respectively, then the file is considered to
-// have an implicit build constraint requiring those terms.
+// (example: source_windows_amd64.go) where GOOS and GOARCH represent
+// any known operating system and architecture values respectively, then
+// the file is considered to have an implicit build constraint requiring
+// those terms.
//
// To keep a file from being considered for the build:
//
@@ -129,4 +133,7 @@
// building the package for Windows; similarly, math_386.s will be included
// only when building the package for 32-bit x86.
//
+// Using GOOS=android matches build tags and files as for GOOS=linux
+// in addition to android tags and files.
+//
package build
diff --git a/libgo/go/go/build/syslist.go b/libgo/go/go/build/syslist.go
index 3580d823b0..0bf4b1573c 100644
--- a/libgo/go/go/build/syslist.go
+++ b/libgo/go/go/build/syslist.go
@@ -4,5 +4,5 @@
package build
-const goosList = "darwin dragonfly freebsd linux netbsd openbsd plan9 windows solaris "
-const goarchList = "386 amd64 arm arm64 alpha m68k mipso32 mipsn32 mipsn64 mipso64 ppc ppc64 sparc sparc64 "
+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 "
diff --git a/libgo/go/go/build/testdata/multi/file.go b/libgo/go/go/build/testdata/multi/file.go
new file mode 100644
index 0000000000..ee946eb2a2
--- /dev/null
+++ b/libgo/go/go/build/testdata/multi/file.go
@@ -0,0 +1,5 @@
+// Test data - not compiled.
+
+package main
+
+func main() {}
diff --git a/libgo/go/go/build/testdata/multi/file_appengine.go b/libgo/go/go/build/testdata/multi/file_appengine.go
new file mode 100644
index 0000000000..4ea31e7031
--- /dev/null
+++ b/libgo/go/go/build/testdata/multi/file_appengine.go
@@ -0,0 +1,5 @@
+// Test data - not compiled.
+
+package test_package
+
+func init() {}
diff --git a/libgo/go/go/doc/comment.go b/libgo/go/go/doc/comment.go
index 5c8c43e0c1..f414ca4090 100644
--- a/libgo/go/go/doc/comment.go
+++ b/libgo/go/go/doc/comment.go
@@ -45,13 +45,13 @@ func commentEscape(w io.Writer, text string, nice bool) {
const (
// Regexp for Go identifiers
- identRx = `[a-zA-Z_][a-zA-Z_0-9]*` // TODO(gri) ASCII only for now - fix this
+ identRx = `[\pL_][\pL_0-9]*`
// Regexp for URLs
- protocol = `(https?|ftp|file|gopher|mailto|news|nntp|telnet|wais|prospero):`
+ protocol = `https?|ftp|file|gopher|mailto|news|nntp|telnet|wais|prospero`
hostPart = `[a-zA-Z0-9_@\-]+`
- filePart = `[a-zA-Z0-9_?%#~&/\-+=]+`
- urlRx = protocol + `//` + // http://
+ filePart = `[a-zA-Z0-9_?%#~&/\-+=()]+` // parentheses may not be matching; see pairedParensPrefixLen
+ urlRx = `(` + protocol + `)://` + // http://
hostPart + `([.:]` + hostPart + `)*/?` + // //www.google.com:8080/
filePart + `([:.,]` + filePart + `)*`
)
@@ -73,6 +73,29 @@ var (
html_endh = []byte("</h3>\n")
)
+// pairedParensPrefixLen returns the length of the longest prefix of s containing paired parentheses.
+func pairedParensPrefixLen(s string) int {
+ parens := 0
+ l := len(s)
+ for i, ch := range s {
+ switch ch {
+ case '(':
+ if parens == 0 {
+ l = i
+ }
+ parens++
+ case ')':
+ parens--
+ if parens == 0 {
+ l = len(s)
+ } else if parens < 0 {
+ return i
+ }
+ }
+ }
+ return l
+}
+
// Emphasize and escape a line of text for HTML. URLs are converted into links;
// if the URL also appears in the words map, the link is taken from the map (if
// the corresponding map value is the empty string, the URL is not converted
@@ -92,18 +115,26 @@ func emphasize(w io.Writer, line string, words map[string]string, nice bool) {
// write text before match
commentEscape(w, line[0:m[0]], nice)
- // analyze match
+ // adjust match if necessary
match := line[m[0]:m[1]]
+ if n := pairedParensPrefixLen(match); n < len(match) {
+ // match contains unpaired parentheses (rare);
+ // redo matching with shortened line for correct indices
+ m = matchRx.FindStringSubmatchIndex(line[:m[0]+n])
+ match = match[:n]
+ }
+
+ // analyze match
url := ""
italics := false
if words != nil {
- url, italics = words[string(match)]
+ url, italics = words[match]
}
if m[2] >= 0 {
// match against first parenthesized sub-regexp; must be match against urlRx
if !italics {
// no alternative URL in words list, use match instead
- url = string(match)
+ url = match
}
italics = false // don't italicize URLs
}
@@ -392,7 +423,9 @@ func ToText(w io.Writer, text string, indent, preIndent string, width int) {
case opPre:
w.Write(nl)
for _, line := range b.lines {
- if !isBlank(line) {
+ if isBlank(line) {
+ w.Write([]byte("\n"))
+ } else {
w.Write([]byte(preIndent))
w.Write([]byte(line))
}
diff --git a/libgo/go/go/doc/comment_test.go b/libgo/go/go/doc/comment_test.go
index aa21b8d1b3..ad65c2a27f 100644
--- a/libgo/go/go/doc/comment_test.go
+++ b/libgo/go/go/doc/comment_test.go
@@ -42,8 +42,9 @@ func TestIsHeading(t *testing.T) {
}
var blocksTests = []struct {
- in string
- out []block
+ in string
+ out []block
+ text string
}{
{
in: `Para 1.
@@ -59,6 +60,22 @@ Para 3.
pre1
Para 4.
+
+ pre
+ pre1
+
+ pre2
+
+Para 5.
+
+
+ pre
+
+
+ pre1
+ pre2
+
+Para 6.
pre
pre2
`,
@@ -69,8 +86,44 @@ Para 4.
{opPara, []string{"Para 3.\n"}},
{opPre, []string{"pre\n", "pre1\n"}},
{opPara, []string{"Para 4.\n"}},
+ {opPre, []string{"pre\n", "pre1\n", "\n", "pre2\n"}},
+ {opPara, []string{"Para 5.\n"}},
+ {opPre, []string{"pre\n", "\n", "\n", "pre1\n", "pre2\n"}},
+ {opPara, []string{"Para 6.\n"}},
{opPre, []string{"pre\n", "pre2\n"}},
},
+ text: `. Para 1. Para 1 line 2.
+
+. Para 2.
+
+
+. Section
+
+. Para 3.
+
+$ pre
+$ pre1
+
+. Para 4.
+
+$ pre
+$ pre1
+
+$ pre2
+
+. Para 5.
+
+$ pre
+
+
+$ pre1
+$ pre2
+
+. Para 6.
+
+$ pre
+$ pre2
+`,
},
}
@@ -83,14 +136,28 @@ func TestBlocks(t *testing.T) {
}
}
+func TestToText(t *testing.T) {
+ var buf bytes.Buffer
+ for i, tt := range blocksTests {
+ ToText(&buf, tt.in, ". ", "$\t", 40)
+ if have := buf.String(); have != tt.text {
+ t.Errorf("#%d: mismatch\nhave: %s\nwant: %s\nhave vs want:\n%q\n%q", i, have, tt.text, have, tt.text)
+ }
+ buf.Reset()
+ }
+}
+
var emphasizeTests = []struct {
- in string
- out string
+ in, out string
}{
{"http://www.google.com/", `<a href="http://www.google.com/">http://www.google.com/</a>`},
{"https://www.google.com/", `<a href="https://www.google.com/">https://www.google.com/</a>`},
{"http://www.google.com/path.", `<a href="http://www.google.com/path">http://www.google.com/path</a>.`},
+ {"http://en.wikipedia.org/wiki/Camellia_(cipher)", `<a href="http://en.wikipedia.org/wiki/Camellia_(cipher)">http://en.wikipedia.org/wiki/Camellia_(cipher)</a>`},
{"(http://www.google.com/)", `(<a href="http://www.google.com/">http://www.google.com/</a>)`},
+ {"http://gmail.com)", `<a href="http://gmail.com">http://gmail.com</a>)`},
+ {"((http://gmail.com))", `((<a href="http://gmail.com">http://gmail.com</a>))`},
+ {"http://gmail.com ((http://gmail.com)) ()", `<a href="http://gmail.com">http://gmail.com</a> ((<a href="http://gmail.com">http://gmail.com</a>)) ()`},
{"Foo bar http://example.com/ quux!", `Foo bar <a href="http://example.com/">http://example.com/</a> quux!`},
{"Hello http://example.com/%2f/ /world.", `Hello <a href="http://example.com/%2f/">http://example.com/%2f/</a> /world.`},
{"Lorem http: ipsum //host/path", "Lorem http: ipsum //host/path"},
@@ -107,3 +174,34 @@ func TestEmphasize(t *testing.T) {
}
}
}
+
+var pairedParensPrefixLenTests = []struct {
+ in, out string
+}{
+ {"", ""},
+ {"foo", "foo"},
+ {"()", "()"},
+ {"foo()", "foo()"},
+ {"foo()()()", "foo()()()"},
+ {"foo()((()()))", "foo()((()()))"},
+ {"foo()((()()))bar", "foo()((()()))bar"},
+ {"foo)", "foo"},
+ {"foo))", "foo"},
+ {"foo)))))", "foo"},
+ {"(foo", ""},
+ {"((foo", ""},
+ {"(((((foo", ""},
+ {"(foo)", "(foo)"},
+ {"((((foo))))", "((((foo))))"},
+ {"foo()())", "foo()()"},
+ {"foo((()())", "foo"},
+ {"foo((()())) (() foo ", "foo((()())) "},
+}
+
+func TestPairedParensPrefixLen(t *testing.T) {
+ for i, tt := range pairedParensPrefixLenTests {
+ if out := tt.in[:pairedParensPrefixLen(tt.in)]; out != tt.out {
+ t.Errorf("#%d: mismatch\nhave: %q\nwant: %q", i, out, tt.out)
+ }
+ }
+}
diff --git a/libgo/go/go/doc/example.go b/libgo/go/go/doc/example.go
index 2358ed3890..c414e548cc 100644
--- a/libgo/go/go/doc/example.go
+++ b/libgo/go/go/doc/example.go
@@ -32,6 +32,17 @@ type Example struct {
// Examples returns the examples found in the files, sorted by Name field.
// The Order fields record the order in which the examples were encountered.
+//
+// Playable Examples must be in a package whose name ends in "_test".
+// An Example is "playable" (the Play field is non-nil) in either of these
+// circumstances:
+// - The example function is self-contained: the function references only
+// identifiers from other packages (or predeclared identifiers, such as
+// "int") and the test file does not include a dot import.
+// - The entire test file is the example: the file contains exactly one
+// example function, zero test or benchmark functions, and at least one
+// top-level function, type, variable, or constant declaration other
+// than the example function.
func Examples(files ...*ast.File) []*Example {
var list []*Example
for _, file := range files {
@@ -244,7 +255,7 @@ func playExample(file *ast.File, body *ast.BlockStmt) *ast.File {
}
}
- // Strip "Output:" commment and adjust body end position.
+ // Strip "Output:" comment and adjust body end position.
body, comments = stripOutputComment(body, comments)
// Synthesize import declaration.
@@ -307,7 +318,7 @@ func playExampleFile(file *ast.File) *ast.File {
return &f
}
-// stripOutputComment finds and removes an "Output:" commment from body
+// stripOutputComment finds and removes an "Output:" comment from body
// and comments, and adjusts the body block's end position.
func stripOutputComment(body *ast.BlockStmt, comments []*ast.CommentGroup) (*ast.BlockStmt, []*ast.CommentGroup) {
// Do nothing if no "Output:" comment found.
diff --git a/libgo/go/go/doc/exports.go b/libgo/go/go/doc/exports.go
index ff01285d4c..1d3b466d8c 100644
--- a/libgo/go/go/doc/exports.go
+++ b/libgo/go/go/doc/exports.go
@@ -6,15 +6,19 @@
package doc
-import "go/ast"
+import (
+ "go/ast"
+ "go/token"
+)
// filterIdentList removes unexported names from list in place
-// and returns the resulting list.
+// and returns the resulting list. If blankOk is set, blank
+// identifiers are considered exported names.
//
-func filterIdentList(list []*ast.Ident) []*ast.Ident {
+func filterIdentList(list []*ast.Ident, blankOk bool) []*ast.Ident {
j := 0
for _, x := range list {
- if ast.IsExported(x.Name) {
+ if ast.IsExported(x.Name) || (blankOk && x.Name == "_") {
list[j] = x
j++
}
@@ -74,7 +78,7 @@ func (r *reader) filterFieldList(parent *namedType, fields *ast.FieldList, ityp
r.remember(ityp)
}
} else {
- field.Names = filterIdentList(field.Names)
+ field.Names = filterIdentList(field.Names, false)
if len(field.Names) < n {
removedFields = true
}
@@ -136,13 +140,15 @@ func (r *reader) filterType(parent *namedType, typ ast.Expr) {
}
}
-func (r *reader) filterSpec(spec ast.Spec) bool {
+func (r *reader) filterSpec(spec ast.Spec, tok token.Token) bool {
switch s := spec.(type) {
case *ast.ImportSpec:
// always keep imports so we can collect them
return true
case *ast.ValueSpec:
- s.Names = filterIdentList(s.Names)
+ // special case: consider blank constants as exported
+ // (work-around for issue 5397)
+ s.Names = filterIdentList(s.Names, tok == token.CONST)
if len(s.Names) > 0 {
r.filterType(nil, s.Type)
return true
@@ -159,10 +165,10 @@ func (r *reader) filterSpec(spec ast.Spec) bool {
return false
}
-func (r *reader) filterSpecList(list []ast.Spec) []ast.Spec {
+func (r *reader) filterSpecList(list []ast.Spec, tok token.Token) []ast.Spec {
j := 0
for _, s := range list {
- if r.filterSpec(s) {
+ if r.filterSpec(s, tok) {
list[j] = s
j++
}
@@ -173,7 +179,7 @@ func (r *reader) filterSpecList(list []ast.Spec) []ast.Spec {
func (r *reader) filterDecl(decl ast.Decl) bool {
switch d := decl.(type) {
case *ast.GenDecl:
- d.Specs = r.filterSpecList(d.Specs)
+ d.Specs = r.filterSpecList(d.Specs, d.Tok)
return len(d.Specs) > 0
case *ast.FuncDecl:
// ok to filter these methods early because any
diff --git a/libgo/go/go/doc/headscan.go b/libgo/go/go/doc/headscan.go
index f559347638..1ccaa15819 100644
--- a/libgo/go/go/doc/headscan.go
+++ b/libgo/go/go/doc/headscan.go
@@ -24,6 +24,7 @@ import (
"go/token"
"os"
"path/filepath"
+ "regexp"
"runtime"
"strings"
)
@@ -33,10 +34,10 @@ var (
verbose = flag.Bool("v", false, "verbose mode")
)
-const (
- html_h = "<h3>"
- html_endh = "</h3>\n"
-)
+// ToHTML in comment.go assigns a (possibly blank) ID to each heading
+var html_h = regexp.MustCompile(`<h3 id="[^"]*">`)
+
+const html_endh = "</h3>\n"
func isGoFile(fi os.FileInfo) bool {
return strings.HasSuffix(fi.Name(), ".go") &&
@@ -47,11 +48,11 @@ func appendHeadings(list []string, comment string) []string {
var buf bytes.Buffer
doc.ToHTML(&buf, comment, nil)
for s := buf.String(); ; {
- i := strings.Index(s, html_h)
- if i < 0 {
+ loc := html_h.FindStringIndex(s)
+ if len(loc) == 0 {
break
}
- i += len(html_h)
+ i := loc[1]
j := strings.Index(s, html_endh)
if j < 0 {
list = append(list, s[i:]) // incorrect HTML
diff --git a/libgo/go/go/doc/testdata/blank.0.golden b/libgo/go/go/doc/testdata/blank.0.golden
new file mode 100644
index 0000000000..dae3ab2aff
--- /dev/null
+++ b/libgo/go/go/doc/testdata/blank.0.golden
@@ -0,0 +1,37 @@
+// Package blank is a go/doc test for the handling of _. See issue ...
+PACKAGE blank
+
+IMPORTPATH
+ testdata/blank
+
+FILENAMES
+ testdata/blank.go
+
+CONSTANTS
+ // Package constants.
+ const (
+ _ int = iota
+ I1
+ I2
+ )
+
+
+TYPES
+ // S has a padding field.
+ type S struct {
+ H uint32
+
+ A uint8
+ // contains filtered or unexported fields
+ }
+
+ //
+ type T int
+
+ // T constants.
+ const (
+ _ T = iota
+ T1
+ T2
+ )
+
diff --git a/libgo/go/go/doc/testdata/blank.1.golden b/libgo/go/go/doc/testdata/blank.1.golden
new file mode 100644
index 0000000000..333d7e5b04
--- /dev/null
+++ b/libgo/go/go/doc/testdata/blank.1.golden
@@ -0,0 +1,46 @@
+// Package blank is a go/doc test for the handling of _. See issue ...
+PACKAGE blank
+
+IMPORTPATH
+ testdata/blank
+
+FILENAMES
+ testdata/blank.go
+
+CONSTANTS
+ // Package constants.
+ const (
+ _ int = iota
+ I1
+ I2
+ )
+
+
+VARIABLES
+ //
+ var _ = T(55)
+
+
+FUNCTIONS
+ //
+ func _()
+
+
+TYPES
+ // S has a padding field.
+ type S struct {
+ H uint32
+ _ uint8
+ A uint8
+ }
+
+ //
+ type T int
+
+ // T constants.
+ const (
+ _ T = iota
+ T1
+ T2
+ )
+
diff --git a/libgo/go/go/doc/testdata/blank.2.golden b/libgo/go/go/doc/testdata/blank.2.golden
new file mode 100644
index 0000000000..dae3ab2aff
--- /dev/null
+++ b/libgo/go/go/doc/testdata/blank.2.golden
@@ -0,0 +1,37 @@
+// Package blank is a go/doc test for the handling of _. See issue ...
+PACKAGE blank
+
+IMPORTPATH
+ testdata/blank
+
+FILENAMES
+ testdata/blank.go
+
+CONSTANTS
+ // Package constants.
+ const (
+ _ int = iota
+ I1
+ I2
+ )
+
+
+TYPES
+ // S has a padding field.
+ type S struct {
+ H uint32
+
+ A uint8
+ // contains filtered or unexported fields
+ }
+
+ //
+ type T int
+
+ // T constants.
+ const (
+ _ T = iota
+ T1
+ T2
+ )
+
diff --git a/libgo/go/go/doc/testdata/blank.go b/libgo/go/go/doc/testdata/blank.go
new file mode 100644
index 0000000000..f812c77b77
--- /dev/null
+++ b/libgo/go/go/doc/testdata/blank.go
@@ -0,0 +1,38 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package blank is a go/doc test for the handling of _.
+// See issue 5397.
+package blank
+
+type T int
+
+// T constants.
+const (
+ _ T = iota
+ T1
+ T2
+)
+
+// Package constants.
+const (
+ _ int = iota
+ I1
+ I2
+)
+
+// Blanks not in doc output:
+
+// S has a padding field.
+type S struct {
+ H uint32
+ _ uint8
+ A uint8
+}
+
+func _() {}
+
+type _ T
+
+var _ = T(55)
diff --git a/libgo/go/go/format/format.go b/libgo/go/go/format/format.go
index 3d00a645db..668a42df2d 100644
--- a/libgo/go/go/format/format.go
+++ b/libgo/go/go/format/format.go
@@ -18,6 +18,8 @@ import (
var config = printer.Config{Mode: printer.UseSpaces | printer.TabIndent, Tabwidth: 8}
+const parserMode = parser.ParseComments
+
// Node formats node in canonical gofmt style and writes the result to dst.
//
// The node type must be *ast.File, *printer.CommentedNode, []ast.Decl,
@@ -52,7 +54,7 @@ func Node(dst io.Writer, fset *token.FileSet, node interface{}) error {
if err != nil {
return err
}
- file, err = parser.ParseFile(fset, "", buf.Bytes(), parser.ParseComments)
+ file, err = parser.ParseFile(fset, "", buf.Bytes(), parserMode)
if err != nil {
// We should never get here. If we do, provide good diagnostic.
return fmt.Errorf("format.Node internal error (%s)", err)
@@ -80,66 +82,18 @@ func Node(dst io.Writer, fset *token.FileSet, node interface{}) error {
//
func Source(src []byte) ([]byte, error) {
fset := token.NewFileSet()
- node, err := parse(fset, src)
+ file, sourceAdj, indentAdj, err := parse(fset, "", src, true)
if err != nil {
return nil, err
}
- var buf bytes.Buffer
- if file, ok := node.(*ast.File); ok {
+ if sourceAdj == nil {
// Complete source file.
+ // TODO(gri) consider doing this always.
ast.SortImports(fset, file)
- err := config.Fprint(&buf, fset, file)
- if err != nil {
- return nil, err
- }
-
- } else {
- // Partial source file.
- // Determine and prepend leading space.
- i, j := 0, 0
- for j < len(src) && isSpace(src[j]) {
- if src[j] == '\n' {
- i = j + 1 // index of last line in leading space
- }
- j++
- }
- buf.Write(src[:i])
-
- // Determine indentation of first code line.
- // Spaces are ignored unless there are no tabs,
- // in which case spaces count as one tab.
- indent := 0
- hasSpace := false
- for _, b := range src[i:j] {
- switch b {
- case ' ':
- hasSpace = true
- case '\t':
- indent++
- }
- }
- if indent == 0 && hasSpace {
- indent = 1
- }
-
- // Format the source.
- cfg := config
- cfg.Indent = indent
- err := cfg.Fprint(&buf, fset, node)
- if err != nil {
- return nil, err
- }
-
- // Determine and append trailing space.
- i = len(src)
- for i > 0 && isSpace(src[i-1]) {
- i--
- }
- buf.Write(src[i:])
}
- return buf.Bytes(), nil
+ return format(fset, file, sourceAdj, indentAdj, src, config)
}
func hasUnsortedImports(file *ast.File) bool {
@@ -160,40 +114,153 @@ func hasUnsortedImports(file *ast.File) bool {
return false
}
-func isSpace(b byte) bool {
- return b == ' ' || b == '\t' || b == '\n' || b == '\r'
-}
+// ----------------------------------------------------------------------------
+// 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.
-func parse(fset *token.FileSet, src []byte) (interface{}, error) {
- // Try as a complete source file.
- file, err := parser.ParseFile(fset, "", src, parser.ParseComments)
- if err == nil {
- return file, nil
- }
- // If the source is missing a package clause, try as a source fragment; otherwise fail.
- if !strings.Contains(err.Error(), "expected 'package'") {
- return nil, err
+// 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
}
- // Try as a declaration list by prepending a package clause in front of src.
- // Use ';' not '\n' to keep line numbers intact.
+ // 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, "", psrc, parser.ParseComments)
+ file, err = parser.ParseFile(fset, filename, psrc, parserMode)
if err == nil {
- return file.Decls, 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 source is missing a declaration, try as a statement list; otherwise fail.
+ // If the error is that the source file didn't begin with a
+ // declaration, fall through to try as a statement list.
+ // Stop and return on any other error.
if !strings.Contains(err.Error(), "expected declaration") {
- return nil, err
+ return
}
- // Try as statement list by wrapping a function around src.
- fsrc := append(append([]byte("package p; func _() {"), src...), '}')
- file, err = parser.ParseFile(fset, "", fsrc, parser.ParseComments)
+ // If 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 {
- return file.Decls[0].(*ast.FuncDecl).Body.List, 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)...)
- // Failed, and out of options.
- return nil, err
+ // 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 93f0992477..d7846bec65 100644
--- a/libgo/go/go/format/format_test.go
+++ b/libgo/go/go/format/format_test.go
@@ -87,7 +87,11 @@ var tests = []string{
"\tx := 0\n\tgo f()\n\n\n",
"\n\t\t\n\n\tx := 0\n\tgo f()\n\n\n",
"\n\t\t\n\n\t\t\tx := 0\n\t\t\tgo f()\n\n\n",
- "\n\t\t\n\n\t\t\tx := 0\n\t\t\tconst s = `\nfoo\n`\n\n\n", // no indentation inside raw strings
+ "\n\t\t\n\n\t\t\tx := 0\n\t\t\tconst s = `\nfoo\n`\n\n\n", // no indentation added inside raw strings
+ "\n\t\t\n\n\t\t\tx := 0\n\t\t\tconst s = `\n\t\tfoo\n`\n\n\n", // no indentation removed inside raw strings
+
+ // comments
+ "i := 5 /* Comment */", // Issue 5551.
// erroneous programs
"ERROR1 + 2 +",
diff --git a/libgo/go/go/parser/error_test.go b/libgo/go/go/parser/error_test.go
index d4d4f909d3..48fb53e5b0 100644
--- a/libgo/go/go/parser/error_test.go
+++ b/libgo/go/go/parser/error_test.go
@@ -34,7 +34,7 @@ import (
const testdata = "testdata"
-var fsetErrs *token.FileSet
+var fsetErrs = token.NewFileSet()
// getFile assumes that each filename occurs at most once
func getFile(filename string) (file *token.File) {
@@ -59,8 +59,11 @@ func getPos(filename string, offset int) token.Pos {
// ERROR comments must be of the form /* ERROR "rx" */ and rx is
// a regular expression that matches the expected error message.
+// The special form /* ERROR HERE "rx" */ must be used for error
+// messages that appear immediately after a token, rather than at
+// a token's position.
//
-var errRx = regexp.MustCompile(`^/\* *ERROR *"([^"]*)" *\*/$`)
+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.
@@ -74,6 +77,7 @@ func expectedErrors(t *testing.T, filename string, src []byte) map[token.Pos]str
// not match the position information collected by the parser
s.Init(getFile(filename), src, nil, scanner.ScanComments)
var prev token.Pos // position of last non-comment, non-semicolon token
+ var here token.Pos // position immediately after the token at position prev
for {
pos, tok, lit := s.Scan()
@@ -82,11 +86,22 @@ func expectedErrors(t *testing.T, filename string, src []byte) map[token.Pos]str
return errors
case token.COMMENT:
s := errRx.FindStringSubmatch(lit)
- if len(s) == 2 {
- errors[prev] = string(s[1])
+ if len(s) == 3 {
+ pos := prev
+ if s[1] == "HERE" {
+ pos = here
+ }
+ errors[pos] = string(s[2])
}
default:
prev = pos
+ var l int // token length
+ if tok.IsLiteral() {
+ l = len(lit)
+ } else {
+ l = len(tok.String())
+ }
+ here = prev + token.Pos(l)
}
}
}
@@ -154,7 +169,6 @@ func checkErrors(t *testing.T, filename string, input interface{}) {
}
func TestErrors(t *testing.T) {
- fsetErrs = token.NewFileSet()
list, err := ioutil.ReadDir(testdata)
if err != nil {
t.Fatal(err)
diff --git a/libgo/go/go/parser/interface.go b/libgo/go/go/parser/interface.go
index 0f83ca9314..49103058b5 100644
--- a/libgo/go/go/parser/interface.go
+++ b/libgo/go/go/parser/interface.go
@@ -182,6 +182,13 @@ func ParseExpr(x string) (ast.Expr, error) {
p.closeScope()
assert(p.topScope == nil, "unbalanced scopes")
+ // If a semicolon was inserted, consume it;
+ // report an error if there's more tokens.
+ if p.tok == token.SEMICOLON && p.lit == "\n" {
+ p.next()
+ }
+ p.expect(token.EOF)
+
if p.errors.Len() > 0 {
p.errors.Sort()
return nil, p.errors.Err()
diff --git a/libgo/go/go/parser/parser.go b/libgo/go/go/parser/parser.go
index c4523318f2..4a005d8ffa 100644
--- a/libgo/go/go/parser/parser.go
+++ b/libgo/go/go/parser/parser.go
@@ -492,6 +492,26 @@ func syncDecl(p *parser) {
}
}
+// safePos returns a valid file position for a given position: If pos
+// is valid to begin with, safePos returns pos. If pos is out-of-range,
+// safePos returns the EOF position.
+//
+// This is hack to work around "artificial" end positions in the AST which
+// are computed by adding 1 to (presumably valid) token positions. If the
+// token positions are invalid due to parse errors, the resulting end position
+// may be past the file's EOF position, which would lead to panics if used
+// later on.
+//
+func (p *parser) safePos(pos token.Pos) (res token.Pos) {
+ defer func() {
+ if recover() != nil {
+ res = token.Pos(p.file.Base() + p.file.Size()) // EOF position
+ }
+ }()
+ _ = p.file.Offset(pos) // trigger a panic if position is out-of-range
+ return pos
+}
+
// ----------------------------------------------------------------------------
// Identifiers
@@ -621,6 +641,7 @@ func (p *parser) parseArrayType() ast.Expr {
}
lbrack := p.expect(token.LBRACK)
+ p.exprLev++
var len ast.Expr
// always permit ellipsis for more fault-tolerant parsing
if p.tok == token.ELLIPSIS {
@@ -629,6 +650,7 @@ func (p *parser) parseArrayType() ast.Expr {
} else if p.tok != token.RBRACK {
len = p.parseRhs()
}
+ p.exprLev--
p.expect(token.RBRACK)
elt := p.parseType()
@@ -679,7 +701,7 @@ func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
if n := len(list); n > 1 || !isTypeName(deref(typ)) {
pos := typ.Pos()
p.errorExpected(pos, "anonymous field")
- typ = &ast.BadExpr{From: pos, To: list[n-1].End()}
+ typ = &ast.BadExpr{From: pos, To: p.safePos(list[n-1].End())}
}
}
@@ -803,9 +825,10 @@ 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.tok == token.COMMA {
- p.next()
+ if !p.atComma("parameter list") {
+ return
}
+ p.next()
for p.tok != token.RPAREN && p.tok != token.EOF {
idents := p.parseIdentList()
typ := p.parseVarType(ellipsisOk)
@@ -820,15 +843,15 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [
}
p.next()
}
- } else {
- // Type { "," Type } (anonymous parameters)
- params = make([]*ast.Field, len(list))
- for i, typ := range list {
- p.resolve(typ)
- params[i] = &ast.Field{Type: typ}
- }
+ return
}
+ // Type { "," Type } (anonymous parameters)
+ params = make([]*ast.Field, len(list))
+ for i, typ := range list {
+ p.resolve(typ)
+ params[i] = &ast.Field{Type: typ}
+ }
return
}
@@ -1168,16 +1191,19 @@ func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
defer un(trace(p, "IndexOrSlice"))
}
+ const N = 3 // change the 3 to 2 to disable 3-index slices
lbrack := p.expect(token.LBRACK)
p.exprLev++
- var index [3]ast.Expr // change the 3 to 2 to disable slice expressions w/ cap
+ var index [N]ast.Expr
+ var colons [N - 1]token.Pos
if p.tok != token.COLON {
index[0] = p.parseRhs()
}
ncolons := 0
- for p.tok == token.COLON && ncolons < len(index)-1 {
- p.next()
+ for p.tok == token.COLON && ncolons < len(colons) {
+ colons[ncolons] = p.pos
ncolons++
+ p.next()
if p.tok != token.COLON && p.tok != token.RBRACK && p.tok != token.EOF {
index[ncolons] = p.parseRhs()
}
@@ -1187,7 +1213,21 @@ func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
if ncolons > 0 {
// slice expression
- return &ast.SliceExpr{X: x, Lbrack: lbrack, Low: index[0], High: index[1], Max: index[2], Slice3: ncolons == 2, Rbrack: rbrack}
+ slice3 := false
+ if ncolons == 2 {
+ slice3 = true
+ // Check presence of 2nd and 3rd index here rather than during type-checking
+ // to prevent erroneous programs from passing through gofmt (was issue 7305).
+ if index[1] == nil {
+ p.error(colons[0], "2nd index required in 3-index slice")
+ index[1] = &ast.BadExpr{From: colons[0] + 1, To: colons[1]}
+ }
+ if index[2] == nil {
+ p.error(colons[1], "3rd index required in 3-index slice")
+ index[2] = &ast.BadExpr{From: colons[1] + 1, To: rbrack}
+ }
+ }
+ return &ast.SliceExpr{X: x, Lbrack: lbrack, Low: index[0], High: index[1], Max: index[2], Slice3: slice3, Rbrack: rbrack}
}
return &ast.IndexExpr{X: x, Lbrack: lbrack, Index: index[0], Rbrack: rbrack}
@@ -1320,7 +1360,7 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr {
default:
// all other nodes are not proper expressions
p.errorExpected(x.Pos(), "expression")
- x = &ast.BadExpr{From: x.Pos(), To: x.End()}
+ x = &ast.BadExpr{From: x.Pos(), To: p.safePos(x.End())}
}
return x
}
@@ -1383,7 +1423,7 @@ func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
case *ast.ArrayType:
if len, isEllipsis := t.Len.(*ast.Ellipsis); isEllipsis {
p.error(len.Pos(), "expected array length, found '...'")
- x = &ast.BadExpr{From: x.Pos(), To: x.End()}
+ x = &ast.BadExpr{From: x.Pos(), To: p.safePos(x.End())}
}
}
@@ -1669,14 +1709,14 @@ func (p *parser) parseSimpleStmt(mode int) (ast.Stmt, bool) {
return &ast.ExprStmt{X: x[0]}, false
}
-func (p *parser) parseCallExpr() *ast.CallExpr {
+func (p *parser) parseCallExpr(callType string) *ast.CallExpr {
x := p.parseRhsOrType() // could be a conversion: (some type)(x)
if call, isCall := x.(*ast.CallExpr); isCall {
return call
}
if _, isBad := x.(*ast.BadExpr); !isBad {
// only report error if it's a new one
- p.errorExpected(x.Pos(), "function/method call")
+ p.error(p.safePos(x.End()), fmt.Sprintf("function must be invoked in %s statement", callType))
}
return nil
}
@@ -1687,7 +1727,7 @@ func (p *parser) parseGoStmt() ast.Stmt {
}
pos := p.expect(token.GO)
- call := p.parseCallExpr()
+ call := p.parseCallExpr("go")
p.expectSemi()
if call == nil {
return &ast.BadStmt{From: pos, To: pos + 2} // len("go")
@@ -1702,7 +1742,7 @@ func (p *parser) parseDeferStmt() ast.Stmt {
}
pos := p.expect(token.DEFER)
- call := p.parseCallExpr()
+ call := p.parseCallExpr("defer")
p.expectSemi()
if call == nil {
return &ast.BadStmt{From: pos, To: pos + 5} // len("defer")
@@ -1745,15 +1785,15 @@ func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
return &ast.BranchStmt{TokPos: pos, Tok: tok, Label: label}
}
-func (p *parser) makeExpr(s ast.Stmt) ast.Expr {
+func (p *parser) makeExpr(s ast.Stmt, kind string) ast.Expr {
if s == nil {
return nil
}
if es, isExpr := s.(*ast.ExprStmt); isExpr {
return p.checkExpr(es.X)
}
- p.error(s.Pos(), "expected condition, found simple statement")
- return &ast.BadExpr{From: s.Pos(), To: s.End()}
+ p.error(s.Pos(), fmt.Sprintf("expected %s, found simple statement (missing parentheses around composite literal?)", kind))
+ return &ast.BadExpr{From: s.Pos(), To: p.safePos(s.End())}
}
func (p *parser) parseIfStmt() *ast.IfStmt {
@@ -1779,7 +1819,7 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
p.next()
x = p.parseRhs()
} else {
- x = p.makeExpr(s)
+ x = p.makeExpr(s, "boolean expression")
s = nil
}
}
@@ -1910,7 +1950,7 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
return &ast.TypeSwitchStmt{Switch: pos, Init: s1, Assign: s2, Body: body}
}
- return &ast.SwitchStmt{Switch: pos, Init: s1, Tag: p.makeExpr(s2), Body: body}
+ return &ast.SwitchStmt{Switch: pos, Init: s1, Tag: p.makeExpr(s2, "switch expression"), Body: body}
}
func (p *parser) parseCommClause() *ast.CommClause {
@@ -2004,7 +2044,16 @@ func (p *parser) parseForStmt() ast.Stmt {
prevLev := p.exprLev
p.exprLev = -1
if p.tok != token.SEMICOLON {
- s2, isRange = p.parseSimpleStmt(rangeOk)
+ if p.tok == token.RANGE {
+ // "for range x" (nil lhs in assignment)
+ pos := p.pos
+ p.next()
+ y := []ast.Expr{&ast.UnaryExpr{OpPos: pos, Op: token.RANGE, X: p.parseRhs()}}
+ s2 = &ast.AssignStmt{Rhs: y}
+ isRange = true
+ } else {
+ s2, isRange = p.parseSimpleStmt(rangeOk)
+ }
}
if !isRange && p.tok == token.SEMICOLON {
p.next()
@@ -2029,13 +2078,15 @@ func (p *parser) parseForStmt() ast.Stmt {
// check lhs
var key, value ast.Expr
switch len(as.Lhs) {
- case 2:
- key, value = as.Lhs[0], as.Lhs[1]
+ case 0:
+ // nothing to do
case 1:
key = as.Lhs[0]
+ case 2:
+ key, value = as.Lhs[0], as.Lhs[1]
default:
- p.errorExpected(as.Lhs[0].Pos(), "1 or 2 expressions")
- return &ast.BadStmt{From: pos, To: body.End()}
+ p.errorExpected(as.Lhs[len(as.Lhs)-1].Pos(), "at most 2 expressions")
+ return &ast.BadStmt{From: pos, To: p.safePos(body.End())}
}
// parseSimpleStmt returned a right-hand side that
// is a single unary expression of the form "range x"
@@ -2055,7 +2106,7 @@ func (p *parser) parseForStmt() ast.Stmt {
return &ast.ForStmt{
For: pos,
Init: s1,
- Cond: p.makeExpr(s2),
+ Cond: p.makeExpr(s2, "boolean or range expression"),
Post: s3,
Body: body,
}
@@ -2259,36 +2310,6 @@ func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.Gen
}
}
-func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
- if p.trace {
- defer un(trace(p, "Receiver"))
- }
-
- par := p.parseParameters(scope, false)
-
- // must have exactly one receiver
- if par.NumFields() != 1 {
- p.errorExpected(par.Opening, "exactly one receiver")
- par.List = []*ast.Field{{Type: &ast.BadExpr{From: par.Opening, To: par.Closing + 1}}}
- return par
- }
-
- // recv type must be of the form ["*"] identifier
- recv := par.List[0]
- base := deref(recv.Type)
- if _, isIdent := base.(*ast.Ident); !isIdent {
- if _, isBad := base.(*ast.BadExpr); !isBad {
- // only report error if it's a new one
- p.errorExpected(base.Pos(), "(unqualified) identifier")
- }
- par.List = []*ast.Field{
- {Type: &ast.BadExpr{From: recv.Pos(), To: recv.End()}},
- }
- }
-
- return par
-}
-
func (p *parser) parseFuncDecl() *ast.FuncDecl {
if p.trace {
defer un(trace(p, "FunctionDecl"))
@@ -2300,7 +2321,7 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl {
var recv *ast.FieldList
if p.tok == token.LPAREN {
- recv = p.parseReceiver(scope)
+ recv = p.parseParameters(scope, false)
}
ident := p.parseIdent()
diff --git a/libgo/go/go/parser/parser_test.go b/libgo/go/go/parser/parser_test.go
index 0a34b7e505..85065fd182 100644
--- a/libgo/go/go/parser/parser_test.go
+++ b/libgo/go/go/parser/parser_test.go
@@ -74,32 +74,57 @@ func TestParseExpr(t *testing.T) {
src := "a + b"
x, err := ParseExpr(src)
if err != nil {
- t.Fatalf("ParseExpr(%s): %v", src, err)
+ t.Errorf("ParseExpr(%q): %v", src, err)
}
// sanity check
if _, ok := x.(*ast.BinaryExpr); !ok {
- t.Errorf("ParseExpr(%s): got %T, expected *ast.BinaryExpr", src, x)
+ t.Errorf("ParseExpr(%q): got %T, want *ast.BinaryExpr", src, x)
}
// a valid type expression
src = "struct{x *int}"
x, err = ParseExpr(src)
if err != nil {
- t.Fatalf("ParseExpr(%s): %v", src, err)
+ t.Errorf("ParseExpr(%q): %v", src, err)
}
// sanity check
if _, ok := x.(*ast.StructType); !ok {
- t.Errorf("ParseExpr(%s): got %T, expected *ast.StructType", src, x)
+ t.Errorf("ParseExpr(%q): got %T, want *ast.StructType", src, x)
}
// an invalid expression
src = "a + *"
- _, err = ParseExpr(src)
- if err == nil {
- t.Fatalf("ParseExpr(%s): %v", src, err)
+ if _, err := ParseExpr(src); err == nil {
+ t.Errorf("ParseExpr(%q): got no error", src)
}
- // it must not crash
+ // a valid expression followed by extra tokens is invalid
+ src = "a[i] := x"
+ if _, err := ParseExpr(src); err == nil {
+ t.Errorf("ParseExpr(%q): got no error", src)
+ }
+
+ // a semicolon is not permitted unless automatically inserted
+ src = "a + b\n"
+ if _, err := ParseExpr(src); err != nil {
+ t.Errorf("ParseExpr(%q): got error %s", src, err)
+ }
+ src = "a + b;"
+ if _, err := ParseExpr(src); err == nil {
+ t.Errorf("ParseExpr(%q): got no error", src)
+ }
+
+ // various other stuff following a valid expression
+ const validExpr = "a + b"
+ const anything = "dh3*#D)#_"
+ for _, c := range "!)]};," {
+ src := validExpr + string(c) + anything
+ if _, err := ParseExpr(src); err == nil {
+ t.Errorf("ParseExpr(%q): got no error", src)
+ }
+ }
+
+ // ParseExpr must not crash
for _, src := range valids {
ParseExpr(src)
}
diff --git a/libgo/go/go/parser/short_test.go b/libgo/go/go/parser/short_test.go
index 0ef0c560c4..05e44de28a 100644
--- a/libgo/go/go/parser/short_test.go
+++ b/libgo/go/go/parser/short_test.go
@@ -35,6 +35,11 @@ var valids = []string{
`package p; func f() { for _ = range "foo" + "bar" {} };`,
`package p; func f() { var s []int; g(s[:], s[i:], s[:j], s[i:j], s[i:j:k], s[:j:k]) };`,
`package p; var ( _ = (struct {*T}).m; _ = (interface {T}).m )`,
+ `package p; func ((T),) m() {}`,
+ `package p; func ((*T),) m() {}`,
+ `package p; func (*(T),) m() {}`,
+ `package p; func _(x []int) { for range x {} }`,
+ `package p; func _() { if [T{}.n]int{} {} }`,
}
func TestValid(t *testing.T) {
@@ -48,14 +53,14 @@ var invalids = []string{
`package p; func f() { if { /* ERROR "expected operand" */ } };`,
`package p; func f() { if ; { /* ERROR "expected operand" */ } };`,
`package p; func f() { if f(); { /* ERROR "expected operand" */ } };`,
- `package p; func f() { if _ /* ERROR "expected condition" */ = range x; true {} };`,
- `package p; func f() { switch _ /* ERROR "expected condition" */ = range x; true {} };`,
+ `package p; func f() { if _ /* ERROR "expected boolean expression" */ = range x; true {} };`,
+ `package p; func f() { switch _ /* ERROR "expected switch expression" */ = range x; true {} };`,
`package p; func f() { for _ = range x ; /* ERROR "expected '{'" */ ; {} };`,
`package p; func f() { for ; ; _ = range /* ERROR "expected operand" */ x {} };`,
- `package p; func f() { for ; _ /* ERROR "expected condition" */ = range x ; {} };`,
- `package p; func f() { switch t /* ERROR "expected condition" */ = t.(type) {} };`,
- `package p; func f() { switch t /* ERROR "expected condition" */ , t = t.(type) {} };`,
- `package p; func f() { switch t /* ERROR "expected condition" */ = t.(type), t {} };`,
+ `package p; func f() { for ; _ /* ERROR "expected boolean or range expression" */ = range x ; {} };`,
+ `package p; func f() { switch t /* ERROR "expected switch expression" */ = t.(type) {} };`,
+ `package p; func f() { switch t /* ERROR "expected switch expression" */ , t = t.(type) {} };`,
+ `package p; func f() { switch t /* ERROR "expected switch expression" */ = t.(type), t {} };`,
`package p; var a = [ /* ERROR "expected expression" */ 1]int;`,
`package p; var a = [ /* ERROR "expected expression" */ ...]int;`,
`package p; var a = struct /* ERROR "expected expression" */ {}`,
@@ -76,8 +81,20 @@ var invalids = []string{
`package p; func f() { _ = x = /* ERROR "expected '=='" */ 0 {}};`,
`package p; func f() { _ = 1 == func()int { var x bool; x = x = /* ERROR "expected '=='" */ true; return x }() };`,
`package p; func f() { var s []int; _ = s[] /* ERROR "expected operand" */ };`,
- `package p; func f() { var s []int; _ = s[::: /* ERROR "expected ']'" */ ] };`,
+ `package p; func f() { var s []int; _ = s[i:j: /* ERROR "3rd index required" */ ] };`,
+ `package p; func f() { var s []int; _ = s[i: /* ERROR "2nd index required" */ :k] };`,
+ `package p; func f() { var s []int; _ = s[i: /* ERROR "2nd index required" */ :] };`,
+ `package p; func f() { var s []int; _ = s[: /* ERROR "2nd index required" */ :] };`,
+ `package p; func f() { var s []int; _ = s[: /* ERROR "2nd index required" */ ::] };`,
`package p; func f() { var s []int; _ = s[i:j:k: /* ERROR "expected ']'" */ l] };`,
+ `package p; func f() { for x /* ERROR "boolean or range expression" */ = []string {} }`,
+ `package p; func f() { for x /* ERROR "boolean or range expression" */ := []string {} }`,
+ `package p; func f() { for i /* ERROR "boolean or range expression" */ , x = []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`,
}
func TestInvalid(t *testing.T) {
diff --git a/libgo/go/go/printer/nodes.go b/libgo/go/go/printer/nodes.go
index 583c6c3709..d5a69349be 100644
--- a/libgo/go/go/printer/nodes.go
+++ b/libgo/go/go/printer/nodes.go
@@ -163,8 +163,8 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
size := 0
// print all list elements
+ prevLine := prev.Line
for i, x := range list {
- prevLine := line
line = p.lineFor(x.Pos())
// determine if the next linebreak, if any, needs to use formfeed:
@@ -207,8 +207,8 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
}
}
+ needsLinebreak := 0 < prevLine && prevLine < line
if i > 0 {
- needsLinebreak := prevLine < line && prevLine > 0 && line > 0
// use position of expression following the comma as
// comma position for correct comment placement, but
// only if the expression is on the same line
@@ -232,16 +232,20 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
}
}
- if isPair && size > 0 && len(list) > 1 {
- // we have a key:value expression that fits onto one line and
- // is in a list with more then one entry: use a column for the
- // key such that consecutive entries can align if possible
+ if len(list) > 1 && isPair && size > 0 && needsLinebreak {
+ // we have a key:value expression that fits onto one line
+ // and it's not on the same line as the prior expression:
+ // use a column for the key such that consecutive entries
+ // can align if possible
+ // (needsLinebreak is set if we started a new line before)
p.expr(pair.Key)
p.print(pair.Colon, token.COLON, vtab)
p.expr(pair.Value)
} else {
p.expr0(x, depth)
}
+
+ prevLine = line
}
if mode&commaTerm != 0 && next.IsValid() && p.pos.Line < next.Line {
@@ -378,10 +382,6 @@ func (p *printer) setLineComment(text string) {
p.setComment(&ast.CommentGroup{List: []*ast.Comment{{Slash: token.NoPos, Text: text}}})
}
-func (p *printer) isMultiLine(n ast.Node) bool {
- return p.lineFor(n.End())-p.lineFor(n.Pos()) > 0
-}
-
func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) {
lbrace := fields.Opening
list := fields.List
@@ -428,13 +428,14 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
if len(list) == 1 {
sep = blank
}
- newSection := false
+ var line int
for i, f := range list {
if i > 0 {
- p.linebreak(p.lineFor(f.Pos()), 1, ignore, newSection)
+ p.linebreak(p.lineFor(f.Pos()), 1, ignore, p.linesFrom(line) > 0)
}
extraTabs := 0
p.setComment(f.Doc)
+ p.recordLine(&line)
if len(f.Names) > 0 {
// named fields
p.identList(f.Names, false)
@@ -460,7 +461,6 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
}
p.setComment(f.Comment)
}
- newSection = p.isMultiLine(f)
}
if isIncomplete {
if len(list) > 0 {
@@ -472,12 +472,13 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
} else { // interface
- newSection := false
+ var line int
for i, f := range list {
if i > 0 {
- p.linebreak(p.lineFor(f.Pos()), 1, ignore, newSection)
+ p.linebreak(p.lineFor(f.Pos()), 1, ignore, p.linesFrom(line) > 0)
}
p.setComment(f.Doc)
+ p.recordLine(&line)
if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp {
// method
p.expr(f.Names[0])
@@ -487,7 +488,6 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
p.expr(f.Type)
}
p.setComment(f.Comment)
- newSection = p.isMultiLine(f)
}
if isIncomplete {
if len(list) > 0 {
@@ -736,7 +736,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
if _, hasParens := x.X.(*ast.ParenExpr); hasParens {
// don't print parentheses around an already parenthesized expression
// TODO(gri) consider making this more general and incorporate precedence levels
- p.expr0(x.X, reduceDepth(depth)) // parentheses undo one level of depth
+ p.expr0(x.X, depth)
} else {
p.print(token.LPAREN)
p.expr0(x.X, reduceDepth(depth)) // parentheses undo one level of depth
@@ -826,10 +826,16 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
}
p.print(x.Lbrace, token.LBRACE)
p.exprList(x.Lbrace, x.Elts, 1, commaTerm, x.Rbrace)
- // do not insert extra line breaks because of comments before
- // the closing '}' as it might break the code if there is no
- // trailing ','
- p.print(noExtraLinebreak, x.Rbrace, token.RBRACE, noExtraLinebreak)
+ // do not insert extra line break following a /*-style comment
+ // before the closing '}' as it might break the code if there
+ // is no trailing ','
+ mode := noExtraLinebreak
+ // do not insert extra blank following a /*-style comment
+ // before the closing '}' unless the literal is empty
+ if len(x.Elts) > 0 {
+ mode |= noExtraBlank
+ }
+ p.print(mode, x.Rbrace, token.RBRACE, mode)
case *ast.Ellipsis:
p.print(token.ELLIPSIS)
@@ -901,20 +907,31 @@ func (p *printer) stmtList(list []ast.Stmt, nindent int, nextIsRBrace bool) {
if nindent > 0 {
p.print(indent)
}
- multiLine := false
+ var line int
i := 0
for _, s := range list {
// ignore empty statements (was issue 3466)
if _, isEmpty := s.(*ast.EmptyStmt); !isEmpty {
- // _indent == 0 only for lists of switch/select case clauses;
+ // nindent == 0 only for lists of switch/select case clauses;
// in those cases each clause is a new section
if len(p.output) > 0 {
// only print line break if we are not at the beginning of the output
// (i.e., we are not printing only a partial program)
- p.linebreak(p.lineFor(s.Pos()), 1, ignore, i == 0 || nindent == 0 || multiLine)
+ p.linebreak(p.lineFor(s.Pos()), 1, ignore, i == 0 || nindent == 0 || p.linesFrom(line) > 0)
}
+ p.recordLine(&line)
p.stmt(s, nextIsRBrace && i == len(list)-1)
- multiLine = p.isMultiLine(s)
+ // labeled statements put labels on a separate line, but here
+ // we only care about the start line of the actual statement
+ // without label - correct line for each label
+ for t := s; ; {
+ lt, _ := t.(*ast.LabeledStmt)
+ if lt == nil {
+ break
+ }
+ line++
+ t = lt.Stmt
+ }
i++
}
}
@@ -1203,14 +1220,17 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool) {
case *ast.RangeStmt:
p.print(token.FOR, blank)
- p.expr(s.Key)
- if s.Value != nil {
- // use position of value following the comma as
- // comma position for correct comment placement
- p.print(s.Value.Pos(), token.COMMA, blank)
- p.expr(s.Value)
- }
- p.print(blank, s.TokPos, s.Tok, blank, token.RANGE, blank)
+ if s.Key != nil {
+ p.expr(s.Key)
+ if s.Value != nil {
+ // use position of value following the comma as
+ // comma position for correct comment placement
+ p.print(s.Value.Pos(), token.COMMA, blank)
+ p.expr(s.Value)
+ }
+ p.print(blank, s.TokPos, s.Tok, blank)
+ }
+ p.print(token.RANGE, blank)
p.expr(stripParens(s.X))
p.print(blank)
p.block(s.Body, 1)
@@ -1375,22 +1395,22 @@ func (p *printer) genDecl(d *ast.GenDecl) {
// two or more grouped const/var declarations:
// determine if the type column must be kept
keepType := keepTypeColumn(d.Specs)
- newSection := false
+ var line int
for i, s := range d.Specs {
if i > 0 {
- p.linebreak(p.lineFor(s.Pos()), 1, ignore, newSection)
+ p.linebreak(p.lineFor(s.Pos()), 1, ignore, p.linesFrom(line) > 0)
}
+ p.recordLine(&line)
p.valueSpec(s.(*ast.ValueSpec), keepType[i])
- newSection = p.isMultiLine(s)
}
} else {
- newSection := false
+ var line int
for i, s := range d.Specs {
if i > 0 {
- p.linebreak(p.lineFor(s.Pos()), 1, ignore, newSection)
+ p.linebreak(p.lineFor(s.Pos()), 1, ignore, p.linesFrom(line) > 0)
}
+ p.recordLine(&line)
p.spec(s, n, false)
- newSection = p.isMultiLine(s)
}
}
p.print(unindent, formfeed)
@@ -1448,13 +1468,16 @@ func (p *printer) bodySize(b *ast.BlockStmt, maxSize int) int {
// opening and closing brace are on different lines - don't make it a one-liner
return maxSize + 1
}
- if len(b.List) > 5 || p.commentBefore(p.posFor(pos2)) {
- // too many statements or there is a comment inside - don't make it a one-liner
+ if len(b.List) > 5 {
+ // too many statements - don't make it a one-liner
return maxSize + 1
}
// otherwise, estimate body size
- bodySize := 0
+ bodySize := p.commentSizeBefore(p.posFor(pos2))
for i, s := range b.List {
+ if bodySize > maxSize {
+ break // no need to continue
+ }
if i > 0 {
bodySize += 2 // space for a semicolon and blank
}
@@ -1488,7 +1511,7 @@ func (p *printer) adjBlock(headerSize int, sep whiteSpace, b *ast.BlockStmt) {
}
p.print(blank)
}
- p.print(b.Rbrace, token.RBRACE)
+ p.print(noExtraLinebreak, b.Rbrace, token.RBRACE, noExtraLinebreak)
return
}
diff --git a/libgo/go/go/printer/printer.go b/libgo/go/go/printer/printer.go
index e06d2edfb2..280c697a0d 100644
--- a/libgo/go/go/printer/printer.go
+++ b/libgo/go/go/printer/printer.go
@@ -39,9 +39,17 @@ const (
type pmode int
const (
- noExtraLinebreak pmode = 1 << iota
+ noExtraBlank pmode = 1 << iota // disables extra blank after /*-style comment
+ noExtraLinebreak // disables extra line break after /*-style comment
)
+type commentInfo struct {
+ cindex int // current comment index
+ comment *ast.CommentGroup // = printer.comments[cindex]; or nil
+ commentOffset int // = printer.posFor(printer.comments[cindex].List[0].Pos()).Offset; or infinity
+ commentNewline bool // true if the comment group contains newlines
+}
+
type printer struct {
// Configuration (does not change after initialization)
Config
@@ -52,7 +60,8 @@ type printer struct {
indent int // current indentation
mode pmode // current printer mode
impliedSemi bool // if set, a linebreak implies a semicolon
- lastTok token.Token // the last token printed (token.ILLEGAL if it's whitespace)
+ lastTok token.Token // last token printed (token.ILLEGAL if it's whitespace)
+ prevOpen token.Token // previous non-brace "open" token (, [, or token.ILLEGAL
wsbuf []whiteSpace // delayed white space
// Positions
@@ -61,19 +70,17 @@ type printer struct {
// white space). If there's a difference and SourcePos is set in
// ConfigMode, //line comments are used in the output to restore
// original source positions for a reader.
- pos token.Position // current position in AST (source) space
- out token.Position // current position in output space
- last token.Position // value of pos after calling writeString
+ pos token.Position // current position in AST (source) space
+ out token.Position // current position in output space
+ last token.Position // value of pos after calling writeString
+ linePtr *int // if set, record out.Line for the next token in *linePtr
// The list of all source comments, in order of appearance.
comments []*ast.CommentGroup // may be nil
- cindex int // current comment index
useNodeComments bool // if not set, ignore lead and line comments of nodes
// Information about p.comments[p.cindex]; set up by nextComment.
- comment *ast.CommentGroup // = p.comments[p.cindex]; or nil
- commentOffset int // = p.posFor(p.comments[p.cindex].List[0].Pos()).Offset; or infinity
- commentNewline bool // true if the comment group contains newlines
+ commentInfo
// Cache of already computed node sizes.
nodeSizes map[ast.Node]int
@@ -93,6 +100,14 @@ func (p *printer) init(cfg *Config, fset *token.FileSet, nodeSizes map[ast.Node]
p.cachedPos = -1
}
+func (p *printer) internalError(msg ...interface{}) {
+ if debug {
+ fmt.Print(p.pos.String() + ": ")
+ fmt.Println(msg...)
+ panic("go/printer")
+ }
+}
+
// commentsHaveNewline reports whether a list of comments belonging to
// an *ast.CommentGroup contains newlines. Because the position information
// may only be partially correct, we also have to read the comment text.
@@ -129,12 +144,49 @@ func (p *printer) nextComment() {
p.commentOffset = infinity
}
-func (p *printer) internalError(msg ...interface{}) {
- if debug {
- fmt.Print(p.pos.String() + ": ")
- fmt.Println(msg...)
- panic("go/printer")
+// commentBefore returns true iff the current comment group occurs
+// before the next position in the source code and printing it does
+// not introduce implicit semicolons.
+//
+func (p *printer) commentBefore(next token.Position) bool {
+ return p.commentOffset < next.Offset && (!p.impliedSemi || !p.commentNewline)
+}
+
+// commentSizeBefore returns the estimated size of the
+// comments on the same line before the next position.
+//
+func (p *printer) commentSizeBefore(next token.Position) int {
+ // save/restore current p.commentInfo (p.nextComment() modifies it)
+ defer func(info commentInfo) {
+ p.commentInfo = info
+ }(p.commentInfo)
+
+ size := 0
+ for p.commentBefore(next) {
+ for _, c := range p.comment.List {
+ size += len(c.Text)
+ }
+ p.nextComment()
}
+ return size
+}
+
+// recordLine records the output line number for the next non-whitespace
+// token in *linePtr. It is used to compute an accurate line number for a
+// formatted construct, independent of pending (not yet emitted) whitespace
+// or comments.
+//
+func (p *printer) recordLine(linePtr *int) {
+ p.linePtr = linePtr
+}
+
+// linesFrom returns the number of output lines between the current
+// output line and the line argument, ignoring any pending (not yet
+// emitted) whitespace or comments. It is used to compute an accurate
+// size (in number of lines) for a formatted construct.
+//
+func (p *printer) linesFrom(line int) int {
+ return p.out.Line - line
}
func (p *printer) posFor(pos token.Pos) token.Position {
@@ -675,10 +727,14 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (wro
if last != nil {
// if the last comment is a /*-style comment and the next item
- // follows on the same line but is not a comma or a "closing"
- // token, add an extra blank for separation
- if last.Text[1] == '*' && p.lineFor(last.Pos()) == next.Line && tok != token.COMMA &&
- tok != token.RPAREN && tok != token.RBRACK && tok != token.RBRACE {
+ // follows on the same line but is not a comma, and not a "closing"
+ // token immediately following its corresponding "opening" token,
+ // add an extra blank for separation unless explicitly disabled
+ if p.mode&noExtraBlank == 0 &&
+ last.Text[1] == '*' && p.lineFor(last.Pos()) == next.Line &&
+ tok != token.COMMA &&
+ (tok != token.RPAREN || p.prevOpen == token.LPAREN) &&
+ (tok != token.RBRACK || p.prevOpen == token.LBRACK) {
p.writeByte(' ', 1)
}
// ensure that there is a line break after a //-style comment,
@@ -735,12 +791,8 @@ func (p *printer) writeWhitespace(n int) {
}
// shift remaining entries down
- i := 0
- for ; n < len(p.wsbuf); n++ {
- p.wsbuf[i] = p.wsbuf[n]
- i++
- }
- p.wsbuf = p.wsbuf[0:i]
+ l := copy(p.wsbuf, p.wsbuf[n:])
+ p.wsbuf = p.wsbuf[:l]
}
// ----------------------------------------------------------------------------
@@ -790,6 +842,17 @@ func (p *printer) print(args ...interface{}) {
var isLit bool
var impliedSemi bool // value for p.impliedSemi after this arg
+ // record previous opening token, if any
+ switch p.lastTok {
+ case token.ILLEGAL:
+ // ignore (white space)
+ case token.LPAREN, token.LBRACK:
+ p.prevOpen = p.lastTok
+ default:
+ // other tokens followed any opening token
+ p.prevOpen = token.ILLEGAL
+ }
+
switch x := arg.(type) {
case pmode:
// toggle printer mode
@@ -899,19 +962,17 @@ func (p *printer) print(args ...interface{}) {
}
}
+ // the next token starts now - record its line number if requested
+ if p.linePtr != nil {
+ *p.linePtr = p.out.Line
+ p.linePtr = nil
+ }
+
p.writeString(next, data, isLit)
p.impliedSemi = impliedSemi
}
}
-// commentBefore returns true iff the current comment group occurs
-// before the next position in the source code and printing it does
-// not introduce implicit semicolons.
-//
-func (p *printer) commentBefore(next token.Position) (result bool) {
- return p.commentOffset < next.Offset && (!p.impliedSemi || !p.commentNewline)
-}
-
// flush prints any pending comments and whitespace occurring textually
// before the position of the next token tok. The flush result indicates
// if a newline was written or if a formfeed was dropped from the whitespace
diff --git a/libgo/go/go/printer/printer_test.go b/libgo/go/go/printer/printer_test.go
index 8454ac12b9..3b0570e5b5 100644
--- a/libgo/go/go/printer/printer_test.go
+++ b/libgo/go/go/printer/printer_test.go
@@ -63,7 +63,7 @@ func format(src []byte, mode checkMode) ([]byte, error) {
return nil, fmt.Errorf("print: %s", err)
}
- // make sure formated output is syntactically correct
+ // make sure formatted output is syntactically correct
res := buf.Bytes()
if _, err := parser.ParseFile(fset, "", res, 0); err != nil {
return nil, fmt.Errorf("re-parse: %s\n%s", err, buf.Bytes())
@@ -159,13 +159,6 @@ func runcheck(t *testing.T, source, golden string, mode checkMode) {
}
func check(t *testing.T, source, golden string, mode checkMode) {
- // start a timer to produce a time-out signal
- tc := make(chan int)
- go func() {
- time.Sleep(10 * time.Second) // plenty of a safety margin, even for very slow machines
- tc <- 0
- }()
-
// run the test
cc := make(chan int)
go func() {
@@ -173,13 +166,13 @@ func check(t *testing.T, source, golden string, mode checkMode) {
cc <- 0
}()
- // wait for the first finisher
+ // wait with timeout
select {
- case <-tc:
+ case <-time.After(10 * time.Second): // plenty of a safety margin, even for very slow machines
// test running past time out
t.Errorf("%s: running too slowly", source)
case <-cc:
- // test finished within alloted time margin
+ // test finished within allotted time margin
}
}
@@ -212,7 +205,7 @@ func TestFiles(t *testing.T) {
}
}
-// TestLineComments, using a simple test case, checks that consequtive line
+// TestLineComments, using a simple test case, checks that consecutive line
// comments are properly terminated with a newline even if the AST position
// information is incorrect.
//
@@ -357,7 +350,7 @@ func idents(f *ast.File) <-chan *ast.Ident {
// identCount returns the number of identifiers found in f.
func identCount(f *ast.File) int {
n := 0
- for _ = range idents(f) {
+ for range idents(f) {
n++
}
return n
diff --git a/libgo/go/go/printer/testdata/comments.golden b/libgo/go/go/printer/testdata/comments.golden
index 610a42a68b..b1af7958a9 100644
--- a/libgo/go/go/printer/testdata/comments.golden
+++ b/libgo/go/go/printer/testdata/comments.golden
@@ -494,16 +494,21 @@ func _() {
func _( /* this */ x /* is */ /* an */ int) {
}
-func _( /* no params */) {}
+func _( /* no params - extra blank before and after comment */ ) {}
+func _(a, b int /* params - no extra blank after comment */) {}
+
+func _() { f( /* no args - extra blank before and after comment */ ) }
+func _() { f(a, b /* args - no extra blank after comment */) }
func _() {
- f( /* no args */)
+ f( /* no args - extra blank before and after comment */ )
+ f(a, b /* args - no extra blank after comment */)
}
func ( /* comment1 */ T /* comment2 */) _() {}
-func _() { /* one-line functions with comments are formatted as multi-line functions */
-}
+func _() { /* "short-ish one-line functions with comments are formatted as multi-line functions */ }
+func _() { x := 0; /* comment */ y = x /* comment */ }
func _() {
_ = 0
diff --git a/libgo/go/go/printer/testdata/comments.input b/libgo/go/go/printer/testdata/comments.input
index d121dd4be7..983e2b2c97 100644
--- a/libgo/go/go/printer/testdata/comments.input
+++ b/libgo/go/go/printer/testdata/comments.input
@@ -500,15 +500,21 @@ func _() {
func _(/* this */x/* is *//* an */ int) {
}
-func _(/* no params */) {}
+func _(/* no params - extra blank before and after comment */) {}
+func _(a, b int /* params - no extra blank after comment */) {}
+
+func _() { f(/* no args - extra blank before and after comment */) }
+func _() { f(a, b /* args - no extra blank after comment */) }
func _() {
- f(/* no args */)
+ f(/* no args - extra blank before and after comment */)
+ f(a, b /* args - no extra blank after comment */)
}
func (/* comment1 */ T /* comment2 */) _() {}
-func _() { /* one-line functions with comments are formatted as multi-line functions */ }
+func _() { /* "short-ish one-line functions with comments are formatted as multi-line functions */ }
+func _() { x := 0; /* comment */ y = x /* comment */ }
func _() {
_ = 0
diff --git a/libgo/go/go/printer/testdata/comments2.golden b/libgo/go/go/printer/testdata/comments2.golden
index d3b50bf3e0..7676a26c12 100644
--- a/libgo/go/go/printer/testdata/comments2.golden
+++ b/libgo/go/go/printer/testdata/comments2.golden
@@ -77,3 +77,29 @@ func main() {
println("test")
}
}
+
+func issue5623() {
+L:
+ _ = yyyyyyyyyyyyyyyy // comment - should be aligned
+ _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx /* comment */
+
+ _ = yyyyyyyyyyyyyyyy /* comment - should be aligned */
+ _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx // comment
+
+LLLLLLL:
+ _ = yyyyyyyyyyyyyyyy // comment - should be aligned
+ _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx // comment
+
+LL:
+LLLLL:
+ _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx /* comment */
+ _ = yyyyyyyyyyyyyyyy /* comment - should be aligned */
+
+ _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx // comment
+ _ = yyyyyyyyyyyyyyyy // comment - should be aligned
+
+ // test case from issue
+label:
+ mask := uint64(1)<<c - 1 // Allocation mask
+ used := atomic.LoadUint64(&h.used) // Current allocations
+}
diff --git a/libgo/go/go/printer/testdata/comments2.input b/libgo/go/go/printer/testdata/comments2.input
index 6f8c85c94a..4a055c8277 100644
--- a/libgo/go/go/printer/testdata/comments2.input
+++ b/libgo/go/go/printer/testdata/comments2.input
@@ -76,4 +76,30 @@ prints test 5 times
for i := 0; i < 5; i++ {
println("test")
}
-} \ No newline at end of file
+}
+
+func issue5623() {
+L:
+ _ = yyyyyyyyyyyyyyyy // comment - should be aligned
+ _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx /* comment */
+
+ _ = yyyyyyyyyyyyyyyy /* comment - should be aligned */
+ _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx // comment
+
+LLLLLLL:
+ _ = yyyyyyyyyyyyyyyy // comment - should be aligned
+ _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx // comment
+
+LL:
+LLLLL:
+ _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx /* comment */
+ _ = yyyyyyyyyyyyyyyy /* comment - should be aligned */
+
+ _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx // comment
+ _ = yyyyyyyyyyyyyyyy // comment - should be aligned
+
+// test case from issue
+label:
+ mask := uint64(1)<<c - 1 // Allocation mask
+ used := atomic.LoadUint64(&h.used) // Current allocations
+}
diff --git a/libgo/go/go/printer/testdata/declarations.golden b/libgo/go/go/printer/testdata/declarations.golden
index 0331615e51..9acd41b7d2 100644
--- a/libgo/go/go/printer/testdata/declarations.golden
+++ b/libgo/go/go/printer/testdata/declarations.golden
@@ -397,6 +397,21 @@ func _() {
}
}
+// use the formatted output rather than the input to decide when to align
+// (was issue 4505)
+const (
+ short = 2 * (1 + 2)
+ aMuchLongerName = 3
+)
+
+var (
+ short = X{}
+ aMuchLongerName = X{}
+
+ x1 = X{} // foo
+ x2 = X{} // foo
+)
+
func _() {
type (
xxxxxx int
@@ -578,7 +593,7 @@ var (
)
func _() {
- var privateKey2 = &Block{Type: "RSA PRIVATE KEY",
+ var privateKey2 = &Block{Type: "RSA PRIVATE KEY",
Headers: map[string]string{},
Bytes: []uint8{0x30, 0x82, 0x1, 0x3a, 0x2, 0x1, 0x0, 0x2,
0x41, 0x0, 0xb2, 0x99, 0xf, 0x49, 0xc4, 0x7d, 0xfa, 0x8c,
@@ -683,6 +698,29 @@ var _ = T4{
c: z,
}
+// no alignment of map composite entries if they are not the first entry on a line
+var _ = T{0: 0} // not aligned
+var _ = T{0: 0, // not aligned
+ 1: 1, // aligned
+ 22: 22, // aligned
+ 333: 333, 1234: 12, 12345: 0, // first on line aligned
+}
+
+// test cases form issue 8685
+// not aligned
+var _ = map[int]string{1: "spring", 2: "summer",
+ 3: "autumn", 4: "winter"}
+
+// not aligned
+var _ = map[string]string{"a": "spring", "b": "summer",
+ "c": "autumn", "d": "winter"}
+
+// aligned
+var _ = map[string]string{"a": "spring",
+ "b": "summer",
+ "c": "autumn",
+ "d": "winter"}
+
func _() {
var _ = T{
a, // must introduce trailing comma
@@ -723,7 +761,8 @@ func _() int {
}
// making function declarations safe for new semicolon rules
-func _() { /* multi-line func because of comment */
+func _() { /* single-line function because of "short-ish" comment */ }
+func _() { /* multi-line function because of "long-ish" comment - much more comment text is following here */ /* and more */
}
func _() {
diff --git a/libgo/go/go/printer/testdata/declarations.input b/libgo/go/go/printer/testdata/declarations.input
index dbdbdfe742..45beec25fc 100644
--- a/libgo/go/go/printer/testdata/declarations.input
+++ b/libgo/go/go/printer/testdata/declarations.input
@@ -409,6 +409,24 @@ func _() {
}
}
+// use the formatted output rather than the input to decide when to align
+// (was issue 4505)
+const (
+ short = 2 * (
+ 1 + 2)
+ aMuchLongerName = 3
+)
+
+var (
+ short = X{
+ }
+ aMuchLongerName = X{}
+
+ x1 = X{} // foo
+ x2 = X{
+ } // foo
+)
+
func _() {
type (
xxxxxx int
@@ -697,6 +715,31 @@ var _ = T4{
}
+// no alignment of map composite entries if they are not the first entry on a line
+var _ = T{0: 0} // not aligned
+var _ = T{0: 0, // not aligned
+ 1: 1, // aligned
+ 22: 22, // aligned
+ 333: 333, 1234: 12, 12345: 0, // first on line aligned
+}
+
+
+// test cases form issue 8685
+// not aligned
+var _ = map[int]string{1: "spring", 2: "summer",
+ 3: "autumn", 4: "winter"}
+
+// not aligned
+var _ = map[string]string{"a": "spring", "b": "summer",
+ "c": "autumn", "d": "winter"}
+
+// aligned
+var _ = map[string]string{"a": "spring",
+"b": "summer",
+ "c": "autumn",
+"d": "winter"}
+
+
func _() {
var _ = T{
a, // must introduce trailing comma
@@ -737,7 +780,8 @@ func _() int {
// making function declarations safe for new semicolon rules
-func _() { /* multi-line func because of comment */ }
+func _() { /* single-line function because of "short-ish" comment */ }
+func _() { /* multi-line function because of "long-ish" comment - much more comment text is following here */ /* and more */ }
func _() {
/* multi-line func because block is on multiple lines */ }
diff --git a/libgo/go/go/printer/testdata/expressions.golden b/libgo/go/go/printer/testdata/expressions.golden
index fbe8275b3a..e3d17a4653 100644
--- a/libgo/go/go/printer/testdata/expressions.golden
+++ b/libgo/go/go/printer/testdata/expressions.golden
@@ -94,6 +94,11 @@ func _() {
_ = Open(dpath+"/file", O_WRONLY|O_CREAT, 0666)
_ = int(c0&_Mask4)<<18 | int(c1&_Maskx)<<12 | int(c2&_Maskx)<<6 | int(c3&_Maskx)
+ // test case for issue 8021
+ // want:
+ // ([]bool{})[([]int{})[((1)+(((1)+((((1)*(((1)+(1))+(1)))+(1))*(1)))+(1)))]]
+ _ = ([]bool{})[([]int{})[((1)+(((1)+((((1)*(((1)+(1))+(1)))+(1))*(1)))+(1)))]]
+
// the parser does not restrict expressions that may appear as statements
true
42
diff --git a/libgo/go/go/printer/testdata/expressions.input b/libgo/go/go/printer/testdata/expressions.input
index f4d20fa0f7..d20a59350e 100644
--- a/libgo/go/go/printer/testdata/expressions.input
+++ b/libgo/go/go/printer/testdata/expressions.input
@@ -95,6 +95,11 @@ func _() {
_ = Open(dpath + "/file", O_WRONLY | O_CREAT, 0666)
_ = int(c0&_Mask4)<<18 | int(c1&_Maskx)<<12 | int(c2&_Maskx)<<6 | int(c3&_Maskx)
+ // test case for issue 8021
+ // want:
+ // ([]bool{})[([]int{})[((1)+(((1)+((((1)*(((1)+(1))+(1)))+(1))*(1)))+(1)))]]
+ _ = ([]bool{})[([]int{})[((1) + (((((1) + (((((((1) * (((((1) + (1))) + (1))))) + (1))) * (1))))) + (1))))]]
+
// the parser does not restrict expressions that may appear as statements
true
42
diff --git a/libgo/go/go/printer/testdata/expressions.raw b/libgo/go/go/printer/testdata/expressions.raw
index 97bc81dad8..2357336957 100644
--- a/libgo/go/go/printer/testdata/expressions.raw
+++ b/libgo/go/go/printer/testdata/expressions.raw
@@ -94,6 +94,11 @@ func _() {
_ = Open(dpath+"/file", O_WRONLY|O_CREAT, 0666)
_ = int(c0&_Mask4)<<18 | int(c1&_Maskx)<<12 | int(c2&_Maskx)<<6 | int(c3&_Maskx)
+ // test case for issue 8021
+ // want:
+ // ([]bool{})[([]int{})[((1)+(((1)+((((1)*(((1)+(1))+(1)))+(1))*(1)))+(1)))]]
+ _ = ([]bool{})[([]int{})[((1)+(((1)+((((1)*(((1)+(1))+(1)))+(1))*(1)))+(1)))]]
+
// the parser does not restrict expressions that may appear as statements
true
42
diff --git a/libgo/go/go/printer/testdata/statements.golden b/libgo/go/go/printer/testdata/statements.golden
index 3b298f95ef..4b13460473 100644
--- a/libgo/go/go/printer/testdata/statements.golden
+++ b/libgo/go/go/printer/testdata/statements.golden
@@ -309,6 +309,9 @@ func _() {
for x := expr; expr; expr = false {
use(x)
}
+ for range []int{} {
+ println("foo")
+ }
for x := range []int{} {
use(x)
}
@@ -338,6 +341,12 @@ func _() {
a[i] = i
} // multiple lines
+ for range a {
+ }
+ for _ = range a {
+ }
+ for _, _ = range a {
+ }
for i := range a {
}
for i := range a {
@@ -435,7 +444,7 @@ func _() {
}
if x == a+b*(T{42}[0]) {
}
- if x == a+(b * (T{42}[0])) {
+ if x == a+(b*(T{42}[0])) {
}
if x == a+b*(T{42}[0]) {
}
diff --git a/libgo/go/go/printer/testdata/statements.input b/libgo/go/go/printer/testdata/statements.input
index e7fcc0e540..cade1576bf 100644
--- a/libgo/go/go/printer/testdata/statements.input
+++ b/libgo/go/go/printer/testdata/statements.input
@@ -269,6 +269,8 @@ func _() {
for x := expr;expr;expr = false {
use(x)
}
+ for range []int{} {
+ println("foo")}
for x := range []int{} {
use(x) }
for x := range (([]int{})) {
@@ -289,6 +291,9 @@ func _() {
for i := 0; i < len(a); 1++ { a[i] = i
} // multiple lines
+ for range a{}
+ for _ = range a{}
+ for _, _ = range a{}
for i := range a {}
for i := range a { a[i] = i }
for i := range a { a[i] = i
diff --git a/libgo/go/go/scanner/scanner.go b/libgo/go/go/scanner/scanner.go
index 1e259d5ed2..cec82ea10e 100644
--- a/libgo/go/go/scanner/scanner.go
+++ b/libgo/go/go/scanner/scanner.go
@@ -148,11 +148,14 @@ func (s *Scanner) interpretLineComment(text []byte) {
// get filename and line number, if any
if i := bytes.LastIndex(text, []byte{':'}); i > 0 {
if line, err := strconv.Atoi(string(text[i+1:])); err == nil && line > 0 {
- // valid //line filename:line comment;
- filename := filepath.Clean(string(text[len(prefix):i]))
- if !filepath.IsAbs(filename) {
- // make filename relative to current directory
- filename = filepath.Join(s.dir, filename)
+ // valid //line filename:line comment
+ filename := string(bytes.TrimSpace(text[len(prefix):i]))
+ if filename != "" {
+ filename = filepath.Clean(filename)
+ if !filepath.IsAbs(filename) {
+ // make filename relative to current directory
+ filename = filepath.Join(s.dir, filename)
+ }
}
// update scanner position
s.file.AddLineInfo(s.lineOffset+len(text)+1, filename, line) // +len(text)+1 since comment applies to next line
@@ -358,73 +361,94 @@ exit:
return tok, string(s.src[offs:s.offset])
}
-func (s *Scanner) scanEscape(quote rune) {
+// scanEscape parses an escape sequence where rune is the accepted
+// escaped quote. In case of a syntax error, it stops at the offending
+// character (without consuming it) and returns false. Otherwise
+// it returns true.
+func (s *Scanner) scanEscape(quote rune) bool {
offs := s.offset
- var i, base, max uint32
+ var n int
+ var base, max uint32
switch s.ch {
case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', quote:
s.next()
- return
+ return true
case '0', '1', '2', '3', '4', '5', '6', '7':
- i, base, max = 3, 8, 255
+ n, base, max = 3, 8, 255
case 'x':
s.next()
- i, base, max = 2, 16, 255
+ n, base, max = 2, 16, 255
case 'u':
s.next()
- i, base, max = 4, 16, unicode.MaxRune
+ n, base, max = 4, 16, unicode.MaxRune
case 'U':
s.next()
- i, base, max = 8, 16, unicode.MaxRune
+ n, base, max = 8, 16, unicode.MaxRune
default:
- s.next() // always make progress
- s.error(offs, "unknown escape sequence")
- return
+ msg := "unknown escape sequence"
+ if s.ch < 0 {
+ msg = "escape sequence not terminated"
+ }
+ s.error(offs, msg)
+ return false
}
var x uint32
- for ; i > 0 && s.ch != quote && s.ch >= 0; i-- {
+ for n > 0 {
d := uint32(digitVal(s.ch))
if d >= base {
- s.error(s.offset, "illegal character in escape sequence")
- break
+ msg := fmt.Sprintf("illegal character %#U in escape sequence", s.ch)
+ if s.ch < 0 {
+ msg = "escape sequence not terminated"
+ }
+ s.error(s.offset, msg)
+ return false
}
x = x*base + d
s.next()
+ n--
}
- // in case of an error, consume remaining chars
- for ; i > 0 && s.ch != quote && s.ch >= 0; i-- {
- s.next()
- }
+
if x > max || 0xD800 <= x && x < 0xE000 {
s.error(offs, "escape sequence is invalid Unicode code point")
+ return false
}
+
+ return true
}
-func (s *Scanner) scanChar() string {
+func (s *Scanner) scanRune() string {
// '\'' opening already consumed
offs := s.offset - 1
+ valid := true
n := 0
- for s.ch != '\'' {
+ for {
ch := s.ch
- n++
- s.next()
if ch == '\n' || ch < 0 {
- s.error(offs, "character literal not terminated")
- n = 1
+ // only report error if we don't have one already
+ if valid {
+ s.error(offs, "rune literal not terminated")
+ valid = false
+ }
break
}
+ s.next()
+ if ch == '\'' {
+ break
+ }
+ n++
if ch == '\\' {
- s.scanEscape('\'')
+ if !s.scanEscape('\'') {
+ valid = false
+ }
+ // continue to read to closing quote
}
}
- s.next()
-
- if n != 1 {
- s.error(offs, "illegal character literal")
+ if valid && n != 1 {
+ s.error(offs, "illegal rune literal")
}
return string(s.src[offs:s.offset])
@@ -434,11 +458,14 @@ func (s *Scanner) scanString() string {
// '"' opening already consumed
offs := s.offset - 1
- for s.ch != '"' {
+ for {
ch := s.ch
- s.next()
if ch == '\n' || ch < 0 {
- s.error(offs, "string not terminated")
+ s.error(offs, "string literal not terminated")
+ break
+ }
+ s.next()
+ if ch == '"' {
break
}
if ch == '\\' {
@@ -446,8 +473,6 @@ func (s *Scanner) scanString() string {
}
}
- s.next()
-
return string(s.src[offs:s.offset])
}
@@ -468,20 +493,21 @@ func (s *Scanner) scanRawString() string {
offs := s.offset - 1
hasCR := false
- for s.ch != '`' {
+ for {
ch := s.ch
+ if ch < 0 {
+ s.error(offs, "raw string literal not terminated")
+ break
+ }
s.next()
+ if ch == '`' {
+ break
+ }
if ch == '\r' {
hasCR = true
}
- if ch < 0 {
- s.error(offs, "string not terminated")
- break
- }
}
- s.next()
-
lit := s.src[offs:s.offset]
if hasCR {
lit = stripCR(lit)
@@ -617,7 +643,7 @@ scanAgain:
case '\'':
insertSemi = true
tok = token.CHAR
- lit = s.scanChar()
+ lit = s.scanRune()
case '`':
insertSemi = true
tok = token.STRING
diff --git a/libgo/go/go/scanner/scanner_test.go b/libgo/go/go/scanner/scanner_test.go
index 8c64c2b95f..fc450d8a6e 100644
--- a/libgo/go/go/scanner/scanner_test.go
+++ b/libgo/go/go/scanner/scanner_test.go
@@ -493,9 +493,9 @@ var segments = []segment{
{"\nline3 //line File1.go:100", filepath.Join("dir", "TestLineComments"), 3}, // bad line comment, ignored
{"\nline4", filepath.Join("dir", "TestLineComments"), 4},
{"\n//line File1.go:100\n line100", filepath.Join("dir", "File1.go"), 100},
+ {"\n//line \t :42\n line1", "", 42},
{"\n//line File2.go:200\n line200", filepath.Join("dir", "File2.go"), 200},
- {"\n//line :1\n line1", "dir", 1},
- {"\n//line foo:42\n line42", filepath.Join("dir", "foo"), 42},
+ {"\n//line foo\t:42\n line42", filepath.Join("dir", "foo"), 42},
{"\n //line foo:42\n line44", filepath.Join("dir", "foo"), 44}, // bad line comment, ignored
{"\n//line foo 42\n line46", filepath.Join("dir", "foo"), 46}, // bad line comment, ignored
{"\n//line foo:42 extra text\n line48", filepath.Join("dir", "foo"), 48}, // bad line comment, ignored
@@ -631,7 +631,7 @@ type errorCollector struct {
pos token.Position // last error position encountered
}
-func checkError(t *testing.T, src string, tok token.Token, pos int, err string) {
+func checkError(t *testing.T, src string, tok token.Token, pos int, lit, err string) {
var s Scanner
var h errorCollector
eh := func(pos token.Position, msg string) {
@@ -640,13 +640,12 @@ func checkError(t *testing.T, src string, tok token.Token, pos int, err string)
h.pos = pos
}
s.Init(fset.AddFile("", fset.Base(), len(src)), []byte(src), eh, ScanComments|dontInsertSemis)
- _, tok0, _ := s.Scan()
- _, tok1, _ := s.Scan()
+ _, tok0, lit0 := s.Scan()
if tok0 != tok {
t.Errorf("%q: got %s, expected %s", src, tok0, tok)
}
- if tok1 != token.EOF {
- t.Errorf("%q: got %s, expected EOF", src, tok1)
+ if tok0 != token.ILLEGAL && lit0 != lit {
+ t.Errorf("%q: got literal %q, expected %q", src, lit0, lit)
}
cnt := 0
if err != "" {
@@ -667,43 +666,71 @@ var errors = []struct {
src string
tok token.Token
pos int
+ lit string
err string
}{
- {"\a", token.ILLEGAL, 0, "illegal character U+0007"},
- {`#`, token.ILLEGAL, 0, "illegal character U+0023 '#'"},
- {`…`, token.ILLEGAL, 0, "illegal character U+2026 '…'"},
- {`' '`, token.CHAR, 0, ""},
- {`''`, token.CHAR, 0, "illegal character literal"},
- {`'\8'`, token.CHAR, 2, "unknown escape sequence"},
- {`'\08'`, token.CHAR, 3, "illegal character in escape sequence"},
- {`'\x0g'`, token.CHAR, 4, "illegal character in escape sequence"},
- {`'\Uffffffff'`, token.CHAR, 2, "escape sequence is invalid Unicode code point"},
- {`'`, token.CHAR, 0, "character literal not terminated"},
- {`""`, token.STRING, 0, ""},
- {`"`, token.STRING, 0, "string not terminated"},
- {"``", token.STRING, 0, ""},
- {"`", token.STRING, 0, "string not terminated"},
- {"/**/", token.COMMENT, 0, ""},
- {"/*", token.COMMENT, 0, "comment not terminated"},
- {"077", token.INT, 0, ""},
- {"078.", token.FLOAT, 0, ""},
- {"07801234567.", token.FLOAT, 0, ""},
- {"078e0", token.FLOAT, 0, ""},
- {"078", token.INT, 0, "illegal octal number"},
- {"07800000009", token.INT, 0, "illegal octal number"},
- {"0x", token.INT, 0, "illegal hexadecimal number"},
- {"0X", token.INT, 0, "illegal hexadecimal number"},
- {"\"abc\x00def\"", token.STRING, 4, "illegal character NUL"},
- {"\"abc\x80def\"", token.STRING, 4, "illegal UTF-8 encoding"},
- {"\ufeff\ufeff", token.ILLEGAL, 3, "illegal byte order mark"}, // only first BOM is ignored
- {"//\ufeff", token.COMMENT, 2, "illegal byte order mark"}, // only first BOM is ignored
- {"'\ufeff" + `'`, token.CHAR, 1, "illegal byte order mark"}, // only first BOM is ignored
- {`"` + "abc\ufeffdef" + `"`, token.STRING, 4, "illegal byte order mark"}, // only first BOM is ignored
+ {"\a", token.ILLEGAL, 0, "", "illegal character U+0007"},
+ {`#`, token.ILLEGAL, 0, "", "illegal character U+0023 '#'"},
+ {`…`, token.ILLEGAL, 0, "", "illegal character U+2026 '…'"},
+ {`' '`, token.CHAR, 0, `' '`, ""},
+ {`''`, token.CHAR, 0, `''`, "illegal rune literal"},
+ {`'12'`, token.CHAR, 0, `'12'`, "illegal rune literal"},
+ {`'123'`, token.CHAR, 0, `'123'`, "illegal rune literal"},
+ {`'\0'`, token.CHAR, 3, `'\0'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\07'`, token.CHAR, 4, `'\07'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\8'`, token.CHAR, 2, `'\8'`, "unknown escape sequence"},
+ {`'\08'`, token.CHAR, 3, `'\08'`, "illegal character U+0038 '8' in escape sequence"},
+ {`'\x'`, token.CHAR, 3, `'\x'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\x0'`, token.CHAR, 4, `'\x0'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\x0g'`, token.CHAR, 4, `'\x0g'`, "illegal character U+0067 'g' in escape sequence"},
+ {`'\u'`, token.CHAR, 3, `'\u'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\u0'`, token.CHAR, 4, `'\u0'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\u00'`, token.CHAR, 5, `'\u00'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\u000'`, token.CHAR, 6, `'\u000'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\u000`, token.CHAR, 6, `'\u000`, "escape sequence not terminated"},
+ {`'\u0000'`, token.CHAR, 0, `'\u0000'`, ""},
+ {`'\U'`, token.CHAR, 3, `'\U'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\U0'`, token.CHAR, 4, `'\U0'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\U00'`, token.CHAR, 5, `'\U00'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\U000'`, token.CHAR, 6, `'\U000'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\U0000'`, token.CHAR, 7, `'\U0000'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\U00000'`, token.CHAR, 8, `'\U00000'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\U000000'`, token.CHAR, 9, `'\U000000'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\U0000000'`, token.CHAR, 10, `'\U0000000'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\U0000000`, token.CHAR, 10, `'\U0000000`, "escape sequence not terminated"},
+ {`'\U00000000'`, token.CHAR, 0, `'\U00000000'`, ""},
+ {`'\Uffffffff'`, token.CHAR, 2, `'\Uffffffff'`, "escape sequence is invalid Unicode code point"},
+ {`'`, token.CHAR, 0, `'`, "rune literal not terminated"},
+ {`'\`, token.CHAR, 2, `'\`, "escape sequence not terminated"},
+ {"'\n", token.CHAR, 0, "'", "rune literal not terminated"},
+ {"'\n ", token.CHAR, 0, "'", "rune literal not terminated"},
+ {`""`, token.STRING, 0, `""`, ""},
+ {`"abc`, token.STRING, 0, `"abc`, "string literal not terminated"},
+ {"\"abc\n", token.STRING, 0, `"abc`, "string literal not terminated"},
+ {"\"abc\n ", token.STRING, 0, `"abc`, "string literal not terminated"},
+ {"``", token.STRING, 0, "``", ""},
+ {"`", token.STRING, 0, "`", "raw string literal not terminated"},
+ {"/**/", token.COMMENT, 0, "/**/", ""},
+ {"/*", token.COMMENT, 0, "/*", "comment not terminated"},
+ {"077", token.INT, 0, "077", ""},
+ {"078.", token.FLOAT, 0, "078.", ""},
+ {"07801234567.", token.FLOAT, 0, "07801234567.", ""},
+ {"078e0", token.FLOAT, 0, "078e0", ""},
+ {"078", token.INT, 0, "078", "illegal octal number"},
+ {"07800000009", token.INT, 0, "07800000009", "illegal octal number"},
+ {"0x", token.INT, 0, "0x", "illegal hexadecimal number"},
+ {"0X", token.INT, 0, "0X", "illegal hexadecimal number"},
+ {"\"abc\x00def\"", token.STRING, 4, "\"abc\x00def\"", "illegal character NUL"},
+ {"\"abc\x80def\"", token.STRING, 4, "\"abc\x80def\"", "illegal UTF-8 encoding"},
+ {"\ufeff\ufeff", token.ILLEGAL, 3, "\ufeff\ufeff", "illegal byte order mark"}, // only first BOM is ignored
+ {"//\ufeff", token.COMMENT, 2, "//\ufeff", "illegal byte order mark"}, // only first BOM is ignored
+ {"'\ufeff" + `'`, token.CHAR, 1, "'\ufeff" + `'`, "illegal byte order mark"}, // only first BOM is ignored
+ {`"` + "abc\ufeffdef" + `"`, token.STRING, 4, `"` + "abc\ufeffdef" + `"`, "illegal byte order mark"}, // only first BOM is ignored
}
func TestScanErrors(t *testing.T) {
for _, e := range errors {
- checkError(t, e.src, e.tok, e.pos, e.err)
+ checkError(t, e.src, e.tok, e.pos, e.lit, e.err)
}
}
diff --git a/libgo/go/go/token/position.go b/libgo/go/go/token/position.go
index e6f0ae6a67..82d90eeb72 100644
--- a/libgo/go/go/token/position.go
+++ b/libgo/go/go/token/position.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.
-// TODO(gri) consider making this a separate package outside the go directory.
-
package token
import (
@@ -184,6 +182,7 @@ func (f *File) SetLines(lines []int) bool {
}
// SetLinesForContent sets the line offsets for the given file content.
+// It ignores position-altering //line comments.
func (f *File) SetLinesForContent(content []byte) {
var lines []int
line := 0
@@ -255,7 +254,6 @@ func (f *File) Offset(p Pos) int {
// p must be a Pos value in that file or NoPos.
//
func (f *File) Line(p Pos) int {
- // TODO(gri) this can be implemented much more efficiently
return f.Position(p).Line
}
@@ -263,13 +261,16 @@ func searchLineInfos(a []lineInfo, x int) int {
return sort.Search(len(a), func(i int) bool { return a[i].Offset > x }) - 1
}
-// info returns the file name, line, and column number for a file offset.
-func (f *File) info(offset int) (filename string, line, column int) {
+// unpack returns the filename and line and column number for a file offset.
+// If adjusted is set, unpack will return the filename and line information
+// possibly adjusted by //line comments; otherwise those comments are ignored.
+//
+func (f *File) unpack(offset int, adjusted bool) (filename string, line, column int) {
filename = f.name
if i := searchInts(f.lines, offset); i >= 0 {
line, column = i+1, offset-f.lines[i]+1
}
- if len(f.infos) > 0 {
+ if adjusted && len(f.infos) > 0 {
// almost no files have extra line infos
if i := searchLineInfos(f.infos, offset); i >= 0 {
alt := &f.infos[i]
@@ -282,26 +283,35 @@ func (f *File) info(offset int) (filename string, line, column int) {
return
}
-func (f *File) position(p Pos) (pos Position) {
+func (f *File) position(p Pos, adjusted bool) (pos Position) {
offset := int(p) - f.base
pos.Offset = offset
- pos.Filename, pos.Line, pos.Column = f.info(offset)
+ pos.Filename, pos.Line, pos.Column = f.unpack(offset, adjusted)
return
}
-// Position returns the Position value for the given file position p;
-// p must be a Pos value in that file or NoPos.
+// PositionFor returns the Position value for the given file position p.
+// If adjusted is set, the position may be adjusted by position-altering
+// //line comments; otherwise those comments are ignored.
+// p must be a Pos value in f or NoPos.
//
-func (f *File) Position(p Pos) (pos Position) {
+func (f *File) PositionFor(p Pos, adjusted bool) (pos Position) {
if p != NoPos {
if int(p) < f.base || int(p) > f.base+f.size {
panic("illegal Pos value")
}
- pos = f.position(p)
+ pos = f.position(p, adjusted)
}
return
}
+// Position returns the Position value for the given file position p.
+// Calling f.Position(p) is equivalent to calling f.PositionFor(p, true).
+//
+func (f *File) Position(p Pos) (pos Position) {
+ return f.PositionFor(p, true)
+}
+
// -----------------------------------------------------------------------------
// FileSet
@@ -427,16 +437,27 @@ func (s *FileSet) File(p Pos) (f *File) {
return
}
-// Position converts a Pos in the fileset into a general Position.
-func (s *FileSet) Position(p Pos) (pos Position) {
+// PositionFor converts a Pos p in the fileset into a Position value.
+// If adjusted is set, the position may be adjusted by position-altering
+// //line comments; otherwise those comments are ignored.
+// p must be a Pos value in s or NoPos.
+//
+func (s *FileSet) PositionFor(p Pos, adjusted bool) (pos Position) {
if p != NoPos {
if f := s.file(p); f != nil {
- pos = f.position(p)
+ pos = f.position(p, adjusted)
}
}
return
}
+// Position converts a Pos p in the fileset into a Position value.
+// Calling s.Position(p) is equivalent to calling s.PositionFor(p, true).
+//
+func (s *FileSet) Position(p Pos) (pos Position) {
+ return s.PositionFor(p, true)
+}
+
// -----------------------------------------------------------------------------
// Helper functions
diff --git a/libgo/go/go/token/position_test.go b/libgo/go/go/token/position_test.go
index ef6cfd93c2..d26939ce27 100644
--- a/libgo/go/go/token/position_test.go
+++ b/libgo/go/go/token/position_test.go
@@ -11,18 +11,18 @@ import (
"testing"
)
-func checkPos(t *testing.T, msg string, p, q Position) {
- if p.Filename != q.Filename {
- t.Errorf("%s: expected filename = %q; got %q", msg, q.Filename, p.Filename)
+func checkPos(t *testing.T, msg string, got, want Position) {
+ if got.Filename != want.Filename {
+ t.Errorf("%s: got filename = %q; want %q", msg, got.Filename, want.Filename)
}
- if p.Offset != q.Offset {
- t.Errorf("%s: expected offset = %d; got %d", msg, q.Offset, p.Offset)
+ if got.Offset != want.Offset {
+ t.Errorf("%s: got offset = %d; want %d", msg, got.Offset, want.Offset)
}
- if p.Line != q.Line {
- t.Errorf("%s: expected line = %d; got %d", msg, q.Line, p.Line)
+ if got.Line != want.Line {
+ t.Errorf("%s: got line = %d; want %d", msg, got.Line, want.Line)
}
- if p.Column != q.Column {
- t.Errorf("%s: expected column = %d; got %d", msg, q.Column, p.Column)
+ if got.Column != want.Column {
+ t.Errorf("%s: got column = %d; want %d", msg, got.Column, want.Column)
}
}
@@ -68,7 +68,7 @@ func verifyPositions(t *testing.T, fset *FileSet, f *File, lines []int) {
p := f.Pos(offs)
offs2 := f.Offset(p)
if offs2 != offs {
- t.Errorf("%s, Offset: expected offset %d; got %d", f.Name(), offs, offs2)
+ t.Errorf("%s, Offset: got offset %d; want %d", f.Name(), offs2, offs)
}
line, col := linecol(lines, offs)
msg := fmt.Sprintf("%s (offs = %d, p = %d)", f.Name(), offs, p)
@@ -93,16 +93,16 @@ func TestPositions(t *testing.T) {
for _, test := range tests {
// verify consistency of test case
if test.source != nil && len(test.source) != test.size {
- t.Errorf("%s: inconsistent test case: expected file size %d; got %d", test.filename, test.size, len(test.source))
+ t.Errorf("%s: inconsistent test case: got file size %d; want %d", test.filename, len(test.source), test.size)
}
// add file and verify name and size
f := fset.AddFile(test.filename, fset.Base()+delta, test.size)
if f.Name() != test.filename {
- t.Errorf("expected filename %q; got %q", test.filename, f.Name())
+ t.Errorf("got filename %q; want %q", f.Name(), test.filename)
}
if f.Size() != test.size {
- t.Errorf("%s: expected file size %d; got %d", f.Name(), test.size, f.Size())
+ t.Errorf("%s: got file size %d; want %d", f.Name(), f.Size(), test.size)
}
if fset.File(f.Pos(0)) != f {
t.Errorf("%s: f.Pos(0) was not found in f", f.Name())
@@ -112,12 +112,12 @@ func TestPositions(t *testing.T) {
for i, offset := range test.lines {
f.AddLine(offset)
if f.LineCount() != i+1 {
- t.Errorf("%s, AddLine: expected line count %d; got %d", f.Name(), i+1, f.LineCount())
+ t.Errorf("%s, AddLine: got line count %d; want %d", f.Name(), f.LineCount(), i+1)
}
// adding the same offset again should be ignored
f.AddLine(offset)
if f.LineCount() != i+1 {
- t.Errorf("%s, AddLine: expected unchanged line count %d; got %d", f.Name(), i+1, f.LineCount())
+ t.Errorf("%s, AddLine: got unchanged line count %d; want %d", f.Name(), f.LineCount(), i+1)
}
verifyPositions(t, fset, f, test.lines[0:i+1])
}
@@ -127,7 +127,7 @@ func TestPositions(t *testing.T) {
t.Errorf("%s: SetLines failed", f.Name())
}
if f.LineCount() != len(test.lines) {
- t.Errorf("%s, SetLines: expected line count %d; got %d", f.Name(), len(test.lines), f.LineCount())
+ t.Errorf("%s, SetLines: got line count %d; want %d", f.Name(), f.LineCount(), len(test.lines))
}
verifyPositions(t, fset, f, test.lines)
@@ -139,7 +139,7 @@ func TestPositions(t *testing.T) {
}
f.SetLinesForContent(src)
if f.LineCount() != len(test.lines) {
- t.Errorf("%s, SetLinesForContent: expected line count %d; got %d", f.Name(), len(test.lines), f.LineCount())
+ t.Errorf("%s, SetLinesForContent: got line count %d; want %d", f.Name(), f.LineCount(), len(test.lines))
}
verifyPositions(t, fset, f, test.lines)
}
@@ -177,13 +177,13 @@ func TestFiles(t *testing.T) {
j := 0
fset.Iterate(func(f *File) bool {
if f.Name() != tests[j].filename {
- t.Errorf("expected filename = %s; got %s", tests[j].filename, f.Name())
+ t.Errorf("got filename = %s; want %s", f.Name(), tests[j].filename)
}
j++
return true
})
if j != i+1 {
- t.Errorf("expected %d files; got %d", i+1, j)
+ t.Errorf("got %d files; want %d", j, i+1)
}
}
}
@@ -195,7 +195,7 @@ func TestFileSetPastEnd(t *testing.T) {
fset.AddFile(test.filename, fset.Base(), test.size)
}
if f := fset.File(Pos(fset.Base())); f != nil {
- t.Errorf("expected nil, got %v", f)
+ t.Errorf("got %v, want nil", f)
}
}
@@ -209,7 +209,7 @@ func TestFileSetCacheUnlikely(t *testing.T) {
for file, pos := range offsets {
f := fset.File(Pos(pos))
if f.Name() != file {
- t.Errorf("expecting %q at position %d, got %q", file, pos, f.Name())
+ t.Errorf("got %q at position %d, want %q", f.Name(), pos, file)
}
}
}
@@ -236,3 +236,62 @@ func TestFileSetRace(t *testing.T) {
}
stop.Wait()
}
+
+func TestPositionFor(t *testing.T) {
+ src := []byte(`
+foo
+b
+ar
+//line :100
+foobar
+//line bar:3
+done
+`)
+
+ const filename = "foo"
+ fset := NewFileSet()
+ f := fset.AddFile(filename, fset.Base(), len(src))
+ f.SetLinesForContent(src)
+
+ // verify position info
+ for i, offs := range f.lines {
+ got1 := f.PositionFor(f.Pos(offs), false)
+ got2 := f.PositionFor(f.Pos(offs), true)
+ got3 := f.Position(f.Pos(offs))
+ want := Position{filename, offs, i + 1, 1}
+ checkPos(t, "1. PositionFor unadjusted", got1, want)
+ checkPos(t, "1. PositionFor adjusted", got2, want)
+ checkPos(t, "1. Position", got3, want)
+ }
+
+ // manually add //line info on lines l1, l2
+ const l1, l2 = 5, 7
+ f.AddLineInfo(f.lines[l1-1], "", 100)
+ f.AddLineInfo(f.lines[l2-1], "bar", 3)
+
+ // unadjusted position info must remain unchanged
+ for i, offs := range f.lines {
+ got1 := f.PositionFor(f.Pos(offs), false)
+ want := Position{filename, offs, i + 1, 1}
+ checkPos(t, "2. PositionFor unadjusted", got1, want)
+ }
+
+ // adjusted position info should have changed
+ for i, offs := range f.lines {
+ got2 := f.PositionFor(f.Pos(offs), true)
+ got3 := f.Position(f.Pos(offs))
+ want := Position{filename, offs, i + 1, 1}
+ // manually compute wanted filename and line
+ line := want.Line
+ if i+1 >= l1 {
+ want.Filename = ""
+ want.Line = line - l1 + 100
+ }
+ if i+1 >= l2 {
+ want.Filename = "bar"
+ want.Line = line - l2 + 3
+ }
+ checkPos(t, "3. PositionFor adjusted", got2, want)
+ checkPos(t, "3. Position", got3, want)
+ }
+}
diff --git a/libgo/go/go/types/testdata/builtins.src b/libgo/go/go/types/testdata/builtins.src
deleted file mode 100644
index 6c848fc277..0000000000
--- a/libgo/go/go/types/testdata/builtins.src
+++ /dev/null
@@ -1,302 +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.
-
-// builtin calls
-
-package builtins
-
-import "unsafe"
-
-func _append() {
- var x int
- var s []byte
- _0 := append /* ERROR "argument" */ ()
- _1 := append("foo" /* ERROR "not a typed slice" */)
- _2 := append(nil /* ERROR "not a typed slice" */, s)
- _3 := append(x /* ERROR "not a typed slice" */, s)
- _4 := append(s)
- append /* ERROR "not used" */ (s)
-}
-
-func _cap() {
- var a [10]bool
- var p *[20]int
- var s []int
- var c chan string
- _0 := cap /* ERROR "argument" */ ()
- _1 := cap /* ERROR "argument" */ (1, 2)
- _2 := cap(42 /* ERROR "invalid" */)
- const _3 = cap(a)
- assert(_3 == 10)
- const _4 = cap(p)
- assert(_4 == 20)
- _5 := cap(c)
- cap /* ERROR "not used" */ (c)
-}
-
-func _close() {
- var c chan int
- var r <-chan int
- close /* ERROR "argument" */ ()
- close /* ERROR "argument" */ (1, 2)
- close(42 /* ERROR "not a channel" */)
- close(r /* ERROR "receive-only channel" */)
- close(c)
-}
-
-func _complex() {
- var i32 int32
- var f32 float32
- var f64 float64
- var c64 complex64
- _ = complex /* ERROR "argument" */ ()
- _ = complex /* ERROR "argument" */ (1)
- _ = complex(true /* ERROR "invalid argument" */ , 0)
- _ = complex(i32 /* ERROR "invalid argument" */ , 0)
- _ = complex("foo" /* ERROR "invalid argument" */ , 0)
- _ = complex(c64 /* ERROR "invalid argument" */ , 0)
- _ = complex(0, true /* ERROR "invalid argument" */ )
- _ = complex(0, i32 /* ERROR "invalid argument" */ )
- _ = complex(0, "foo" /* ERROR "invalid argument" */ )
- _ = complex(0, c64 /* ERROR "invalid argument" */ )
- _ = complex(f32, f32)
- _ = complex(f32, 1)
- _ = complex(f32, 1.0)
- _ = complex(f32, 'a')
- _ = complex(f64, f64)
- _ = complex(f64, 1)
- _ = complex(f64, 1.0)
- _ = complex(f64, 'a')
- _ = complex(f32 /* ERROR "mismatched types" */, f64)
- _ = complex(f64 /* ERROR "mismatched types" */, f32)
- _ = complex(1, 1)
- _ = complex(1, 1.1)
- _ = complex(1, 'a')
- complex /* ERROR "not used" */ (1, 2)
-}
-
-func _copy() {
- copy /* ERROR "not enough arguments" */ ()
- copy /* ERROR "not enough arguments" */ ("foo")
- copy([ /* ERROR "copy expects slice arguments" */ ...]int{}, []int{})
- copy([ /* ERROR "copy expects slice arguments" */ ]int{}, [...]int{})
- copy([ /* ERROR "different element types" */ ]int8{}, "foo")
-
- // spec examples
- var a = [...]int{0, 1, 2, 3, 4, 5, 6, 7}
- var s = make([]int, 6)
- var b = make([]byte, 5)
- n1 := copy(s, a[0:]) // n1 == 6, s == []int{0, 1, 2, 3, 4, 5}
- n2 := copy(s, s[2:]) // n2 == 4, s == []int{2, 3, 4, 5, 4, 5}
- n3 := copy(b, "Hello, World!") // n3 == 5, b == []byte("Hello")
-}
-
-func _delete() {
- var m map[string]int
- var s string
- delete /* ERROR "argument" */ ()
- delete /* ERROR "argument" */ (1)
- delete /* ERROR "argument" */ (1, 2, 3)
- delete(m, 0 /* ERROR "not assignable" */)
- delete(m, s)
-}
-
-func _imag() {
- var f32 float32
- var f64 float64
- var c64 complex64
- var c128 complex128
- _ = imag /* ERROR "argument" */ ()
- _ = imag /* ERROR "argument" */ (1, 2)
- _ = imag(10 /* ERROR "must be a complex number" */)
- _ = imag(2.7182818 /* ERROR "must be a complex number" */)
- _ = imag("foo" /* ERROR "must be a complex number" */)
- const _5 = imag(1 + 2i)
- assert(_5 == 2)
- f32 = _5
- f64 = _5
- const _6 = imag(0i)
- assert(_6 == 0)
- f32 = imag(c64)
- f64 = imag(c128)
- f32 = imag /* ERROR "cannot assign" */ (c128)
- f64 = imag /* ERROR "cannot assign" */ (c64)
- imag /* ERROR "not used" */ (c64)
-}
-
-func _len() {
- const c = "foobar"
- var a [10]bool
- var p *[20]int
- var s []int
- var m map[string]complex128
- _ = len /* ERROR "argument" */ ()
- _ = len /* ERROR "argument" */ (1, 2)
- _ = len(42 /* ERROR "invalid" */)
- const _3 = len(c)
- assert(_3 == 6)
- const _4 = len(a)
- assert(_4 == 10)
- const _5 = len(p)
- assert(_5 == 20)
- _ = len(m)
- len /* ERROR "not used" */ (c)
-
- // esoteric case
- var t string
- var hash map[interface{}][]*[10]int
- const n = len /* ERROR "not constant" */ (hash[recover()][len(t)])
- assert /* ERROR "failed" */ (n == 10)
- var ch <-chan int
- const nn = len /* ERROR "not constant" */ (hash[<-ch][len(t)])
- _ = nn // TODO(gri) remove this once unused constants get type-checked
-}
-
-func _make() {
- n := 0
-
- _ = make /* ERROR "argument" */ ()
- _ = make(1 /* ERROR "not a type" */)
- _ = make(int /* ERROR "cannot make" */)
-
- // slices
- _ = make/* ERROR "arguments" */ ([]int)
- _ = make/* ERROR "arguments" */ ([]int, 2, 3, 4)
- _ = make([]int, int /* ERROR "not an expression" */)
- _ = make([]int, 10, float32 /* ERROR "not an expression" */)
- _ = make([]int, "foo" /* ERROR "must be an integer" */)
- _ = make([]int, 10, 2.3 /* ERROR "must be an integer" */)
- _ = make([]int, 5, 10.0)
- _ = make([]int, 0i)
- _ = make([]int, - /* ERROR "must not be negative" */ 1, 10)
- _ = make([]int, 0, - /* ERROR "must not be negative" */ 1)
- _ = make([]int, - /* ERROR "must not be negative" */ 1, - /* ERROR "must not be negative" */ 1)
- _ = make([]int, 1<<100, 1<<100) // run-time panic
- _ = make([]int, 1 /* ERROR "length and capacity swapped" */ <<100 + 1, 1<<100)
- _ = make([]int, 1 /* ERROR "length and capacity swapped" */ <<100, 12345)
-
- // maps
- _ = make /* ERROR "arguments" */ (map[int]string, 10, 20)
- _ = make(map[int]float32, int /* ERROR "not an expression" */)
- _ = make(map[int]float32, "foo" /* ERROR "must be an integer" */)
- _ = make(map[int]float32, 10)
- _ = make(map[int]float32, n)
- _ = make(map[int]float32, int64(n))
-
- // channels
- _ = make /* ERROR "arguments" */ (chan int, 10, 20)
- _ = make(chan int, int /* ERROR "not an expression" */)
- _ = make(chan<- int, "foo" /* ERROR "must be an integer" */)
- _ = make(<-chan float64, 10)
- _ = make(chan chan int, n)
- _ = make(chan string, int64(n))
-
- make /* ERROR "not used" */ ([]int, 10)
-}
-
-func _new() {
- _ = new /* ERROR "argument" */ ()
- _ = new /* ERROR "argument" */ (1, 2)
- _ = new("foo" /* ERROR "not a type" */)
- p := new(float64)
- _ = new(struct{ x, y int })
- q := new(*float64)
- _ = *p == **q
- new /* ERROR "not used" */ (int)
-}
-
-func _real() {
- var f32 float32
- var f64 float64
- var c64 complex64
- var c128 complex128
- _ = real /* ERROR "argument" */ ()
- _ = real /* ERROR "argument" */ (1, 2)
- _ = real(10 /* ERROR "must be a complex number" */)
- _ = real(2.7182818 /* ERROR "must be a complex number" */)
- _ = real("foo" /* ERROR "must be a complex number" */)
- const _5 = real(1 + 2i)
- assert(_5 == 1)
- f32 = _5
- f64 = _5
- const _6 = real(0i)
- assert(_6 == 0)
- f32 = real(c64)
- f64 = real(c128)
- f32 = real /* ERROR "cannot assign" */ (c128)
- f64 = real /* ERROR "cannot assign" */ (c64)
- real /* ERROR "not used" */ (c64)
-}
-
-func _recover() {
- _ = recover()
- _ = recover /* ERROR "argument" */ (10)
- recover()
-}
-
-func _Alignof() {
- var x int
- _ = unsafe /* ERROR "argument" */ .Alignof()
- _ = unsafe /* ERROR "argument" */ .Alignof(1, 2)
- _ = unsafe.Alignof(int /* ERROR "not an expression" */)
- _ = unsafe.Alignof(42)
- _ = unsafe.Alignof(new(struct{}))
- unsafe /* ERROR "not used" */ .Alignof(x)
-}
-
-func _Offsetof() {
- var x struct{ f int }
- _ = unsafe /* ERROR "argument" */ .Offsetof()
- _ = unsafe /* ERROR "argument" */ .Offsetof(1, 2)
- _ = unsafe.Offsetof(int /* ERROR "not an expression" */)
- _ = unsafe.Offsetof(x /* ERROR "not a selector" */)
- _ = unsafe.Offsetof(x.f)
- _ = unsafe.Offsetof((x.f))
- _ = unsafe.Offsetof((((((((x))).f)))))
- unsafe /* ERROR "not used" */ .Offsetof(x.f)
-}
-
-func _Sizeof() {
- var x int
- _ = unsafe /* ERROR "argument" */ .Sizeof()
- _ = unsafe /* ERROR "argument" */ .Sizeof(1, 2)
- _ = unsafe.Sizeof(int /* ERROR "not an expression" */)
- _ = unsafe.Sizeof(42)
- _ = unsafe.Sizeof(new(complex128))
- unsafe /* ERROR "not used" */ .Sizeof(x)
-
- // basic types have size guarantees
- assert(unsafe.Sizeof(byte(0)) == 1)
- assert(unsafe.Sizeof(uint8(0)) == 1)
- assert(unsafe.Sizeof(int8(0)) == 1)
- assert(unsafe.Sizeof(uint16(0)) == 2)
- assert(unsafe.Sizeof(int16(0)) == 2)
- assert(unsafe.Sizeof(uint32(0)) == 4)
- assert(unsafe.Sizeof(int32(0)) == 4)
- assert(unsafe.Sizeof(float32(0)) == 4)
- assert(unsafe.Sizeof(uint64(0)) == 8)
- assert(unsafe.Sizeof(int64(0)) == 8)
- assert(unsafe.Sizeof(float64(0)) == 8)
- assert(unsafe.Sizeof(complex64(0)) == 8)
- assert(unsafe.Sizeof(complex128(0)) == 16)
-}
-
-// self-testing only
-func _assert() {
- var x int
- assert /* ERROR "argument" */ ()
- assert /* ERROR "argument" */ (1, 2)
- assert("foo" /* ERROR "boolean constant" */ )
- assert(x /* ERROR "boolean constant" */)
- assert(true)
- assert /* ERROR "failed" */ (false)
-}
-
-// self-testing only
-func _trace() {
- // Uncomment the code below to test trace - will produce console output
- // _ = trace /* ERROR "no value" */ ()
- // _ = trace(1)
- // _ = trace(true, 1.2, '\'', "foo", 42i, "foo" <= "bar")
-}
diff --git a/libgo/go/go/types/testdata/const0.src b/libgo/go/go/types/testdata/const0.src
deleted file mode 100644
index a2ca344c78..0000000000
--- a/libgo/go/go/types/testdata/const0.src
+++ /dev/null
@@ -1,215 +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.
-
-// constant declarations
-
-package const0
-
-// constants declarations must be initialized by constants
-var x = 0
-const c0 = x /* ERROR "not constant" */
-
-// untyped constants
-const (
- // boolean values
- ub0 = false
- ub1 = true
- ub2 = 2 < 1
- ub3 = ui1 == uf1
- ub4 = true /* ERROR "cannot convert" */ == 0
-
- // integer values
- ui0 = 0
- ui1 = 1
- ui2 = 42
- ui3 = 3141592653589793238462643383279502884197169399375105820974944592307816406286
- ui4 = -10
-
- ui5 = ui0 + ui1
- ui6 = ui1 - ui1
- ui7 = ui2 * ui1
- ui8 = ui3 / ui3
- ui9 = ui3 % ui3
-
- ui10 = 1 / 0 /* ERROR "division by zero" */
- ui11 = ui1 / 0 /* ERROR "division by zero" */
- ui12 = ui3 / ui0 /* ERROR "division by zero" */
- ui13 = 1 % 0 /* ERROR "division by zero" */
- ui14 = ui1 % 0 /* ERROR "division by zero" */
- ui15 = ui3 % ui0 /* ERROR "division by zero" */
-
- ui16 = ui2 & ui3
- ui17 = ui2 | ui3
- ui18 = ui2 ^ ui3
-
- // floating point values
- uf0 = 0.
- uf1 = 1.
- uf2 = 4.2e1
- uf3 = 3.141592653589793238462643383279502884197169399375105820974944592307816406286
- uf4 = 1e-1
-
- uf5 = uf0 + uf1
- uf6 = uf1 - uf1
- uf7 = uf2 * uf1
- uf8 = uf3 / uf3
- uf9 = uf3 /* ERROR "not defined" */ % uf3
-
- uf10 = 1 / 0 /* ERROR "division by zero" */
- uf11 = uf1 / 0 /* ERROR "division by zero" */
- uf12 = uf3 / uf0 /* ERROR "division by zero" */
-
- uf16 = uf2 /* ERROR "not defined" */ & uf3
- uf17 = uf2 /* ERROR "not defined" */ | uf3
- uf18 = uf2 /* ERROR "not defined" */ ^ uf3
-
- // complex values
- uc0 = 0.i
- uc1 = 1.i
- uc2 = 4.2e1i
- uc3 = 3.141592653589793238462643383279502884197169399375105820974944592307816406286i
- uc4 = 1e-1i
-
- uc5 = uc0 + uc1
- uc6 = uc1 - uc1
- uc7 = uc2 * uc1
- uc8 = uc3 / uc3
- uc9 = uc3 /* ERROR "not defined" */ % uc3
-
- uc10 = 1 / 0 /* ERROR "division by zero" */
- uc11 = uc1 / 0 /* ERROR "division by zero" */
- uc12 = uc3 / uc0 /* ERROR "division by zero" */
-
- uc16 = uc2 /* ERROR "not defined" */ & uc3
- uc17 = uc2 /* ERROR "not defined" */ | uc3
- uc18 = uc2 /* ERROR "not defined" */ ^ uc3
-)
-
-type (
- mybool bool
- myint int
- myfloat float64
- mycomplex complex128
-)
-
-// typed constants
-const (
- // boolean values
- tb0 bool = false
- tb1 bool = true
- tb2 mybool = 2 < 1
- tb3 mybool = ti1 /* ERROR "cannot compare" */ == tf1
-
- // integer values
- ti0 int8 = ui0
- ti1 int32 = ui1
- ti2 int64 = ui2
- ti3 myint = ui3 /* ERROR "overflows" */
- ti4 myint = ui4
-
- ti5 = ti0 /* ERROR "mismatched types" */ + ti1
- ti6 = ti1 - ti1
- ti7 = ti2 /* ERROR "mismatched types" */ * ti1
- //ti8 = ti3 / ti3 // TODO(gri) enable this
- //ti9 = ti3 % ti3 // TODO(gri) enable this
-
- ti10 = 1 / 0 /* ERROR "division by zero" */
- ti11 = ti1 / 0 /* ERROR "division by zero" */
- ti12 = ti3 /* ERROR "mismatched types" */ / ti0
- ti13 = 1 % 0 /* ERROR "division by zero" */
- ti14 = ti1 % 0 /* ERROR "division by zero" */
- ti15 = ti3 /* ERROR "mismatched types" */ % ti0
-
- ti16 = ti2 /* ERROR "mismatched types" */ & ti3
- ti17 = ti2 /* ERROR "mismatched types" */ | ti4
- ti18 = ti2 ^ ti5 // no mismatched types error because the type of ti5 is unknown
-
- // floating point values
- tf0 float32 = 0.
- tf1 float32 = 1.
- tf2 float64 = 4.2e1
- tf3 myfloat = 3.141592653589793238462643383279502884197169399375105820974944592307816406286
- tf4 myfloat = 1e-1
-
- tf5 = tf0 + tf1
- tf6 = tf1 - tf1
- tf7 = tf2 /* ERROR "mismatched types" */ * tf1
- // tf8 = tf3 / tf3 // TODO(gri) enable this
- tf9 = tf3 /* ERROR "not defined" */ % tf3
-
- tf10 = 1 / 0 /* ERROR "division by zero" */
- tf11 = tf1 / 0 /* ERROR "division by zero" */
- tf12 = tf3 /* ERROR "mismatched types" */ / tf0
-
- tf16 = tf2 /* ERROR "mismatched types" */ & tf3
- tf17 = tf2 /* ERROR "mismatched types" */ | tf3
- tf18 = tf2 /* ERROR "mismatched types" */ ^ tf3
-
- // complex values
- tc0 = 0.i
- tc1 = 1.i
- tc2 = 4.2e1i
- tc3 = 3.141592653589793238462643383279502884197169399375105820974944592307816406286i
- tc4 = 1e-1i
-
- tc5 = tc0 + tc1
- tc6 = tc1 - tc1
- tc7 = tc2 * tc1
- tc8 = tc3 / tc3
- tc9 = tc3 /* ERROR "not defined" */ % tc3
-
- tc10 = 1 / 0 /* ERROR "division by zero" */
- tc11 = tc1 / 0 /* ERROR "division by zero" */
- tc12 = tc3 / tc0 /* ERROR "division by zero" */
-
- tc16 = tc2 /* ERROR "not defined" */ & tc3
- tc17 = tc2 /* ERROR "not defined" */ | tc3
- tc18 = tc2 /* ERROR "not defined" */ ^ tc3
-)
-
-// initialization cycles
-const (
- a /* ERROR "cycle" */ = a
- b /* ERROR "cycle" */ , c /* ERROR "cycle" */, d, e = e, d, c, b // TODO(gri) should only have one cycle error
- f float64 = d
-)
-
-// multiple initialization
-const (
- a1, a2, a3 = 7, 3.1415926, "foo"
- b1, b2, b3 = b3, b1, 42
- _p0 = assert(a1 == 7)
- _p1 = assert(a2 == 3.1415926)
- _p2 = assert(a3 == "foo")
- _p3 = assert(b1 == 42)
- _p4 = assert(b2 == 42)
- _p5 = assert(b3 == 42)
-)
-
-// iota
-const (
- iota0 = iota
- iota1 = iota
- iota2 = iota*2
- _a0 = assert(iota0 == 0)
- _a1 = assert(iota1 == 1)
- _a2 = assert(iota2 == 4)
- iota6 = iota*3
-
- iota7
- iota8
- _a3 = assert(iota7 == 21)
- _a4 = assert(iota8 == 24)
-)
-
-const (
- _b0 = iota
- _b1 = assert(iota + iota2 == 5)
-)
-
-// special cases
-const (
- _n0 = nil /* ERROR "invalid constant type" */
- _n1 = [ /* ERROR "not constant" */ ]int{}
-) \ No newline at end of file
diff --git a/libgo/go/go/types/testdata/conversions.src b/libgo/go/go/types/testdata/conversions.src
deleted file mode 100644
index 1b1518366f..0000000000
--- a/libgo/go/go/types/testdata/conversions.src
+++ /dev/null
@@ -1,18 +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.
-
-// conversions
-
-package conversions
-
-// argument count
-var (
- _v0 = int /* ERROR "one argument" */ ()
- _v1 = int /* ERROR "one argument" */ (1, 2)
-)
-
-//
-var (
- _v2 = int8(0)
-) \ No newline at end of file
diff --git a/libgo/go/go/types/testdata/decls0.src b/libgo/go/go/types/testdata/decls0.src
deleted file mode 100644
index 33d4b38014..0000000000
--- a/libgo/go/go/types/testdata/decls0.src
+++ /dev/null
@@ -1,177 +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.
-
-// type declarations
-
-package decls0
-
-import (
- "unsafe"
- // we can have multiple blank imports (was bug)
- _ "math"
- _ "net/rpc"
-)
-
-const pi = 3.1415
-
-type (
- N undeclared /* ERROR "undeclared" */
- B bool
- I int32
- A [10]P
- T struct {
- x, y P
- }
- P *T
- R (*R)
- F func(A) I
- Y interface {
- f(A) I
- }
- S [](((P)))
- M map[I]F
- C chan<- I
-
- // blank types must be typechecked
- _ pi /* ERROR "not a type" */
- _ struct{}
- _ struct{ pi /* ERROR "not a type" */ }
-)
-
-
-// invalid array types
-type (
- iA0 [... /* ERROR "invalid use of '...'" */ ]byte
- iA1 [1 /* ERROR "invalid array length" */ <<100]int
- iA2 [- /* ERROR "invalid array length" */ 1]complex128
- iA3 ["foo" /* ERROR "invalid array length" */ ]string
-)
-
-
-type (
- p1 pi /* ERROR "no single field or method foo" */ .foo
- p2 unsafe.Pointer
-)
-
-
-type (
- Pi pi /* ERROR "not a type" */
-
- a /* ERROR "illegal cycle" */ a
- a /* ERROR "redeclared" */ int
-
- // where the cycle error appears depends on the
- // order in which declarations are processed
- // (which depends on the order in which a map
- // is iterated through)
- b /* ERROR "illegal cycle" */ c
- c d
- d e
- e b
-
- t *t
-
- U V
- V *W
- W U
-
- P1 *S2
- P2 P1
-
- S0 struct {
- }
- S1 struct {
- a, b, c int
- u, v, a /* ERROR "redeclared" */ float32
- }
- S2 struct {
- U // anonymous field
- // TODO(gri) recognize double-declaration below
- // U /* ERROR "redeclared" */ int
- }
- S3 struct {
- x S2
- }
- S4/* ERROR "illegal cycle" */ struct {
- S4
- }
- S5 /* ERROR "illegal cycle" */ struct {
- S6
- }
- S6 struct {
- field S7
- }
- S7 struct {
- S5
- }
-
- L1 []L1
- L2 []int
-
- A1 [10.0]int
- A2 /* ERROR "illegal cycle" */ [10]A2
- A3 /* ERROR "illegal cycle" */ [10]struct {
- x A4
- }
- A4 [10]A3
-
- F1 func()
- F2 func(x, y, z float32)
- F3 func(x, y, x /* ERROR "redeclared" */ float32)
- F4 func() (x, y, x /* ERROR "redeclared" */ float32)
- F5 func(x int) (x /* ERROR "redeclared" */ float32)
- F6 func(x ...int)
-
- I1 interface{}
- I2 interface {
- m1()
- }
- I3 interface { /* ERROR "multiple methods named m1" */
- m1()
- m1 /* ERROR "redeclared" */ ()
- }
- I4 interface {
- m1(x, y, x /* ERROR "redeclared" */ float32)
- m2() (x, y, x /* ERROR "redeclared" */ float32)
- m3(x int) (x /* ERROR "redeclared" */ float32)
- }
- I5 interface {
- m1(I5)
- }
- I6 interface {
- S0 /* ERROR "not an interface" */
- }
- I7 interface {
- I1
- I1
- }
- I8 /* ERROR "illegal cycle" */ interface {
- I8
- }
- // Use I09 (rather than I9) because it appears lexically before
- // I10 so that we get the illegal cycle here rather then in the
- // declaration of I10. If the implementation sorts by position
- // rather than name, the error message will still be here.
- I09 /* ERROR "illegal cycle" */ interface {
- I10
- }
- I10 interface {
- I11
- }
- I11 interface {
- I09
- }
-
- C1 chan int
- C2 <-chan int
- C3 chan<- C3
- C4 chan C5
- C5 chan C6
- C6 chan C4
-
- M1 map[Last]string
- M2 map[string]M2
-
- Last int
-)
diff --git a/libgo/go/go/types/testdata/decls1.src b/libgo/go/go/types/testdata/decls1.src
deleted file mode 100644
index dd63ba9809..0000000000
--- a/libgo/go/go/types/testdata/decls1.src
+++ /dev/null
@@ -1,132 +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.
-
-// variable declarations
-
-package decls1
-
-import (
- "math"
-)
-
-// Global variables without initialization
-var (
- a, b bool
- c byte
- d uint8
- r rune
- i int
- j, k, l int
- x, y float32
- xx, yy float64
- u, v complex64
- uu, vv complex128
- s, t string
- array []byte
- iface interface{}
-
- blank _ /* ERROR "cannot use _" */
-)
-
-// Global variables with initialization
-var (
- s1 = i + j
- s2 = i /* ERROR "mismatched types" */ + x
- s3 = c + d
- s4 = s + t
- s5 = s /* ERROR "invalid operation" */ / t
- s6 = array[t1]
- s7 = array[x /* ERROR "index" */]
- s8 = &a
- s10 = &42 /* ERROR "cannot take address" */
- s11 = &v
- s12 = -(u + *t11) / *&v
- s13 = a /* ERROR "shifted operand" */ << d
- s14 = i << j /* ERROR "must be unsigned" */
- s18 = math.Pi * 10.0
- s19 = s1 /* ERROR "cannot call" */ ()
- s20 = f0 /* ERROR "no value" */ ()
- s21 = f6(1, s1, i)
- s22 = f6(1, s1, uu /* ERROR "cannot assign" */ )
-
- t1 int = i + j
- t2 int = i /* ERROR "mismatched types" */ + x
- t3 int = c /* ERROR "cannot assign" */ + d
- t4 string = s + t
- t5 string = s /* ERROR "invalid operation" */ / t
- t6 byte = array[t1]
- t7 byte = array[x /* ERROR "index" */]
- t8 *int = & /* ERROR "cannot assign" */ a
- t10 *int = &42 /* ERROR "cannot take address" */
- t11 *complex64 = &v
- t12 complex64 = -(u + *t11) / *&v
- t13 int = a /* ERROR "shifted operand" */ << d
- t14 int = i << j /* ERROR "must be unsigned" */
- t15 math /* ERROR "not in selector" */
- t16 math.xxx /* ERROR "unexported" */
- t17 math /* ERROR "not a type" */ .Pi
- t18 float64 = math.Pi * 10.0
- t19 int = t1 /* ERROR "cannot call" */ ()
- t20 int = f0 /* ERROR "no value" */ ()
-)
-
-// Various more complex expressions
-var (
- u1 = x /* ERROR "not an interface" */ .(int)
- u2 = iface.([]int)
- u3 = iface.(a /* ERROR "not a type" */ )
- u4, ok = iface.(int)
- u5 /* ERROR "assignment count mismatch" */ , ok2, ok3 = iface.(int)
-)
-
-// Constant expression initializations
-var (
- v1 = 1 /* ERROR "cannot convert" */ + "foo"
- v2 = c + 255
- v3 = c + 256 /* ERROR "overflows" */
- v4 = r + 2147483647
- v5 = r + 2147483648 /* ERROR "overflows" */
- v6 = 42
- v7 = v6 + 2147483647
- v8 = v6 + 2147483648 /* ERROR "overflows" */
- v9 = i + 1 << 10
- v10 byte = 1024 /* ERROR "overflows" */
- v11 = xx/yy*yy - xx
- v12 = true && false
- v13 = nil /* ERROR "use of untyped nil" */
-)
-
-// Multiple assignment expressions
-var (
- m1a, m1b = 1, 2
- m2a /* ERROR "assignment count mismatch" */ , m2b, m2c = 1, 2
- m3a /* ERROR "assignment count mismatch" */ , m3b = 1, 2, 3
-)
-
-// Declaration of parameters and results
-func f0() {}
-func f1(a /* ERROR "not a type" */) {}
-func f2(a, b, c d /* ERROR "not a type" */) {}
-
-func f3() int {}
-func f4() a /* ERROR "not a type" */ {}
-func f5() (a, b, c d /* ERROR "not a type" */) {}
-
-func f6(a, b, c int) complex128 { return 0 }
-
-// Declaration of receivers
-type T struct{}
-
-func (T) m0() {}
-func (*T) m1() {}
-func (x T) m2() {}
-func (x *T) m3() {}
-
-
-// Initialization functions
-func init() {}
-func /* ERROR "no arguments and no return values" */ init(int) {}
-func /* ERROR "no arguments and no return values" */ init() int { return 0 }
-func /* ERROR "no arguments and no return values" */ init(int) int {}
-func (T) init(int) int { return 0 }
diff --git a/libgo/go/go/types/testdata/decls2a.src b/libgo/go/go/types/testdata/decls2a.src
deleted file mode 100644
index 3867be7376..0000000000
--- a/libgo/go/go/types/testdata/decls2a.src
+++ /dev/null
@@ -1,67 +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.
-
-// method declarations
-
-package decls2
-
-import "time"
-
-// T1 declared before its methods.
-type T1 struct{
- f int
-}
-
-func (T1) m() {}
-func (T1) m /* ERROR "redeclared" */ () {}
-func (x *T1) f /* ERROR "field and method" */ () {}
-
-// T2's method declared before the type.
-func (*T2) f /* ERROR "field and method" */ () {}
-
-type T2 struct {
- f int
-}
-
-// Methods declared without a declared type.
-func (undeclared /* ERROR "undeclared" */) m() {}
-func (x *undeclared /* ERROR "undeclared" */) m() {}
-
-// TODO(gri) try to get rid of double error reporting here
-func (pi /* ERROR "not a type" */) m1() {}
-func (x pi /* ERROR "not a type" */) m2() {}
-func (x *pi /* ERROR "not a type" */ ) m3() {} // TODO(gri) not closing the last /* comment crashes the system
-
-// Blank types.
-type _ struct { m int }
-type _ struct { m int }
-
-// TODO(gri) blank idents not fully checked - disabled for now
-// func (_ /* ERROR "cannot use _" */) m() {}
-// func (_ /* ERROR "cannot use _" */) m() {}
-
-// Methods with receiver base type declared in another file.
-func (T3) m1() {}
-func (*T3) m2() {}
-func (x T3) m3() {}
-func (x *T3) f /* ERROR "field and method" */ () {}
-
-// Methods of non-struct type.
-type T4 func()
-
-func (self T4) m() func() { return self }
-
-// Methods associated with an interface.
-type T5 interface {
- m() int
-}
-
-func (T5 /* ERROR "invalid receiver" */) m1() {}
-func (T5 /* ERROR "invalid receiver" */) m2() {}
-
-// Methods associated with non-local or unnamed types.
-func (int /* ERROR "non-local type" */ ) m() {}
-func ([ /* ERROR "expected" */ ]int) m() {}
-func (time /* ERROR "expected" */ .Time) m() {}
-func (x interface /* ERROR "expected" */ {}) m() {}
diff --git a/libgo/go/go/types/testdata/decls2b.src b/libgo/go/go/types/testdata/decls2b.src
deleted file mode 100644
index c7f9ddf01a..0000000000
--- a/libgo/go/go/types/testdata/decls2b.src
+++ /dev/null
@@ -1,28 +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.
-
-// method declarations
-
-package decls2
-
-const pi = 3.1415
-
-func (T1) m /* ERROR "redeclared" */ () {}
-
-type T3 struct {
- f *T3
-}
-
-type T6 struct {
- x int
-}
-
-func (t *T6) m1() int {
- return t.x
-}
-
-func f() {
- var t *T6
- t.m1()
-} \ No newline at end of file
diff --git a/libgo/go/go/types/testdata/decls3.src b/libgo/go/go/types/testdata/decls3.src
deleted file mode 100644
index 4bc7d41494..0000000000
--- a/libgo/go/go/types/testdata/decls3.src
+++ /dev/null
@@ -1,231 +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.
-
-// embedded types
-
-package decls3
-
-// fields with the same name at the same level cancel each other out
-
-func _() {
- type (
- T1 struct { X int }
- T2 struct { X int }
- T3 struct { T1; T2 } // X is embedded twice at the same level via T1->X, T2->X
- )
-
- var t T3
- _ = t /* ERROR "no single field or method" */ .X
-}
-
-func _() {
- type (
- T1 struct { X int }
- T2 struct { T1 }
- T3 struct { T1 }
- T4 struct { T2; T3 } // X is embedded twice at the same level via T2->T1->X, T3->T1->X
- )
-
- var t T4
- _ = t /* ERROR "no single field or method" */ .X
-}
-
-func issue4355() {
- type (
- T1 struct {X int}
- T2 struct {T1}
- T3 struct {T2}
- T4 struct {T2}
- T5 struct {T3; T4} // X is embedded twice at the same level via T3->T2->T1->X, T4->T2->T1->X
- )
-
- var t T5
- _ = t /* ERROR "no single field or method" */ .X
-}
-
-// Borrowed from the FieldByName test cases in reflect/all_test.go.
-
-type D1 struct {
- d int
-}
-type D2 struct {
- d int
-}
-
-type S0 struct {
- A, B, C int
- D1
- D2
-}
-
-type S1 struct {
- B int
- S0
-}
-
-type S2 struct {
- A int
- *S1
-}
-
-type S1x struct {
- S1
-}
-
-type S1y struct {
- S1
-}
-
-type S3 struct {
- S1x
- S2
- D, E int
- *S1y
-}
-
-type S4 struct {
- *S4
- A int
-}
-
-// The X in S6 and S7 annihilate, but they also block the X in S8.S9.
-type S5 struct {
- S6
- S7
- S8
-}
-
-type S6 struct {
- X int
-}
-
-type S7 S6
-
-type S8 struct {
- S9
-}
-
-type S9 struct {
- X int
- Y int
-}
-
-// The X in S11.S6 and S12.S6 annihilate, but they also block the X in S13.S8.S9.
-type S10 struct {
- S11
- S12
- S13
-}
-
-type S11 struct {
- S6
-}
-
-type S12 struct {
- S6
-}
-
-type S13 struct {
- S8
-}
-
-func _() {
- _ = struct /* ERROR "no single field or method" */ {}{}.Foo
- _ = S0{}.A
- _ = S0 /* ERROR "no single field or method" */ {}.D
- _ = S1{}.A
- _ = S1{}.B
- _ = S1{}.S0
- _ = S1{}.C
- _ = S2{}.A
- _ = S2{}.S1
- _ = S2{}.B
- _ = S2{}.C
- _ = S2 /* ERROR "no single field or method" */ {}.D
- _ = S3 /* ERROR "no single field or method" */ {}.S1
- _ = S3{}.A
- _ = S3 /* ERROR "no single field or method" */ {}.B
- _ = S3{}.D
- _ = S3{}.E
- _ = S4{}.A
- _ = S4 /* ERROR "no single field or method" */ {}.B
- _ = S5 /* ERROR "no single field or method" */ {}.X
- _ = S5{}.Y
- _ = S10 /* ERROR "no single field or method" */ {}.X
- _ = S10{}.Y
-}
-
-// Borrowed from the FieldByName benchmark in reflect/all_test.go.
-
-type R0 struct {
- *R1
- *R2
- *R3
- *R4
-}
-
-type R1 struct {
- *R5
- *R6
- *R7
- *R8
-}
-
-type R2 R1
-type R3 R1
-type R4 R1
-
-type R5 struct {
- *R9
- *R10
- *R11
- *R12
-}
-
-type R6 R5
-type R7 R5
-type R8 R5
-
-type R9 struct {
- *R13
- *R14
- *R15
- *R16
-}
-
-type R10 R9
-type R11 R9
-type R12 R9
-
-type R13 struct {
- *R17
- *R18
- *R19
- *R20
-}
-
-type R14 R13
-type R15 R13
-type R16 R13
-
-type R17 struct {
- *R21
- *R22
- *R23
- *R24
-}
-
-type R18 R17
-type R19 R17
-type R20 R17
-
-type R21 struct {
- X int
-}
-
-type R22 R21
-type R23 R21
-type R24 R21
-
-var _ = R0 /* ERROR "no single field or method" */ {}.X \ No newline at end of file
diff --git a/libgo/go/go/types/testdata/expr0.src b/libgo/go/go/types/testdata/expr0.src
deleted file mode 100644
index c3233d36fe..0000000000
--- a/libgo/go/go/types/testdata/expr0.src
+++ /dev/null
@@ -1,151 +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.
-
-// unary expressions
-
-package expr0
-
-var (
- // bool
- b0 = true
- b1 bool = b0
- b2 = !true
- b3 = !b1
- b4 bool = !true
- b5 bool = !b4
- b6 = +b0 /* ERROR "not defined" */
- b7 = -b0 /* ERROR "not defined" */
- b8 = ^b0 /* ERROR "not defined" */
- b9 = *b0 /* ERROR "cannot indirect" */
- b10 = &true /* ERROR "cannot take address" */
- b11 = &b0
- b12 = <-b0 /* ERROR "cannot receive" */
-
- // int
- i0 = 1
- i1 int = i0
- i2 = +1
- i3 = +i0
- i4 int = +1
- i5 int = +i4
- i6 = -1
- i7 = -i0
- i8 int = -1
- i9 int = -i4
- i10 = !i0 /* ERROR "not defined" */
- i11 = ^1
- i12 = ^i0
- i13 int = ^1
- i14 int = ^i4
- i15 = *i0 /* ERROR "cannot indirect" */
- i16 = &i0
- i17 = *i16
- i18 = <-i16 /* ERROR "cannot receive" */
-
- // uint
- u0 = uint(1)
- u1 uint = u0
- u2 = +1
- u3 = +u0
- u4 uint = +1
- u5 uint = +u4
- u6 = -1
- u7 = -u0
- u8 uint = - /* ERROR "overflows" */ 1
- u9 uint = -u4
- u10 = !u0 /* ERROR "not defined" */
- u11 = ^1
- u12 = ^i0
- u13 uint = ^ /* ERROR "overflows" */ 1
- u14 uint = ^u4
- u15 = *u0 /* ERROR "cannot indirect" */
- u16 = &u0
- u17 = *u16
- u18 = <-u16 /* ERROR "cannot receive" */
- u19 = ^uint(0)
-
- // float64
- f0 = float64(1)
- f1 float64 = f0
- f2 = +1
- f3 = +f0
- f4 float64 = +1
- f5 float64 = +f4 /* ERROR not defined */
- f6 = -1
- f7 = -f0
- f8 float64 = -1
- f9 float64 = -f4
- f10 = !f0 /* ERROR "not defined" */
- f11 = ^1
- f12 = ^i0
- f13 float64 = ^1
- f14 float64 = ^f4 /* ERROR "not defined" */
- f15 = *f0 /* ERROR "cannot indirect" */
- f16 = &f0
- f17 = *u16
- f18 = <-u16 /* ERROR "cannot receive" */
-
- // complex128
- c0 = complex128(1)
- c1 complex128 = c0
- c2 = +1
- c3 = +c0
- c4 complex128 = +1
- c5 complex128 = +c4 /* ERROR not defined */
- c6 = -1
- c7 = -c0
- c8 complex128 = -1
- c9 complex128 = -c4
- c10 = !c0 /* ERROR "not defined" */
- c11 = ^1
- c12 = ^i0
- c13 complex128 = ^1
- c14 complex128 = ^c4 /* ERROR "not defined" */
- c15 = *c0 /* ERROR "cannot indirect" */
- c16 = &c0
- c17 = *u16
- c18 = <-u16 /* ERROR "cannot receive" */
-
- // string
- s0 = "foo"
- s1 = +"foo" /* ERROR "not defined" */
- s2 = -s0 /* ERROR "not defined" */
- s3 = !s0 /* ERROR "not defined" */
- s4 = ^s0 /* ERROR "not defined" */
- s5 = *s4 /* ERROR "cannot indirect" */
- s6 = &s4
- s7 = *s6
- s8 = <-s7 /* ERROR "cannot receive" */
-
- // channel
- ch chan int
- rc <-chan float64
- sc chan <- string
- ch0 = +ch /* ERROR "not defined" */
- ch1 = -ch /* ERROR "not defined" */
- ch2 = !ch /* ERROR "not defined" */
- ch3 = ^ch /* ERROR "not defined" */
- ch4 = *ch /* ERROR "cannot indirect" */
- ch5 = &ch
- ch6 = *ch5
- ch7 = <-ch
- ch8 = <-rc
- ch9 = <-sc /* ERROR "cannot receive" */
-)
-
-// address of composite literals
-type T struct{x, y int}
-
-func f() T { return T{} }
-
-var (
- _ = &T{1, 2}
- _ = &[...]int{}
- _ = &[]int{}
- _ = &[]int{}
- _ = &map[string]T{}
- _ = &(T{1, 2})
- _ = &((((T{1, 2}))))
- _ = &f /* ERROR "cannot take address" */ ()
-)
diff --git a/libgo/go/go/types/testdata/expr2.src b/libgo/go/go/types/testdata/expr2.src
deleted file mode 100644
index 674be4005d..0000000000
--- a/libgo/go/go/types/testdata/expr2.src
+++ /dev/null
@@ -1,23 +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.
-
-// comparisons
-
-package expr2
-
-func _bool() {
- const t = true == true
- const f = true == false
- _ = t /* ERROR "cannot compare" */ < f
- _ = 0 /* ERROR "cannot convert" */ == t
- var b bool
- var x, y float32
- b = x < y
- _ = struct{b bool}{x < y}
-}
-
-// corner cases
-var (
- v0 = nil /* ERROR "cannot compare" */ == nil
-) \ No newline at end of file
diff --git a/libgo/go/go/types/testdata/expr3.src b/libgo/go/go/types/testdata/expr3.src
deleted file mode 100644
index 519e3f567a..0000000000
--- a/libgo/go/go/types/testdata/expr3.src
+++ /dev/null
@@ -1,367 +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.
-
-// various expressions
-
-package expr3
-
-func shifts1() {
- var (
- i0 int
- u0 uint
- )
-
- var (
- v0 = 1<<0
- v1 = 1<<i0 /* ERROR "must be unsigned" */
- v2 = 1<<u0
- v3 = 1<<"foo" /* ERROR "must be unsigned" */
- v4 = 1<<- /* ERROR "stupid shift" */ 1
- v5 = 1<<1025 /* ERROR "stupid shift" */
- v6 = 1 /* ERROR "overflows" */ <<100
-
- v10 uint = 1 << 0
- v11 uint = 1 << u0
- v12 float32 = 1 /* ERROR "must be integer" */ << u0
- )
-}
-
-func shifts2() {
- // TODO(gri) enable commented out tests below.
- var (
- s uint = 33
- i = 1<<s // 1 has type int
- j int32 = 1<<s // 1 has type int32; j == 0
- k = uint64(1<<s) // 1 has type uint64; k == 1<<33
- m int = 1.0<<s // 1.0 has type int
- // n = 1.0<<s != 0 // 1.0 has type int; n == false if ints are 32bits in size
- o = 1<<s == 2<<s // 1 and 2 have type int; o == true if ints are 32bits in size
- // p = 1<<s == 1 /* ERROR "overflows" */ <<33 // illegal if ints are 32bits in size: 1 has type int, but 1<<33 overflows int
- u = 1.0 /* ERROR "must be integer" */ <<s // illegal: 1.0 has type float64, cannot shift
- v float32 = 1 /* ERROR "must be integer" */ <<s // illegal: 1 has type float32, cannot shift
- w int64 = 1.0<<33 // 1.0<<33 is a constant shift expression
- )
-}
-
-// TODO(gri) The error messages below depond on adjusting the spec
-// to reflect what gc is doing at the moment (the spec
-// asks for run-time errors at the moment - see issue 4231).
-//
-func indexes() {
- _ = 1 /* ERROR "cannot index" */ [0]
- _ = indexes /* ERROR "cannot index" */ [0]
- _ = ( /* ERROR "cannot slice" */ 12 + 3)[1:2]
-
- var a [10]int
- _ = a[true /* ERROR "must be integer" */ ]
- _ = a["foo" /* ERROR "must be integer" */ ]
- _ = a[1.1 /* ERROR "must be integer" */ ]
- _ = a[1.0]
- _ = a[- /* ERROR "index .* negative" */ 1]
- _ = a[- /* ERROR "index .* negative" */ 1 :]
- _ = a[: - /* ERROR "index .* negative" */ 1]
- var a0 int
- a0 = a[0]
- var a1 int32
- a1 = a /* ERROR "cannot assign" */ [1]
- _ = a[9]
- _ = a[10 /* ERROR "index .* out of bounds" */ ]
- _ = a[1 /* ERROR "stupid index" */ <<100]
- _ = a[10:]
- _ = a[:10]
- _ = a[10:10]
- _ = a[11 /* ERROR "index .* out of bounds" */ :]
- _ = a[: 11 /* ERROR "index .* out of bounds" */ ]
- _ = a[: 1 /* ERROR "stupid index" */ <<100]
-
- pa := &a
- _ = pa[9]
- _ = pa[10 /* ERROR "index .* out of bounds" */ ]
- _ = pa[1 /* ERROR "stupid index" */ <<100]
- _ = pa[10:]
- _ = pa[:10]
- _ = pa[10:10]
- _ = pa[11 /* ERROR "index .* out of bounds" */ :]
- _ = pa[: 11 /* ERROR "index .* out of bounds" */ ]
- _ = pa[: 1 /* ERROR "stupid index" */ <<100]
-
- var b [0]int
- _ = b[0 /* ERROR "index .* out of bounds" */ ]
- _ = b[:]
- _ = b[0:]
- _ = b[:0]
- _ = b[0:0]
-
- var s []int
- _ = s[- /* ERROR "index .* negative" */ 1]
- _ = s[- /* ERROR "index .* negative" */ 1 :]
- _ = s[: - /* ERROR "index .* negative" */ 1]
- _ = s[0]
- _ = s[1 : 2]
- _ = s[2 /* ERROR "inverted slice range" */ : 1]
- _ = s[2 :]
- _ = s[: 1 /* ERROR "stupid index" */ <<100]
- _ = s[1 /* ERROR "stupid index" */ <<100 :]
- _ = s[1 /* ERROR "stupid index" */ <<100 : 1 /* ERROR "stupid index" */ <<100]
-
- var t string
- _ = t[- /* ERROR "index .* negative" */ 1]
- _ = t[- /* ERROR "index .* negative" */ 1 :]
- _ = t[: - /* ERROR "index .* negative" */ 1]
- var t0 byte
- t0 = t[0]
- var t1 rune
- t1 = t /* ERROR "cannot assign" */ [2]
- _ = ("foo" + "bar")[5]
- _ = ("foo" + "bar")[6 /* ERROR "index .* out of bounds" */ ]
-
- const c = "foo"
- _ = c[- /* ERROR "index .* negative" */ 1]
- _ = c[- /* ERROR "index .* negative" */ 1 :]
- _ = c[: - /* ERROR "index .* negative" */ 1]
- var c0 byte
- c0 = c[0]
- var c2 float32
- c2 = c /* ERROR "cannot assign" */ [2]
- _ = c[3 /* ERROR "index .* out of bounds" */ ]
- _ = ""[0 /* ERROR "index .* out of bounds" */ ]
-
- _ = s[1<<30] // no compile-time error here
-}
-
-type T struct {
- x int
-}
-
-func (*T) m() {}
-
-func method_expressions() {
- _ = T /* ERROR "no single field or method" */ .a
- _ = T /* ERROR "has no method" */ .x
- _ = T.m
- var f func(*T) = (*T).m
- var g func(*T) = ( /* ERROR "cannot assign" */ T).m
-}
-
-func struct_literals() {
- type T0 struct {
- a, b, c int
- }
-
- type T1 struct {
- T0
- a, b int
- u float64
- s string
- }
-
- // keyed elements
- _ = T1{}
- _ = T1{a: 0, 1 /* ERROR "mixture of .* elements" */ }
- _ = T1{aa /* ERROR "unknown field" */ : 0}
- _ = T1{1 /* ERROR "invalid field name" */ : 0}
- _ = T1{a: 0, s: "foo", u: 0, a /* ERROR "duplicate field" */: 10}
- _ = T1{a: "foo" /* ERROR "cannot use" */ }
- _ = T1{c /* ERROR "unknown field" */ : 0}
- _ = T1{T0: { /* ERROR "missing type" */ }}
- _ = T1{T0: T0{}}
- _ = T1{T0 /* ERROR "invalid field name" */ .a: 0}
-
- // unkeyed elements
- _ = T0{1, 2, 3}
- _ = T0{1, b /* ERROR "mixture" */ : 2, 3}
- _ = T0{1, 2} /* ERROR "too few values" */
- _ = T0{1, 2, 3, 4 /* ERROR "too many values" */ }
- _ = T0{1, "foo" /* ERROR "cannot use" */, 3.4 /* ERROR "cannot use" */}
-}
-
-func array_literals() {
- type A0 [0]int
- _ = A0{}
- _ = A0{0 /* ERROR "index .* out of bounds" */}
- _ = A0{0 /* ERROR "index .* out of bounds" */ : 0}
-
- type A1 [10]int
- _ = A1{}
- _ = A1{0, 1, 2}
- _ = A1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
- _ = A1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 /* ERROR "index .* out of bounds" */ }
- _ = A1{- /* ERROR "index .* negative" */ 1: 0}
- _ = A1{8: 8, 9}
- _ = A1{8: 8, 9, 10 /* ERROR "index .* out of bounds" */ }
- _ = A1{0, 1, 2, 0 /* ERROR "duplicate index" */ : 0, 3: 3, 4}
- _ = A1{5: 5, 6, 7, 3: 3, 4}
- _ = A1{5: 5, 6, 7, 3: 3, 4, 5 /* ERROR "duplicate index" */ }
- _ = A1{10 /* ERROR "index .* out of bounds" */ : 10, 10 /* ERROR "index .* out of bounds" */ : 10}
- _ = A1{5: 5, 6, 7, 3: 3, 1 /* ERROR "stupid index" */ <<100: 4, 5 /* ERROR "duplicate index" */ }
- _ = A1{5: 5, 6, 7, 4: 4, 1 /* ERROR "stupid index" */ <<100: 4}
- _ = A1{2.0}
- _ = A1{2.1 /* ERROR "cannot use" */ }
- _ = A1{"foo" /* ERROR "cannot use" */ }
-
- a0 := [...]int{}
- assert(len(a0) == 0)
-
- a1 := [...]int{0, 1, 2}
- assert(len(a1) == 3)
- var a13 [3]int
- var a14 [4]int
- a13 = a1
- a14 = a1 /* ERROR "cannot assign" */
-
- a2 := [...]int{- /* ERROR "index .* negative" */ 1: 0}
-
- a3 := [...]int{0, 1, 2, 0 /* ERROR "duplicate index" */ : 0, 3: 3, 4}
- assert(len(a3) == 5) // somewhat arbitrary
-
- a4 := [...]complex128{0, 1, 2, 1<<10-2: -1i, 1i, 400: 10, 12, 14}
- assert(len(a4) == 1024)
-
- // from the spec
- type Point struct { x, y float32 }
- _ = [...]Point{Point{1.5, -3.5}, Point{0, 0}}
- _ = [...]Point{{1.5, -3.5}, {0, 0}}
- _ = [][]int{[]int{1, 2, 3}, []int{4, 5}}
- _ = [][]int{{1, 2, 3}, {4, 5}}
- _ = [...]*Point{&Point{1.5, -3.5}, &Point{0, 0}}
- _ = [...]*Point{{1.5, -3.5}, {0, 0}}
-}
-
-func slice_literals() {
- type S0 []int
- _ = S0{}
- _ = S0{0, 1, 2}
- _ = S0{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
- _ = S0{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
- _ = S0{- /* ERROR "index .* negative" */ 1: 0}
- _ = S0{8: 8, 9}
- _ = S0{8: 8, 9, 10}
- _ = S0{0, 1, 2, 0 /* ERROR "duplicate index" */ : 0, 3: 3, 4}
- _ = S0{5: 5, 6, 7, 3: 3, 4}
- _ = S0{5: 5, 6, 7, 3: 3, 4, 5 /* ERROR "duplicate index" */ }
- _ = S0{10: 10, 10 /* ERROR "duplicate index" */ : 10}
- _ = S0{5: 5, 6, 7, 3: 3, 1 /* ERROR "stupid index" */ <<100: 4, 5 /* ERROR "duplicate index" */ }
- _ = S0{5: 5, 6, 7, 4: 4, 1 /* ERROR "stupid index" */ <<100: 4}
- _ = S0{2.0}
- _ = S0{2.1 /* ERROR "cannot use" */ }
- _ = S0{"foo" /* ERROR "cannot use" */ }
-
- // indices must be resolved correctly
- // (for details, see comment in go/parser/parser.go, method parseElement)
- index1 := 1
- _ = S0{index1: 1}
- _ = S0{index2: 2}
- _ = S0{index3 /* ERROR "undeclared name" */ : 3}
-}
-
-var index2 int = 2
-
-func map_literals() {
- type M0 map[string]int
-
- _ = M0{}
- _ = M0{1 /* ERROR "missing key" */ }
- _ = M0{1 /* ERROR "cannot use .* as string key" */ : 2}
- _ = M0{"foo": "bar" /* ERROR "cannot use .* as int value" */ }
- _ = M0{"foo": 1, "bar": 2, "foo" /* ERROR "duplicate key" */ : 3 }
-
- // map keys must be resolved correctly
- // (for detials, see comment in go/parser/parser.go, method parseElement)
- key1 := "foo"
- _ = M0{key1: 1}
- _ = M0{key2: 2}
- _ = M0{key3 /* ERROR "undeclared name" */ : 2}
-}
-
-var key2 string = "bar"
-
-type I interface {
- m()
-}
-
-type I2 interface {
- m(int)
-}
-
-type T1 struct{}
-type T2 struct{}
-
-func (T2) m(int) {}
-
-func type_asserts() {
- var x int
- _ = x /* ERROR "not an interface" */ .(int)
-
- var e interface{}
- var ok bool
- x, ok = e.(int)
-
- var t I
- _ = t /* ERROR "use of .* outside type switch" */ .(type)
- _ = t.(T)
- _ = t.(T1 /* ERROR "missing method m" */ )
- _ = t.(T2 /* ERROR "wrong type for method m" */ )
- _ = t.(I2 /* ERROR "wrong type for method m" */ )
-}
-
-func f0() {}
-func f1(x int) {}
-func f2(u float32, s string) {}
-func fs(s []byte) {}
-func fv(x ...int) {}
-func fi(x ... interface{}) {}
-
-func g0() {}
-func g1() int { return 0}
-func g2() (u float32, s string) { return }
-func gs() []byte { return nil }
-
-func _calls() {
- var x int
- var y float32
- var s []int
-
- f0()
- _ = f0 /* ERROR "used as value" */ ()
- f0(g0 /* ERROR "too many arguments" */ )
-
- f1(0)
- f1(x)
- f1(10.0)
- f1 /* ERROR "too few arguments" */ ()
- f1(x, y /* ERROR "too many arguments" */ )
- f1(s /* ERROR "cannot assign" */ )
- f1(x ... /* ERROR "cannot use ..." */ )
- f1(g0 /* ERROR "used as value" */ ())
- f1(g1())
- // f1(g2()) // TODO(gri) missing position in error message
-
- f2 /* ERROR "too few arguments" */ ()
- f2 /* ERROR "too few arguments" */ (3.14)
- f2(3.14, "foo")
- f2(x /* ERROR "cannot assign" */ , "foo")
- f2(g0 /* ERROR "used as value" */ ())
- f2 /* ERROR "too few arguments" */ (g1 /* ERROR "cannot assign" */ ())
- f2(g2())
-
- fs /* ERROR "too few arguments" */ ()
- fs(g0 /* ERROR "used as value" */ ())
- fs(g1 /* ERROR "cannot assign" */ ())
- // fs(g2()) // TODO(gri) missing position in error message
- fs(gs())
-
- fv()
- fv(1, 2.0, x)
- fv(s /* ERROR "cannot assign" */ )
- fv(s...)
- fv(1, s /* ERROR "can only use ... with matching parameter" */ ...)
- fv(gs /* ERROR "cannot assign" */ ())
- fv(gs /* ERROR "cannot assign" */ ()...)
-
- fi()
- fi(1, 2.0, x, 3.14, "foo")
- fi(g2())
- fi(0, g2)
- fi(0, g2 /* ERROR "2-valued expression" */ ())
-} \ No newline at end of file
diff --git a/libgo/go/go/types/testdata/stmt0.src b/libgo/go/go/types/testdata/stmt0.src
deleted file mode 100644
index ca36834fde..0000000000
--- a/libgo/go/go/types/testdata/stmt0.src
+++ /dev/null
@@ -1,274 +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.
-
-// statements
-
-package stmt0
-
-func _() {
- b, i, f, c, s := false, 1, 1.0, 1i, "foo"
- b = i /* ERROR "cannot assign" */
- i = f /* ERROR "cannot assign" */
- f = c /* ERROR "cannot assign" */
- c = s /* ERROR "cannot assign" */
- s = b /* ERROR "cannot assign" */
-
- v0 /* ERROR "mismatch" */, v1, v2 := 1, 2, 3, 4
-
- b = true
-
- i += 1
- i += "foo" /* ERROR "cannot convert.*int" */
-
- f -= 1
- f -= "foo" /* ERROR "cannot convert.*float64" */
-
- c *= 1
- c /= 0 /* ERROR "division by zero" */
-
- s += "bar"
- s += 1 /* ERROR "cannot convert.*string" */
-}
-
-func _incdecs() {
- const c = 3.14
- c /* ERROR "cannot assign" */ ++
- s := "foo"
- s /* ERROR "cannot convert" */ --
- 3.14 /* ERROR "cannot assign" */ ++
- var (
- x int
- y float32
- z complex128
- )
- x++
- y--
- z++
-}
-
-func _sends() {
- var ch chan int
- var rch <-chan int
- var x int
- x /* ERROR "cannot send" */ <- x
- rch /* ERROR "cannot send" */ <- x
- ch /* ERROR "cannot send" */ <- "foo"
- ch <- x
-}
-
-func _selects() {
- select {}
- var (
- ch chan int
- sc chan <- bool
- x int
- )
- select {
- case <-ch:
- ch <- x
- case t, ok := <-ch:
- x = t
- case <-sc /* ERROR "cannot receive from send-only channel" */ :
- }
- select {
- default:
- default /* ERROR "multiple defaults" */ :
- }
-}
-
-func _gos() {
- go 1 /* ERROR "expected function/method call" */
- go _gos()
- var c chan int
- go close(c)
- go len(c) // TODO(gri) this should not be legal
-}
-
-func _defers() {
- defer 1 /* ERROR "expected function/method call" */
- defer _defers()
- var c chan int
- defer close(c)
- defer len(c) // TODO(gri) this should not be legal
-}
-
-func _switches() {
- var x int
-
- switch x {
- default:
- default /* ERROR "multiple defaults" */ :
- }
-
- switch {
- case 1 /* ERROR "cannot convert" */ :
- }
-
- switch int32(x) {
- case 1, 2:
- case x /* ERROR "cannot compare" */ :
- }
-
- switch x {
- case 1 /* ERROR "overflows int" */ << 100:
- }
-
- switch x {
- case 1:
- case 1 /* ERROR "duplicate case" */ :
- case 2, 3, 4:
- case 1 /* ERROR "duplicate case" */ :
- }
-
- // TODO(gri) duplicate 64bit values that don't fit into an int64 are not yet detected
- switch uint64(x) {
- case 1<<64-1:
- case 1<<64-1:
- }
-}
-
-type I interface {
- m()
-}
-
-type I2 interface {
- m(int)
-}
-
-type T struct{}
-type T1 struct{}
-type T2 struct{}
-
-func (T) m() {}
-func (T2) m(int) {}
-
-func _typeswitches() {
- var i int
- var x interface{}
-
- switch x.(type) {}
- switch (x /* ERROR "outside type switch" */ .(type)) {}
-
- switch x.(type) {
- default:
- default /* ERROR "multiple defaults" */ :
- }
-
- switch x := x.(type) {}
-
- switch x := x.(type) {
- case int:
- var y int = x
- }
-
- switch x := i /* ERROR "not an interface" */ .(type) {}
-
- switch t := x.(type) {
- case nil:
- var v bool = t /* ERROR "cannot assign" */
- case int:
- var v int = t
- case float32, complex64:
- var v float32 = t /* ERROR "cannot assign" */
- default:
- var v float32 = t /* ERROR "cannot assign" */
- }
-
- var t I
- switch t.(type) {
- case T:
- case T1 /* ERROR "missing method m" */ :
- case T2 /* ERROR "wrong type for method m" */ :
- case I2 /* ERROR "wrong type for method m" */ :
- }
-}
-
-func _rangeloops() {
- var (
- x int
- a [10]float32
- b []string
- p *[10]complex128
- pp **[10]complex128
- s string
- m map[int]bool
- c chan int
- sc chan<- int
- rc <-chan int
- )
-
- for _ = range x /* ERROR "cannot range over" */ {}
- for i := range x /* ERROR "cannot range over" */ {}
-
- for i := range a {
- var ii int
- ii = i
- }
- for i, x := range a {
- var ii int
- ii = i
- var xx float64
- xx = x /* ERROR "cannot assign" */
- }
- var ii int
- var xx float32
- for ii, xx := range a {}
-
- for i := range b {
- var ii int
- ii = i
- }
- for i, x := range b {
- var ii int
- ii = i
- var xx string
- xx = x
- }
-
- for i := range s {
- var ii int
- ii = i
- }
- for i, x := range s {
- var ii int
- ii = i
- var xx rune
- xx = x
- }
-
- for _, x := range p {
- var xx complex128
- xx = x
- }
-
- for _, x := range pp /* ERROR "cannot range over" */ {}
-
- for k := range m {
- var kk int32
- kk = k /* ERROR "cannot assign" */
- }
- for k, v := range m {
- var kk int
- kk = k
- if v {}
- }
-
- for _, _ /* ERROR "only one iteration variable" */ = range c {}
- for e := range c {
- var ee int
- ee = e
- }
- for _ = range sc /* ERROR "cannot range over send-only channel" */ {}
- for _ = range rc {}
-
- // constant strings
- const cs = "foo"
- for i, x := range cs {}
- for i, x := range "" {
- var ii int
- ii = i
- var xx rune
- xx = x
- }
-} \ No newline at end of file
diff --git a/libgo/go/hash/crc32/crc32.go b/libgo/go/hash/crc32/crc32.go
index a2a21a06f9..6a6b9473be 100644
--- a/libgo/go/hash/crc32/crc32.go
+++ b/libgo/go/hash/crc32/crc32.go
@@ -17,8 +17,8 @@ const Size = 4
// Predefined polynomials.
const (
- // Far and away the most common CRC-32 polynomial.
- // Used by ethernet (IEEE 802.3), v.42, fddi, gzip, zip, png, mpeg-2, ...
+ // IEEE is by far and away the most common CRC-32 polynomial.
+ // Used by ethernet (IEEE 802.3), v.42, fddi, gzip, zip, png, ...
IEEE = 0xedb88320
// Castagnoli's polynomial, used in iSCSI.
diff --git a/libgo/go/hash/crc32/crc32_amd64.go b/libgo/go/hash/crc32/crc32_amd64x.go
index b5bc6d3cf0..b7e359930a 100644
--- a/libgo/go/hash/crc32/crc32_amd64.go
+++ b/libgo/go/hash/crc32/crc32_amd64x.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 amd64 amd64p32
+
package crc32
// This file contains the code to call the SSE 4.2 version of the Castagnoli
diff --git a/libgo/go/hash/fnv/fnv.go b/libgo/go/hash/fnv/fnv.go
index b5ecd4a7c6..c0206613ac 100644
--- a/libgo/go/hash/fnv/fnv.go
+++ b/libgo/go/hash/fnv/fnv.go
@@ -4,7 +4,8 @@
// Package fnv implements FNV-1 and FNV-1a, non-cryptographic hash functions
// created by Glenn Fowler, Landon Curt Noll, and Phong Vo.
-// See http://isthe.com/chongo/tech/comp/fnv/.
+// See
+// http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function.
package fnv
import (
diff --git a/libgo/go/html/escape_test.go b/libgo/go/html/escape_test.go
index b405d4b4a7..2d7ad8ac26 100644
--- a/libgo/go/html/escape_test.go
+++ b/libgo/go/html/escape_test.go
@@ -64,6 +64,24 @@ var unescapeTests = []unescapeTest{
"Footnote&#x87;",
"Footnote‡",
},
+ // Handle single ampersand.
+ {
+ "copySingleAmpersand",
+ "&",
+ "&",
+ },
+ // Handle ampersand followed by non-entity.
+ {
+ "copyAmpersandNonEntity",
+ "text &test",
+ "text &test",
+ },
+ // Handle "&#".
+ {
+ "copyAmpersandHash",
+ "text &#",
+ "text &#",
+ },
}
func TestUnescape(t *testing.T) {
diff --git a/libgo/go/html/template/attr.go b/libgo/go/html/template/attr.go
index 3ea02880d4..d65d340073 100644
--- a/libgo/go/html/template/attr.go
+++ b/libgo/go/html/template/attr.go
@@ -90,7 +90,7 @@ var attrTypeMap = map[string]contentType{
"name": contentTypePlain,
"novalidate": contentTypeUnsafe,
// Skip handler names from
- // http://www.w3.org/TR/html5/Overview.html#event-handlers-on-elements-document-objects-and-window-objects
+ // http://www.w3.org/TR/html5/webappapis.html#event-handlers-on-elements,-document-objects,-and-window-objects
// since we have special handling in attrType.
"open": contentTypePlain,
"optimum": contentTypePlain,
@@ -160,7 +160,7 @@ func attrType(name string) contentType {
// Heuristics to prevent "javascript:..." injection in custom
// data attributes and custom attributes like g:tweetUrl.
- // http://www.w3.org/TR/html5/elements.html#embedding-custom-non-visible-data-with-the-data-attributes:
+ // http://www.w3.org/TR/html5/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes
// "Custom data attributes are intended to store custom data
// private to the page or application, for which there are no
// more appropriate attributes or elements."
diff --git a/libgo/go/html/template/content.go b/libgo/go/html/template/content.go
index 41b1116a66..3715ed5c93 100644
--- a/libgo/go/html/template/content.go
+++ b/libgo/go/html/template/content.go
@@ -16,7 +16,8 @@ type (
// 2. The CSS3 rule production, such as `a[href=~"https:"].foo#bar`.
// 3. CSS3 declaration productions, such as `color: red; margin: 2px`.
// 4. The CSS3 value production, such as `rgba(0, 0, 255, 127)`.
- // See http://www.w3.org/TR/css3-syntax/#style
+ // See http://www.w3.org/TR/css3-syntax/#parsing and
+ // https://web.archive.org/web/20090211114933/http://w3.org/TR/css3-syntax#style
CSS string
// HTML encapsulates a known safe HTML document fragment.
diff --git a/libgo/go/html/template/context.go b/libgo/go/html/template/context.go
index eb47e2be3c..59e794d686 100644
--- a/libgo/go/html/template/context.go
+++ b/libgo/go/html/template/context.go
@@ -13,7 +13,7 @@ import (
//
// The zero value of type context is the start context for a template that
// produces an HTML fragment as defined at
-// http://www.w3.org/TR/html5/the-end.html#parsing-html-fragments
+// http://www.w3.org/TR/html5/syntax.html#the-end
// where the context element is null.
type context struct {
state state
@@ -96,7 +96,7 @@ const (
// stateHTMLCmt occurs inside an <!-- HTML comment -->.
stateHTMLCmt
// stateRCDATA occurs inside an RCDATA element (<textarea> or <title>)
- // as described at http://dev.w3.org/html5/spec/syntax.html#elements-0
+ // as described at http://www.w3.org/TR/html5/syntax.html#elements-0
stateRCDATA
// stateAttr occurs inside an HTML attribute whose content is text.
stateAttr
diff --git a/libgo/go/html/template/error.go b/libgo/go/html/template/error.go
index 46e49ccf83..8f99e1b962 100644
--- a/libgo/go/html/template/error.go
+++ b/libgo/go/html/template/error.go
@@ -6,12 +6,16 @@ package template
import (
"fmt"
+ "text/template/parse"
)
// Error describes a problem encountered during template Escaping.
type Error struct {
// ErrorCode describes the kind of error.
ErrorCode ErrorCode
+ // Node is the node that caused the problem, if known.
+ // If not nil, it overrides Name and Line.
+ Node parse.Node
// Name is the name of the template in which the error was encountered.
Name string
// Line is the line number of the error in the template source or 0.
@@ -182,9 +186,13 @@ const (
)
func (e *Error) Error() string {
- if e.Line != 0 {
+ switch {
+ case e.Node != nil:
+ loc, _ := (*parse.Tree)(nil).ErrorContext(e.Node)
+ return fmt.Sprintf("html/template:%s: %s", loc, e.Description)
+ case e.Line != 0:
return fmt.Sprintf("html/template:%s:%d: %s", e.Name, e.Line, e.Description)
- } else if e.Name != "" {
+ case e.Name != "":
return fmt.Sprintf("html/template:%s: %s", e.Name, e.Description)
}
return "html/template: " + e.Description
@@ -192,6 +200,6 @@ func (e *Error) Error() string {
// errorf creates an error given a format string f and args.
// The template Name still needs to be supplied.
-func errorf(k ErrorCode, line int, f string, args ...interface{}) *Error {
- return &Error{k, "", line, fmt.Sprintf(f, args...)}
+func errorf(k ErrorCode, node parse.Node, line int, f string, args ...interface{}) *Error {
+ return &Error{k, node, "", line, fmt.Sprintf(f, args...)}
}
diff --git a/libgo/go/html/template/escape.go b/libgo/go/html/template/escape.go
index 9ae9749db0..ee01fb12ab 100644
--- a/libgo/go/html/template/escape.go
+++ b/libgo/go/html/template/escape.go
@@ -13,37 +13,34 @@ import (
"text/template/parse"
)
-// escapeTemplates rewrites the named templates, which must be
+// escapeTemplate rewrites the named template, which must be
// associated with t, to guarantee that the output of any of the named
-// templates is properly escaped. Names should include the names of
-// all templates that might be Executed but need not include helper
-// templates. If no error is returned, then the named templates have
+// templates is properly escaped. If no error is returned, then the named templates have
// been modified. Otherwise the named templates have been rendered
// unusable.
-func escapeTemplates(tmpl *Template, names ...string) error {
+func escapeTemplate(tmpl *Template, node parse.Node, name string) error {
e := newEscaper(tmpl)
- for _, name := range names {
- c, _ := e.escapeTree(context{}, name, 0)
- var err error
- if c.err != nil {
- err, c.err.Name = c.err, name
- } else if c.state != stateText {
- err = &Error{ErrEndContext, name, 0, fmt.Sprintf("ends in a non-text context: %v", c)}
+ c, _ := e.escapeTree(context{}, node, name, 0)
+ var err error
+ if c.err != nil {
+ err, c.err.Name = c.err, name
+ } else if c.state != stateText {
+ err = &Error{ErrEndContext, nil, name, 0, fmt.Sprintf("ends in a non-text context: %v", c)}
+ }
+ if err != nil {
+ // Prevent execution of unsafe templates.
+ if t := tmpl.set[name]; t != nil {
+ t.escapeErr = err
+ t.text.Tree = nil
+ t.Tree = nil
}
- if err != nil {
- // Prevent execution of unsafe templates.
- for _, name := range names {
- if t := tmpl.set[name]; t != nil {
- t.text.Tree = nil
- t.Tree = nil
- }
- }
- return err
- }
- tmpl.escaped = true
- tmpl.Tree = tmpl.text.Tree
+ return err
}
e.commit()
+ if t := tmpl.set[name]; t != nil {
+ t.escapeErr = escapeOK
+ t.Tree = t.text.Tree
+ }
return nil
}
@@ -164,7 +161,7 @@ func (e *escaper) escapeAction(c context, n *parse.ActionNode) context {
case urlPartUnknown:
return context{
state: stateError,
- err: errorf(ErrAmbigContext, n.Line, "%s appears in an ambiguous URL context", n),
+ err: errorf(ErrAmbigContext, n, n.Line, "%s appears in an ambiguous URL context", n),
}
default:
panic(c.urlPart.String())
@@ -207,6 +204,18 @@ func (e *escaper) escapeAction(c context, n *parse.ActionNode) context {
return c
}
+// allIdents returns the names of the identifiers under the Ident field of the node,
+// which might be a singleton (Identifier) or a slice (Field).
+func allIdents(node parse.Node) []string {
+ switch node := node.(type) {
+ case *parse.IdentifierNode:
+ return []string{node.Ident}
+ case *parse.FieldNode:
+ return node.Ident
+ }
+ panic("unidentified node type in allIdents")
+}
+
// ensurePipelineContains ensures that the pipeline has commands with
// the identifiers in s in order.
// If the pipeline already has some of the sanitizers, do not interfere.
@@ -229,27 +238,31 @@ func ensurePipelineContains(p *parse.PipeNode, s []string) {
idents = p.Cmds[i+1:]
}
dups := 0
- for _, id := range idents {
- if escFnsEq(s[dups], (id.Args[0].(*parse.IdentifierNode)).Ident) {
- dups++
- if dups == len(s) {
- return
+ for _, idNode := range idents {
+ for _, ident := range allIdents(idNode.Args[0]) {
+ if escFnsEq(s[dups], ident) {
+ dups++
+ if dups == len(s) {
+ return
+ }
}
}
}
newCmds := make([]*parse.CommandNode, n-len(idents), n+len(s)-dups)
copy(newCmds, p.Cmds)
// Merge existing identifier commands with the sanitizers needed.
- for _, id := range idents {
- pos := id.Args[0].Position()
- i := indexOfStr((id.Args[0].(*parse.IdentifierNode)).Ident, s, escFnsEq)
- if i != -1 {
- for _, name := range s[:i] {
- newCmds = appendCmd(newCmds, newIdentCmd(name, pos))
+ for _, idNode := range idents {
+ pos := idNode.Args[0].Position()
+ for _, ident := range allIdents(idNode.Args[0]) {
+ i := indexOfStr(ident, s, escFnsEq)
+ if i != -1 {
+ for _, name := range s[:i] {
+ newCmds = appendCmd(newCmds, newIdentCmd(name, pos))
+ }
+ s = s[i+1:]
}
- s = s[i+1:]
}
- newCmds = appendCmd(newCmds, id)
+ newCmds = appendCmd(newCmds, idNode)
}
// Create any remaining sanitizers.
for _, name := range s {
@@ -318,7 +331,7 @@ func escFnsEq(a, b string) bool {
func newIdentCmd(identifier string, pos parse.Pos) *parse.CommandNode {
return &parse.CommandNode{
NodeType: parse.NodeCommand,
- Args: []parse.Node{parse.NewIdentifier(identifier).SetPos(pos)},
+ Args: []parse.Node{parse.NewIdentifier(identifier).SetTree(nil).SetPos(pos)}, // TODO: SetTree.
}
}
@@ -352,7 +365,7 @@ func nudge(c context) context {
// join joins the two contexts of a branch template node. The result is an
// error context if either of the input contexts are error contexts, or if the
// the input contexts differ.
-func join(a, b context, line int, nodeName string) context {
+func join(a, b context, node parse.Node, nodeName string) context {
if a.state == stateError {
return a
}
@@ -385,14 +398,14 @@ func join(a, b context, line int, nodeName string) context {
// ends in an unquoted value state even though the else branch
// ends in stateBeforeValue.
if c, d := nudge(a), nudge(b); !(c.eq(a) && d.eq(b)) {
- if e := join(c, d, line, nodeName); e.state != stateError {
+ if e := join(c, d, node, nodeName); e.state != stateError {
return e
}
}
return context{
state: stateError,
- err: errorf(ErrBranchEnd, line, "{{%s}} branches end in different contexts: %v, %v", nodeName, a, b),
+ err: errorf(ErrBranchEnd, node, 0, "{{%s}} branches end in different contexts: %v, %v", nodeName, a, b),
}
}
@@ -404,7 +417,7 @@ func (e *escaper) escapeBranch(c context, n *parse.BranchNode, nodeName string)
// We check that executing n.List once results in the same context
// as executing n.List twice.
c1, _ := e.escapeListConditionally(c0, n.List, nil)
- c0 = join(c0, c1, n.Line, nodeName)
+ c0 = join(c0, c1, n, nodeName)
if c0.state == stateError {
// Make clear that this is a problem on loop re-entry
// since developers tend to overlook that branch when
@@ -415,7 +428,7 @@ func (e *escaper) escapeBranch(c context, n *parse.BranchNode, nodeName string)
}
}
c1 := e.escapeList(c, n.ElseList)
- return join(c0, c1, n.Line, nodeName)
+ return join(c0, c1, n, nodeName)
}
// escapeList escapes a list template node.
@@ -467,7 +480,7 @@ func (e *escaper) escapeListConditionally(c context, n *parse.ListNode, filter f
// escapeTemplate escapes a {{template}} call node.
func (e *escaper) escapeTemplate(c context, n *parse.TemplateNode) context {
- c, name := e.escapeTree(c, n.Name, n.Line)
+ c, name := e.escapeTree(c, n, n.Name, n.Line)
if name != n.Name {
e.editTemplateNode(n, name)
}
@@ -476,7 +489,7 @@ func (e *escaper) escapeTemplate(c context, n *parse.TemplateNode) context {
// escapeTree escapes the named template starting in the given context as
// necessary and returns its output context.
-func (e *escaper) escapeTree(c context, name string, line int) (context, string) {
+func (e *escaper) escapeTree(c context, node parse.Node, name string, line int) (context, string) {
// Mangle the template name with the input context to produce a reliable
// identifier.
dname := c.mangle(name)
@@ -492,12 +505,12 @@ func (e *escaper) escapeTree(c context, name string, line int) (context, string)
if e.tmpl.set[name] != nil {
return context{
state: stateError,
- err: errorf(ErrNoSuchTemplate, line, "%q is an incomplete or empty template", name),
+ err: errorf(ErrNoSuchTemplate, node, line, "%q is an incomplete or empty template", name),
}, dname
}
return context{
state: stateError,
- err: errorf(ErrNoSuchTemplate, line, "no such template %q", name),
+ err: errorf(ErrNoSuchTemplate, node, line, "no such template %q", name),
}, dname
}
if dname != name {
@@ -529,8 +542,7 @@ func (e *escaper) computeOutCtx(c context, t *template.Template) context {
if !ok && c1.state != stateError {
return context{
state: stateError,
- // TODO: Find the first node with a line in t.text.Tree.Root
- err: errorf(ErrOutputContext, 0, "cannot compute output context for template %s", t.Name()),
+ err: errorf(ErrOutputContext, t.Tree.Root, 0, "cannot compute output context for template %s", t.Name()),
}
}
return c1
@@ -664,7 +676,7 @@ func contextAfterText(c context, s []byte) (context, int) {
i = len(s)
}
if c.delim == delimSpaceOrTagEnd {
- // http://www.w3.org/TR/html5/tokenization.html#attribute-value-unquoted-state
+ // http://www.w3.org/TR/html5/syntax.html#attribute-value-(unquoted)-state
// lists the runes below as error characters.
// Error out because HTML parsers may differ on whether
// "<a id= onclick=f(" ends inside id's or onclick's value,
@@ -674,7 +686,7 @@ func contextAfterText(c context, s []byte) (context, int) {
if j := bytes.IndexAny(s[:i], "\"'<=`"); j >= 0 {
return context{
state: stateError,
- err: errorf(ErrBadHTML, 0, "%q in unquoted attr: %q", s[j:j+1], s[:i]),
+ err: errorf(ErrBadHTML, nil, 0, "%q in unquoted attr: %q", s[j:j+1], s[:i]),
}, len(s)
}
}
diff --git a/libgo/go/html/template/escape_test.go b/libgo/go/html/template/escape_test.go
index 58383a6cd4..ef7b877484 100644
--- a/libgo/go/html/template/escape_test.go
+++ b/libgo/go/html/template/escape_test.go
@@ -861,29 +861,29 @@ func TestErrors(t *testing.T) {
// Error cases.
{
"{{if .Cond}}<a{{end}}",
- "z:1: {{if}} branches",
+ "z:1:5: {{if}} branches",
},
{
"{{if .Cond}}\n{{else}}\n<a{{end}}",
- "z:1: {{if}} branches",
+ "z:1:5: {{if}} branches",
},
{
// Missing quote in the else branch.
`{{if .Cond}}<a href="foo">{{else}}<a href="bar>{{end}}`,
- "z:1: {{if}} branches",
+ "z:1:5: {{if}} branches",
},
{
// Different kind of attribute: href implies a URL.
"<a {{if .Cond}}href='{{else}}title='{{end}}{{.X}}'>",
- "z:1: {{if}} branches",
+ "z:1:8: {{if}} branches",
},
{
"\n{{with .X}}<a{{end}}",
- "z:2: {{with}} branches",
+ "z:2:7: {{with}} branches",
},
{
"\n{{with .X}}<a>{{else}}<a{{end}}",
- "z:2: {{with}} branches",
+ "z:2:7: {{with}} branches",
},
{
"{{range .Items}}<a{{end}}",
@@ -891,7 +891,7 @@ func TestErrors(t *testing.T) {
},
{
"\n{{range .Items}} x='<a{{end}}",
- "z:2: on range loop re-entry: {{range}} branches",
+ "z:2:8: on range loop re-entry: {{range}} branches",
},
{
"<a b=1 c={{.H}}",
@@ -903,7 +903,7 @@ func TestErrors(t *testing.T) {
},
{
`<a href="{{if .F}}/foo?a={{else}}/bar/{{end}}{{.H}}">`,
- "z:1: {{.H}} appears in an ambiguous URL context",
+ "z:1:47: {{.H}} appears in an ambiguous URL context",
},
{
`<a onclick="alert('Hello \`,
@@ -932,7 +932,7 @@ func TestErrors(t *testing.T) {
},
{
`{{template "foo"}}`,
- "z:1: no such template \"foo\"",
+ "z:1:11: no such template \"foo\"",
},
{
`<div{{template "y"}}>` +
@@ -994,6 +994,11 @@ func TestErrors(t *testing.T) {
t.Errorf("input=%q: error\n\t%q\ndoes not contain expected string\n\t%q", test.input, got, test.err)
continue
}
+ // Check that we get the same error if we call Execute again.
+ if err := tmpl.Execute(buf, nil); err == nil || err.Error() != got {
+ t.Errorf("input=%q: unexpected error on second call %q", test.input, err)
+
+ }
}
}
@@ -1649,6 +1654,38 @@ func TestEmptyTemplate(t *testing.T) {
}
}
+type Issue7379 int
+
+func (Issue7379) SomeMethod(x int) string {
+ return fmt.Sprintf("<%d>", x)
+}
+
+// This is a test for issue 7379: type assertion error caused panic, and then
+// the code to handle the panic breaks escaping. It's hard to see the second
+// problem once the first is fixed, but its fix is trivial so we let that go. See
+// the discussion for issue 7379.
+func TestPipeToMethodIsEscaped(t *testing.T) {
+ tmpl := Must(New("x").Parse("<html>{{0 | .SomeMethod}}</html>\n"))
+ tryExec := func() string {
+ defer func() {
+ panicValue := recover()
+ if panicValue != nil {
+ t.Errorf("panicked: %v\n", panicValue)
+ }
+ }()
+ var b bytes.Buffer
+ tmpl.Execute(&b, Issue7379(0))
+ return b.String()
+ }
+ for i := 0; i < 3; i++ {
+ str := tryExec()
+ const expect = "<html>&lt;0&gt;</html>\n"
+ if str != expect {
+ t.Errorf("expected %q got %q", expect, str)
+ }
+ }
+}
+
func BenchmarkEscapedExecute(b *testing.B) {
tmpl := Must(New("t").Parse(`<a onclick="alert('{{.}}')">{{.}}</a>`))
var buf bytes.Buffer
diff --git a/libgo/go/html/template/html.go b/libgo/go/html/template/html.go
index f25f1074c7..9c069efd1d 100644
--- a/libgo/go/html/template/html.go
+++ b/libgo/go/html/template/html.go
@@ -50,12 +50,12 @@ func htmlEscaper(args ...interface{}) string {
// htmlReplacementTable contains the runes that need to be escaped
// inside a quoted attribute value or in a text node.
var htmlReplacementTable = []string{
- // http://www.w3.org/TR/html5/tokenization.html#attribute-value-unquoted-state: "
+ // http://www.w3.org/TR/html5/syntax.html#attribute-value-(unquoted)-state
// U+0000 NULL Parse error. Append a U+FFFD REPLACEMENT
// CHARACTER character to the current attribute's value.
// "
// and similarly
- // http://www.w3.org/TR/html5/tokenization.html#before-attribute-value-state
+ // http://www.w3.org/TR/html5/syntax.html#before-attribute-value-state
0: "\uFFFD",
'"': "&#34;",
'&': "&amp;",
diff --git a/libgo/go/html/template/js.go b/libgo/go/html/template/js.go
index d594e0ad71..999a61ed07 100644
--- a/libgo/go/html/template/js.go
+++ b/libgo/go/html/template/js.go
@@ -99,7 +99,7 @@ func nextJSCtx(s []byte, preceding jsCtx) jsCtx {
return jsCtxDivOp
}
-// regexPrecederKeywords is a set of reserved JS keywords that can precede a
+// regexpPrecederKeywords is a set of reserved JS keywords that can precede a
// regular expression in JS source.
var regexpPrecederKeywords = map[string]bool{
"break": true,
diff --git a/libgo/go/html/template/js_test.go b/libgo/go/html/template/js_test.go
index 311e1d2c4e..7af7997de9 100644
--- a/libgo/go/html/template/js_test.go
+++ b/libgo/go/html/template/js_test.go
@@ -138,7 +138,7 @@ func TestJSValEscaper(t *testing.T) {
// Newlines.
{"\r\n\u2028\u2029", `"\r\n\u2028\u2029"`},
// "\v" == "v" on IE 6 so use "\x0b" instead.
- {"\t\x0b", `"\u0009\u000b"`},
+ {"\t\x0b", `"\t\u000b"`},
{struct{ X, Y int }{1, 2}, `{"X":1,"Y":2}`},
{[]interface{}{}, "[]"},
{[]interface{}{42, "foo", nil}, `[42,"foo",null]`},
diff --git a/libgo/go/html/template/template.go b/libgo/go/html/template/template.go
index 11cc34a50a..ce6170105c 100644
--- a/libgo/go/html/template/template.go
+++ b/libgo/go/html/template/template.go
@@ -17,7 +17,8 @@ import (
// Template is a specialized Template from "text/template" that produces a safe
// HTML document fragment.
type Template struct {
- escaped bool
+ // Sticky error if escaping fails.
+ escapeErr error
// We could embed the text/template field, but it's safer not to because
// we need to keep our version of the name space and the underlying
// template's in sync.
@@ -27,6 +28,9 @@ type Template struct {
*nameSpace // common to all associated templates
}
+// escapeOK is a sentinel value used to indicate valid escaping.
+var escapeOK = fmt.Errorf("template escaped correctly")
+
// nameSpace is the data structure shared by all templates in an association.
type nameSpace struct {
mu sync.Mutex
@@ -51,17 +55,22 @@ func (t *Template) Templates() []*Template {
func (t *Template) escape() error {
t.nameSpace.mu.Lock()
defer t.nameSpace.mu.Unlock()
- if !t.escaped {
- if err := escapeTemplates(t, t.Name()); err != nil {
+ if t.escapeErr == nil {
+ if err := escapeTemplate(t, t.text.Root, t.Name()); err != nil {
return err
}
- t.escaped = true
+ } else if t.escapeErr != escapeOK {
+ return t.escapeErr
}
return nil
}
// Execute applies a parsed template to the specified data object,
// writing the output to wr.
+// If an error occurs executing the template or writing its output,
+// execution stops, but partial results may already have been written to
+// the output writer.
+// A template may be executed safely in parallel.
func (t *Template) Execute(wr io.Writer, data interface{}) error {
if err := t.escape(); err != nil {
return err
@@ -71,6 +80,10 @@ func (t *Template) Execute(wr io.Writer, data interface{}) error {
// ExecuteTemplate applies the template associated with t that has the given
// name to the specified data object and writes the output to wr.
+// If an error occurs executing the template or writing its output,
+// execution stops, but partial results may already have been written to
+// the output writer.
+// A template may be executed safely in parallel.
func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error {
tmpl, err := t.lookupAndEscapeTemplate(name)
if err != nil {
@@ -89,14 +102,17 @@ func (t *Template) lookupAndEscapeTemplate(name string) (tmpl *Template, err err
if tmpl == nil {
return nil, fmt.Errorf("html/template: %q is undefined", name)
}
+ if tmpl.escapeErr != nil && tmpl.escapeErr != escapeOK {
+ return nil, tmpl.escapeErr
+ }
if tmpl.text.Tree == nil || tmpl.text.Root == nil {
return nil, fmt.Errorf("html/template: %q is an incomplete template", name)
}
if t.text.Lookup(name) == nil {
panic("html/template internal error: template escaping out of sync")
}
- if tmpl != nil && !tmpl.escaped {
- err = escapeTemplates(tmpl, name)
+ if tmpl.escapeErr == nil {
+ err = escapeTemplate(tmpl, tmpl.text.Root, name)
}
return tmpl, err
}
@@ -111,7 +127,7 @@ func (t *Template) lookupAndEscapeTemplate(name string) (tmpl *Template, err err
// other than space, comments, and template definitions.)
func (t *Template) Parse(src string) (*Template, error) {
t.nameSpace.mu.Lock()
- t.escaped = false
+ t.escapeErr = nil
t.nameSpace.mu.Unlock()
ret, err := t.text.Parse(src)
if err != nil {
@@ -129,7 +145,7 @@ func (t *Template) Parse(src string) (*Template, error) {
tmpl = t.new(name)
}
// Restore our record of this text/template to its unescaped original state.
- tmpl.escaped = false
+ tmpl.escapeErr = nil
tmpl.text = v
tmpl.Tree = v.Tree
}
@@ -143,7 +159,7 @@ func (t *Template) Parse(src string) (*Template, error) {
func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) {
t.nameSpace.mu.Lock()
defer t.nameSpace.mu.Unlock()
- if t.escaped {
+ if t.escapeErr != nil {
return nil, fmt.Errorf("html/template: cannot AddParseTree to %q after it has executed", t.Name())
}
text, err := t.text.AddParseTree(name, tree)
@@ -151,7 +167,7 @@ func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error
return nil, err
}
ret := &Template{
- false,
+ nil,
text,
text.Tree,
t.nameSpace,
@@ -171,7 +187,7 @@ func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error
func (t *Template) Clone() (*Template, error) {
t.nameSpace.mu.Lock()
defer t.nameSpace.mu.Unlock()
- if t.escaped {
+ if t.escapeErr != nil {
return nil, fmt.Errorf("html/template: cannot Clone %q after it has executed", t.Name())
}
textClone, err := t.text.Clone()
@@ -179,7 +195,7 @@ func (t *Template) Clone() (*Template, error) {
return nil, err
}
ret := &Template{
- false,
+ nil,
textClone,
textClone.Tree,
&nameSpace{
@@ -189,12 +205,12 @@ func (t *Template) Clone() (*Template, error) {
for _, x := range textClone.Templates() {
name := x.Name()
src := t.set[name]
- if src == nil || src.escaped {
+ if src == nil || src.escapeErr != nil {
return nil, fmt.Errorf("html/template: cannot Clone %q after it has executed", t.Name())
}
x.Tree = x.Tree.Copy()
ret.set[name] = &Template{
- false,
+ nil,
x,
x.Tree,
ret.nameSpace,
@@ -206,7 +222,7 @@ func (t *Template) Clone() (*Template, error) {
// New allocates a new HTML template with the given name.
func New(name string) *Template {
tmpl := &Template{
- false,
+ nil,
template.New(name),
nil,
&nameSpace{
@@ -229,7 +245,7 @@ func (t *Template) New(name string) *Template {
// new is the implementation of New, without the lock.
func (t *Template) new(name string) *Template {
tmpl := &Template{
- false,
+ nil,
t.text.New(name),
nil,
t.nameSpace,
diff --git a/libgo/go/html/template/transition.go b/libgo/go/html/template/transition.go
index 7f30a7ab8d..b486fcd285 100644
--- a/libgo/go/html/template/transition.go
+++ b/libgo/go/html/template/transition.go
@@ -102,7 +102,7 @@ func tTag(c context, s []byte) (context, int) {
if i == j {
return context{
state: stateError,
- err: errorf(ErrBadHTML, 0, "expected space, attr name, or end of tag, but got %q", s[i:]),
+ err: errorf(ErrBadHTML, nil, 0, "expected space, attr name, or end of tag, but got %q", s[i:]),
}, len(s)
}
switch attrType(string(s[i:j])) {
@@ -245,7 +245,7 @@ func tJS(c context, s []byte) (context, int) {
default:
return context{
state: stateError,
- err: errorf(ErrSlashAmbig, 0, "'/' could start a division or regexp: %.32q", s[i:]),
+ err: errorf(ErrSlashAmbig, nil, 0, "'/' could start a division or regexp: %.32q", s[i:]),
}, len(s)
}
default:
@@ -277,7 +277,7 @@ func tJSDelimited(c context, s []byte) (context, int) {
if i == len(s) {
return context{
state: stateError,
- err: errorf(ErrPartialEscape, 0, "unfinished escape sequence in JS string: %q", s),
+ err: errorf(ErrPartialEscape, nil, 0, "unfinished escape sequence in JS string: %q", s),
}, len(s)
}
case '[':
@@ -299,7 +299,7 @@ func tJSDelimited(c context, s []byte) (context, int) {
// into charsets is desired.
return context{
state: stateError,
- err: errorf(ErrPartialCharset, 0, "unfinished JS regexp charset: %q", s),
+ err: errorf(ErrPartialCharset, nil, 0, "unfinished JS regexp charset: %q", s),
}, len(s)
}
@@ -459,7 +459,7 @@ func tCSSStr(c context, s []byte) (context, int) {
if i == len(s) {
return context{
state: stateError,
- err: errorf(ErrPartialEscape, 0, "unfinished escape sequence in CSS string: %q", s),
+ err: errorf(ErrPartialEscape, nil, 0, "unfinished escape sequence in CSS string: %q", s),
}, len(s)
}
} else {
@@ -489,7 +489,7 @@ func eatAttrName(s []byte, i int) (int, *Error) {
// These result in a parse warning in HTML5 and are
// indicative of serious problems if seen in an attr
// name in a template.
- return -1, errorf(ErrBadHTML, 0, "%q in attribute name: %.32q", s[j:j+1], s)
+ return -1, errorf(ErrBadHTML, nil, 0, "%q in attribute name: %.32q", s[j:j+1], s)
default:
// No-op.
}
diff --git a/libgo/go/image/color/palette/gen.go b/libgo/go/image/color/palette/gen.go
index f20c021de1..2b5fdaaf2b 100644
--- a/libgo/go/image/color/palette/gen.go
+++ b/libgo/go/image/color/palette/gen.go
@@ -7,25 +7,49 @@
package main
// This program generates palette.go. Invoke it as
-// go run gen.go | gofmt > palette.go
+// go run gen.go -output palette.go
import (
+ "bytes"
+ "flag"
"fmt"
+ "go/format"
+ "io"
+ "io/ioutil"
+ "log"
)
+var filename = flag.String("output", "palette.go", "output file name")
+
func main() {
- fmt.Println("// generated by go run gen.go; DO NOT EDIT")
- fmt.Println()
- fmt.Println("// Package palette provides standard color palettes.")
- fmt.Println("package palette")
- fmt.Println()
- fmt.Println(`import "image/color"`)
- fmt.Println()
- printPlan9()
- printWebSafe()
+ flag.Parse()
+
+ var buf bytes.Buffer
+
+ fmt.Fprintln(&buf, `// 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.`)
+ fmt.Fprintln(&buf)
+ fmt.Fprintln(&buf, "// generated by go run gen.go -output palette.go; DO NOT EDIT")
+ fmt.Fprintln(&buf)
+ fmt.Fprintln(&buf, "package palette")
+ fmt.Fprintln(&buf)
+ fmt.Fprintln(&buf, `import "image/color"`)
+ fmt.Fprintln(&buf)
+ printPlan9(&buf)
+ printWebSafe(&buf)
+
+ data, err := format.Source(buf.Bytes())
+ if err != nil {
+ log.Fatal(err)
+ }
+ err = ioutil.WriteFile(*filename, data, 0644)
+ if err != nil {
+ log.Fatal(err)
+ }
}
-func printPlan9() {
+func printPlan9(w io.Writer) {
c, lines := [3]int{}, [256]string{}
for r, i := 0, 0; r != 4; r++ {
for v := 0; v != 4; v, i = v+1, i+16 {
@@ -54,27 +78,27 @@ func printPlan9() {
}
}
}
- fmt.Println("// Plan9 is a 256-color palette that partitions the 24-bit RGB space")
- fmt.Println("// into 4×4×4 subdivision, with 4 shades in each subcube. Compared to the")
- fmt.Println("// WebSafe, the idea is to reduce the color resolution by dicing the")
- fmt.Println("// color cube into fewer cells, and to use the extra space to increase the")
- fmt.Println("// intensity resolution. This results in 16 gray shades (4 gray subcubes with")
- fmt.Println("// 4 samples in each), 13 shades of each primary and secondary color (3")
- fmt.Println("// subcubes with 4 samples plus black) and a reasonable selection of colors")
- fmt.Println("// covering the rest of the color cube. The advantage is better representation")
- fmt.Println("// of continuous tones.")
- fmt.Println("//")
- fmt.Println("// This palette was used in the Plan 9 Operating System, described at")
- fmt.Println("// http://plan9.bell-labs.com/magic/man2html/6/color")
- fmt.Println("var Plan9 = []color.Color{")
+ fmt.Fprintln(w, "// Plan9 is a 256-color palette that partitions the 24-bit RGB space")
+ fmt.Fprintln(w, "// into 4×4×4 subdivision, with 4 shades in each subcube. Compared to the")
+ fmt.Fprintln(w, "// WebSafe, the idea is to reduce the color resolution by dicing the")
+ fmt.Fprintln(w, "// color cube into fewer cells, and to use the extra space to increase the")
+ fmt.Fprintln(w, "// intensity resolution. This results in 16 gray shades (4 gray subcubes with")
+ fmt.Fprintln(w, "// 4 samples in each), 13 shades of each primary and secondary color (3")
+ fmt.Fprintln(w, "// subcubes with 4 samples plus black) and a reasonable selection of colors")
+ fmt.Fprintln(w, "// covering the rest of the color cube. The advantage is better representation")
+ fmt.Fprintln(w, "// of continuous tones.")
+ fmt.Fprintln(w, "//")
+ fmt.Fprintln(w, "// This palette was used in the Plan 9 Operating System, described at")
+ fmt.Fprintln(w, "// http://plan9.bell-labs.com/magic/man2html/6/color")
+ fmt.Fprintln(w, "var Plan9 = []color.Color{")
for _, line := range lines {
- fmt.Println(line)
+ fmt.Fprintln(w, line)
}
- fmt.Println("}")
- fmt.Println()
+ fmt.Fprintln(w, "}")
+ fmt.Fprintln(w)
}
-func printWebSafe() {
+func printWebSafe(w io.Writer) {
lines := [6 * 6 * 6]string{}
for r := 0; r < 6; r++ {
for g := 0; g < 6; g++ {
@@ -84,14 +108,14 @@ func printWebSafe() {
}
}
}
- fmt.Println("// WebSafe is a 216-color palette that was popularized by early versions")
- fmt.Println("// of Netscape Navigator. It is also known as the Netscape Color Cube.")
- fmt.Println("//")
- fmt.Println("// See http://en.wikipedia.org/wiki/Web_colors#Web-safe_colors for details.")
- fmt.Println("var WebSafe = []color.Color{")
+ fmt.Fprintln(w, "// WebSafe is a 216-color palette that was popularized by early versions")
+ fmt.Fprintln(w, "// of Netscape Navigator. It is also known as the Netscape Color Cube.")
+ fmt.Fprintln(w, "//")
+ fmt.Fprintln(w, "// See http://en.wikipedia.org/wiki/Web_colors#Web-safe_colors for details.")
+ fmt.Fprintln(w, "var WebSafe = []color.Color{")
for _, line := range lines {
- fmt.Println(line)
+ fmt.Fprintln(w, line)
}
- fmt.Println("}")
- fmt.Println()
+ fmt.Fprintln(w, "}")
+ fmt.Fprintln(w)
}
diff --git a/libgo/go/image/color/palette/generate.go b/libgo/go/image/color/palette/generate.go
new file mode 100644
index 0000000000..64c2ec0d9a
--- /dev/null
+++ b/libgo/go/image/color/palette/generate.go
@@ -0,0 +1,8 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:generate go run gen.go -output palette.go
+
+// Package palette provides standard color palettes.
+package palette
diff --git a/libgo/go/image/color/palette/palette.go b/libgo/go/image/color/palette/palette.go
index 3aba7401d1..0bf2c8e1aa 100644
--- a/libgo/go/image/color/palette/palette.go
+++ b/libgo/go/image/color/palette/palette.go
@@ -1,6 +1,9 @@
-// generated by go run gen.go; DO NOT EDIT
+// 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.
+
+// generated by go run gen.go -output palette.go; DO NOT EDIT
-// Package palette provides standard color palettes.
package palette
import "image/color"
diff --git a/libgo/go/image/gif/reader.go b/libgo/go/image/gif/reader.go
index 8b0298a29f..5a863e204f 100644
--- a/libgo/go/image/gif/reader.go
+++ b/libgo/go/image/gif/reader.go
@@ -79,7 +79,8 @@ type decoder struct {
imageFields byte
// From graphics control.
- transparentIndex byte
+ transparentIndex byte
+ hasTransparentIndex bool
// Computed.
pixelSize uint
@@ -170,16 +171,22 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
if err != nil {
return err
}
- if d.imageFields&fColorMapFollows != 0 {
+ useLocalColorMap := d.imageFields&fColorMapFollows != 0
+ if useLocalColorMap {
m.Palette, err = d.readColorMap()
if err != nil {
return err
}
- // TODO: do we set transparency in this map too? That would be
- // d.setTransparency(m.Palette)
} else {
m.Palette = d.globalColorMap
}
+ if d.hasTransparentIndex && int(d.transparentIndex) < len(m.Palette) {
+ if !useLocalColorMap {
+ // Clone the global color map.
+ m.Palette = append(color.Palette(nil), d.globalColorMap...)
+ }
+ m.Palette[d.transparentIndex] = color.RGBA{}
+ }
litWidth, err := d.r.ReadByte()
if err != nil {
return err
@@ -228,7 +235,11 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
d.image = append(d.image, m)
d.delay = append(d.delay, d.delayTime)
- d.delayTime = 0 // TODO: is this correct, or should we hold on to the value?
+ // 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.
+ d.delayTime = 0
+ d.hasTransparentIndex = false
case sTrailer:
if len(d.image) == 0 {
@@ -339,17 +350,11 @@ func (d *decoder) readGraphicControl() error {
d.delayTime = int(d.tmp[2]) | int(d.tmp[3])<<8
if d.flags&gcTransparentColorSet != 0 {
d.transparentIndex = d.tmp[4]
- d.setTransparency(d.globalColorMap)
+ d.hasTransparentIndex = true
}
return nil
}
-func (d *decoder) setTransparency(colorMap color.Palette) {
- if int(d.transparentIndex) < len(colorMap) {
- colorMap[d.transparentIndex] = color.RGBA{}
- }
-}
-
func (d *decoder) newImageFromDescriptor() (*image.Paletted, error) {
if _, err := io.ReadFull(d.r, d.tmp[0:9]); err != nil {
return nil, fmt.Errorf("gif: can't read image descriptor: %s", err)
diff --git a/libgo/go/image/gif/reader_test.go b/libgo/go/image/gif/reader_test.go
index 09867132d3..7b6f504367 100644
--- a/libgo/go/image/gif/reader_test.go
+++ b/libgo/go/image/gif/reader_test.go
@@ -1,3 +1,7 @@
+// 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 gif
import (
@@ -18,16 +22,16 @@ const (
trailerStr = "\x3b"
)
-func TestDecode(t *testing.T) {
- // lzwEncode returns an LZW encoding (with 2-bit literals) of n zeroes.
- lzwEncode := func(n int) []byte {
- b := &bytes.Buffer{}
- w := lzw.NewWriter(b, lzw.LSB, 2)
- w.Write(make([]byte, n))
- w.Close()
- return b.Bytes()
- }
+// lzwEncode returns an LZW encoding (with 2-bit literals) of n zeroes.
+func lzwEncode(n int) []byte {
+ b := &bytes.Buffer{}
+ w := lzw.NewWriter(b, lzw.LSB, 2)
+ w.Write(make([]byte, n))
+ w.Close()
+ return b.Bytes()
+}
+func TestDecode(t *testing.T) {
testCases := []struct {
nPix int // The number of pixels in the image data.
extra bool // Whether to write an extra block after the LZW-encoded data.
@@ -86,6 +90,52 @@ func TestDecode(t *testing.T) {
}
}
+func TestTransparentIndex(t *testing.T) {
+ b := &bytes.Buffer{}
+ b.WriteString(headerStr)
+ b.WriteString(paletteStr)
+ for transparentIndex := 0; transparentIndex < 3; transparentIndex++ {
+ if transparentIndex < 2 {
+ // Write the graphic control for the transparent index.
+ b.WriteString("\x21\xf9\x00\x01\x00\x00")
+ b.WriteByte(byte(transparentIndex))
+ b.WriteByte(0)
+ }
+ // Write an image with bounds 2x1, as per TestDecode.
+ b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
+ enc := lzwEncode(2)
+ if len(enc) > 0xff {
+ t.Fatalf("compressed length %d is too large", len(enc))
+ }
+ b.WriteByte(byte(len(enc)))
+ b.Write(enc)
+ b.WriteByte(0x00)
+ }
+ b.WriteString(trailerStr)
+
+ g, err := DecodeAll(b)
+ if err != nil {
+ t.Fatalf("DecodeAll: %v", err)
+ }
+ c0 := color.RGBA{paletteStr[0], paletteStr[1], paletteStr[2], 0xff}
+ c1 := color.RGBA{paletteStr[3], paletteStr[4], paletteStr[5], 0xff}
+ cz := color.RGBA{}
+ wants := []color.Palette{
+ {cz, c1},
+ {c0, cz},
+ {c0, c1},
+ }
+ if len(g.Image) != len(wants) {
+ t.Fatalf("got %d images, want %d", len(g.Image), len(wants))
+ }
+ for i, want := range wants {
+ got := g.Image[i].Palette
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("palette #%d:\ngot %v\nwant %v", i, got, want)
+ }
+ }
+}
+
// testGIF is a simple GIF that we can modify to test different scenarios.
var testGIF = []byte{
'G', 'I', 'F', '8', '9', 'a',
diff --git a/libgo/go/image/gif/writer.go b/libgo/go/image/gif/writer.go
index 15cd40fadf..49abde704c 100644
--- a/libgo/go/image/gif/writer.go
+++ b/libgo/go/image/gif/writer.go
@@ -233,10 +233,20 @@ func (e *encoder) writeImageBlock(pm *image.Paletted, delay int) {
e.writeByte(uint8(litWidth)) // LZW Minimum Code Size.
lzww := lzw.NewWriter(blockWriter{e: e}, lzw.LSB, litWidth)
- _, e.err = lzww.Write(pm.Pix)
- if e.err != nil {
- lzww.Close()
- return
+ if dx := b.Dx(); dx == pm.Stride {
+ _, e.err = lzww.Write(pm.Pix)
+ if e.err != nil {
+ lzww.Close()
+ return
+ }
+ } else {
+ for i, y := 0, b.Min.Y; y < b.Max.Y; i, y = i+pm.Stride, y+1 {
+ _, e.err = lzww.Write(pm.Pix[i : i+dx])
+ if e.err != nil {
+ lzww.Close()
+ return
+ }
+ }
}
lzww.Close()
e.writeByte(0x00) // Block Terminator.
diff --git a/libgo/go/image/gif/writer_test.go b/libgo/go/image/gif/writer_test.go
index c1ada769c2..93306ffdb3 100644
--- a/libgo/go/image/gif/writer_test.go
+++ b/libgo/go/image/gif/writer_test.go
@@ -102,6 +102,29 @@ func TestWriter(t *testing.T) {
}
}
+func TestSubImage(t *testing.T) {
+ m0, err := readImg("../testdata/video-001.gif")
+ if err != nil {
+ t.Fatalf("readImg: %v", err)
+ }
+ m0 = m0.(*image.Paletted).SubImage(image.Rect(0, 0, 50, 30))
+ var buf bytes.Buffer
+ err = Encode(&buf, m0, nil)
+ if err != nil {
+ t.Fatalf("Encode: %v", err)
+ }
+ m1, err := Decode(&buf)
+ if err != nil {
+ t.Fatalf("Decode: %v", err)
+ }
+ if m0.Bounds() != m1.Bounds() {
+ t.Fatalf("bounds differ: %v and %v", m0.Bounds(), m1.Bounds())
+ }
+ if averageDelta(m0, m1) != 0 {
+ t.Fatalf("images differ")
+ }
+}
+
var frames = []string{
"../testdata/video-001.gif",
"../testdata/video-005.gray.gif",
@@ -116,7 +139,7 @@ func TestEncodeAll(t *testing.T) {
for i, f := range frames {
m, err := readGIF(f)
if err != nil {
- t.Error(f, err)
+ t.Fatal(f, err)
}
g0.Image[i] = m.Image[0]
}
diff --git a/libgo/go/image/image.go b/libgo/go/image/image.go
index 32a89ef34c..6b8e5c4877 100644
--- a/libgo/go/image/image.go
+++ b/libgo/go/image/image.go
@@ -72,6 +72,10 @@ func (p *RGBA) ColorModel() color.Model { return color.RGBAModel }
func (p *RGBA) Bounds() Rectangle { return p.Rect }
func (p *RGBA) At(x, y int) color.Color {
+ return p.RGBAAt(x, y)
+}
+
+func (p *RGBA) RGBAAt(x, y int) color.RGBA {
if !(Point{x, y}.In(p.Rect)) {
return color.RGBA{}
}
@@ -167,6 +171,10 @@ func (p *RGBA64) ColorModel() color.Model { return color.RGBA64Model }
func (p *RGBA64) Bounds() Rectangle { return p.Rect }
func (p *RGBA64) At(x, y int) color.Color {
+ return p.RGBA64At(x, y)
+}
+
+func (p *RGBA64) RGBA64At(x, y int) color.RGBA64 {
if !(Point{x, y}.In(p.Rect)) {
return color.RGBA64{}
}
@@ -275,6 +283,10 @@ func (p *NRGBA) ColorModel() color.Model { return color.NRGBAModel }
func (p *NRGBA) Bounds() Rectangle { return p.Rect }
func (p *NRGBA) At(x, y int) color.Color {
+ return p.NRGBAAt(x, y)
+}
+
+func (p *NRGBA) NRGBAAt(x, y int) color.NRGBA {
if !(Point{x, y}.In(p.Rect)) {
return color.NRGBA{}
}
@@ -370,6 +382,10 @@ func (p *NRGBA64) ColorModel() color.Model { return color.NRGBA64Model }
func (p *NRGBA64) Bounds() Rectangle { return p.Rect }
func (p *NRGBA64) At(x, y int) color.Color {
+ return p.NRGBA64At(x, y)
+}
+
+func (p *NRGBA64) NRGBA64At(x, y int) color.NRGBA64 {
if !(Point{x, y}.In(p.Rect)) {
return color.NRGBA64{}
}
@@ -478,6 +494,10 @@ func (p *Alpha) ColorModel() color.Model { return color.AlphaModel }
func (p *Alpha) Bounds() Rectangle { return p.Rect }
func (p *Alpha) At(x, y int) color.Color {
+ return p.AlphaAt(x, y)
+}
+
+func (p *Alpha) AlphaAt(x, y int) color.Alpha {
if !(Point{x, y}.In(p.Rect)) {
return color.Alpha{}
}
@@ -566,6 +586,10 @@ func (p *Alpha16) ColorModel() color.Model { return color.Alpha16Model }
func (p *Alpha16) Bounds() Rectangle { return p.Rect }
func (p *Alpha16) At(x, y int) color.Color {
+ return p.Alpha16At(x, y)
+}
+
+func (p *Alpha16) Alpha16At(x, y int) color.Alpha16 {
if !(Point{x, y}.In(p.Rect)) {
return color.Alpha16{}
}
@@ -657,6 +681,10 @@ func (p *Gray) ColorModel() color.Model { return color.GrayModel }
func (p *Gray) Bounds() Rectangle { return p.Rect }
func (p *Gray) At(x, y int) color.Color {
+ return p.GrayAt(x, y)
+}
+
+func (p *Gray) GrayAt(x, y int) color.Gray {
if !(Point{x, y}.In(p.Rect)) {
return color.Gray{}
}
@@ -732,6 +760,10 @@ func (p *Gray16) ColorModel() color.Model { return color.Gray16Model }
func (p *Gray16) Bounds() Rectangle { return p.Rect }
func (p *Gray16) At(x, y int) color.Color {
+ return p.Gray16At(x, y)
+}
+
+func (p *Gray16) Gray16At(x, y int) color.Gray16 {
if !(Point{x, y}.In(p.Rect)) {
return color.Gray16{}
}
diff --git a/libgo/go/image/jpeg/huffman.go b/libgo/go/image/jpeg/huffman.go
index 9b731fdc4f..d4ff4cfa0c 100644
--- a/libgo/go/image/jpeg/huffman.go
+++ b/libgo/go/image/jpeg/huffman.go
@@ -4,88 +4,96 @@
package jpeg
-import "io"
+import (
+ "io"
+)
-// Each code is at most 16 bits long.
+// maxCodeLength is the maximum (inclusive) number of bits in a Huffman code.
const maxCodeLength = 16
-// Each decoded value is a uint8, so there are at most 256 such values.
-const maxNumValues = 256
+// maxNCodes is the maximum (inclusive) number of codes in a Huffman tree.
+const maxNCodes = 256
-// Bit stream for the Huffman decoder.
-// The n least significant bits of a form the unread bits, to be read in MSB to LSB order.
-type bits struct {
- a uint32 // accumulator.
- m uint32 // mask. m==1<<(n-1) when n>0, with m==0 when n==0.
- n int // the number of unread bits in a.
-}
+// lutSize is the log-2 size of the Huffman decoder's look-up table.
+const lutSize = 8
-// Huffman table decoder, specified in section C.
+// huffman is a Huffman decoder, specified in section C.
type huffman struct {
- l [maxCodeLength]int
- length int // sum of l[i].
- val [maxNumValues]uint8 // the decoded values, as sorted by their encoding.
- size [maxNumValues]int // size[i] is the number of bits to encode val[i].
- code [maxNumValues]int // code[i] is the encoding of val[i].
- minCode [maxCodeLength]int // min codes of length i, or -1 if no codes of that length.
- maxCode [maxCodeLength]int // max codes of length i, or -1 if no codes of that length.
- valIndex [maxCodeLength]int // index into val of minCode[i].
+ // length is the number of codes in the tree.
+ nCodes int32
+ // lut is the look-up table for the next lutSize bits in the bit-stream.
+ // The high 8 bits of the uint16 are the encoded value. The low 8 bits
+ // are 1 plus the code length, or 0 if the value is too large to fit in
+ // lutSize bits.
+ lut [1 << lutSize]uint16
+ // vals are the decoded values, sorted by their encoding.
+ vals [maxNCodes]uint8
+ // minCodes[i] is the minimum code of length i, or -1 if there are no
+ // codes of that length.
+ minCodes [maxCodeLength]int32
+ // maxCodes[i] is the maximum code of length i, or -1 if there are no
+ // codes of that length.
+ maxCodes [maxCodeLength]int32
+ // valsIndices[i] is the index into vals of minCodes[i].
+ valsIndices [maxCodeLength]int32
}
-// Reads bytes from the io.Reader to ensure that bits.n is at least n.
-func (d *decoder) ensureNBits(n int) error {
- for d.b.n < n {
- c, err := d.r.ReadByte()
+// errShortHuffmanData means that an unexpected EOF occurred while decoding
+// Huffman data.
+var errShortHuffmanData = FormatError("short Huffman data")
+
+// ensureNBits reads bytes from the byte buffer to ensure that d.bits.n is at
+// least n. For best performance (avoiding function calls inside hot loops),
+// the caller is the one responsible for first checking that d.bits.n < n.
+func (d *decoder) ensureNBits(n int32) error {
+ for {
+ c, err := d.readByteStuffedByte()
if err != nil {
+ if err == io.EOF {
+ return errShortHuffmanData
+ }
return err
}
- d.b.a = d.b.a<<8 | uint32(c)
- d.b.n += 8
- if d.b.m == 0 {
- d.b.m = 1 << 7
+ d.bits.a = d.bits.a<<8 | uint32(c)
+ d.bits.n += 8
+ if d.bits.m == 0 {
+ d.bits.m = 1 << 7
} else {
- d.b.m <<= 8
+ d.bits.m <<= 8
}
- // Byte stuffing, specified in section F.1.2.3.
- if c == 0xff {
- c, err = d.r.ReadByte()
- if err != nil {
- return err
- }
- if c != 0x00 {
- return FormatError("missing 0xff00 sequence")
- }
+ if d.bits.n >= n {
+ break
}
}
return nil
}
-// The composition of RECEIVE and EXTEND, specified in section F.2.2.1.
+// receiveExtend is the composition of RECEIVE and EXTEND, specified in section
+// F.2.2.1.
func (d *decoder) receiveExtend(t uint8) (int32, error) {
- if d.b.n < int(t) {
- if err := d.ensureNBits(int(t)); err != nil {
+ if d.bits.n < int32(t) {
+ if err := d.ensureNBits(int32(t)); err != nil {
return 0, err
}
}
- d.b.n -= int(t)
- d.b.m >>= t
+ d.bits.n -= int32(t)
+ d.bits.m >>= t
s := int32(1) << t
- x := int32(d.b.a>>uint8(d.b.n)) & (s - 1)
+ x := int32(d.bits.a>>uint8(d.bits.n)) & (s - 1)
if x < s>>1 {
x += ((-1) << t) + 1
}
return x, nil
}
-// Processes a Define Huffman Table marker, and initializes a huffman struct from its contents.
-// Specified in section B.2.4.2.
+// processDHT processes a Define Huffman Table marker, and initializes a huffman
+// struct from its contents. Specified in section B.2.4.2.
func (d *decoder) processDHT(n int) error {
for n > 0 {
if n < 17 {
return FormatError("DHT has wrong length")
}
- _, err := io.ReadFull(d.r, d.tmp[0:17])
- if err != nil {
+ if err := d.readFull(d.tmp[:17]); err != nil {
return err
}
tc := d.tmp[0] >> 4
@@ -98,89 +106,112 @@ func (d *decoder) processDHT(n int) error {
}
h := &d.huff[tc][th]
- // Read l and val (and derive length).
- h.length = 0
- for i := 0; i < maxCodeLength; i++ {
- h.l[i] = int(d.tmp[i+1])
- h.length += h.l[i]
+ // Read nCodes and h.vals (and derive h.nCodes).
+ // nCodes[i] is the number of codes with code length i.
+ // h.nCodes is the total number of codes.
+ h.nCodes = 0
+ var nCodes [maxCodeLength]int32
+ for i := range nCodes {
+ nCodes[i] = int32(d.tmp[i+1])
+ h.nCodes += nCodes[i]
}
- if h.length == 0 {
+ if h.nCodes == 0 {
return FormatError("Huffman table has zero length")
}
- if h.length > maxNumValues {
+ if h.nCodes > maxNCodes {
return FormatError("Huffman table has excessive length")
}
- n -= h.length + 17
+ n -= int(h.nCodes) + 17
if n < 0 {
return FormatError("DHT has wrong length")
}
- _, err = io.ReadFull(d.r, h.val[0:h.length])
- if err != nil {
+ if err := d.readFull(h.vals[:h.nCodes]); err != nil {
return err
}
- // Derive size.
- k := 0
- for i := 0; i < maxCodeLength; i++ {
- for j := 0; j < h.l[i]; j++ {
- h.size[k] = i + 1
- k++
+ // Derive the look-up table.
+ for i := range h.lut {
+ h.lut[i] = 0
+ }
+ var x, code uint32
+ for i := uint32(0); i < lutSize; i++ {
+ code <<= 1
+ for j := int32(0); j < nCodes[i]; j++ {
+ // The codeLength is 1+i, so shift code by 8-(1+i) to
+ // calculate the high bits for every 8-bit sequence
+ // whose codeLength's high bits matches code.
+ // The high 8 bits of lutValue are the encoded value.
+ // The low 8 bits are 1 plus the codeLength.
+ base := uint8(code << (7 - i))
+ lutValue := uint16(h.vals[x])<<8 | uint16(2+i)
+ for k := uint8(0); k < 1<<(7-i); k++ {
+ h.lut[base|k] = lutValue
+ }
+ code++
+ x++
}
}
- // Derive code.
- code := 0
- size := h.size[0]
- for i := 0; i < h.length; i++ {
- if size != h.size[i] {
- code <<= uint8(h.size[i] - size)
- size = h.size[i]
- }
- h.code[i] = code
- code++
- }
-
- // Derive minCode, maxCode, and valIndex.
- k = 0
- index := 0
- for i := 0; i < maxCodeLength; i++ {
- if h.l[i] == 0 {
- h.minCode[i] = -1
- h.maxCode[i] = -1
- h.valIndex[i] = -1
+ // Derive minCodes, maxCodes, and valsIndices.
+ var c, index int32
+ for i, n := range nCodes {
+ if n == 0 {
+ h.minCodes[i] = -1
+ h.maxCodes[i] = -1
+ h.valsIndices[i] = -1
} else {
- h.minCode[i] = k
- h.maxCode[i] = k + h.l[i] - 1
- h.valIndex[i] = index
- k += h.l[i]
- index += h.l[i]
+ h.minCodes[i] = c
+ h.maxCodes[i] = c + n - 1
+ h.valsIndices[i] = index
+ c += n
+ index += n
}
- k <<= 1
+ c <<= 1
}
}
return nil
}
-// Returns the next Huffman-coded value from the bit stream, decoded according to h.
-// TODO(nigeltao): This decoding algorithm is simple, but slow. A lookahead table, instead of always
-// peeling off only 1 bit at time, ought to be faster.
+// decodeHuffman returns the next Huffman-coded value from the bit-stream,
+// decoded according to h.
func (d *decoder) decodeHuffman(h *huffman) (uint8, error) {
- if h.length == 0 {
+ if h.nCodes == 0 {
return 0, FormatError("uninitialized Huffman table")
}
- for i, code := 0, 0; i < maxCodeLength; i++ {
- if d.b.n == 0 {
+
+ if d.bits.n < 8 {
+ if err := d.ensureNBits(8); err != nil {
+ if err != errMissingFF00 && err != errShortHuffmanData {
+ return 0, err
+ }
+ // 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()
+ goto slowPath
+ }
+ }
+ if v := h.lut[(d.bits.a>>uint32(d.bits.n-lutSize))&0xff]; v != 0 {
+ n := (v & 0xff) - 1
+ d.bits.n -= int32(n)
+ d.bits.m >>= n
+ return uint8(v >> 8), nil
+ }
+
+slowPath:
+ for i, code := 0, int32(0); i < maxCodeLength; i++ {
+ if d.bits.n == 0 {
if err := d.ensureNBits(1); err != nil {
return 0, err
}
}
- if d.b.a&d.b.m != 0 {
+ if d.bits.a&d.bits.m != 0 {
code |= 1
}
- d.b.n--
- d.b.m >>= 1
- if code <= h.maxCode[i] {
- return h.val[h.valIndex[i]+code-h.minCode[i]], nil
+ d.bits.n--
+ d.bits.m >>= 1
+ if code <= h.maxCodes[i] {
+ return h.vals[h.valsIndices[i]+code-h.minCodes[i]], nil
}
code <<= 1
}
@@ -188,26 +219,26 @@ func (d *decoder) decodeHuffman(h *huffman) (uint8, error) {
}
func (d *decoder) decodeBit() (bool, error) {
- if d.b.n == 0 {
+ if d.bits.n == 0 {
if err := d.ensureNBits(1); err != nil {
return false, err
}
}
- ret := d.b.a&d.b.m != 0
- d.b.n--
- d.b.m >>= 1
+ ret := d.bits.a&d.bits.m != 0
+ d.bits.n--
+ d.bits.m >>= 1
return ret, nil
}
-func (d *decoder) decodeBits(n int) (uint32, error) {
- if d.b.n < n {
+func (d *decoder) decodeBits(n int32) (uint32, error) {
+ if d.bits.n < n {
if err := d.ensureNBits(n); err != nil {
return 0, err
}
}
- ret := d.b.a >> uint(d.b.n-n)
- ret &= (1 << uint(n)) - 1
- d.b.n -= n
- d.b.m >>= uint(n)
+ ret := d.bits.a >> uint32(d.bits.n-n)
+ ret &= (1 << uint32(n)) - 1
+ d.bits.n -= n
+ d.bits.m >>= uint32(n)
return ret, nil
}
diff --git a/libgo/go/image/jpeg/reader.go b/libgo/go/image/jpeg/reader.go
index 356d56220a..6d8b1d1d03 100644
--- a/libgo/go/image/jpeg/reader.go
+++ b/libgo/go/image/jpeg/reader.go
@@ -8,7 +8,6 @@
package jpeg
import (
- "bufio"
"image"
"image/color"
"io"
@@ -84,15 +83,36 @@ var unzig = [blockSize]int{
53, 60, 61, 54, 47, 55, 62, 63,
}
-// If the passed in io.Reader does not also have ReadByte, then Decode will introduce its own buffering.
+// Reader is deprecated.
type Reader interface {
+ io.ByteReader
io.Reader
- ReadByte() (c byte, err error)
+}
+
+// bits holds the unprocessed bits that have been taken from the byte-stream.
+// The n least significant bits of a form the unread bits, to be read in MSB to
+// LSB order.
+type bits struct {
+ a uint32 // accumulator.
+ m uint32 // mask. m==1<<(n-1) when n>0, with m==0 when n==0.
+ n int32 // the number of unread bits in a.
}
type decoder struct {
- r Reader
- b bits
+ r io.Reader
+ bits bits
+ // bytes is a byte buffer, similar to a bufio.Reader, except that it
+ // has to be able to unread more than 1 byte, due to byte stuffing.
+ // Byte stuffing is specified in section F.1.2.3.
+ bytes struct {
+ // buf[i:j] are the buffered bytes read from the underlying
+ // io.Reader that haven't yet been passed further on.
+ buf [4096]byte
+ i, j int
+ // nUnreadable is the number of bytes to back up i after
+ // overshooting. It can be 0, 1 or 2.
+ nUnreadable int
+ }
width, height int
img1 *image.Gray
img3 *image.YCbCr
@@ -104,21 +124,160 @@ type decoder struct {
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 [1024]byte
+ tmp [blockSize + 1]byte
+}
+
+// fill fills up the d.bytes.buf buffer from the underlying io.Reader. It
+// should only be called when there are no unread bytes in d.bytes.
+func (d *decoder) fill() error {
+ if d.bytes.i != d.bytes.j {
+ panic("jpeg: fill called when unread bytes exist")
+ }
+ // Move the last 2 bytes to the start of the buffer, in case we need
+ // to call unreadByteStuffedByte.
+ if d.bytes.j > 2 {
+ d.bytes.buf[0] = d.bytes.buf[d.bytes.j-2]
+ d.bytes.buf[1] = d.bytes.buf[d.bytes.j-1]
+ d.bytes.i, d.bytes.j = 2, 2
+ }
+ // Fill in the rest of the buffer.
+ n, err := d.r.Read(d.bytes.buf[d.bytes.j:])
+ d.bytes.j += n
+ if n > 0 {
+ err = nil
+ }
+ return err
+}
+
+// unreadByteStuffedByte undoes the most recent readByteStuffedByte call,
+// giving a byte of data back from d.bits to d.bytes. The Huffman look-up table
+// requires at least 8 bits for look-up, which means that Huffman decoding can
+// 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 {
+ d.bits.a >>= 8
+ d.bits.n -= 8
+ d.bits.m >>= 8
+ }
+}
+
+// readByte returns the next byte, whether buffered or not buffered. It does
+// not care about byte stuffing.
+func (d *decoder) readByte() (x byte, err error) {
+ for d.bytes.i == d.bytes.j {
+ if err = d.fill(); err != nil {
+ return 0, err
+ }
+ }
+ x = d.bytes.buf[d.bytes.i]
+ d.bytes.i++
+ d.bytes.nUnreadable = 0
+ return x, nil
+}
+
+// errMissingFF00 means that readByteStuffedByte encountered an 0xff byte (a
+// marker byte) that wasn't the expected byte-stuffed sequence 0xff, 0x00.
+var errMissingFF00 = FormatError("missing 0xff00 sequence")
+
+// readByteStuffedByte is like readByte but is for byte-stuffed Huffman data.
+func (d *decoder) readByteStuffedByte() (x byte, err error) {
+ // Take the fast path if d.bytes.buf contains at least two bytes.
+ if d.bytes.i+2 <= d.bytes.j {
+ x = d.bytes.buf[d.bytes.i]
+ d.bytes.i++
+ d.bytes.nUnreadable = 1
+ if x != 0xff {
+ return x, err
+ }
+ if d.bytes.buf[d.bytes.i] != 0x00 {
+ return 0, errMissingFF00
+ }
+ d.bytes.i++
+ d.bytes.nUnreadable = 2
+ return 0xff, nil
+ }
+
+ x, err = d.readByte()
+ if err != nil {
+ return 0, err
+ }
+ 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
+ if x != 0x00 {
+ return 0, errMissingFF00
+ }
+ return 0xff, nil
}
-// Reads and ignores the next n bytes.
+// readFull reads exactly len(p) bytes into p. It does not care about byte
+// stuffing.
+func (d *decoder) readFull(p []byte) error {
+ // Unread the overshot bytes, if any.
+ if d.bytes.nUnreadable != 0 {
+ if d.bits.n >= 8 {
+ d.unreadByteStuffedByte()
+ }
+ d.bytes.nUnreadable = 0
+ }
+
+ for {
+ n := copy(p, d.bytes.buf[d.bytes.i:d.bytes.j])
+ p = p[n:]
+ d.bytes.i += n
+ if len(p) == 0 {
+ break
+ }
+ if err := d.fill(); err != nil {
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return err
+ }
+ }
+ return nil
+}
+
+// ignore ignores the next n bytes.
func (d *decoder) ignore(n int) error {
- for n > 0 {
- m := len(d.tmp)
+ // Unread the overshot bytes, if any.
+ if d.bytes.nUnreadable != 0 {
+ if d.bits.n >= 8 {
+ d.unreadByteStuffedByte()
+ }
+ d.bytes.nUnreadable = 0
+ }
+
+ for {
+ m := d.bytes.j - d.bytes.i
if m > n {
m = n
}
- _, err := io.ReadFull(d.r, d.tmp[0:m])
- if err != nil {
+ d.bytes.i += m
+ n -= m
+ if n == 0 {
+ break
+ }
+ if err := d.fill(); err != nil {
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
return err
}
- n -= m
}
return nil
}
@@ -133,8 +292,7 @@ func (d *decoder) processSOF(n int) error {
default:
return UnsupportedError("SOF has wrong length")
}
- _, err := io.ReadFull(d.r, d.tmp[:n])
- if err != nil {
+ if err := d.readFull(d.tmp[:n]); err != nil {
return err
}
// We only support 8-bit precision.
@@ -187,8 +345,7 @@ func (d *decoder) processSOF(n int) error {
func (d *decoder) processDQT(n int) error {
const qtLength = 1 + blockSize
for ; n >= qtLength; n -= qtLength {
- _, err := io.ReadFull(d.r, d.tmp[0:qtLength])
- if err != nil {
+ if err := d.readFull(d.tmp[:qtLength]); err != nil {
return err
}
pq := d.tmp[0] >> 4
@@ -214,8 +371,7 @@ func (d *decoder) processDRI(n int) error {
if n != 2 {
return FormatError("DRI has wrong length")
}
- _, err := io.ReadFull(d.r, d.tmp[0:2])
- if err != nil {
+ if err := d.readFull(d.tmp[:2]); err != nil {
return err
}
d.ri = int(d.tmp[0])<<8 + int(d.tmp[1])
@@ -224,15 +380,10 @@ func (d *decoder) processDRI(n int) error {
// 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) {
- if rr, ok := r.(Reader); ok {
- d.r = rr
- } else {
- d.r = bufio.NewReader(r)
- }
+ d.r = r
// Check for the Start Of Image marker.
- _, err := io.ReadFull(d.r, d.tmp[0:2])
- if err != nil {
+ if err := d.readFull(d.tmp[:2]); err != nil {
return nil, err
}
if d.tmp[0] != 0xff || d.tmp[1] != soiMarker {
@@ -241,7 +392,7 @@ func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, error) {
// Process the remaining segments until the End Of Image marker.
for {
- _, err := io.ReadFull(d.r, d.tmp[0:2])
+ err := d.readFull(d.tmp[:2])
if err != nil {
return nil, err
}
@@ -267,7 +418,7 @@ func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, error) {
// Note that extraneous 0xff bytes in e.g. SOS data are escaped as
// "\xff\x00", and so are detected a little further down below.
d.tmp[0] = d.tmp[1]
- d.tmp[1], err = d.r.ReadByte()
+ d.tmp[1], err = d.readByte()
if err != nil {
return nil, err
}
@@ -280,7 +431,7 @@ func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, error) {
for marker == 0xff {
// Section B.1.1.2 says, "Any marker may optionally be preceded by any
// number of fill bytes, which are bytes assigned code X'FF'".
- marker, err = d.r.ReadByte()
+ marker, err = d.readByte()
if err != nil {
return nil, err
}
@@ -300,8 +451,7 @@ func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, error) {
// Read the 16-bit length of the segment. The value includes the 2 bytes for the
// length itself, so we subtract 2 to get the number of remaining bytes.
- _, err = io.ReadFull(d.r, d.tmp[0:2])
- if err != nil {
+ if err = d.readFull(d.tmp[:2]); err != nil {
return nil, err
}
n := int(d.tmp[0])<<8 + int(d.tmp[1]) - 2
diff --git a/libgo/go/image/jpeg/reader_test.go b/libgo/go/image/jpeg/reader_test.go
index e951e038c0..4de2e8ee73 100644
--- a/libgo/go/image/jpeg/reader_test.go
+++ b/libgo/go/image/jpeg/reader_test.go
@@ -9,6 +9,7 @@ import (
"fmt"
"image"
"image/color"
+ "io"
"io/ioutil"
"math/rand"
"os"
@@ -28,6 +29,7 @@ func TestDecodeProgressive(t *testing.T) {
"../testdata/video-001.q50.444",
"../testdata/video-005.gray.q50",
"../testdata/video-005.gray.q50.2x2",
+ "../testdata/video-001.separate.dc.progression",
}
for _, tc := range testCases {
m0, err := decodeFile(tc + ".jpeg")
@@ -44,6 +46,12 @@ func TestDecodeProgressive(t *testing.T) {
t.Errorf("%s: bounds differ: %v and %v", tc, m0.Bounds(), m1.Bounds())
continue
}
+ // All of the video-*.jpeg files are 150x103.
+ if m0.Bounds() != image.Rect(0, 0, 150, 103) {
+ t.Errorf("%s: bad bounds: %v", tc, m0.Bounds())
+ continue
+ }
+
switch m0 := m0.(type) {
case *image.YCbCr:
m1 := m1.(*image.YCbCr)
@@ -79,23 +87,64 @@ func decodeFile(filename string) (image.Image, error) {
}
defer f.Close()
return Decode(f)
+}
+
+type eofReader struct {
+ data []byte // deliver from Read without EOF
+ dataEOF []byte // then deliver from Read with EOF on last chunk
+ lenAtEOF int
+}
+func (r *eofReader) Read(b []byte) (n int, err error) {
+ if len(r.data) > 0 {
+ n = copy(b, r.data)
+ r.data = r.data[n:]
+ } else {
+ n = copy(b, r.dataEOF)
+ r.dataEOF = r.dataEOF[n:]
+ if len(r.dataEOF) == 0 {
+ err = io.EOF
+ if r.lenAtEOF == -1 {
+ r.lenAtEOF = n
+ }
+ }
+ }
+ return
+}
+
+func TestDecodeEOF(t *testing.T) {
+ // Check that if reader returns final data and EOF at same time, jpeg handles it.
+ data, err := ioutil.ReadFile("../testdata/video-001.jpeg")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ n := len(data)
+ for i := 0; i < n; {
+ r := &eofReader{data[:n-i], data[n-i:], -1}
+ _, err := Decode(r)
+ if err != nil {
+ t.Errorf("Decode with Read() = %d, EOF: %v", r.lenAtEOF, err)
+ }
+ if i == 0 {
+ i = 1
+ } else {
+ i *= 2
+ }
+ }
}
// check checks that the two pix data are equal, within the given bounds.
func check(bounds image.Rectangle, pix0, pix1 []byte, stride0, stride1 int) error {
- if len(pix0) != len(pix1) {
- return fmt.Errorf("len(pix) %d and %d differ", len(pix0), len(pix1))
- }
- if stride0 != stride1 {
- return fmt.Errorf("strides %d and %d differ", stride0, stride1)
+ if stride0 <= 0 || stride0%8 != 0 {
+ return fmt.Errorf("bad stride %d", stride0)
}
- if stride0%8 != 0 {
- return fmt.Errorf("stride %d is not a multiple of 8", stride0)
+ if stride1 <= 0 || stride1%8 != 0 {
+ return fmt.Errorf("bad stride %d", stride1)
}
// Compare the two pix data, one 8x8 block at a time.
- for y := 0; y < len(pix0)/stride0; y += 8 {
- for x := 0; x < stride0; x += 8 {
+ for y := 0; y < len(pix0)/stride0 && y < len(pix1)/stride1; y += 8 {
+ for x := 0; x < stride0 && x < stride1; x += 8 {
if x >= bounds.Max.X || y >= bounds.Max.Y {
// We don't care if the two pix data differ if the 8x8 block is
// entirely outside of the image's bounds. For example, this can
@@ -108,8 +157,9 @@ func check(bounds image.Rectangle, pix0, pix1 []byte, stride0, stride1 int) erro
for j := 0; j < 8; j++ {
for i := 0; i < 8; i++ {
- index := (y+j)*stride0 + (x + i)
- if pix0[index] != pix1[index] {
+ index0 := (y+j)*stride0 + (x + i)
+ index1 := (y+j)*stride1 + (x + i)
+ if pix0[index0] != pix1[index1] {
return fmt.Errorf("blocks at (%d, %d) differ:\n%sand\n%s", x, y,
pixString(pix0, stride0, x, y),
pixString(pix1, stride1, x, y),
diff --git a/libgo/go/image/jpeg/scan.go b/libgo/go/image/jpeg/scan.go
index a69ed17489..2bd1d9d531 100644
--- a/libgo/go/image/jpeg/scan.go
+++ b/libgo/go/image/jpeg/scan.go
@@ -6,7 +6,6 @@ package jpeg
import (
"image"
- "io"
)
// makeImg allocates and initializes the destination image.
@@ -41,8 +40,7 @@ func (d *decoder) processSOS(n int) error {
if n < 6 || 4+2*d.nComp < n || n%2 != 0 {
return FormatError("SOS has wrong length")
}
- _, err := io.ReadFull(d.r, d.tmp[:n])
- if err != nil {
+ if err := d.readFull(d.tmp[:n]); err != nil {
return err
}
nComp := int(d.tmp[0])
@@ -67,7 +65,13 @@ func (d *decoder) processSOS(n int) error {
}
scan[i].compIndex = uint8(compIndex)
scan[i].td = d.tmp[2+2*i] >> 4
+ if scan[i].td > maxTh {
+ return FormatError("bad Td value")
+ }
scan[i].ta = d.tmp[2+2*i] & 0x0f
+ if scan[i].ta > maxTh {
+ return FormatError("bad Ta value")
+ }
}
// zigStart and zigEnd are the spectral selection bounds.
@@ -119,18 +123,17 @@ func (d *decoder) processSOS(n int) error {
}
}
- d.b = bits{}
+ d.bits = bits{}
mcu, expectedRST := 0, uint8(rst0Marker)
var (
// b is the decoded coefficients, in natural (not zig-zag) order.
b block
dc [nColorComponent]int32
- // mx0 and my0 are the location of the current (in terms of 8x8 blocks).
+ // 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:
- // mx0 is 2 and my0 is 0, even though the pixel is in the second MCU.
- // TODO(nigeltao): rename mx0 and my0 to bx and by?
- mx0, my0 int
+ // bx is 2 and by is 0, even though the pixel is in the second MCU.
+ bx, by int
blockCount int
)
for my := 0; my < myy; my++ {
@@ -141,45 +144,50 @@ func (d *decoder) processSOS(n int) error {
for j := 0; j < d.comp[compIndex].h*d.comp[compIndex].v; 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.
+ //
// For a baseline 32x16 pixel image, the Y blocks visiting order is:
// 0 1 4 5
// 2 3 6 7
//
- // For progressive images, the DC data blocks (zigStart == 0) are traversed
- // as above, but AC data blocks are traversed left to right, top to bottom:
+ // For progressive images, the interleaved scans (those with nComp > 1)
+ // are traversed as above, but non-interleaved scans are traversed left
+ // to right, top to bottom:
// 0 1 2 3
// 4 5 6 7
+ // Only DC scans (zigStart == 0) can be interleaved. AC scans must have
+ // only one component.
//
- // To further complicate matters, there is no AC data for any blocks that
- // are inside the image at the MCU level but outside the image at the pixel
- // level. For example, a 24x16 pixel 4:2:0 progressive image consists of
- // two 16x16 MCUs. The earlier scans will process 8 Y blocks:
+ // To further complicate matters, for non-interleaved scans, there is no
+ // data for any blocks that are inside the image at the MCU level but
+ // outside the image at the pixel level. For example, a 24x16 pixel 4:2:0
+ // progressive image consists of two 16x16 MCUs. The interleaved scans
+ // will process 8 Y blocks:
// 0 1 4 5
// 2 3 6 7
- // The later scans will process only 6 Y blocks:
+ // The non-interleaved scans will process only 6 Y blocks:
// 0 1 2
// 3 4 5
- if zigStart == 0 {
- mx0, my0 = d.comp[compIndex].h*mx, d.comp[compIndex].v*my
+ if nComp != 1 {
+ bx, by = d.comp[compIndex].h*mx, d.comp[compIndex].v*my
if h0 == 1 {
- my0 += j
+ by += j
} else {
- mx0 += j % 2
- my0 += j / 2
+ bx += j % 2
+ by += j / 2
}
} else {
q := mxx * d.comp[compIndex].h
- mx0 = blockCount % q
- my0 = blockCount / q
+ bx = blockCount % q
+ by = blockCount / q
blockCount++
- if mx0*8 >= d.width || my0*8 >= d.height {
+ if bx*8 >= d.width || by*8 >= d.height {
continue
}
}
// Load the previous partially decoded coefficients, if applicable.
if d.progressive {
- b = d.progCoeffs[compIndex][my0*mxx*d.comp[compIndex].h+mx0]
+ b = d.progCoeffs[compIndex][by*mxx*d.comp[compIndex].h+bx]
} else {
b = block{}
}
@@ -212,8 +220,9 @@ func (d *decoder) processSOS(n int) error {
d.eobRun--
} else {
// Decode the AC coefficients, as specified in section F.2.2.2.
+ huff := &d.huff[acTable][scan[i].ta]
for ; zig <= zigEnd; zig++ {
- value, err := d.decodeHuffman(&d.huff[acTable][scan[i].ta])
+ value, err := d.decodeHuffman(huff)
if err != nil {
return err
}
@@ -233,7 +242,7 @@ func (d *decoder) processSOS(n int) error {
if val0 != 0x0f {
d.eobRun = uint16(1 << val0)
if val0 != 0 {
- bits, err := d.decodeBits(int(val0))
+ bits, err := d.decodeBits(int32(val0))
if err != nil {
return err
}
@@ -251,7 +260,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][my0*mxx*d.comp[compIndex].h+mx0] = b
+ d.progCoeffs[compIndex][by*mxx*d.comp[compIndex].h+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,
@@ -268,15 +277,15 @@ func (d *decoder) processSOS(n int) error {
idct(&b)
dst, stride := []byte(nil), 0
if d.nComp == nGrayComponent {
- dst, stride = d.img1.Pix[8*(my0*d.img1.Stride+mx0):], d.img1.Stride
+ dst, stride = d.img1.Pix[8*(by*d.img1.Stride+bx):], d.img1.Stride
} else {
switch compIndex {
case 0:
- dst, stride = d.img3.Y[8*(my0*d.img3.YStride+mx0):], d.img3.YStride
+ dst, stride = d.img3.Y[8*(by*d.img3.YStride+bx):], d.img3.YStride
case 1:
- dst, stride = d.img3.Cb[8*(my0*d.img3.CStride+mx0):], d.img3.CStride
+ dst, stride = d.img3.Cb[8*(by*d.img3.CStride+bx):], d.img3.CStride
case 2:
- dst, stride = d.img3.Cr[8*(my0*d.img3.CStride+mx0):], d.img3.CStride
+ dst, stride = d.img3.Cr[8*(by*d.img3.CStride+bx):], d.img3.CStride
default:
return UnsupportedError("too many components")
}
@@ -303,8 +312,7 @@ func (d *decoder) processSOS(n int) error {
if d.ri > 0 && mcu%d.ri == 0 && mcu < mxx*myy {
// A more sophisticated decoder could use RST[0-7] markers to resynchronize from corrupt input,
// but this one assumes well-formed input, and hence the restart marker follows immediately.
- _, err := io.ReadFull(d.r, d.tmp[0:2])
- if err != nil {
+ if err := d.readFull(d.tmp[:2]); err != nil {
return err
}
if d.tmp[0] != 0xff || d.tmp[1] != expectedRST {
@@ -315,7 +323,7 @@ func (d *decoder) processSOS(n int) error {
expectedRST = rst0Marker
}
// Reset the Huffman decoder.
- d.b = bits{}
+ d.bits = bits{}
// Reset the DC components, as per section F.2.1.3.1.
dc = [nColorComponent]int32{}
// Reset the progressive decoder state, as per section G.1.2.2.
@@ -363,7 +371,7 @@ func (d *decoder) refine(b *block, h *huffman, zigStart, zigEnd, delta int32) er
if val0 != 0x0f {
d.eobRun = uint16(1 << val0)
if val0 != 0 {
- bits, err := d.decodeBits(int(val0))
+ bits, err := d.decodeBits(int32(val0))
if err != nil {
return err
}
diff --git a/libgo/go/image/jpeg/writer.go b/libgo/go/image/jpeg/writer.go
index c58fbf3055..91bbde3bf8 100644
--- a/libgo/go/image/jpeg/writer.go
+++ b/libgo/go/image/jpeg/writer.go
@@ -249,7 +249,7 @@ func (e *encoder) writeByte(b byte) {
e.err = e.w.WriteByte(b)
}
-// emit emits the least significant nBits bits of bits to the bitstream.
+// emit emits the least significant nBits bits of bits to the bit-stream.
// The precondition is bits < 1<<nBits && nBits <= 16.
func (e *encoder) emit(bits, nBits uint32) {
nBits += e.nBits
@@ -312,32 +312,44 @@ func (e *encoder) writeDQT() {
}
// writeSOF0 writes the Start Of Frame (Baseline) marker.
-func (e *encoder) writeSOF0(size image.Point) {
- const markerlen = 8 + 3*nColorComponent
+func (e *encoder) writeSOF0(size image.Point, nComponent int) {
+ markerlen := 8 + 3*nComponent
e.writeMarkerHeader(sof0Marker, markerlen)
e.buf[0] = 8 // 8-bit color.
e.buf[1] = uint8(size.Y >> 8)
e.buf[2] = uint8(size.Y & 0xff)
e.buf[3] = uint8(size.X >> 8)
e.buf[4] = uint8(size.X & 0xff)
- e.buf[5] = nColorComponent
- for i := 0; i < nColorComponent; i++ {
- e.buf[3*i+6] = uint8(i + 1)
- // We use 4:2:0 chroma subsampling.
- e.buf[3*i+7] = "\x22\x11\x11"[i]
- e.buf[3*i+8] = "\x00\x01\x01"[i]
+ e.buf[5] = uint8(nComponent)
+ if nComponent == 1 {
+ e.buf[6] = 1
+ // No subsampling for grayscale image.
+ e.buf[7] = 0x11
+ e.buf[8] = 0x00
+ } else {
+ for i := 0; i < nComponent; i++ {
+ e.buf[3*i+6] = uint8(i + 1)
+ // We use 4:2:0 chroma subsampling.
+ e.buf[3*i+7] = "\x22\x11\x11"[i]
+ e.buf[3*i+8] = "\x00\x01\x01"[i]
+ }
}
- e.write(e.buf[:3*(nColorComponent-1)+9])
+ e.write(e.buf[:3*(nComponent-1)+9])
}
// writeDHT writes the Define Huffman Table marker.
-func (e *encoder) writeDHT() {
+func (e *encoder) writeDHT(nComponent int) {
markerlen := 2
- for _, s := range theHuffmanSpec {
+ specs := theHuffmanSpec[:]
+ if nComponent == 1 {
+ // Drop the Chrominance tables.
+ specs = specs[:2]
+ }
+ for _, s := range specs {
markerlen += 1 + 16 + len(s.value)
}
e.writeMarkerHeader(dhtMarker, markerlen)
- for i, s := range theHuffmanSpec {
+ for i, s := range specs {
e.writeByte("\x00\x10\x01\x11"[i])
e.write(s.count[:])
e.write(s.value)
@@ -345,8 +357,8 @@ func (e *encoder) writeDHT() {
}
// writeBlock writes a block of pixel data using the given quantization table,
-// returning the post-quantized DC value of the DCT-transformed block.
-// b is in natural (not zig-zag) order.
+// returning the post-quantized DC value of the DCT-transformed block. b is in
+// natural (not zig-zag) order.
func (e *encoder) writeBlock(b *block, q quantIndex, prevDC int32) int32 {
fdct(b)
// Emit the DC delta.
@@ -390,6 +402,20 @@ func toYCbCr(m image.Image, p image.Point, yBlock, cbBlock, crBlock *block) {
}
}
+// grayToY stores the 8x8 region of m whose top-left corner is p in yBlock.
+func grayToY(m *image.Gray, p image.Point, yBlock *block) {
+ b := m.Bounds()
+ xmax := b.Max.X - 1
+ ymax := b.Max.Y - 1
+ pix := m.Pix
+ for j := 0; j < 8; j++ {
+ for i := 0; i < 8; i++ {
+ idx := m.PixOffset(min(p.X+i, xmax), min(p.Y+j, ymax))
+ yBlock[8*j+i] = int32(pix[idx])
+ }
+ }
+}
+
// rgbaToYCbCr is a specialized version of toYCbCr for image.RGBA images.
func rgbaToYCbCr(m *image.RGBA, p image.Point, yBlock, cbBlock, crBlock *block) {
b := m.Bounds()
@@ -430,7 +456,18 @@ func scale(dst *block, src *[4]block) {
}
}
-// sosHeader is the SOS marker "\xff\xda" followed by 12 bytes:
+// sosHeaderY is the SOS marker "\xff\xda" followed by 8 bytes:
+// - the marker length "\x00\x08",
+// - the number of components "\x01",
+// - component 1 uses DC table 0 and AC table 0 "\x01\x00",
+// - the bytes "\x00\x3f\x00". Section B.2.3 of the spec says that for
+// sequential DCTs, those bytes (8-bit Ss, 8-bit Se, 4-bit Ah, 4-bit Al)
+// should be 0x00, 0x3f, 0x00<<4 | 0x00.
+var sosHeaderY = []byte{
+ 0xff, 0xda, 0x00, 0x08, 0x01, 0x01, 0x00, 0x00, 0x3f, 0x00,
+}
+
+// sosHeaderYCbCr is the SOS marker "\xff\xda" followed by 12 bytes:
// - the marker length "\x00\x0c",
// - the number of components "\x03",
// - component 1 uses DC table 0 and AC table 0 "\x01\x00",
@@ -439,14 +476,19 @@ func scale(dst *block, src *[4]block) {
// - the bytes "\x00\x3f\x00". Section B.2.3 of the spec says that for
// sequential DCTs, those bytes (8-bit Ss, 8-bit Se, 4-bit Ah, 4-bit Al)
// should be 0x00, 0x3f, 0x00<<4 | 0x00.
-var sosHeader = []byte{
+var sosHeaderYCbCr = []byte{
0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02,
0x11, 0x03, 0x11, 0x00, 0x3f, 0x00,
}
// writeSOS writes the StartOfScan marker.
func (e *encoder) writeSOS(m image.Image) {
- e.write(sosHeader)
+ switch m.(type) {
+ case *image.Gray:
+ e.write(sosHeaderY)
+ default:
+ e.write(sosHeaderYCbCr)
+ }
var (
// Scratch buffers to hold the YCbCr values.
// The blocks are in natural (not zig-zag) order.
@@ -456,24 +498,36 @@ func (e *encoder) writeSOS(m image.Image) {
prevDCY, prevDCCb, prevDCCr int32
)
bounds := m.Bounds()
- rgba, _ := m.(*image.RGBA)
- for y := bounds.Min.Y; y < bounds.Max.Y; y += 16 {
- for x := bounds.Min.X; x < bounds.Max.X; x += 16 {
- for i := 0; i < 4; i++ {
- xOff := (i & 1) * 8
- yOff := (i & 2) * 4
- p := image.Pt(x+xOff, y+yOff)
- if rgba != nil {
- rgbaToYCbCr(rgba, p, &b, &cb[i], &cr[i])
- } else {
- toYCbCr(m, p, &b, &cb[i], &cr[i])
- }
+ switch m := m.(type) {
+ // TODO(wathiede): switch on m.ColorModel() instead of type.
+ case *image.Gray:
+ for y := bounds.Min.Y; y < bounds.Max.Y; y += 8 {
+ for x := bounds.Min.X; x < bounds.Max.X; x += 8 {
+ p := image.Pt(x, y)
+ grayToY(m, p, &b)
prevDCY = e.writeBlock(&b, 0, prevDCY)
}
- scale(&b, &cb)
- prevDCCb = e.writeBlock(&b, 1, prevDCCb)
- scale(&b, &cr)
- prevDCCr = e.writeBlock(&b, 1, prevDCCr)
+ }
+ default:
+ rgba, _ := m.(*image.RGBA)
+ for y := bounds.Min.Y; y < bounds.Max.Y; y += 16 {
+ for x := bounds.Min.X; x < bounds.Max.X; x += 16 {
+ for i := 0; i < 4; i++ {
+ xOff := (i & 1) * 8
+ yOff := (i & 2) * 4
+ p := image.Pt(x+xOff, y+yOff)
+ if rgba != nil {
+ rgbaToYCbCr(rgba, p, &b, &cb[i], &cr[i])
+ } else {
+ toYCbCr(m, p, &b, &cb[i], &cr[i])
+ }
+ prevDCY = e.writeBlock(&b, 0, prevDCY)
+ }
+ scale(&b, &cb)
+ prevDCCb = e.writeBlock(&b, 1, prevDCCb)
+ scale(&b, &cr)
+ prevDCCr = e.writeBlock(&b, 1, prevDCCr)
+ }
}
}
// Pad the last byte with 1's.
@@ -532,6 +586,13 @@ func Encode(w io.Writer, m image.Image, o *Options) error {
e.quant[i][j] = uint8(x)
}
}
+ // Compute number of components based on input image type.
+ nComponent := 3
+ switch m.(type) {
+ // TODO(wathiede): switch on m.ColorModel() instead of type.
+ case *image.Gray:
+ nComponent = 1
+ }
// Write the Start Of Image marker.
e.buf[0] = 0xff
e.buf[1] = 0xd8
@@ -539,9 +600,9 @@ func Encode(w io.Writer, m image.Image, o *Options) error {
// Write the quantization tables.
e.writeDQT()
// Write the image dimensions.
- e.writeSOF0(b.Size())
+ e.writeSOF0(b.Size(), nComponent)
// Write the Huffman tables.
- e.writeDHT()
+ e.writeDHT(nComponent)
// Write the image data.
e.writeSOS(m)
// Write the End Of Image marker.
diff --git a/libgo/go/image/jpeg/writer_test.go b/libgo/go/image/jpeg/writer_test.go
index 514b455dce..3df3cfcc5b 100644
--- a/libgo/go/image/jpeg/writer_test.go
+++ b/libgo/go/image/jpeg/writer_test.go
@@ -160,6 +160,34 @@ func TestWriter(t *testing.T) {
}
}
+// TestWriteGrayscale tests that a grayscale images survives a round-trip
+// through encode/decode cycle.
+func TestWriteGrayscale(t *testing.T) {
+ m0 := image.NewGray(image.Rect(0, 0, 32, 32))
+ for i := range m0.Pix {
+ m0.Pix[i] = uint8(i)
+ }
+ var buf bytes.Buffer
+ if err := Encode(&buf, m0, nil); err != nil {
+ t.Fatal(err)
+ }
+ m1, err := Decode(&buf)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if m0.Bounds() != m1.Bounds() {
+ t.Fatalf("bounds differ: %v and %v", m0.Bounds(), m1.Bounds())
+ }
+ if _, ok := m1.(*image.Gray); !ok {
+ t.Errorf("got %T, want *image.Gray", m1)
+ }
+ // Compare the average delta to the tolerance level.
+ want := int64(2 << 8)
+ if got := averageDelta(m0, m1); got > want {
+ t.Errorf("average delta too high; got %d, want <= %d", got, want)
+ }
+}
+
// averageDelta returns the average delta in RGB space. The two images must
// have the same bounds.
func averageDelta(m0, m1 image.Image) int64 {
diff --git a/libgo/go/image/png/paeth.go b/libgo/go/image/png/paeth.go
index 37978aa662..9ed6300c86 100644
--- a/libgo/go/image/png/paeth.go
+++ b/libgo/go/image/png/paeth.go
@@ -4,6 +4,21 @@
package png
+// intSize is either 32 or 64.
+const intSize = 32 << (^uint(0) >> 63)
+
+func abs(x int) int {
+ // m := -1 if x < 0. m := 0 otherwise.
+ m := x >> (intSize - 1)
+
+ // In two's complement representation, the negative number
+ // of any number (except the smallest one) can be computed
+ // by flipping all the bits and add 1. This is faster than
+ // code with a branch.
+ // See Hacker's Delight, section 2-4.
+ return (x ^ m) - m
+}
+
// paeth implements the Paeth filter function, as per the PNG specification.
func paeth(a, b, c uint8) uint8 {
// This is an optimized version of the sample code in the PNG spec.
@@ -16,16 +31,9 @@ func paeth(a, b, c uint8) uint8 {
pc := int(c)
pa := int(b) - pc
pb := int(a) - pc
- pc = pa + pb
- if pa < 0 {
- pa = -pa
- }
- if pb < 0 {
- pb = -pb
- }
- if pc < 0 {
- pc = -pc
- }
+ pc = abs(pa + pb)
+ pa = abs(pa)
+ pb = abs(pb)
if pa <= pb && pa <= pc {
return a
} else if pb <= pc {
@@ -44,16 +52,9 @@ func filterPaeth(cdat, pdat []byte, bytesPerPixel int) {
b = int(pdat[j])
pa = b - c
pb = a - c
- pc = pa + pb
- if pa < 0 {
- pa = -pa
- }
- if pb < 0 {
- pb = -pb
- }
- if pc < 0 {
- pc = -pc
- }
+ pc = abs(pa + pb)
+ pa = abs(pa)
+ pb = abs(pb)
if pa <= pb && pa <= pc {
// No-op.
} else if pb <= pc {
diff --git a/libgo/go/image/png/paeth_test.go b/libgo/go/image/png/paeth_test.go
index bb084861ae..cfc1896cd7 100644
--- a/libgo/go/image/png/paeth_test.go
+++ b/libgo/go/image/png/paeth_test.go
@@ -10,7 +10,7 @@ import (
"testing"
)
-func abs(x int) int {
+func slowAbs(x int) int {
if x < 0 {
return -x
}
@@ -21,9 +21,9 @@ func abs(x int) int {
// It is a straight port of the sample code in the PNG spec, section 9.4.
func slowPaeth(a, b, c uint8) uint8 {
p := int(a) + int(b) - int(c)
- pa := abs(p - int(a))
- pb := abs(p - int(b))
- pc := abs(p - int(c))
+ pa := slowAbs(p - int(a))
+ pb := slowAbs(p - int(b))
+ pc := slowAbs(p - int(c))
if pa <= pb && pa <= pc {
return a
} else if pb <= pc {
diff --git a/libgo/go/image/png/reader.go b/libgo/go/image/png/reader.go
index a6bf86ede6..0a40ca161d 100644
--- a/libgo/go/image/png/reader.go
+++ b/libgo/go/image/png/reader.go
@@ -57,6 +57,29 @@ const (
nFilter = 5
)
+// Interlace type.
+const (
+ itNone = 0
+ itAdam7 = 1
+)
+
+// interlaceScan defines the placement and size of a pass for Adam7 interlacing.
+type interlaceScan struct {
+ xFactor, yFactor, xOffset, yOffset int
+}
+
+// interlacing defines Adam7 interlacing, with 7 passes of reduced images.
+// See http://www.w3.org/TR/PNG/#8Interlace
+var interlacing = []interlaceScan{
+ {8, 8, 0, 0},
+ {8, 8, 4, 0},
+ {4, 8, 0, 4},
+ {4, 4, 2, 0},
+ {2, 4, 0, 2},
+ {2, 2, 1, 0},
+ {1, 2, 0, 1},
+}
+
// 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
@@ -84,6 +107,7 @@ type decoder struct {
stage int
idatLength uint32
tmp [3 * 256]byte
+ interlace int
}
// A FormatError reports that the input is not a valid PNG.
@@ -113,9 +137,16 @@ func (d *decoder) parseIHDR(length uint32) error {
return err
}
d.crc.Write(d.tmp[:13])
- if d.tmp[10] != 0 || d.tmp[11] != 0 || d.tmp[12] != 0 {
- return UnsupportedError("compression, filter or interlace method")
+ if d.tmp[10] != 0 {
+ return UnsupportedError("compression method")
+ }
+ if d.tmp[11] != 0 {
+ return UnsupportedError("filter method")
+ }
+ if d.tmp[12] != itNone && d.tmp[12] != itAdam7 {
+ return FormatError("invalid interlace method")
}
+ d.interlace = int(d.tmp[12])
w := int32(binary.BigEndian.Uint32(d.tmp[0:4]))
h := int32(binary.BigEndian.Uint32(d.tmp[4:8]))
if w < 0 || h < 0 {
@@ -287,7 +318,42 @@ func (d *decoder) decode() (image.Image, error) {
return nil, err
}
defer r.Close()
- bitsPerPixel := 0
+ var img image.Image
+ if d.interlace == itNone {
+ img, err = d.readImagePass(r, 0, false)
+ } else if d.interlace == itAdam7 {
+ // Allocate a blank image of the full size.
+ img, err = d.readImagePass(nil, 0, true)
+ for pass := 0; pass < 7; pass++ {
+ imagePass, err := d.readImagePass(r, pass, false)
+ if err != nil {
+ return nil, err
+ }
+ d.mergePassInto(img, imagePass, pass)
+ }
+ }
+
+ // Check for EOF, to verify the zlib checksum.
+ n := 0
+ for i := 0; n == 0 && err == nil; i++ {
+ if i == 100 {
+ return nil, io.ErrNoProgress
+ }
+ n, err = r.Read(d.tmp[:1])
+ }
+ if err != nil && err != io.EOF {
+ return nil, FormatError(err.Error())
+ }
+ if n != 0 || d.idatLength != 0 {
+ return nil, FormatError("too much pixel data")
+ }
+
+ return img, nil
+}
+
+// readImagePass reads a single image pass, sized according to the pass number.
+func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image.Image, error) {
+ var bitsPerPixel int = 0
pixOffset := 0
var (
gray *image.Gray
@@ -299,52 +365,63 @@ func (d *decoder) decode() (image.Image, error) {
nrgba64 *image.NRGBA64
img image.Image
)
+ width, height := d.width, d.height
+ if d.interlace == itAdam7 && !allocateOnly {
+ p := interlacing[pass]
+ // 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
+ }
switch d.cb {
case cbG1, cbG2, cbG4, cbG8:
bitsPerPixel = d.depth
- gray = image.NewGray(image.Rect(0, 0, d.width, d.height))
+ gray = image.NewGray(image.Rect(0, 0, width, height))
img = gray
case cbGA8:
bitsPerPixel = 16
- nrgba = image.NewNRGBA(image.Rect(0, 0, d.width, d.height))
+ nrgba = image.NewNRGBA(image.Rect(0, 0, width, height))
img = nrgba
case cbTC8:
bitsPerPixel = 24
- rgba = image.NewRGBA(image.Rect(0, 0, d.width, d.height))
+ rgba = image.NewRGBA(image.Rect(0, 0, width, height))
img = rgba
case cbP1, cbP2, cbP4, cbP8:
bitsPerPixel = d.depth
- paletted = image.NewPaletted(image.Rect(0, 0, d.width, d.height), d.palette)
+ paletted = image.NewPaletted(image.Rect(0, 0, width, height), d.palette)
img = paletted
case cbTCA8:
bitsPerPixel = 32
- nrgba = image.NewNRGBA(image.Rect(0, 0, d.width, d.height))
+ nrgba = image.NewNRGBA(image.Rect(0, 0, width, height))
img = nrgba
case cbG16:
bitsPerPixel = 16
- gray16 = image.NewGray16(image.Rect(0, 0, d.width, d.height))
+ gray16 = image.NewGray16(image.Rect(0, 0, width, height))
img = gray16
case cbGA16:
bitsPerPixel = 32
- nrgba64 = image.NewNRGBA64(image.Rect(0, 0, d.width, d.height))
+ nrgba64 = image.NewNRGBA64(image.Rect(0, 0, width, height))
img = nrgba64
case cbTC16:
bitsPerPixel = 48
- rgba64 = image.NewRGBA64(image.Rect(0, 0, d.width, d.height))
+ rgba64 = image.NewRGBA64(image.Rect(0, 0, width, height))
img = rgba64
case cbTCA16:
bitsPerPixel = 64
- nrgba64 = image.NewNRGBA64(image.Rect(0, 0, d.width, d.height))
+ nrgba64 = image.NewNRGBA64(image.Rect(0, 0, width, height))
img = nrgba64
}
+ if allocateOnly {
+ return img, nil
+ }
bytesPerPixel := (bitsPerPixel + 7) / 8
- // cr and pr are the bytes for the current and previous row.
// The +1 is for the per-row filter type, which is at cr[0].
- cr := make([]uint8, 1+(bitsPerPixel*d.width+7)/8)
- pr := make([]uint8, 1+(bitsPerPixel*d.width+7)/8)
+ rowSize := 1 + (bitsPerPixel*width+7)/8
+ // cr and pr are the bytes for the current and previous row.
+ cr := make([]uint8, rowSize)
+ pr := make([]uint8, rowSize)
- for y := 0; y < d.height; y++ {
+ for y := 0; y < height; y++ {
// Read the decompressed bytes.
_, err := io.ReadFull(r, cr)
if err != nil {
@@ -381,25 +458,25 @@ func (d *decoder) decode() (image.Image, error) {
// Convert from bytes to colors.
switch d.cb {
case cbG1:
- for x := 0; x < d.width; x += 8 {
+ for x := 0; x < width; x += 8 {
b := cdat[x/8]
- for x2 := 0; x2 < 8 && x+x2 < d.width; x2++ {
+ for x2 := 0; x2 < 8 && x+x2 < width; x2++ {
gray.SetGray(x+x2, y, color.Gray{(b >> 7) * 0xff})
b <<= 1
}
}
case cbG2:
- for x := 0; x < d.width; x += 4 {
+ for x := 0; x < width; x += 4 {
b := cdat[x/4]
- for x2 := 0; x2 < 4 && x+x2 < d.width; x2++ {
+ for x2 := 0; x2 < 4 && x+x2 < width; x2++ {
gray.SetGray(x+x2, y, color.Gray{(b >> 6) * 0x55})
b <<= 2
}
}
case cbG4:
- for x := 0; x < d.width; x += 2 {
+ for x := 0; x < width; x += 2 {
b := cdat[x/2]
- for x2 := 0; x2 < 2 && x+x2 < d.width; x2++ {
+ for x2 := 0; x2 < 2 && x+x2 < width; x2++ {
gray.SetGray(x+x2, y, color.Gray{(b >> 4) * 0x11})
b <<= 4
}
@@ -408,13 +485,13 @@ func (d *decoder) decode() (image.Image, error) {
copy(gray.Pix[pixOffset:], cdat)
pixOffset += gray.Stride
case cbGA8:
- for x := 0; x < d.width; x++ {
+ for x := 0; x < width; x++ {
ycol := cdat[2*x+0]
nrgba.SetNRGBA(x, y, color.NRGBA{ycol, ycol, ycol, cdat[2*x+1]})
}
case cbTC8:
pix, i, j := rgba.Pix, pixOffset, 0
- for x := 0; x < d.width; x++ {
+ for x := 0; x < width; x++ {
pix[i+0] = cdat[j+0]
pix[i+1] = cdat[j+1]
pix[i+2] = cdat[j+2]
@@ -424,9 +501,9 @@ func (d *decoder) decode() (image.Image, error) {
}
pixOffset += rgba.Stride
case cbP1:
- for x := 0; x < d.width; x += 8 {
+ for x := 0; x < width; x += 8 {
b := cdat[x/8]
- for x2 := 0; x2 < 8 && x+x2 < d.width; x2++ {
+ for x2 := 0; x2 < 8 && x+x2 < width; x2++ {
idx := b >> 7
if len(paletted.Palette) <= int(idx) {
paletted.Palette = paletted.Palette[:int(idx)+1]
@@ -436,9 +513,9 @@ func (d *decoder) decode() (image.Image, error) {
}
}
case cbP2:
- for x := 0; x < d.width; x += 4 {
+ for x := 0; x < width; x += 4 {
b := cdat[x/4]
- for x2 := 0; x2 < 4 && x+x2 < d.width; x2++ {
+ for x2 := 0; x2 < 4 && x+x2 < width; x2++ {
idx := b >> 6
if len(paletted.Palette) <= int(idx) {
paletted.Palette = paletted.Palette[:int(idx)+1]
@@ -448,9 +525,9 @@ func (d *decoder) decode() (image.Image, error) {
}
}
case cbP4:
- for x := 0; x < d.width; x += 2 {
+ for x := 0; x < width; x += 2 {
b := cdat[x/2]
- for x2 := 0; x2 < 2 && x+x2 < d.width; x2++ {
+ for x2 := 0; x2 < 2 && x+x2 < width; x2++ {
idx := b >> 4
if len(paletted.Palette) <= int(idx) {
paletted.Palette = paletted.Palette[:int(idx)+1]
@@ -461,7 +538,7 @@ func (d *decoder) decode() (image.Image, error) {
}
case cbP8:
if len(paletted.Palette) != 255 {
- for x := 0; x < d.width; x++ {
+ for x := 0; x < width; x++ {
if len(paletted.Palette) <= int(cdat[x]) {
paletted.Palette = paletted.Palette[:int(cdat[x])+1]
}
@@ -473,25 +550,25 @@ func (d *decoder) decode() (image.Image, error) {
copy(nrgba.Pix[pixOffset:], cdat)
pixOffset += nrgba.Stride
case cbG16:
- for x := 0; x < d.width; x++ {
+ for x := 0; x < width; x++ {
ycol := uint16(cdat[2*x+0])<<8 | uint16(cdat[2*x+1])
gray16.SetGray16(x, y, color.Gray16{ycol})
}
case cbGA16:
- for x := 0; x < d.width; x++ {
+ for x := 0; x < width; x++ {
ycol := uint16(cdat[4*x+0])<<8 | uint16(cdat[4*x+1])
acol := uint16(cdat[4*x+2])<<8 | uint16(cdat[4*x+3])
nrgba64.SetNRGBA64(x, y, color.NRGBA64{ycol, ycol, ycol, acol})
}
case cbTC16:
- for x := 0; x < d.width; x++ {
+ for x := 0; x < width; x++ {
rcol := uint16(cdat[6*x+0])<<8 | uint16(cdat[6*x+1])
gcol := uint16(cdat[6*x+2])<<8 | uint16(cdat[6*x+3])
bcol := uint16(cdat[6*x+4])<<8 | uint16(cdat[6*x+5])
rgba64.SetRGBA64(x, y, color.RGBA64{rcol, gcol, bcol, 0xffff})
}
case cbTCA16:
- for x := 0; x < d.width; x++ {
+ for x := 0; x < width; x++ {
rcol := uint16(cdat[8*x+0])<<8 | uint16(cdat[8*x+1])
gcol := uint16(cdat[8*x+2])<<8 | uint16(cdat[8*x+3])
bcol := uint16(cdat[8*x+4])<<8 | uint16(cdat[8*x+5])
@@ -504,18 +581,68 @@ func (d *decoder) decode() (image.Image, error) {
pr, cr = cr, pr
}
- // Check for EOF, to verify the zlib checksum.
- n, err := r.Read(pr[:1])
- if err != io.EOF {
- return nil, FormatError(err.Error())
- }
- if n != 0 || d.idatLength != 0 {
- return nil, FormatError("too much pixel data")
- }
-
return img, nil
}
+// mergePassInto merges a single pass into a full sized image.
+func (d *decoder) mergePassInto(dst image.Image, src image.Image, pass int) {
+ p := interlacing[pass]
+ var (
+ srcPix []uint8
+ dstPix []uint8
+ stride int
+ rect image.Rectangle
+ bytesPerPixel int
+ )
+ switch target := dst.(type) {
+ case *image.Alpha:
+ srcPix = src.(*image.Alpha).Pix
+ dstPix, stride, rect = target.Pix, target.Stride, target.Rect
+ bytesPerPixel = 1
+ case *image.Alpha16:
+ srcPix = src.(*image.Alpha16).Pix
+ dstPix, stride, rect = target.Pix, target.Stride, target.Rect
+ bytesPerPixel = 2
+ case *image.Gray:
+ srcPix = src.(*image.Gray).Pix
+ dstPix, stride, rect = target.Pix, target.Stride, target.Rect
+ bytesPerPixel = 1
+ case *image.Gray16:
+ srcPix = src.(*image.Gray16).Pix
+ dstPix, stride, rect = target.Pix, target.Stride, target.Rect
+ bytesPerPixel = 2
+ case *image.NRGBA:
+ srcPix = src.(*image.NRGBA).Pix
+ dstPix, stride, rect = target.Pix, target.Stride, target.Rect
+ bytesPerPixel = 4
+ case *image.NRGBA64:
+ srcPix = src.(*image.NRGBA64).Pix
+ dstPix, stride, rect = target.Pix, target.Stride, target.Rect
+ bytesPerPixel = 8
+ case *image.Paletted:
+ srcPix = src.(*image.Paletted).Pix
+ dstPix, stride, rect = target.Pix, target.Stride, target.Rect
+ bytesPerPixel = 1
+ case *image.RGBA:
+ srcPix = src.(*image.RGBA).Pix
+ dstPix, stride, rect = target.Pix, target.Stride, target.Rect
+ bytesPerPixel = 4
+ case *image.RGBA64:
+ srcPix = src.(*image.RGBA64).Pix
+ dstPix, stride, rect = target.Pix, target.Stride, target.Rect
+ bytesPerPixel = 8
+ }
+ s, bounds := 0, src.Bounds()
+ for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
+ dBase := (y*p.yFactor+p.yOffset-rect.Min.Y)*stride + (p.xOffset-rect.Min.X)*bytesPerPixel
+ for x := bounds.Min.X; x < bounds.Max.X; x++ {
+ d := dBase + x*p.xFactor*bytesPerPixel
+ copy(dstPix[d:], srcPix[s:s+bytesPerPixel])
+ s += bytesPerPixel
+ }
+ }
+}
+
func (d *decoder) parseIDAT(length uint32) (err error) {
d.idatLength = length
d.img, err = d.decode()
diff --git a/libgo/go/image/png/reader_test.go b/libgo/go/image/png/reader_test.go
index ac0d949a9d..ce772eb6f0 100644
--- a/libgo/go/image/png/reader_test.go
+++ b/libgo/go/image/png/reader_test.go
@@ -30,6 +30,7 @@ var filenames = []string{
"basn3p01",
"basn3p02",
"basn3p04",
+ "basn3p04-31i",
"basn3p08",
"basn3p08-trns",
"basn4a08",
@@ -186,6 +187,13 @@ func sng(w io.WriteCloser, filename string, png image.Image) {
c = 0
}
}
+ if c != 0 {
+ for c != 8/bitdepth {
+ b = b << uint(bitdepth)
+ c++
+ }
+ fmt.Fprintf(w, "%02x", b)
+ }
}
io.WriteString(w, "\n")
}
@@ -235,8 +243,8 @@ func TestReader(t *testing.T) {
// Compare the two, in SNG format, line by line.
for {
- pdone := pb.Scan()
- sdone := sb.Scan()
+ pdone := !pb.Scan()
+ sdone := !sb.Scan()
if pdone && sdone {
break
}
@@ -348,3 +356,7 @@ func BenchmarkDecodePaletted(b *testing.B) {
func BenchmarkDecodeRGB(b *testing.B) {
benchmarkDecode(b, "testdata/benchRGB.png", 4)
}
+
+func BenchmarkDecodeInterlacing(b *testing.B) {
+ benchmarkDecode(b, "testdata/benchRGB-interlace.png", 4)
+}
diff --git a/libgo/go/image/png/testdata/benchGray.png b/libgo/go/image/png/testdata/benchGray.png
new file mode 100644
index 0000000000..42bc6c3a0a
--- /dev/null
+++ b/libgo/go/image/png/testdata/benchGray.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/benchNRGBA-gradient.png b/libgo/go/image/png/testdata/benchNRGBA-gradient.png
new file mode 100644
index 0000000000..961934ccad
--- /dev/null
+++ b/libgo/go/image/png/testdata/benchNRGBA-gradient.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/benchNRGBA-opaque.png b/libgo/go/image/png/testdata/benchNRGBA-opaque.png
new file mode 100644
index 0000000000..ca4f4a037d
--- /dev/null
+++ b/libgo/go/image/png/testdata/benchNRGBA-opaque.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/benchPaletted.png b/libgo/go/image/png/testdata/benchPaletted.png
new file mode 100644
index 0000000000..4b4d5b9928
--- /dev/null
+++ b/libgo/go/image/png/testdata/benchPaletted.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/benchRGB.png b/libgo/go/image/png/testdata/benchRGB.png
new file mode 100644
index 0000000000..31ac65a3f2
--- /dev/null
+++ b/libgo/go/image/png/testdata/benchRGB.png
Binary files differ
diff --git a/libgo/go/image/png/writer.go b/libgo/go/image/png/writer.go
index 629452cbfa..df23270ee9 100644
--- a/libgo/go/image/png/writer.go
+++ b/libgo/go/image/png/writer.go
@@ -14,7 +14,13 @@ import (
"strconv"
)
+// Encoder configures encoding PNG images.
+type Encoder struct {
+ CompressionLevel CompressionLevel
+}
+
type encoder struct {
+ enc *Encoder
w io.Writer
m image.Image
cb int
@@ -24,6 +30,18 @@ type encoder struct {
tmp [4 * 256]byte
}
+type CompressionLevel int
+
+const (
+ DefaultCompression CompressionLevel = 0
+ NoCompression CompressionLevel = -1
+ BestSpeed CompressionLevel = -2
+ BestCompression CompressionLevel = -3
+
+ // Positive CompressionLevel values are reserved to mean a numeric zlib
+ // compression level, although that is not implemented yet.
+)
+
// Big-endian.
func writeUint32(b []uint8, u uint32) {
b[0] = uint8(u >> 24)
@@ -188,7 +206,7 @@ func filter(cr *[nFilter][]byte, pr []byte, bpp int) int {
// The Paeth filter.
sum = 0
for i := 0; i < bpp; i++ {
- cdat4[i] = cdat0[i] - paeth(0, pdat[i], 0)
+ cdat4[i] = cdat0[i] - pdat[i]
sum += abs8(cdat4[i])
}
for i := bpp; i < n; i++ {
@@ -255,8 +273,11 @@ func filter(cr *[nFilter][]byte, pr []byte, bpp int) int {
return filter
}
-func writeImage(w io.Writer, m image.Image, cb int) error {
- zw := zlib.NewWriter(w)
+func writeImage(w io.Writer, m image.Image, cb int, level int) error {
+ zw, err := zlib.NewWriterLevel(w, level)
+ if err != nil {
+ return err
+ }
defer zw.Close()
bpp := 0 // Bytes per pixel.
@@ -399,7 +420,10 @@ func writeImage(w io.Writer, m image.Image, cb int) error {
}
// Apply the filter.
- f := filter(&cr, pr, bpp)
+ f := ftNone
+ if level != zlib.NoCompression {
+ f = filter(&cr, pr, bpp)
+ }
// Write the compressed bytes.
if _, err := zw.Write(cr[f]); err != nil {
@@ -419,18 +443,41 @@ func (e *encoder) writeIDATs() {
}
var bw *bufio.Writer
bw = bufio.NewWriterSize(e, 1<<15)
- e.err = writeImage(bw, e.m, e.cb)
+ e.err = writeImage(bw, e.m, e.cb, levelToZlib(e.enc.CompressionLevel))
if e.err != nil {
return
}
e.err = bw.Flush()
}
+// This function is required because we want the zero value of
+// Encoder.CompressionLevel to map to zlib.DefaultCompression.
+func levelToZlib(l CompressionLevel) int {
+ switch l {
+ case DefaultCompression:
+ return zlib.DefaultCompression
+ case NoCompression:
+ return zlib.NoCompression
+ case BestSpeed:
+ return zlib.BestSpeed
+ case BestCompression:
+ return zlib.BestCompression
+ default:
+ return zlib.DefaultCompression
+ }
+}
+
func (e *encoder) writeIEND() { e.writeChunk(nil, "IEND") }
-// Encode writes the Image m to w in PNG format. Any Image may be encoded, but
-// images that are not image.NRGBA might be encoded lossily.
+// Encode writes the Image m to w in PNG format. Any Image may be
+// encoded, but images that are not image.NRGBA might be encoded lossily.
func Encode(w io.Writer, m image.Image) error {
+ var e Encoder
+ return e.Encode(w, m)
+}
+
+// Encode writes the Image m to w in PNG format.
+func (enc *Encoder) Encode(w io.Writer, m image.Image) error {
// Obviously, negative widths and heights are invalid. Furthermore, the PNG
// spec section 11.2.2 says that zero is invalid. Excessively large images are
// also rejected.
@@ -440,6 +487,7 @@ func Encode(w io.Writer, m image.Image) error {
}
var e encoder
+ e.enc = enc
e.w = w
e.m = m
diff --git a/libgo/go/image/png/writer_test.go b/libgo/go/image/png/writer_test.go
index 3116fc9ff9..d67a815698 100644
--- a/libgo/go/image/png/writer_test.go
+++ b/libgo/go/image/png/writer_test.go
@@ -40,11 +40,7 @@ func encodeDecode(m image.Image) (image.Image, error) {
if err != nil {
return nil, err
}
- m, err = Decode(&b)
- if err != nil {
- return nil, err
- }
- return m, nil
+ return Decode(&b)
}
func TestWriter(t *testing.T) {
@@ -81,6 +77,29 @@ func TestWriter(t *testing.T) {
}
}
+func TestWriterLevels(t *testing.T) {
+ m := image.NewNRGBA(image.Rect(0, 0, 100, 100))
+
+ var b1, b2 bytes.Buffer
+ if err := (&Encoder{}).Encode(&b1, m); err != nil {
+ t.Fatal(err)
+ }
+ noenc := &Encoder{CompressionLevel: NoCompression}
+ if err := noenc.Encode(&b2, m); err != nil {
+ t.Fatal(err)
+ }
+
+ if b2.Len() <= b1.Len() {
+ t.Error("DefaultCompression encoding was larger than NoCompression encoding")
+ }
+ if _, err := Decode(&b1); err != nil {
+ t.Error("cannot decode DefaultCompression")
+ }
+ if _, err := Decode(&b2); err != nil {
+ t.Error("cannot decode NoCompression")
+ }
+}
+
func TestSubImage(t *testing.T) {
m0 := image.NewRGBA(image.Rect(0, 0, 256, 256))
for y := 0; y < 256; y++ {
diff --git a/libgo/go/image/testdata/video-001.separate.dc.progression.jpeg b/libgo/go/image/testdata/video-001.separate.dc.progression.jpeg
new file mode 100644
index 0000000000..107f0fa0cd
--- /dev/null
+++ b/libgo/go/image/testdata/video-001.separate.dc.progression.jpeg
Binary files differ
diff --git a/libgo/go/image/testdata/video-001.separate.dc.progression.progressive.jpeg b/libgo/go/image/testdata/video-001.separate.dc.progression.progressive.jpeg
new file mode 100644
index 0000000000..a1d493ef80
--- /dev/null
+++ b/libgo/go/image/testdata/video-001.separate.dc.progression.progressive.jpeg
Binary files differ
diff --git a/libgo/go/image/testdata/video-005.gray.gif b/libgo/go/image/testdata/video-005.gray.gif
new file mode 100644
index 0000000000..23350d6dc1
--- /dev/null
+++ b/libgo/go/image/testdata/video-005.gray.gif
Binary files differ
diff --git a/libgo/go/image/ycbcr.go b/libgo/go/image/ycbcr.go
index 5b73bef789..7c773f2f0a 100644
--- a/libgo/go/image/ycbcr.go
+++ b/libgo/go/image/ycbcr.go
@@ -60,6 +60,10 @@ func (p *YCbCr) Bounds() Rectangle {
}
func (p *YCbCr) At(x, y int) color.Color {
+ return p.YCbCrAt(x, y)
+}
+
+func (p *YCbCr) YCbCrAt(x, y int) color.YCbCr {
if !(Point{x, y}.In(p.Rect)) {
return color.YCbCr{}
}
diff --git a/libgo/go/index/suffixarray/suffixarray_test.go b/libgo/go/index/suffixarray/suffixarray_test.go
index df3e449d32..644f00c757 100644
--- a/libgo/go/index/suffixarray/suffixarray_test.go
+++ b/libgo/go/index/suffixarray/suffixarray_test.go
@@ -287,7 +287,7 @@ func BenchmarkNewIndexRepeat(b *testing.B) {
func BenchmarkSaveRestore(b *testing.B) {
b.StopTimer()
r := rand.New(rand.NewSource(0x5a77a1)) // guarantee always same sequence
- data := make([]byte, 10<<20) // 10MB of data to index
+ data := make([]byte, 1<<20) // 1MB of data to index
for i := range data {
data[i] = byte(r.Intn(256))
}
diff --git a/libgo/go/internal/syscall/dummy.go b/libgo/go/internal/syscall/dummy.go
new file mode 100644
index 0000000000..b00eb273f9
--- /dev/null
+++ b/libgo/go/internal/syscall/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 syscall
diff --git a/libgo/go/internal/syscall/getrandom_linux.go b/libgo/go/internal/syscall/getrandom_linux.go
new file mode 100644
index 0000000000..944bab3f5d
--- /dev/null
+++ b/libgo/go/internal/syscall/getrandom_linux.go
@@ -0,0 +1,56 @@
+// 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/io/io.go b/libgo/go/io/io.go
index f7073ffc06..7507a84929 100644
--- a/libgo/go/io/io.go
+++ b/libgo/go/io/io.go
@@ -62,8 +62,11 @@ var ErrNoProgress = errors.New("multiple Read calls return no data or error")
// allowed EOF behaviors.
//
// Implementations of Read are discouraged from returning a
-// zero byte count with a nil error, and callers should treat
-// that situation as a no-op.
+// zero byte count with a nil error, except when len(p) == 0.
+// Callers should treat a return of 0 and nil as indicating that
+// nothing happened; in particular it does not indicate EOF.
+//
+// Implementations must not retain p.
type Reader interface {
Read(p []byte) (n int, err error)
}
@@ -74,6 +77,9 @@ type Reader interface {
// It returns the number of bytes written from p (0 <= n <= len(p))
// and any error encountered that caused the write to stop early.
// Write must return a non-nil error if it returns n < len(p).
+// Write must not modify the slice data, even temporarily.
+//
+// Implementations must not retain p.
type Writer interface {
Write(p []byte) (n int, err error)
}
@@ -191,6 +197,8 @@ type WriterTo interface {
//
// Clients of ReadAt can execute parallel ReadAt calls on the
// same input source.
+//
+// Implementations must not retain p.
type ReaderAt interface {
ReadAt(p []byte, off int64) (n int, err error)
}
@@ -208,6 +216,8 @@ type ReaderAt interface {
//
// Clients of WriteAt can execute parallel WriteAt calls on the same
// destination if the ranges do not overlap.
+//
+// Implementations must not retain p.
type WriterAt interface {
WriteAt(p []byte, off int64) (n int, err error)
}
diff --git a/libgo/go/io/io_test.go b/libgo/go/io/io_test.go
index bd7a82f17b..57db1fbf0b 100644
--- a/libgo/go/io/io_test.go
+++ b/libgo/go/io/io_test.go
@@ -281,6 +281,8 @@ func TestSectionReader_ReadAt(t *testing.T) {
{data: dat, off: 3, n: len(dat), bufLen: len(dat) / 2, at: 2, exp: dat[5 : 5+len(dat)/2], err: nil},
{data: dat, off: 3, n: len(dat) / 2, bufLen: len(dat)/2 - 2, at: 2, exp: dat[5 : 5+len(dat)/2-2], err: nil},
{data: dat, off: 3, n: len(dat) / 2, bufLen: len(dat)/2 + 2, at: 2, exp: dat[5 : 5+len(dat)/2-2], err: EOF},
+ {data: dat, off: 0, n: 0, bufLen: 0, at: -1, exp: "", err: EOF},
+ {data: dat, off: 0, n: 0, bufLen: 0, at: 1, exp: "", err: EOF},
}
for i, tt := range tests {
r := strings.NewReader(tt.data)
@@ -319,3 +321,21 @@ func TestSectionReader_Seek(t *testing.T) {
t.Errorf("Read = %v, %v; want 0, EOF", n, err)
}
}
+
+func TestSectionReader_Size(t *testing.T) {
+ tests := []struct {
+ data string
+ want int64
+ }{
+ {"a long sample data, 1234567890", 30},
+ {"", 0},
+ }
+
+ for _, tt := range tests {
+ r := strings.NewReader(tt.data)
+ sr := NewSectionReader(r, 0, int64(len(tt.data)))
+ if got := sr.Size(); got != tt.want {
+ t.Errorf("Size = %v; want %v", got, tt.want)
+ }
+ }
+}
diff --git a/libgo/go/io/ioutil/blackhole.go b/libgo/go/io/ioutil/blackhole.go
deleted file mode 100644
index 101d2c1215..0000000000
--- a/libgo/go/io/ioutil/blackhole.go
+++ /dev/null
@@ -1,23 +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 ioutil
-
-var blackHoleBuf = make(chan []byte, 1)
-
-func blackHole() []byte {
- select {
- case b := <-blackHoleBuf:
- return b
- default:
- }
- return make([]byte, 8192)
-}
-
-func blackHolePut(p []byte) {
- select {
- case blackHoleBuf <- p:
- default:
- }
-}
diff --git a/libgo/go/io/ioutil/ioutil.go b/libgo/go/io/ioutil/ioutil.go
index b2508b7899..909a815632 100644
--- a/libgo/go/io/ioutil/ioutil.go
+++ b/libgo/go/io/ioutil/ioutil.go
@@ -10,6 +10,7 @@ import (
"io"
"os"
"sort"
+ "sync"
)
// readAll reads from r until an error or EOF and returns the data it read
@@ -136,14 +137,21 @@ func (devNull) WriteString(s string) (int, error) {
return len(s), nil
}
+var blackHolePool = sync.Pool{
+ New: func() interface{} {
+ b := make([]byte, 8192)
+ return &b
+ },
+}
+
func (devNull) ReadFrom(r io.Reader) (n int64, err error) {
- buf := blackHole()
- defer blackHolePut(buf)
+ bufp := blackHolePool.Get().(*[]byte)
readSize := 0
for {
- readSize, err = r.Read(buf)
+ readSize, err = r.Read(*bufp)
n += int64(readSize)
if err != nil {
+ blackHolePool.Put(bufp)
if err == io.EOF {
return n, nil
}
diff --git a/libgo/go/io/multi.go b/libgo/go/io/multi.go
index 2c7e816cff..e26cc53e9e 100644
--- a/libgo/go/io/multi.go
+++ b/libgo/go/io/multi.go
@@ -26,9 +26,12 @@ func (mr *multiReader) Read(p []byte) (n int, err error) {
// MultiReader returns a Reader that's the logical concatenation of
// the provided input readers. They're read sequentially. Once all
-// inputs are drained, Read will return EOF.
+// inputs have returned EOF, Read will return EOF. If any of the readers
+// return a non-nil, non-EOF error, Read will return that error.
func MultiReader(readers ...Reader) Reader {
- return &multiReader{readers}
+ r := make([]Reader, len(readers))
+ copy(r, readers)
+ return &multiReader{r}
}
type multiWriter struct {
@@ -52,5 +55,7 @@ func (t *multiWriter) Write(p []byte) (n int, err error) {
// MultiWriter creates a writer that duplicates its writes to all the
// provided writers, similar to the Unix tee(1) command.
func MultiWriter(writers ...Writer) Writer {
- return &multiWriter{writers}
+ w := make([]Writer, len(writers))
+ copy(w, writers)
+ return &multiWriter{w}
}
diff --git a/libgo/go/io/multi_test.go b/libgo/go/io/multi_test.go
index eb717f7bc2..56c6769a9e 100644
--- a/libgo/go/io/multi_test.go
+++ b/libgo/go/io/multi_test.go
@@ -9,6 +9,7 @@ import (
"crypto/sha1"
"fmt"
. "io"
+ "io/ioutil"
"strings"
"testing"
)
@@ -86,3 +87,29 @@ func TestMultiWriter(t *testing.T) {
t.Errorf("expected %q; got %q", sourceString, sink.String())
}
}
+
+// Test that MultiReader copies the input slice and is insulated from future modification.
+func TestMultiReaderCopy(t *testing.T) {
+ slice := []Reader{strings.NewReader("hello world")}
+ r := MultiReader(slice...)
+ slice[0] = nil
+ data, err := ioutil.ReadAll(r)
+ if err != nil || string(data) != "hello world" {
+ t.Errorf("ReadAll() = %q, %v, want %q, nil", data, err, "hello world")
+ }
+}
+
+// Test that MultiWriter copies the input slice and is insulated from future modification.
+func TestMultiWriterCopy(t *testing.T) {
+ var buf bytes.Buffer
+ slice := []Writer{&buf}
+ w := MultiWriter(slice...)
+ slice[0] = nil
+ n, err := w.Write([]byte("hello world"))
+ if err != nil || n != 11 {
+ t.Errorf("Write(`hello world`) = %d, %v, want 11, nil", n, err)
+ }
+ if buf.String() != "hello world" {
+ t.Errorf("buf.String() = %q, want %q", buf.String(), "hello world")
+ }
+}
diff --git a/libgo/go/log/syslog/syslog.go b/libgo/go/log/syslog/syslog.go
index 0cbfa9011b..5e09599162 100644
--- a/libgo/go/log/syslog/syslog.go
+++ b/libgo/go/log/syslog/syslog.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 !windows,!plan9
+// +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
@@ -115,9 +115,10 @@ func New(priority Priority, tag string) (w *Writer, err error) {
}
// Dial establishes a connection to a log daemon by connecting to
-// address raddr on the network net. Each write to the returned
+// address raddr on the specified network. Each write to the returned
// writer sends a log message with the given facility, severity and
// tag.
+// If network is empty, Dial will connect to the local syslog server.
func Dial(network, raddr string, priority Priority, tag string) (*Writer, error) {
if priority < 0 || priority > LOG_LOCAL7|LOG_DEBUG {
return nil, errors.New("log/syslog: invalid priority")
diff --git a/libgo/go/log/syslog/syslog_test.go b/libgo/go/log/syslog/syslog_test.go
index 760a5c7d1e..6a863fed31 100644
--- a/libgo/go/log/syslog/syslog_test.go
+++ b/libgo/go/log/syslog/syslog_test.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 !windows,!plan9
+// +build !windows,!nacl,!plan9
package syslog
@@ -314,7 +314,7 @@ func TestConcurrentReconnect(t *testing.T) {
count := make(chan int)
go func() {
ct := 0
- for _ = range done {
+ for range done {
ct++
// we are looking for 500 out of 1000 events
// here because lots of log messages are lost
diff --git a/libgo/go/log/syslog/syslog_unix.go b/libgo/go/log/syslog/syslog_unix.go
index 28a294af96..1cdabec692 100644
--- a/libgo/go/log/syslog/syslog_unix.go
+++ b/libgo/go/log/syslog/syslog_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 !windows,!plan9
+// +build !windows,!nacl,!plan9
package syslog
@@ -16,7 +16,7 @@ import (
func unixSyslog() (conn serverConn, err error) {
logTypes := []string{"unixgram", "unix"}
- logPaths := []string{"/dev/log", "/var/run/syslog"}
+ logPaths := []string{"/dev/log", "/var/run/syslog", "/var/run/log"}
for _, network := range logTypes {
for _, path := range logPaths {
conn, err := net.Dial(network, path)
diff --git a/libgo/go/math/all_test.go b/libgo/go/math/all_test.go
index 0d8b10f67f..763efb2e64 100644
--- a/libgo/go/math/all_test.go
+++ b/libgo/go/math/all_test.go
@@ -456,7 +456,19 @@ var modf = [][2]float64{
{1.0000000000000000e+00, 8.2530809168085506044576505e-01},
{-8.0000000000000000e+00, -6.8592476857560136238589621e-01},
}
-var nextafter = []float64{
+var nextafter32 = []float32{
+ 4.979012489318848e+00,
+ 7.738873004913330e+00,
+ -2.768800258636475e-01,
+ -5.010602951049805e+00,
+ 9.636294364929199e+00,
+ 2.926377534866333e+00,
+ 5.229084014892578e+00,
+ 2.727940082550049e+00,
+ 1.825308203697205e+00,
+ -8.685923576354980e+00,
+}
+var nextafter64 = []float64{
4.97901192488367438926388786e+00,
7.73887247457810545370193722e+00,
-2.7688005719200153853520874e-01,
@@ -1331,7 +1343,32 @@ var modfSC = [][2]float64{
{NaN(), NaN()},
}
-var vfnextafterSC = [][2]float64{
+var vfnextafter32SC = [][2]float32{
+ {0, 0},
+ {0, float32(Copysign(0, -1))},
+ {0, -1},
+ {0, float32(NaN())},
+ {float32(Copysign(0, -1)), 1},
+ {float32(Copysign(0, -1)), 0},
+ {float32(Copysign(0, -1)), float32(Copysign(0, -1))},
+ {float32(Copysign(0, -1)), -1},
+ {float32(NaN()), 0},
+ {float32(NaN()), float32(NaN())},
+}
+var nextafter32SC = []float32{
+ 0,
+ 0,
+ -1.401298464e-45, // Float32frombits(0x80000001)
+ float32(NaN()),
+ 1.401298464e-45, // Float32frombits(0x00000001)
+ float32(Copysign(0, -1)),
+ float32(Copysign(0, -1)),
+ -1.401298464e-45, // Float32frombits(0x80000001)
+ float32(NaN()),
+ float32(NaN()),
+}
+
+var vfnextafter64SC = [][2]float64{
{0, 0},
{0, Copysign(0, -1)},
{0, -1},
@@ -1343,7 +1380,7 @@ var vfnextafterSC = [][2]float64{
{NaN(), 0},
{NaN(), NaN()},
}
-var nextafterSC = []float64{
+var nextafter64SC = []float64{
0,
0,
-4.9406564584124654418e-324, // Float64frombits(0x8000000000000001)
@@ -2303,15 +2340,29 @@ func TestModf(t *testing.T) {
}
}
-func TestNextafter(t *testing.T) {
+func TestNextafter32(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ vfi := float32(vf[i])
+ if f := Nextafter32(vfi, 10); nextafter32[i] != f {
+ t.Errorf("Nextafter32(%g, %g) = %g want %g", vfi, 10.0, f, nextafter32[i])
+ }
+ }
+ for i := 0; i < len(vfnextafter32SC); i++ {
+ if f := Nextafter32(vfnextafter32SC[i][0], vfnextafter32SC[i][1]); !alike(float64(nextafter32SC[i]), float64(f)) {
+ t.Errorf("Nextafter32(%g, %g) = %g want %g", vfnextafter32SC[i][0], vfnextafter32SC[i][1], f, nextafter32SC[i])
+ }
+ }
+}
+
+func TestNextafter64(t *testing.T) {
for i := 0; i < len(vf); i++ {
- if f := Nextafter(vf[i], 10); nextafter[i] != f {
- t.Errorf("Nextafter(%g, %g) = %g want %g", vf[i], 10.0, f, nextafter[i])
+ if f := Nextafter(vf[i], 10); nextafter64[i] != f {
+ t.Errorf("Nextafter64(%g, %g) = %g want %g", vf[i], 10.0, f, nextafter64[i])
}
}
- for i := 0; i < len(vfnextafterSC); i++ {
- if f := Nextafter(vfnextafterSC[i][0], vfnextafterSC[i][1]); !alike(nextafterSC[i], f) {
- t.Errorf("Nextafter(%g, %g) = %g want %g", vfnextafterSC[i][0], vfnextafterSC[i][1], f, nextafterSC[i])
+ for i := 0; i < len(vfnextafter64SC); i++ {
+ if f := Nextafter(vfnextafter64SC[i][0], vfnextafter64SC[i][1]); !alike(nextafter64SC[i], f) {
+ t.Errorf("Nextafter64(%g, %g) = %g want %g", vfnextafter64SC[i][0], vfnextafter64SC[i][1], f, nextafter64SC[i])
}
}
}
@@ -2827,7 +2878,13 @@ func BenchmarkModf(b *testing.B) {
}
}
-func BenchmarkNextafter(b *testing.B) {
+func BenchmarkNextafter32(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Nextafter32(.5, 1)
+ }
+}
+
+func BenchmarkNextafter64(b *testing.B) {
for i := 0; i < b.N; i++ {
Nextafter(.5, 1)
}
diff --git a/libgo/go/math/big/arith.go b/libgo/go/math/big/arith.go
index 306bf0ac65..c5ff4252d5 100644
--- a/libgo/go/math/big/arith.go
+++ b/libgo/go/math/big/arith.go
@@ -136,12 +136,11 @@ func divWW_g(u1, u0, v Word) (q, r Word) {
q1 := un32 / vn1
rhat := un32 - q1*vn1
-again1:
- if q1 >= _B2 || q1*vn0 > _B2*rhat+un1 {
+ for q1 >= _B2 || q1*vn0 > _B2*rhat+un1 {
q1--
rhat += vn1
- if rhat < _B2 {
- goto again1
+ if rhat >= _B2 {
+ break
}
}
@@ -149,12 +148,11 @@ again1:
q0 := un21 / vn1
rhat = un21 - q0*vn1
-again2:
- if q0 >= _B2 || q0*vn0 > _B2*rhat+un0 {
+ for q0 >= _B2 || q0*vn0 > _B2*rhat+un0 {
q0--
rhat += vn1
- if rhat < _B2 {
- goto again2
+ if rhat >= _B2 {
+ break
}
}
diff --git a/libgo/go/math/big/int.go b/libgo/go/math/big/int.go
index 7bbb152d79..ade5c2fc8c 100644
--- a/libgo/go/math/big/int.go
+++ b/libgo/go/math/big/int.go
@@ -510,10 +510,30 @@ func (z *Int) Scan(s fmt.ScanState, ch rune) error {
return err
}
+// low32 returns the least significant 32 bits of z.
+func low32(z nat) uint32 {
+ if len(z) == 0 {
+ return 0
+ }
+ return uint32(z[0])
+}
+
+// low64 returns the least significant 64 bits of z.
+func low64(z nat) uint64 {
+ if len(z) == 0 {
+ return 0
+ }
+ v := uint64(z[0])
+ if _W == 32 && len(z) > 1 {
+ v |= uint64(z[1]) << 32
+ }
+ return v
+}
+
// Int64 returns the int64 representation of x.
// If x cannot be represented in an int64, the result is undefined.
func (x *Int) Int64() int64 {
- v := int64(x.Uint64())
+ v := int64(low64(x.abs))
if x.neg {
v = -v
}
@@ -523,14 +543,7 @@ func (x *Int) Int64() int64 {
// Uint64 returns the uint64 representation of x.
// If x cannot be represented in a uint64, the result is undefined.
func (x *Int) Uint64() uint64 {
- if len(x.abs) == 0 {
- return 0
- }
- v := uint64(x.abs[0])
- if _W == 32 && len(x.abs) > 1 {
- v |= uint64(x.abs[1]) << 32
- }
- return v
+ return low64(x.abs)
}
// SetString sets z to the value of s, interpreted in the given base,
@@ -576,21 +589,28 @@ func (x *Int) BitLen() int {
}
// Exp sets z = x**y mod |m| (i.e. the sign of m is ignored), and returns z.
-// If y <= 0, the result is 1; if m == nil or m == 0, z = x**y.
+// If y <= 0, the result is 1 mod |m|; if m == nil or m == 0, z = x**y.
// See Knuth, volume 2, section 4.6.3.
func (z *Int) Exp(x, y, m *Int) *Int {
- if y.neg || len(y.abs) == 0 {
- return z.SetInt64(1)
+ var yWords nat
+ if !y.neg {
+ yWords = y.abs
}
- // y > 0
+ // y >= 0
var mWords nat
if m != nil {
mWords = m.abs // m.abs may be nil for m == 0
}
- z.abs = z.abs.expNN(x.abs, y.abs, mWords)
- z.neg = len(z.abs) > 0 && x.neg && y.abs[0]&1 == 1 // 0 has no sign
+ z.abs = z.abs.expNN(x.abs, yWords, mWords)
+ z.neg = len(z.abs) > 0 && x.neg && len(yWords) > 0 && yWords[0]&1 == 1 // 0 has no sign
+ if z.neg && len(mWords) > 0 {
+ // make modulus result positive
+ z.abs = z.abs.sub(mWords, z.abs) // z == x**y mod |m| && 0 <= z < |m|
+ z.neg = false
+ }
+
return z
}
@@ -732,15 +752,16 @@ func (z *Int) Rand(rnd *rand.Rand, n *Int) *Int {
return z
}
-// ModInverse sets z to the multiplicative inverse of g in the group ℤ/pℤ (where
-// p is a prime) and returns z.
-func (z *Int) ModInverse(g, p *Int) *Int {
+// ModInverse sets z to the multiplicative inverse of g in the ring ℤ/nℤ
+// and returns z. If g and n are not relatively prime, the result is undefined.
+func (z *Int) ModInverse(g, n *Int) *Int {
var d Int
- d.GCD(z, nil, g, p)
- // x and y are such that g*x + p*y = d. Since p is prime, d = 1. Taking
- // that modulo p results in g*x = 1, therefore x is the inverse element.
+ d.GCD(z, nil, g, n)
+ // x and y are such that g*x + n*y = d. Since g and n are
+ // relatively prime, d = 1. Taking that modulo n results in
+ // g*x = 1, therefore x is the inverse element.
if z.neg {
- z.Add(z, p)
+ z.Add(z, n)
}
return z
}
@@ -866,7 +887,7 @@ func (z *Int) AndNot(x, y *Int) *Int {
}
// x &^ (-y) == x &^ ^(y-1) == x & (y-1)
- y1 := nat(nil).add(y.abs, natOne)
+ y1 := nat(nil).sub(y.abs, natOne)
z.abs = z.abs.and(x.abs, y1)
z.neg = false
return z
@@ -982,17 +1003,29 @@ func (z *Int) GobDecode(buf []byte) error {
}
// MarshalJSON implements the json.Marshaler interface.
-func (x *Int) MarshalJSON() ([]byte, error) {
+func (z *Int) MarshalJSON() ([]byte, error) {
// TODO(gri): get rid of the []byte/string conversions
- return []byte(x.String()), nil
+ return []byte(z.String()), nil
}
// UnmarshalJSON implements the json.Unmarshaler interface.
-func (z *Int) UnmarshalJSON(x []byte) error {
+func (z *Int) UnmarshalJSON(text []byte) error {
// TODO(gri): get rid of the []byte/string conversions
- _, ok := z.SetString(string(x), 0)
- if !ok {
- return fmt.Errorf("math/big: cannot unmarshal %s into a *big.Int", x)
+ if _, ok := z.SetString(string(text), 0); !ok {
+ return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Int", text)
+ }
+ return nil
+}
+
+// MarshalText implements the encoding.TextMarshaler interface.
+func (z *Int) MarshalText() (text []byte, err error) {
+ return []byte(z.String()), nil
+}
+
+// UnmarshalText implements the encoding.TextUnmarshaler interface.
+func (z *Int) UnmarshalText(text []byte) error {
+ if _, ok := z.SetString(string(text), 0); !ok {
+ return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Int", text)
}
return nil
}
diff --git a/libgo/go/math/big/int_test.go b/libgo/go/math/big/int_test.go
index 87b975d5c4..2d762dbc89 100644
--- a/libgo/go/math/big/int_test.go
+++ b/libgo/go/math/big/int_test.go
@@ -9,6 +9,7 @@ import (
"encoding/gob"
"encoding/hex"
"encoding/json"
+ "encoding/xml"
"fmt"
"math/rand"
"testing"
@@ -767,12 +768,26 @@ var expTests = []struct {
x, y, m string
out string
}{
+ // y <= 0
+ {"0", "0", "", "1"},
+ {"1", "0", "", "1"},
+ {"-10", "0", "", "1"},
+ {"1234", "-1", "", "1"},
+
+ // m == 1
+ {"0", "0", "1", "0"},
+ {"1", "0", "1", "0"},
+ {"-10", "0", "1", "0"},
+ {"1234", "-1", "1", "0"},
+
+ // misc
{"5", "-7", "", "1"},
{"-5", "-7", "", "1"},
{"5", "0", "", "1"},
{"-5", "0", "", "1"},
{"5", "1", "", "5"},
{"-5", "1", "", "-5"},
+ {"-5", "1", "7", "2"},
{"-2", "3", "2", "0"},
{"5", "2", "", "25"},
{"1", "65537", "2", "1"},
@@ -788,6 +803,13 @@ var expTests = []struct {
"29834729834729834729347290846729561262544958723956495615629569234729836259263598127342374289365912465901365498236492183464",
"23537740700184054162508175125554701713153216681790245129157191391322321508055833908509185839069455749219131480588829346291",
},
+ // test case for issue 8822
+ {
+ "-0x1BCE04427D8032319A89E5C4136456671AC620883F2C4139E57F91307C485AD2D6204F4F87A58262652DB5DBBAC72B0613E51B835E7153BEC6068F5C8D696B74DBD18FEC316AEF73985CF0475663208EB46B4F17DD9DA55367B03323E5491A70997B90C059FB34809E6EE55BCFBD5F2F52233BFE62E6AA9E4E26A1D4C2439883D14F2633D55D8AA66A1ACD5595E778AC3A280517F1157989E70C1A437B849F1877B779CC3CDDEDE2DAA6594A6C66D181A00A5F777EE60596D8773998F6E988DEAE4CCA60E4DDCF9590543C89F74F603259FCAD71660D30294FBBE6490300F78A9D63FA660DC9417B8B9DDA28BEB3977B621B988E23D4D954F322C3540541BC649ABD504C50FADFD9F0987D58A2BF689313A285E773FF02899A6EF887D1D4A0D2",
+ "0xB08FFB20760FFED58FADA86DFEF71AD72AA0FA763219618FE022C197E54708BB1191C66470250FCE8879487507CEE41381CA4D932F81C2B3F1AB20B539D50DCD",
+ "0xAC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73",
+ "21484252197776302499639938883777710321993113097987201050501182909581359357618579566746556372589385361683610524730509041328855066514963385522570894839035884713051640171474186548713546686476761306436434146475140156284389181808675016576845833340494848283681088886584219750554408060556769486628029028720727393293111678826356480455433909233520504112074401376133077150471237549474149190242010469539006449596611576612573955754349042329130631128234637924786466585703488460540228477440853493392086251021228087076124706778899179648655221663765993962724699135217212118535057766739392069738618682722216712319320435674779146070442",
+ },
}
func TestExp(t *testing.T) {
@@ -819,12 +841,12 @@ func TestExp(t *testing.T) {
}
if m == nil {
- // the result should be the same as for m == 0;
- // specifically, there should be no div-zero panic
+ // The result should be the same as for m == 0;
+ // specifically, there should be no div-zero panic.
m = &Int{abs: nat{}} // m != nil && len(m.abs) == 0
z2 := new(Int).Exp(x, y, m)
if z2.Cmp(z1) != 0 {
- t.Errorf("#%d: got %s want %s", i, z1, z2)
+ t.Errorf("#%d: got %s want %s", i, z2, z1)
}
}
}
@@ -1179,6 +1201,7 @@ var bitwiseTests = []struct {
{"-0x01", "-0x01", "-0x01", "-0x01", "0x00", "0x00"},
{"0x07", "0x08", "0x00", "0x0f", "0x0f", "0x07"},
{"0x05", "0x0f", "0x05", "0x0f", "0x0a", "0x00"},
+ {"0xff", "-0x0a", "0xf6", "-0x01", "-0xf7", "0x09"},
{"0x013ff6", "0x9a4e", "0x1a46", "0x01bffe", "0x01a5b8", "0x0125b0"},
{"-0x013ff6", "0x9a4e", "0x800a", "-0x0125b2", "-0x01a5bc", "-0x01c000"},
{"-0x013ff6", "-0x9a4e", "-0x01bffe", "-0x1a46", "0x01a5b8", "0x8008"},
@@ -1426,24 +1449,40 @@ func TestNot(t *testing.T) {
var modInverseTests = []struct {
element string
- prime string
+ modulus string
}{
- {"1", "7"},
- {"1", "13"},
+ {"1234567", "458948883992"},
{"239487239847", "2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919"},
}
func TestModInverse(t *testing.T) {
- var element, prime Int
+ var element, modulus, gcd, inverse Int
one := NewInt(1)
for i, test := range modInverseTests {
(&element).SetString(test.element, 10)
- (&prime).SetString(test.prime, 10)
- inverse := new(Int).ModInverse(&element, &prime)
- inverse.Mul(inverse, &element)
- inverse.Mod(inverse, &prime)
- if inverse.Cmp(one) != 0 {
- t.Errorf("#%d: failed (e·e^(-1)=%s)", i, inverse)
+ (&modulus).SetString(test.modulus, 10)
+ (&inverse).ModInverse(&element, &modulus)
+ (&inverse).Mul(&inverse, &element)
+ (&inverse).Mod(&inverse, &modulus)
+ if (&inverse).Cmp(one) != 0 {
+ t.Errorf("#%d: failed (e·e^(-1)=%s)", i, &inverse)
+ }
+ }
+ // exhaustive test for small values
+ for n := 2; n < 100; n++ {
+ (&modulus).SetInt64(int64(n))
+ for x := 1; x < n; x++ {
+ (&element).SetInt64(int64(x))
+ (&gcd).GCD(nil, nil, &element, &modulus)
+ if (&gcd).Cmp(one) != 0 {
+ continue
+ }
+ (&inverse).ModInverse(&element, &modulus)
+ (&inverse).Mul(&inverse, &element)
+ (&inverse).Mod(&inverse, &modulus)
+ if (&inverse).Cmp(one) != 0 {
+ t.Errorf("ModInverse(%d,%d)*%d%%%d=%d, not 1", &element, &modulus, &element, &modulus, &inverse)
+ }
}
}
}
@@ -1528,6 +1567,58 @@ func TestIntJSONEncoding(t *testing.T) {
}
}
+var intVals = []string{
+ "-141592653589793238462643383279502884197169399375105820974944592307816406286",
+ "-1415926535897932384626433832795028841971",
+ "-141592653589793",
+ "-1",
+ "0",
+ "1",
+ "141592653589793",
+ "1415926535897932384626433832795028841971",
+ "141592653589793238462643383279502884197169399375105820974944592307816406286",
+}
+
+func TestIntJSONEncodingTextMarshaller(t *testing.T) {
+ for _, num := range intVals {
+ var tx Int
+ tx.SetString(num, 0)
+ b, err := json.Marshal(&tx)
+ if err != nil {
+ t.Errorf("marshaling of %s failed: %s", &tx, err)
+ continue
+ }
+ var rx Int
+ if err := json.Unmarshal(b, &rx); err != nil {
+ t.Errorf("unmarshaling of %s failed: %s", &tx, err)
+ continue
+ }
+ if rx.Cmp(&tx) != 0 {
+ t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx)
+ }
+ }
+}
+
+func TestIntXMLEncodingTextMarshaller(t *testing.T) {
+ for _, num := range intVals {
+ var tx Int
+ tx.SetString(num, 0)
+ b, err := xml.Marshal(&tx)
+ if err != nil {
+ t.Errorf("marshaling of %s failed: %s", &tx, err)
+ continue
+ }
+ var rx Int
+ if err := xml.Unmarshal(b, &rx); err != nil {
+ t.Errorf("unmarshaling of %s failed: %s", &tx, err)
+ continue
+ }
+ if rx.Cmp(&tx) != 0 {
+ t.Errorf("XML encoding of %s failed: got %s want %s", &tx, &rx, &tx)
+ }
+ }
+}
+
func TestIssue2607(t *testing.T) {
// This code sequence used to hang.
n := NewInt(10)
diff --git a/libgo/go/math/big/nat.go b/libgo/go/math/big/nat.go
index 6874900d0b..16a87f5c53 100644
--- a/libgo/go/math/big/nat.go
+++ b/libgo/go/math/big/nat.go
@@ -1233,10 +1233,15 @@ func (z nat) expNN(x, y, m nat) nat {
z = nil
}
+ // x**y mod 1 == 0
+ if len(m) == 1 && m[0] == 1 {
+ return z.setWord(0)
+ }
+ // m == 0 || m > 1
+
+ // x**0 == 1
if len(y) == 0 {
- z = z.make(1)
- z[0] = 1
- return z
+ return z.setWord(1)
}
// y > 0
diff --git a/libgo/go/math/big/nat_test.go b/libgo/go/math/big/nat_test.go
index 1d4dfe80d3..a2ae53385c 100644
--- a/libgo/go/math/big/nat_test.go
+++ b/libgo/go/math/big/nat_test.go
@@ -437,20 +437,11 @@ func BenchmarkStringPiParallel(b *testing.B) {
if x.decimalString() != pi {
panic("benchmark incorrect: conversion failed")
}
- n := runtime.GOMAXPROCS(0)
- m := b.N / n // n*m <= b.N due to flooring, but the error is neglibible (n is not very large)
- c := make(chan int, n)
- for i := 0; i < n; i++ {
- go func() {
- for j := 0; j < m; j++ {
- x.decimalString()
- }
- c <- 0
- }()
- }
- for i := 0; i < n; i++ {
- <-c
- }
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ x.decimalString()
+ }
+ })
}
func BenchmarkScan10Base2(b *testing.B) { ScanHelper(b, 2, 10, 10) }
@@ -723,6 +714,12 @@ var expNNTests = []struct {
x, y, m string
out string
}{
+ {"0", "0", "0", "1"},
+ {"0", "0", "1", "0"},
+ {"1", "1", "1", "0"},
+ {"2", "1", "1", "0"},
+ {"2", "2", "1", "0"},
+ {"10", "100000000000", "1", "0"},
{"0x8000000000000000", "2", "", "0x40000000000000000000000000000000"},
{"0x8000000000000000", "2", "6719", "4944"},
{"0x8000000000000000", "3", "6719", "5447"},
@@ -750,7 +747,7 @@ func TestExpNN(t *testing.T) {
z := nat(nil).expNN(x, y, m)
if z.cmp(out) != 0 {
- t.Errorf("#%d got %v want %v", i, z, out)
+ t.Errorf("#%d got %s want %s", i, z.decimalString(), out.decimalString())
}
}
}
diff --git a/libgo/go/math/big/rat.go b/libgo/go/math/big/rat.go
index 7faee61a46..c5339fe443 100644
--- a/libgo/go/math/big/rat.go
+++ b/libgo/go/math/big/rat.go
@@ -47,7 +47,7 @@ func (z *Rat) SetFloat64(f float64) *Rat {
shift := 52 - exp
- // Optimisation (?): partially pre-normalise.
+ // Optimization (?): partially pre-normalise.
for mantissa&1 == 0 && shift > 0 {
mantissa >>= 1
shift--
@@ -64,28 +64,125 @@ func (z *Rat) SetFloat64(f float64) *Rat {
return z.norm()
}
-// 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
-}
+// quotToFloat32 returns the non-negative float32 value
+// nearest to the quotient a/b, using round-to-even in
+// halfway cases. It does not mutate its arguments.
+// Preconditions: b is non-zero; a and b have no common factors.
+func quotToFloat32(a, b nat) (f float32, exact bool) {
+ const (
+ // float size in bits
+ Fsize = 32
+
+ // mantissa
+ Msize = 23
+ Msize1 = Msize + 1 // incl. implicit 1
+ Msize2 = Msize1 + 1
+
+ // exponent
+ Esize = Fsize - Msize1
+ Ebias = 1<<(Esize-1) - 1
+ Emin = 1 - Ebias
+ Emax = Ebias
+ )
+
+ // TODO(adonovan): specialize common degenerate cases: 1.0, integers.
+ alen := a.bitLen()
+ if alen == 0 {
+ return 0, true
+ }
+ blen := b.bitLen()
+ if blen == 0 {
+ panic("division by zero")
+ }
+
+ // 1. Left-shift A or B such that quotient A/B is in [1<<Msize1, 1<<(Msize2+1)
+ // (Msize2 bits if A < B when they are left-aligned, Msize2+1 bits if A >= B).
+ // This is 2 or 3 more than the float32 mantissa field width of Msize:
+ // - the optional extra bit is shifted away in step 3 below.
+ // - the high-order 1 is omitted in "normal" representation;
+ // - the low-order 1 will be used during rounding then discarded.
+ exp := alen - blen
+ var a2, b2 nat
+ a2 = a2.set(a)
+ b2 = b2.set(b)
+ if shift := Msize2 - exp; shift > 0 {
+ a2 = a2.shl(a2, uint(shift))
+ } else if shift < 0 {
+ b2 = b2.shl(b2, uint(-shift))
+ }
+
+ // 2. Compute quotient and remainder (q, r). NB: due to the
+ // extra shift, the low-order bit of q is logically the
+ // high-order bit of r.
+ var q nat
+ q, r := q.div(a2, a2, b2) // (recycle a2)
+ mantissa := low32(q)
+ haveRem := len(r) > 0 // mantissa&1 && !haveRem => remainder is exactly half
-// low64 returns the least significant 64 bits of natural number z.
-func low64(z nat) uint64 {
- if len(z) == 0 {
- return 0
+ // 3. If quotient didn't fit in Msize2 bits, redo division by b2<<1
+ // (in effect---we accomplish this incrementally).
+ if mantissa>>Msize2 == 1 {
+ if mantissa&1 == 1 {
+ haveRem = true
+ }
+ mantissa >>= 1
+ exp++
}
- if _W == 32 && len(z) > 1 {
- return uint64(z[1])<<32 | uint64(z[0])
+ if mantissa>>Msize1 != 1 {
+ panic(fmt.Sprintf("expected exactly %d bits of result", Msize2))
}
- return uint64(z[0])
+
+ // 4. Rounding.
+ if Emin-Msize <= exp && exp <= Emin {
+ // Denormal case; lose 'shift' bits of precision.
+ shift := uint(Emin - (exp - 1)) // [1..Esize1)
+ lostbits := mantissa & (1<<shift - 1)
+ haveRem = haveRem || lostbits != 0
+ mantissa >>= shift
+ exp = 2 - Ebias // == exp + shift
+ }
+ // Round q using round-half-to-even.
+ exact = !haveRem
+ if mantissa&1 != 0 {
+ exact = false
+ if haveRem || mantissa&2 != 0 {
+ if mantissa++; mantissa >= 1<<Msize2 {
+ // Complete rollover 11...1 => 100...0, so shift is safe
+ mantissa >>= 1
+ exp++
+ }
+ }
+ }
+ mantissa >>= 1 // discard rounding bit. Mantissa now scaled by 1<<Msize1.
+
+ f = float32(math.Ldexp(float64(mantissa), exp-Msize1))
+ if math.IsInf(float64(f), 0) {
+ exact = false
+ }
+ return
}
-// quotToFloat returns the non-negative IEEE 754 double-precision
-// value nearest to the quotient a/b, using round-to-even in halfway
-// cases. It does not mutate its arguments.
+// quotToFloat64 returns the non-negative float64 value
+// nearest to the quotient a/b, using round-to-even in
+// halfway cases. It does not mutate its arguments.
// Preconditions: b is non-zero; a and b have no common factors.
-func quotToFloat(a, b nat) (f float64, exact bool) {
+func quotToFloat64(a, b nat) (f float64, exact bool) {
+ const (
+ // float size in bits
+ Fsize = 64
+
+ // mantissa
+ Msize = 52
+ Msize1 = Msize + 1 // incl. implicit 1
+ Msize2 = Msize1 + 1
+
+ // exponent
+ Esize = Fsize - Msize1
+ Ebias = 1<<(Esize-1) - 1
+ Emin = 1 - Ebias
+ Emax = Ebias
+ )
+
// TODO(adonovan): specialize common degenerate cases: 1.0, integers.
alen := a.bitLen()
if alen == 0 {
@@ -96,17 +193,17 @@ func quotToFloat(a, b nat) (f float64, exact bool) {
panic("division by zero")
}
- // 1. Left-shift A or B such that quotient A/B is in [1<<53, 1<<55).
- // (54 bits if A<B when they are left-aligned, 55 bits if A>=B.)
- // This is 2 or 3 more than the float64 mantissa field width of 52:
+ // 1. Left-shift A or B such that quotient A/B is in [1<<Msize1, 1<<(Msize2+1)
+ // (Msize2 bits if A < B when they are left-aligned, Msize2+1 bits if A >= B).
+ // This is 2 or 3 more than the float64 mantissa field width of Msize:
// - the optional extra bit is shifted away in step 3 below.
- // - the high-order 1 is omitted in float64 "normal" representation;
+ // - the high-order 1 is omitted in "normal" representation;
// - the low-order 1 will be used during rounding then discarded.
exp := alen - blen
var a2, b2 nat
a2 = a2.set(a)
b2 = b2.set(b)
- if shift := 54 - exp; shift > 0 {
+ if shift := Msize2 - exp; shift > 0 {
a2 = a2.shl(a2, uint(shift))
} else if shift < 0 {
b2 = b2.shl(b2, uint(-shift))
@@ -120,49 +217,65 @@ func quotToFloat(a, b nat) (f float64, exact bool) {
mantissa := low64(q)
haveRem := len(r) > 0 // mantissa&1 && !haveRem => remainder is exactly half
- // 3. If quotient didn't fit in 54 bits, re-do division by b2<<1
+ // 3. If quotient didn't fit in Msize2 bits, redo division by b2<<1
// (in effect---we accomplish this incrementally).
- if mantissa>>54 == 1 {
+ if mantissa>>Msize2 == 1 {
if mantissa&1 == 1 {
haveRem = true
}
mantissa >>= 1
exp++
}
- if mantissa>>53 != 1 {
- panic("expected exactly 54 bits of result")
+ if mantissa>>Msize1 != 1 {
+ panic(fmt.Sprintf("expected exactly %d bits of result", Msize2))
}
// 4. Rounding.
- if -1022-52 <= exp && exp <= -1022 {
+ if Emin-Msize <= exp && exp <= Emin {
// Denormal case; lose 'shift' bits of precision.
- shift := uint64(-1022 - (exp - 1)) // [1..53)
+ shift := uint(Emin - (exp - 1)) // [1..Esize1)
lostbits := mantissa & (1<<shift - 1)
haveRem = haveRem || lostbits != 0
mantissa >>= shift
- exp = -1023 + 2
+ exp = 2 - Ebias // == exp + shift
}
// Round q using round-half-to-even.
exact = !haveRem
if mantissa&1 != 0 {
exact = false
if haveRem || mantissa&2 != 0 {
- if mantissa++; mantissa >= 1<<54 {
+ if mantissa++; mantissa >= 1<<Msize2 {
// Complete rollover 11...1 => 100...0, so shift is safe
mantissa >>= 1
exp++
}
}
}
- mantissa >>= 1 // discard rounding bit. Mantissa now scaled by 2^53.
+ mantissa >>= 1 // discard rounding bit. Mantissa now scaled by 1<<Msize1.
- f = math.Ldexp(float64(mantissa), exp-53)
+ f = math.Ldexp(float64(mantissa), exp-Msize1)
if math.IsInf(f, 0) {
exact = false
}
return
}
+// Float32 returns the nearest float32 value for x and a bool indicating
+// whether f represents x exactly. If the magnitude of x is too large to
+// be represented by a float32, f is an infinity and exact is false.
+// The sign of f always matches the sign of x, even if f == 0.
+func (x *Rat) Float32() (f float32, exact bool) {
+ b := x.b.abs
+ if len(b) == 0 {
+ b = b.set(natOne) // materialize denominator
+ }
+ f, exact = quotToFloat32(x.a.abs, b)
+ if x.a.neg {
+ f = -f
+ }
+ return
+}
+
// Float64 returns the nearest float64 value for x and a bool indicating
// whether f represents x exactly. If the magnitude of x is too large to
// be represented by a float64, f is an infinity and exact is false.
@@ -172,7 +285,7 @@ func (x *Rat) Float64() (f float64, exact bool) {
if len(b) == 0 {
b = b.set(natOne) // materialize denominator
}
- f, exact = quotToFloat(x.a.abs, b)
+ f, exact = quotToFloat64(x.a.abs, b)
if x.a.neg {
f = -f
}
@@ -439,6 +552,9 @@ func (z *Rat) SetString(s string) (*Rat, bool) {
if z.b.abs, _, err = z.b.abs.scan(strings.NewReader(s), 10); err != nil {
return nil, false
}
+ if len(z.b.abs) == 0 {
+ return nil, false
+ }
return z.norm(), true
}
@@ -477,7 +593,7 @@ func (z *Rat) SetString(s string) (*Rat, bool) {
return z, true
}
-// String returns a string representation of z in the form "a/b" (even if b == 1).
+// 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 {
@@ -486,7 +602,7 @@ func (x *Rat) String() string {
return x.a.String() + s
}
-// RatString returns a string representation of z in the form "a/b" if b != 1,
+// 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() {
@@ -495,7 +611,7 @@ func (x *Rat) RatString() string {
return x.String()
}
-// FloatString returns a string representation of z in decimal form with prec
+// 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() {
@@ -585,3 +701,16 @@ func (z *Rat) GobDecode(buf []byte) error {
z.b.abs = z.b.abs.setBytes(buf[i:])
return nil
}
+
+// MarshalText implements the encoding.TextMarshaler interface.
+func (r *Rat) MarshalText() (text []byte, err error) {
+ return []byte(r.RatString()), nil
+}
+
+// UnmarshalText implements the encoding.TextUnmarshaler interface.
+func (r *Rat) UnmarshalText(text []byte) error {
+ if _, ok := r.SetString(string(text)); !ok {
+ return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Rat", text)
+ }
+ return nil
+}
diff --git a/libgo/go/math/big/rat_test.go b/libgo/go/math/big/rat_test.go
index 0d432637ba..5dbbb3510f 100644
--- a/libgo/go/math/big/rat_test.go
+++ b/libgo/go/math/big/rat_test.go
@@ -7,6 +7,8 @@ package big
import (
"bytes"
"encoding/gob"
+ "encoding/json"
+ "encoding/xml"
"fmt"
"math"
"strconv"
@@ -87,6 +89,7 @@ var setStringTests = []struct {
{"53/70893980658822810696", "53/70893980658822810696", true},
{"106/141787961317645621392", "53/70893980658822810696", true},
{"204211327800791583.81095", "4084226556015831676219/20000", true},
+ {in: "1/0", ok: false},
}
func TestRatSetString(t *testing.T) {
@@ -433,6 +436,69 @@ func TestGobEncodingNilRatInSlice(t *testing.T) {
}
}
+var ratNums = []string{
+ "-141592653589793238462643383279502884197169399375105820974944592307816406286",
+ "-1415926535897932384626433832795028841971",
+ "-141592653589793",
+ "-1",
+ "0",
+ "1",
+ "141592653589793",
+ "1415926535897932384626433832795028841971",
+ "141592653589793238462643383279502884197169399375105820974944592307816406286",
+}
+
+var ratDenoms = []string{
+ "1",
+ "718281828459045",
+ "7182818284590452353602874713526624977572",
+ "718281828459045235360287471352662497757247093699959574966967627724076630353",
+}
+
+func TestRatJSONEncoding(t *testing.T) {
+ for _, num := range ratNums {
+ for _, denom := range ratDenoms {
+ var tx Rat
+ tx.SetString(num + "/" + denom)
+ b, err := json.Marshal(&tx)
+ if err != nil {
+ t.Errorf("marshaling of %s failed: %s", &tx, err)
+ continue
+ }
+ var rx Rat
+ if err := json.Unmarshal(b, &rx); err != nil {
+ t.Errorf("unmarshaling of %s failed: %s", &tx, err)
+ continue
+ }
+ if rx.Cmp(&tx) != 0 {
+ t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx)
+ }
+ }
+ }
+}
+
+func TestRatXMLEncoding(t *testing.T) {
+ for _, num := range ratNums {
+ for _, denom := range ratDenoms {
+ var tx Rat
+ tx.SetString(num + "/" + denom)
+ b, err := xml.Marshal(&tx)
+ if err != nil {
+ t.Errorf("marshaling of %s failed: %s", &tx, err)
+ continue
+ }
+ var rx Rat
+ if err := xml.Unmarshal(b, &rx); err != nil {
+ t.Errorf("unmarshaling of %s failed: %s", &tx, err)
+ continue
+ }
+ if rx.Cmp(&tx) != 0 {
+ t.Errorf("XML encoding of %s failed: got %s want %s", &tx, &rx, &tx)
+ }
+ }
+ }
+}
+
func TestIssue2379(t *testing.T) {
// 1) no aliasing
q := NewRat(3, 2)
@@ -686,7 +752,6 @@ var float64inputs = []string{
// 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).
@@ -725,6 +790,68 @@ var float64inputs = []string{
"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:") {
@@ -765,13 +892,13 @@ func TestFloat64SpecialCases(t *testing.T) {
}
// 2. Check f is best approximation to r.
- if !checkIsBestApprox(t, f, r) {
+ if !checkIsBestApprox64(t, f, r) {
// Append context information.
t.Errorf("(input was %q)", input)
}
// 3. Check f->R->f roundtrip is non-lossy.
- checkNonLossyRoundtrip(t, f)
+ checkNonLossyRoundtrip64(t, f)
// 4. Check exactness using slow algorithm.
if wasExact := new(Rat).SetFloat64(f).Cmp(r) == 0; wasExact != exact {
@@ -780,6 +907,54 @@ func TestFloat64SpecialCases(t *testing.T) {
}
}
+func TestFloat32Distribution(t *testing.T) {
+ // Generate a distribution of (sign, mantissa, exp) values
+ // broader than the float32 range, and check Rat.Float32()
+ // always picks the closest float32 approximation.
+ var add = []int64{
+ 0,
+ 1,
+ 3,
+ 5,
+ 7,
+ 9,
+ 11,
+ }
+ var winc, einc = uint64(1), 1 // soak test (~1.5s on x86-64)
+ if testing.Short() {
+ winc, einc = 5, 15 // quick test (~60ms on x86-64)
+ }
+
+ for _, sign := range "+-" {
+ for _, a := range add {
+ for wid := uint64(0); wid < 30; wid += winc {
+ b := 1<<wid + a
+ if sign == '-' {
+ b = -b
+ }
+ for exp := -150; exp < 150; exp += einc {
+ num, den := NewInt(b), NewInt(1)
+ if exp > 0 {
+ num.Lsh(num, uint(exp))
+ } else {
+ den.Lsh(den, uint(-exp))
+ }
+ r := new(Rat).SetFrac(num, den)
+ f, _ := r.Float32()
+
+ if !checkIsBestApprox32(t, f, r) {
+ // Append context information.
+ t.Errorf("(input was mantissa %#x, exp %d; f = %g (%b); f ~ %g; r = %v)",
+ b, exp, f, f, math.Ldexp(float64(b), exp), r)
+ }
+
+ checkNonLossyRoundtrip32(t, f)
+ }
+ }
+ }
+ }
+}
+
func TestFloat64Distribution(t *testing.T) {
// Generate a distribution of (sign, mantissa, exp) values
// broader than the float64 range, and check Rat.Float64()
@@ -793,7 +968,7 @@ func TestFloat64Distribution(t *testing.T) {
9,
11,
}
- var winc, einc = uint64(1), int(1) // soak test (~75s on x86-64)
+ var winc, einc = uint64(1), 1 // soak test (~75s on x86-64)
if testing.Short() {
winc, einc = 10, 500 // quick test (~12ms on x86-64)
}
@@ -801,7 +976,7 @@ func TestFloat64Distribution(t *testing.T) {
for _, sign := range "+-" {
for _, a := range add {
for wid := uint64(0); wid < 60; wid += winc {
- b := int64(1<<wid + a)
+ b := 1<<wid + a
if sign == '-' {
b = -b
}
@@ -815,20 +990,20 @@ func TestFloat64Distribution(t *testing.T) {
r := new(Rat).SetFrac(num, den)
f, _ := r.Float64()
- if !checkIsBestApprox(t, f, r) {
+ if !checkIsBestApprox64(t, f, r) {
// Append context information.
t.Errorf("(input was mantissa %#x, exp %d; f = %g (%b); f ~ %g; r = %v)",
b, exp, f, f, math.Ldexp(float64(b), exp), r)
}
- checkNonLossyRoundtrip(t, f)
+ checkNonLossyRoundtrip64(t, f)
}
}
}
}
}
-// TestFloat64NonFinite checks that SetFloat64 of a non-finite value
+// TestSetFloat64NonFinite checks that SetFloat64 of a non-finite value
// returns nil.
func TestSetFloat64NonFinite(t *testing.T) {
for _, f := range []float64{math.NaN(), math.Inf(+1), math.Inf(-1)} {
@@ -839,9 +1014,27 @@ func TestSetFloat64NonFinite(t *testing.T) {
}
}
-// checkNonLossyRoundtrip checks that a float->Rat->float roundtrip is
+// checkNonLossyRoundtrip32 checks that a float->Rat->float roundtrip is
+// non-lossy for finite f.
+func checkNonLossyRoundtrip32(t *testing.T, f float32) {
+ if !isFinite(float64(f)) {
+ return
+ }
+ r := new(Rat).SetFloat64(float64(f))
+ if r == nil {
+ t.Errorf("Rat.SetFloat64(float64(%g) (%b)) == nil", f, f)
+ return
+ }
+ f2, exact := r.Float32()
+ if f != f2 || !exact {
+ t.Errorf("Rat.SetFloat64(float64(%g)).Float32() = %g (%b), %v, want %g (%b), %v; delta = %b",
+ f, f2, f2, exact, f, f, true, f2-f)
+ }
+}
+
+// checkNonLossyRoundtrip64 checks that a float->Rat->float roundtrip is
// non-lossy for finite f.
-func checkNonLossyRoundtrip(t *testing.T, f float64) {
+func checkNonLossyRoundtrip64(t *testing.T, f float64) {
if !isFinite(f) {
return
}
@@ -863,10 +1056,47 @@ func delta(r *Rat, f float64) *Rat {
return d.Abs(d)
}
-// checkIsBestApprox checks that f is the best possible float64
+// checkIsBestApprox32 checks that f is the best possible float32
+// approximation of r.
+// Returns true on success.
+func checkIsBestApprox32(t *testing.T, f float32, r *Rat) bool {
+ if math.Abs(float64(f)) >= math.MaxFloat32 {
+ // Cannot check +Inf, -Inf, nor the float next to them (MaxFloat32).
+ // But we have tests for these special cases.
+ return true
+ }
+
+ // r must be strictly between f0 and f1, the floats bracketing f.
+ f0 := math.Nextafter32(f, float32(math.Inf(-1)))
+ f1 := math.Nextafter32(f, float32(math.Inf(+1)))
+
+ // For f to be correct, r must be closer to f than to f0 or f1.
+ df := delta(r, float64(f))
+ df0 := delta(r, float64(f0))
+ df1 := delta(r, float64(f1))
+ if df.Cmp(df0) > 0 {
+ t.Errorf("Rat(%v).Float32() = %g (%b), but previous float32 %g (%b) is closer", r, f, f, f0, f0)
+ return false
+ }
+ if df.Cmp(df1) > 0 {
+ t.Errorf("Rat(%v).Float32() = %g (%b), but next float32 %g (%b) is closer", r, f, f, f1, f1)
+ return false
+ }
+ if df.Cmp(df0) == 0 && !isEven32(f) {
+ t.Errorf("Rat(%v).Float32() = %g (%b); halfway should have rounded to %g (%b) instead", r, f, f, f0, f0)
+ return false
+ }
+ if df.Cmp(df1) == 0 && !isEven32(f) {
+ t.Errorf("Rat(%v).Float32() = %g (%b); halfway should have rounded to %g (%b) instead", r, f, f, f1, f1)
+ return false
+ }
+ return true
+}
+
+// checkIsBestApprox64 checks that f is the best possible float64
// approximation of r.
// Returns true on success.
-func checkIsBestApprox(t *testing.T, f float64, r *Rat) bool {
+func checkIsBestApprox64(t *testing.T, f float64, r *Rat) bool {
if math.Abs(f) >= math.MaxFloat64 {
// Cannot check +Inf, -Inf, nor the float next to them (MaxFloat64).
// But we have tests for these special cases.
@@ -889,18 +1119,19 @@ func checkIsBestApprox(t *testing.T, f float64, r *Rat) bool {
t.Errorf("Rat(%v).Float64() = %g (%b), but next float64 %g (%b) is closer", r, f, f, f1, f1)
return false
}
- if df.Cmp(df0) == 0 && !isEven(f) {
+ if df.Cmp(df0) == 0 && !isEven64(f) {
t.Errorf("Rat(%v).Float64() = %g (%b); halfway should have rounded to %g (%b) instead", r, f, f, f0, f0)
return false
}
- if df.Cmp(df1) == 0 && !isEven(f) {
+ if df.Cmp(df1) == 0 && !isEven64(f) {
t.Errorf("Rat(%v).Float64() = %g (%b); halfway should have rounded to %g (%b) instead", r, f, f, f1, f1)
return false
}
return true
}
-func isEven(f float64) bool { return math.Float64bits(f)&1 == 0 }
+func isEven32(f float32) bool { return math.Float32bits(f)&1 == 0 }
+func isEven64(f float64) bool { return math.Float64bits(f)&1 == 0 }
func TestIsFinite(t *testing.T) {
finites := []float64{
diff --git a/libgo/go/math/cmplx/cmath_test.go b/libgo/go/math/cmplx/cmath_test.go
index 610ca8cebb..f285646af7 100644
--- a/libgo/go/math/cmplx/cmath_test.go
+++ b/libgo/go/math/cmplx/cmath_test.go
@@ -656,6 +656,19 @@ func TestPolar(t *testing.T) {
}
}
func TestPow(t *testing.T) {
+ // Special cases for Pow(0, c).
+ var zero = complex(0, 0)
+ zeroPowers := [][2]complex128{
+ {0, 1 + 0i},
+ {1.5, 0 + 0i},
+ {-1.5, complex(math.Inf(0), 0)},
+ {-1.5 + 1.5i, Inf()},
+ }
+ for _, zp := range zeroPowers {
+ if f := Pow(zero, zp[0]); f != zp[1] {
+ t.Errorf("Pow(%g, %g) = %g, want %g", zero, zp[0], f, zp[1])
+ }
+ }
var a = complex(3.0, 3.0)
for i := 0; i < len(vc); i++ {
if f := Pow(a, vc[i]); !cSoclose(pow[i], f, 4e-15) {
diff --git a/libgo/go/math/cmplx/pow.go b/libgo/go/math/cmplx/pow.go
index 4dbc58398b..1630b879b8 100644
--- a/libgo/go/math/cmplx/pow.go
+++ b/libgo/go/math/cmplx/pow.go
@@ -43,7 +43,25 @@ import "math"
// IEEE -10,+10 30000 9.4e-15 1.5e-15
// Pow returns x**y, the base-x exponential of y.
+// For generalized compatibility with math.Pow:
+// Pow(0, ±0) returns 1+0i
+// Pow(0, c) for real(c)<0 returns Inf+0i if imag(c) is zero, otherwise Inf+Inf i.
func Pow(x, y complex128) complex128 {
+ if x == 0 { // Guaranteed also true for x == -0.
+ r, i := real(y), imag(y)
+ switch {
+ case r == 0:
+ return 1
+ case r < 0:
+ if i == 0 {
+ return complex(math.Inf(1), 0)
+ }
+ return Inf()
+ case r > 0:
+ return 0
+ }
+ panic("not reached")
+ }
modulus := Abs(x)
if modulus == 0 {
return complex(0, 0)
diff --git a/libgo/go/math/cmplx/sqrt.go b/libgo/go/math/cmplx/sqrt.go
index 179b5396ab..4ef6807add 100644
--- a/libgo/go/math/cmplx/sqrt.go
+++ b/libgo/go/math/cmplx/sqrt.go
@@ -54,6 +54,7 @@ import "math"
// IEEE -10,+10 1,000,000 2.9e-16 6.1e-17
// Sqrt returns the square root of x.
+// The result r is chosen so that real(r) ≥ 0 and imag(r) has the same sign as imag(x).
func Sqrt(x complex128) complex128 {
if imag(x) == 0 {
if real(x) == 0 {
diff --git a/libgo/go/math/ldexp.go b/libgo/go/math/ldexp.go
index 4c63edd731..2898f5dd49 100644
--- a/libgo/go/math/ldexp.go
+++ b/libgo/go/math/ldexp.go
@@ -17,16 +17,6 @@ func libc_ldexp(float64, int) float64
func Ldexp(frac float64, exp int) float64 {
r := libc_ldexp(frac, exp)
-
- // Work around a bug in the implementation of ldexp on Solaris
- // 9. If multiplying a negative number by 2 raised to a
- // negative exponent underflows, we want to return negative
- // zero, but the Solaris 9 implementation returns positive
- // zero. This workaround can be removed when and if we no
- // longer care about Solaris 9.
- if r == 0 && frac < 0 && exp < 0 {
- r = Copysign(0, frac)
- }
return r
}
diff --git a/libgo/go/math/nextafter.go b/libgo/go/math/nextafter.go
index 7c4b5bcdfe..bbb139986a 100644
--- a/libgo/go/math/nextafter.go
+++ b/libgo/go/math/nextafter.go
@@ -4,12 +4,32 @@
package math
-// Nextafter returns the next representable value after x towards y.
-// If x == y, then x is returned.
-//
-// Special cases are:
-// Nextafter(NaN, y) = NaN
-// Nextafter(x, NaN) = NaN
+// Nextafter32 returns the next representable float32 value after x towards y.
+// Special cases:
+// Nextafter32(x, x) = x
+// 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
+ r = float32(NaN())
+ case x == y:
+ r = x
+ case x == 0:
+ r = float32(Copysign(float64(Float32frombits(1)), float64(y)))
+ case (y > x) == (x > 0):
+ r = Float32frombits(Float32bits(x) + 1)
+ default:
+ r = Float32frombits(Float32bits(x) - 1)
+ }
+ return
+}
+
+// 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
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 2157cdb465..3ffb5c4e5c 100644
--- a/libgo/go/math/rand/rand.go
+++ b/libgo/go/math/rand/rand.go
@@ -60,6 +60,9 @@ func (r *Rand) Int63n(n int64) int64 {
if n <= 0 {
panic("invalid argument to Int63n")
}
+ if n&(n-1) == 0 { // n is power of two, can mask
+ return r.Int63() & (n - 1)
+ }
max := int64((1 << 63) - 1 - (1<<63)%uint64(n))
v := r.Int63()
for v > max {
@@ -74,6 +77,9 @@ func (r *Rand) Int31n(n int32) int32 {
if n <= 0 {
panic("invalid argument to Int31n")
}
+ if n&(n-1) == 0 { // n is power of two, can mask
+ return r.Int31() & (n - 1)
+ }
max := int32((1 << 31) - 1 - (1<<31)%uint32(n))
v := r.Int31()
for v > max {
@@ -95,20 +101,54 @@ func (r *Rand) Intn(n int) int {
}
// Float64 returns, as a float64, a pseudo-random number in [0.0,1.0).
-func (r *Rand) Float64() float64 { return float64(r.Int63()) / (1 << 63) }
+func (r *Rand) Float64() float64 {
+ // A clearer, simpler implementation would be:
+ // return float64(r.Int63n(1<<53)) / (1<<53)
+ // However, Go 1 shipped with
+ // return float64(r.Int63()) / (1 << 63)
+ // and we want to preserve that value stream.
+ //
+ // There is one bug in the value stream: r.Int63() may be so close
+ // to 1<<63 that the division rounds up to 1.0, and we've guaranteed
+ // that the result is always less than 1.0. To fix that, we treat the
+ // range as cyclic and map 1 back to 0. This is justified by observing
+ // that while some of the values rounded down to 0, nothing was
+ // rounding up to 0, so 0 was underrepresented in the results.
+ // Mapping 1 back to zero restores some balance.
+ // (The balance is not perfect because the implementation
+ // returns denormalized numbers for very small r.Int63(),
+ // and those steal from what would normally be 0 results.)
+ // The remapping only happens 1/2⁵³ of the time, so most clients
+ // will not observe it anyway.
+ f := float64(r.Int63()) / (1 << 63)
+ if f == 1 {
+ f = 0
+ }
+ return f
+}
// Float32 returns, as a float32, a pseudo-random number in [0.0,1.0).
-func (r *Rand) Float32() float32 { return float32(r.Float64()) }
+func (r *Rand) Float32() float32 {
+ // Same rationale as in Float64: we want to preserve the Go 1 value
+ // stream except we want to fix it not to return 1.0
+ // There is a double rounding going on here, but the argument for
+ // mapping 1 to 0 still applies: 0 was underrepresented before,
+ // so mapping 1 to 0 doesn't cause too many 0s.
+ // This only happens 1/2²⁴ of the time (plus the 1/2⁵³ of the time in Float64).
+ f := float32(r.Float64())
+ if f == 1 {
+ f = 0
+ }
+ return f
+}
// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n).
func (r *Rand) Perm(n int) []int {
m := make([]int, n)
for i := 0; i < n; i++ {
- m[i] = i
- }
- for i := 0; i < n; i++ {
j := r.Intn(i + 1)
- m[i], m[j] = m[j], m[i]
+ m[i] = m[j]
+ m[j] = i
}
return m
}
diff --git a/libgo/go/math/rand/rand_test.go b/libgo/go/math/rand/rand_test.go
index 4d3abdb606..ab0dc49b41 100644
--- a/libgo/go/math/rand/rand_test.go
+++ b/libgo/go/math/rand/rand_test.go
@@ -322,6 +322,17 @@ func TestExpTables(t *testing.T) {
}
}
+// For issue 6721, the problem came after 7533753 calls, so check 10e6.
+func TestFloat32(t *testing.T) {
+ r := New(NewSource(1))
+ for ct := 0; ct < 10e6; ct++ {
+ f := r.Float32()
+ if f >= 1 {
+ t.Fatal("Float32() should be in range [0,1). ct:", ct, "f:", f)
+ }
+ }
+}
+
// Benchmarks
func BenchmarkInt63Threadsafe(b *testing.B) {
@@ -357,3 +368,31 @@ func BenchmarkInt31n1000(b *testing.B) {
r.Int31n(1000)
}
}
+
+func BenchmarkFloat32(b *testing.B) {
+ r := New(NewSource(1))
+ for n := b.N; n > 0; n-- {
+ r.Float32()
+ }
+}
+
+func BenchmarkFloat64(b *testing.B) {
+ r := New(NewSource(1))
+ for n := b.N; n > 0; n-- {
+ r.Float64()
+ }
+}
+
+func BenchmarkPerm3(b *testing.B) {
+ r := New(NewSource(1))
+ for n := b.N; n > 0; n-- {
+ r.Perm(3)
+ }
+}
+
+func BenchmarkPerm30(b *testing.B) {
+ r := New(NewSource(1))
+ for n := b.N; n > 0; n-- {
+ r.Perm(30)
+ }
+}
diff --git a/libgo/go/math/rand/regress_test.go b/libgo/go/math/rand/regress_test.go
new file mode 100644
index 0000000000..2b012af893
--- /dev/null
+++ b/libgo/go/math/rand/regress_test.go
@@ -0,0 +1,355 @@
+// 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.
+
+// Test that random number sequences generated by a specific seed
+// do not change from version to version.
+//
+// Do NOT make changes to the golden outputs. If bugs need to be fixed
+// in the underlying code, find ways to fix them that do not affect the
+// outputs.
+
+package rand_test
+
+import (
+ "flag"
+ "fmt"
+ . "math/rand"
+ "reflect"
+ "testing"
+)
+
+var printgolden = flag.Bool("printgolden", false, "print golden results for regression test")
+
+func TestRegress(t *testing.T) {
+ var int32s = []int32{1, 10, 32, 1 << 20, 1<<20 + 1, 1000000000, 1 << 30, 1<<31 - 2, 1<<31 - 1}
+ var int64s = []int64{1, 10, 32, 1 << 20, 1<<20 + 1, 1000000000, 1 << 30, 1<<31 - 2, 1<<31 - 1, 1000000000000000000, 1 << 60, 1<<63 - 2, 1<<63 - 1}
+ var permSizes = []int{0, 1, 5, 8, 9, 10, 16}
+ r := New(NewSource(0))
+
+ rv := reflect.ValueOf(r)
+ n := rv.NumMethod()
+ p := 0
+ if *printgolden {
+ fmt.Printf("var regressGolden = []interface{}{\n")
+ }
+ for i := 0; i < n; i++ {
+ m := rv.Type().Method(i)
+ mv := rv.Method(i)
+ mt := mv.Type()
+ if mt.NumOut() == 0 {
+ continue
+ }
+ if mt.NumOut() != 1 {
+ t.Fatalf("unexpected result count for r.%s", m.Name)
+ }
+ r.Seed(0)
+ for repeat := 0; repeat < 20; repeat++ {
+ var args []reflect.Value
+ var argstr string
+ if mt.NumIn() == 1 {
+ var x interface{}
+ switch mt.In(0).Kind() {
+ default:
+ t.Fatalf("unexpected argument type for r.%s", m.Name)
+
+ case reflect.Int:
+ if m.Name == "Perm" {
+ x = permSizes[repeat%len(permSizes)]
+ break
+ }
+ big := int64s[repeat%len(int64s)]
+ if int64(int(big)) != big {
+ r.Int63n(big) // what would happen on 64-bit machine, to keep stream in sync
+ if *printgolden {
+ fmt.Printf("\tskipped, // must run printgolden on 64-bit machine\n")
+ }
+ p++
+ continue
+ }
+ x = int(big)
+
+ case reflect.Int32:
+ x = int32s[repeat%len(int32s)]
+
+ case reflect.Int64:
+ x = int64s[repeat%len(int64s)]
+ }
+ argstr = fmt.Sprint(x)
+ args = append(args, reflect.ValueOf(x))
+ }
+ out := mv.Call(args)[0].Interface()
+ if m.Name == "Int" || m.Name == "Intn" {
+ out = int64(out.(int))
+ }
+ if *printgolden {
+ var val string
+ big := int64(1 << 60)
+ if int64(int(big)) != big && (m.Name == "Int" || m.Name == "Intn") {
+ // 32-bit machine cannot print 64-bit results
+ val = "truncated"
+ } else if reflect.TypeOf(out).Kind() == reflect.Slice {
+ val = fmt.Sprintf("%#v", out)
+ } else {
+ val = fmt.Sprintf("%T(%v)", out, out)
+ }
+ fmt.Printf("\t%s, // %s(%s)\n", val, m.Name, argstr)
+ } else {
+ want := regressGolden[p]
+ if m.Name == "Int" {
+ want = int64(int(uint(want.(int64)) << 1 >> 1))
+ }
+ if !reflect.DeepEqual(out, want) {
+ t.Errorf("r.%s(%s) = %v, want %v", m.Name, argstr, out, want)
+ }
+ }
+ p++
+ }
+ }
+ if *printgolden {
+ fmt.Printf("}\n")
+ }
+}
+
+var regressGolden = []interface{}{
+ float64(4.668112973579268), // ExpFloat64()
+ float64(0.1601593871172866), // ExpFloat64()
+ float64(3.0465834105636), // ExpFloat64()
+ float64(0.06385839451671879), // ExpFloat64()
+ float64(1.8578917487258961), // ExpFloat64()
+ float64(0.784676123472182), // ExpFloat64()
+ float64(0.11225477361256932), // ExpFloat64()
+ float64(0.20173283329802255), // ExpFloat64()
+ float64(0.3468619496201105), // ExpFloat64()
+ float64(0.35601103454384536), // ExpFloat64()
+ float64(0.888376329507869), // ExpFloat64()
+ float64(1.4081362450365698), // ExpFloat64()
+ float64(1.0077753823151994), // ExpFloat64()
+ float64(0.23594100766227588), // ExpFloat64()
+ float64(2.777245612300007), // ExpFloat64()
+ float64(0.5202997830662377), // ExpFloat64()
+ float64(1.2842705247770294), // ExpFloat64()
+ float64(0.030307408362776206), // ExpFloat64()
+ float64(2.204156824853721), // ExpFloat64()
+ float64(2.09891923895058), // ExpFloat64()
+ float32(0.94519615), // Float32()
+ float32(0.24496509), // Float32()
+ float32(0.65595627), // Float32()
+ float32(0.05434384), // Float32()
+ float32(0.3675872), // Float32()
+ float32(0.28948045), // Float32()
+ float32(0.1924386), // Float32()
+ float32(0.65533215), // Float32()
+ float32(0.8971697), // Float32()
+ float32(0.16735445), // Float32()
+ float32(0.28858566), // Float32()
+ float32(0.9026048), // Float32()
+ float32(0.84978026), // Float32()
+ float32(0.2730468), // Float32()
+ float32(0.6090802), // Float32()
+ float32(0.253656), // Float32()
+ float32(0.7746542), // Float32()
+ float32(0.017480763), // Float32()
+ float32(0.78707397), // Float32()
+ float32(0.7993937), // Float32()
+ float64(0.9451961492941164), // Float64()
+ float64(0.24496508529377975), // Float64()
+ float64(0.6559562651954052), // Float64()
+ float64(0.05434383959970039), // Float64()
+ float64(0.36758720663245853), // Float64()
+ float64(0.2894804331565928), // Float64()
+ float64(0.19243860967493215), // Float64()
+ float64(0.6553321508148324), // Float64()
+ float64(0.897169713149801), // Float64()
+ float64(0.16735444255905835), // Float64()
+ float64(0.2885856518054551), // Float64()
+ float64(0.9026048462705047), // Float64()
+ float64(0.8497802817628735), // Float64()
+ float64(0.2730468047134829), // Float64()
+ float64(0.6090801919903561), // Float64()
+ float64(0.25365600644283687), // Float64()
+ float64(0.7746542391859803), // Float64()
+ float64(0.017480762156647272), // Float64()
+ float64(0.7870739563039942), // Float64()
+ float64(0.7993936979594545), // Float64()
+ int64(8717895732742165505), // Int()
+ int64(2259404117704393152), // Int()
+ int64(6050128673802995827), // Int()
+ int64(501233450539197794), // Int()
+ int64(3390393562759376202), // Int()
+ int64(2669985732393126063), // Int()
+ int64(1774932891286980153), // Int()
+ int64(6044372234677422456), // Int()
+ int64(8274930044578894929), // Int()
+ int64(1543572285742637646), // Int()
+ int64(2661732831099943416), // Int()
+ int64(8325060299420976708), // Int()
+ int64(7837839688282259259), // Int()
+ int64(2518412263346885298), // Int()
+ int64(5617773211005988520), // Int()
+ int64(2339563716805116249), // Int()
+ int64(7144924247938981575), // Int()
+ int64(161231572858529631), // Int()
+ int64(7259475919510918339), // Int()
+ int64(7373105480197164748), // Int()
+ int32(2029793274), // Int31()
+ int32(526058514), // Int31()
+ int32(1408655353), // Int31()
+ int32(116702506), // Int31()
+ int32(789387515), // Int31()
+ int32(621654496), // Int31()
+ int32(413258767), // Int31()
+ int32(1407315077), // Int31()
+ int32(1926657288), // Int31()
+ int32(359390928), // Int31()
+ int32(619732968), // Int31()
+ int32(1938329147), // Int31()
+ int32(1824889259), // Int31()
+ int32(586363548), // Int31()
+ int32(1307989752), // Int31()
+ int32(544722126), // Int31()
+ int32(1663557311), // Int31()
+ int32(37539650), // Int31()
+ int32(1690228450), // Int31()
+ int32(1716684894), // Int31()
+ int32(0), // Int31n(1)
+ int32(4), // Int31n(10)
+ int32(25), // Int31n(32)
+ int32(310570), // Int31n(1048576)
+ int32(857611), // Int31n(1048577)
+ int32(621654496), // Int31n(1000000000)
+ int32(413258767), // Int31n(1073741824)
+ int32(1407315077), // Int31n(2147483646)
+ int32(1926657288), // Int31n(2147483647)
+ int32(0), // Int31n(1)
+ int32(8), // Int31n(10)
+ int32(27), // Int31n(32)
+ int32(367019), // Int31n(1048576)
+ int32(209005), // Int31n(1048577)
+ int32(307989752), // Int31n(1000000000)
+ int32(544722126), // Int31n(1073741824)
+ int32(1663557311), // Int31n(2147483646)
+ int32(37539650), // Int31n(2147483647)
+ int32(0), // Int31n(1)
+ int32(4), // Int31n(10)
+ int64(8717895732742165505), // Int63()
+ int64(2259404117704393152), // Int63()
+ int64(6050128673802995827), // Int63()
+ int64(501233450539197794), // Int63()
+ int64(3390393562759376202), // Int63()
+ int64(2669985732393126063), // Int63()
+ int64(1774932891286980153), // Int63()
+ int64(6044372234677422456), // Int63()
+ int64(8274930044578894929), // Int63()
+ int64(1543572285742637646), // Int63()
+ int64(2661732831099943416), // Int63()
+ int64(8325060299420976708), // Int63()
+ int64(7837839688282259259), // Int63()
+ int64(2518412263346885298), // Int63()
+ int64(5617773211005988520), // Int63()
+ int64(2339563716805116249), // Int63()
+ int64(7144924247938981575), // Int63()
+ int64(161231572858529631), // Int63()
+ int64(7259475919510918339), // Int63()
+ int64(7373105480197164748), // Int63()
+ int64(0), // Int63n(1)
+ int64(2), // Int63n(10)
+ int64(19), // Int63n(32)
+ int64(959842), // Int63n(1048576)
+ int64(688912), // Int63n(1048577)
+ int64(393126063), // Int63n(1000000000)
+ int64(89212473), // Int63n(1073741824)
+ int64(834026388), // Int63n(2147483646)
+ int64(1577188963), // Int63n(2147483647)
+ int64(543572285742637646), // Int63n(1000000000000000000)
+ int64(355889821886249464), // Int63n(1152921504606846976)
+ int64(8325060299420976708), // Int63n(9223372036854775806)
+ int64(7837839688282259259), // Int63n(9223372036854775807)
+ int64(0), // Int63n(1)
+ int64(0), // Int63n(10)
+ int64(25), // Int63n(32)
+ int64(679623), // Int63n(1048576)
+ int64(882178), // Int63n(1048577)
+ int64(510918339), // Int63n(1000000000)
+ int64(782454476), // Int63n(1073741824)
+ int64(0), // Intn(1)
+ int64(4), // Intn(10)
+ int64(25), // Intn(32)
+ int64(310570), // Intn(1048576)
+ int64(857611), // Intn(1048577)
+ int64(621654496), // Intn(1000000000)
+ int64(413258767), // Intn(1073741824)
+ int64(1407315077), // Intn(2147483646)
+ int64(1926657288), // Intn(2147483647)
+ int64(543572285742637646), // Intn(1000000000000000000)
+ int64(355889821886249464), // Intn(1152921504606846976)
+ int64(8325060299420976708), // Intn(9223372036854775806)
+ int64(7837839688282259259), // Intn(9223372036854775807)
+ int64(0), // Intn(1)
+ int64(2), // Intn(10)
+ int64(14), // Intn(32)
+ int64(515775), // Intn(1048576)
+ int64(839455), // Intn(1048577)
+ int64(690228450), // Intn(1000000000)
+ int64(642943070), // Intn(1073741824)
+ float64(-0.28158587086436215), // NormFloat64()
+ float64(0.570933095808067), // NormFloat64()
+ float64(-1.6920196326157044), // NormFloat64()
+ float64(0.1996229111693099), // NormFloat64()
+ float64(1.9195199291234621), // NormFloat64()
+ float64(0.8954838794918353), // NormFloat64()
+ float64(0.41457072128813166), // NormFloat64()
+ float64(-0.48700161491544713), // NormFloat64()
+ float64(-0.1684059662402393), // NormFloat64()
+ float64(0.37056410998929545), // NormFloat64()
+ float64(1.0156889027029008), // NormFloat64()
+ float64(-0.5174422210625114), // NormFloat64()
+ float64(-0.5565834214413804), // NormFloat64()
+ float64(0.778320596648391), // NormFloat64()
+ float64(-1.8970718197702225), // NormFloat64()
+ float64(0.5229525761688676), // NormFloat64()
+ float64(-1.5515595563231523), // NormFloat64()
+ float64(0.0182029289376123), // NormFloat64()
+ float64(-0.6820951356608795), // NormFloat64()
+ float64(-0.5987943422687668), // NormFloat64()
+ []int{}, // Perm(0)
+ []int{0}, // Perm(1)
+ []int{0, 4, 1, 3, 2}, // Perm(5)
+ []int{3, 1, 0, 4, 7, 5, 2, 6}, // Perm(8)
+ []int{5, 0, 3, 6, 7, 4, 2, 1, 8}, // Perm(9)
+ []int{4, 5, 0, 2, 6, 9, 3, 1, 8, 7}, // Perm(10)
+ []int{14, 2, 0, 8, 3, 5, 13, 12, 1, 4, 6, 7, 11, 9, 15, 10}, // Perm(16)
+ []int{}, // Perm(0)
+ []int{0}, // Perm(1)
+ []int{3, 0, 1, 2, 4}, // Perm(5)
+ []int{5, 1, 2, 0, 4, 7, 3, 6}, // Perm(8)
+ []int{4, 0, 6, 8, 1, 5, 2, 7, 3}, // Perm(9)
+ []int{8, 6, 1, 7, 5, 4, 3, 2, 9, 0}, // Perm(10)
+ []int{0, 3, 13, 2, 15, 4, 10, 1, 8, 14, 7, 6, 12, 9, 5, 11}, // Perm(16)
+ []int{}, // Perm(0)
+ []int{0}, // Perm(1)
+ []int{0, 4, 2, 1, 3}, // Perm(5)
+ []int{2, 1, 7, 0, 6, 3, 4, 5}, // Perm(8)
+ []int{8, 7, 5, 3, 4, 6, 0, 1, 2}, // Perm(9)
+ []int{1, 0, 2, 5, 7, 6, 9, 8, 3, 4}, // Perm(10)
+ uint32(4059586549), // Uint32()
+ uint32(1052117029), // Uint32()
+ uint32(2817310706), // Uint32()
+ uint32(233405013), // Uint32()
+ uint32(1578775030), // Uint32()
+ uint32(1243308993), // Uint32()
+ uint32(826517535), // Uint32()
+ uint32(2814630155), // Uint32()
+ uint32(3853314576), // Uint32()
+ uint32(718781857), // Uint32()
+ uint32(1239465936), // Uint32()
+ uint32(3876658295), // Uint32()
+ uint32(3649778518), // Uint32()
+ uint32(1172727096), // Uint32()
+ uint32(2615979505), // Uint32()
+ uint32(1089444252), // Uint32()
+ uint32(3327114623), // Uint32()
+ uint32(75079301), // Uint32()
+ uint32(3380456901), // Uint32()
+ uint32(3433369789), // Uint32()
+}
diff --git a/libgo/go/math/sqrt.go b/libgo/go/math/sqrt.go
index 78475973eb..56122b5981 100644
--- a/libgo/go/math/sqrt.go
+++ b/libgo/go/math/sqrt.go
@@ -87,7 +87,7 @@ func Sqrt(x float64) float64 {
//
//
// Notes: Rounding mode detection omitted. The constants "mask", "shift",
-// and "bias" are found in src/pkg/math/bits.go
+// and "bias" are found in src/math/bits.go
// Sqrt returns the square root of x.
//
diff --git a/libgo/go/mime/mediatype.go b/libgo/go/mime/mediatype.go
index 608f759da8..ad63f9bb98 100644
--- a/libgo/go/mime/mediatype.go
+++ b/libgo/go/mime/mediatype.go
@@ -8,6 +8,7 @@ import (
"bytes"
"errors"
"fmt"
+ "sort"
"strings"
"unicode"
)
@@ -31,7 +32,14 @@ func FormatMediaType(t string, param map[string]string) string {
b.WriteByte('/')
b.WriteString(strings.ToLower(sub))
- for attribute, value := range param {
+ attrs := make([]string, 0, len(param))
+ for a := range param {
+ attrs = append(attrs, a)
+ }
+ sort.Strings(attrs)
+
+ for _, attribute := range attrs {
+ value := param[attribute]
b.WriteByte(';')
b.WriteByte(' ')
if !isToken(attribute) {
diff --git a/libgo/go/mime/mediatype_test.go b/libgo/go/mime/mediatype_test.go
index 29511445bc..026bfa4d73 100644
--- a/libgo/go/mime/mediatype_test.go
+++ b/libgo/go/mime/mediatype_test.go
@@ -293,6 +293,7 @@ var formatTests = []formatTest{
{"foo/BAR", map[string]string{"": "empty attribute"}, ""},
{"foo/BAR", map[string]string{"bad attribute": "baz"}, ""},
{"foo/BAR", map[string]string{"nonascii": "not an ascii character: ä"}, ""},
+ {"foo/bar", map[string]string{"a": "av", "b": "bv", "c": "cv"}, "foo/bar; a=av; b=bv; c=cv"},
}
func TestFormatMediaType(t *testing.T) {
diff --git a/libgo/go/mime/multipart/formdata_test.go b/libgo/go/mime/multipart/formdata_test.go
index 4bc4649317..6e2388bafe 100644
--- a/libgo/go/mime/multipart/formdata_test.go
+++ b/libgo/go/mime/multipart/formdata_test.go
@@ -9,12 +9,13 @@ import (
"io"
"os"
"regexp"
+ "strings"
"testing"
)
func TestReadForm(t *testing.T) {
testBody := regexp.MustCompile("\n").ReplaceAllString(message, "\r\n")
- b := bytes.NewBufferString(testBody)
+ b := strings.NewReader(testBody)
r := NewReader(b, boundary)
f, err := r.ReadForm(25)
if err != nil {
diff --git a/libgo/go/mime/multipart/multipart.go b/libgo/go/mime/multipart/multipart.go
index 2b4f5b433e..01a667d930 100644
--- a/libgo/go/mime/multipart/multipart.go
+++ b/libgo/go/mime/multipart/multipart.go
@@ -81,13 +81,16 @@ func (p *Part) parseContentDisposition() {
}
}
-// NewReader creates a new multipart Reader reading from reader using the
+// NewReader creates a new multipart Reader reading from r using the
// given MIME boundary.
-func NewReader(reader io.Reader, boundary string) *Reader {
+//
+// The boundary is usually obtained from the "boundary" parameter of
+// the message's "Content-Type" header. Use mime.ParseMediaType to
+// parse such headers.
+func NewReader(r io.Reader, boundary string) *Reader {
b := []byte("\r\n--" + boundary + "--")
return &Reader{
- bufReader: bufio.NewReader(reader),
-
+ bufReader: bufio.NewReader(r),
nl: b[:2],
nlDashBoundary: b[:len(b)-2],
dashBoundaryDash: b[2:],
diff --git a/libgo/go/mime/multipart/quotedprintable_test.go b/libgo/go/mime/multipart/quotedprintable_test.go
index 8a95f7f037..c4de3eb756 100644
--- a/libgo/go/mime/multipart/quotedprintable_test.go
+++ b/libgo/go/mime/multipart/quotedprintable_test.go
@@ -131,7 +131,7 @@ func TestQPExhaustive(t *testing.T) {
return
}
if strings.HasSuffix(errStr, "0x0a") || strings.HasSuffix(errStr, "0x0d") {
- // bunch of cases; since whitespace at the end of of a line before \n is removed.
+ // bunch of cases; since whitespace at the end of a line before \n is removed.
return
}
}
diff --git a/libgo/go/mime/multipart/writer_test.go b/libgo/go/mime/multipart/writer_test.go
index 52d68bcb68..ba00c97ece 100644
--- a/libgo/go/mime/multipart/writer_test.go
+++ b/libgo/go/mime/multipart/writer_test.go
@@ -111,3 +111,18 @@ func TestWriterSetBoundary(t *testing.T) {
t.Errorf("expected my-separator in output. got: %q", got)
}
}
+
+func TestWriterBoundaryGoroutines(t *testing.T) {
+ // Verify there's no data race accessing any lazy boundary if it's used by
+ // different goroutines. This was previously broken by
+ // https://codereview.appspot.com/95760043/ and reverted in
+ // https://codereview.appspot.com/117600043/
+ w := NewWriter(ioutil.Discard)
+ done := make(chan int)
+ go func() {
+ w.CreateFormField("foo")
+ done <- 1
+ }()
+ w.Boundary()
+ <-done
+}
diff --git a/libgo/go/mime/type.go b/libgo/go/mime/type.go
index 00cff263ba..ffda1f0ce5 100644
--- a/libgo/go/mime/type.go
+++ b/libgo/go/mime/type.go
@@ -11,26 +11,41 @@ import (
"sync"
)
-var mimeTypes = 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",
-}
+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)
+)
-var mimeLock sync.RWMutex
+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")
+ }
+ }
+ return m2
+}
-var once sync.Once
+var once sync.Once // guards initMime
// 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 "".
//
+// Extensions are looked up first case-sensitively, then case-insensitively.
+//
// The built-in table is small but on unix it is augmented by the local
// system's mime.types file(s) if available under one or more of these
// names:
@@ -39,23 +54,49 @@ var once sync.Once
// /etc/apache2/mime.types
// /etc/apache/mime.types
//
-// Windows system mime types are extracted from registry.
+// On Windows, MIME types are extracted from the registry.
//
// Text types have the charset parameter set to "utf-8" by default.
func TypeByExtension(ext string) string {
once.Do(initMime)
mimeLock.RLock()
- typename := mimeTypes[ext]
- mimeLock.RUnlock()
- return typename
+ defer mimeLock.RUnlock()
+
+ // Case-sensitive lookup.
+ v := mimeTypes[ext]
+ if v != "" {
+ return v
+ }
+
+ // Case-insensitive lookup.
+ // Optimistically assume a short ASCII extension and be
+ // allocation-free in that case.
+ var buf [10]byte
+ lower := buf[:0]
+ const utf8RuneSelf = 0x80 // from utf8 package, but not importing it.
+ for i := 0; i < len(ext); i++ {
+ c := ext[i]
+ if c >= utf8RuneSelf {
+ // Slow path.
+ return mimeTypesLower[strings.ToLower(ext)]
+ }
+ if 'A' <= c && c <= 'Z' {
+ lower = append(lower, c+('a'-'A'))
+ } else {
+ lower = append(lower, c)
+ }
+ }
+ // The conversion from []byte to string doesn't allocate in
+ // a map lookup.
+ return mimeTypesLower[string(lower)]
}
// AddExtensionType sets the MIME type associated with
-// the extension ext to typ. The extension should begin with
+// the extension ext to typ. The extension should begin with
// a leading dot, as in ".html".
func AddExtensionType(ext, typ string) error {
- if ext == "" || ext[0] != '.' {
- return fmt.Errorf(`mime: extension "%s" misses dot`, ext)
+ if !strings.HasPrefix(ext, ".") {
+ return fmt.Errorf(`mime: extension %q misses dot`, ext)
}
once.Do(initMime)
return setExtensionType(ext, typ)
@@ -70,8 +111,11 @@ func setExtensionType(extension, mimeType string) error {
param["charset"] = "utf-8"
mimeType = FormatMediaType(mimeType, param)
}
+ extLower := strings.ToLower(extension)
+
mimeLock.Lock()
mimeTypes[extension] = mimeType
+ mimeTypesLower[extLower] = mimeType
mimeLock.Unlock()
return nil
}
diff --git a/libgo/go/mime/type_plan9.go b/libgo/go/mime/type_plan9.go
index b8f0511ee7..8cbf6777f1 100644
--- a/libgo/go/mime/type_plan9.go
+++ b/libgo/go/mime/type_plan9.go
@@ -48,6 +48,6 @@ func initMimeForTests() map[string]string {
return map[string]string{
".t1": "application/test",
".t2": "text/test; charset=utf-8",
- ".png": "image/png",
+ ".pNg": "image/png",
}
}
diff --git a/libgo/go/mime/type_test.go b/libgo/go/mime/type_test.go
index 07e1cd5dae..e4ec25450c 100644
--- a/libgo/go/mime/type_test.go
+++ b/libgo/go/mime/type_test.go
@@ -4,7 +4,9 @@
package mime
-import "testing"
+import (
+ "testing"
+)
var typeTests = initMimeForTests()
@@ -14,16 +16,40 @@ func TestTypeByExtension(t *testing.T) {
if val != want {
t.Errorf("TypeByExtension(%q) = %q, want %q", ext, val, want)
}
-
}
}
-func TestCustomExtension(t *testing.T) {
- custom := "text/xml; charset=iso-8859-1"
- if error := AddExtensionType(".xml", custom); error != nil {
- t.Fatalf("error %s for AddExtension(%s)", error, custom)
+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)
+ }
+
+ // case-sensitive lookup
+ if got := TypeByExtension(".tesT"); got != custom {
+ t.Fatalf("for .tesT, got %q; want %q", got, custom)
+ }
+ if got := TypeByExtension(".TEST"); got != caps {
+ t.Fatalf("for .TEST, got %q; want %s", got, caps)
}
- if registered := TypeByExtension(".xml"); registered != custom {
- t.Fatalf("registered %s instead of %s", registered, custom)
+
+ // case-insensitive
+ if got := TypeByExtension(".TesT"); got != custom {
+ t.Fatalf("for .TesT, got %q; want %q", got, custom)
+ }
+}
+
+func TestLookupMallocs(t *testing.T) {
+ n := testing.AllocsPerRun(10000, func() {
+ TypeByExtension(".html")
+ TypeByExtension(".HtML")
+ })
+ // Changed from 0 to 1 for gccgo, pending escape analysis.
+ if n > 1 {
+ t.Errorf("allocs = %v; want 0", n)
}
}
diff --git a/libgo/go/mime/type_unix.go b/libgo/go/mime/type_unix.go
index 713e301cdf..3e404cf742 100644
--- a/libgo/go/mime/type_unix.go
+++ b/libgo/go/mime/type_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 netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package mime
@@ -53,7 +53,7 @@ func initMime() {
func initMimeForTests() map[string]string {
typeFiles = []string{"testdata/test.types"}
return map[string]string{
- ".t1": "application/test",
+ ".T1": "application/test",
".t2": "text/test; charset=utf-8",
".png": "image/png",
}
diff --git a/libgo/go/mime/type_windows.go b/libgo/go/mime/type_windows.go
index 180f948d16..ae758d78b3 100644
--- a/libgo/go/mime/type_windows.go
+++ b/libgo/go/mime/type_windows.go
@@ -58,6 +58,6 @@ func initMime() {
func initMimeForTests() map[string]string {
return map[string]string{
- ".png": "image/png",
+ ".PnG": "image/png",
}
}
diff --git a/libgo/go/net/cgo_android.go b/libgo/go/net/cgo_android.go
new file mode 100644
index 0000000000..3819ce56a4
--- /dev/null
+++ b/libgo/go/net/cgo_android.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 cgo,!netgo
+
+package net
+
+//#include <netdb.h>
+import "C"
+
+func cgoAddrInfoFlags() C.int {
+ return C.AI_CANONNAME
+}
diff --git a/libgo/go/net/cgo_bsd.go b/libgo/go/net/cgo_bsd.go
index 3852fc2298..ce46f2e8c3 100644
--- a/libgo/go/net/cgo_bsd.go
+++ b/libgo/go/net/cgo_bsd.go
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// +build !netgo
-// +build darwin dragonfly freebsd
+// +build darwin dragonfly freebsd solaris
package net
diff --git a/libgo/go/net/cgo_linux.go b/libgo/go/net/cgo_linux.go
index 77522f9141..0e332261ac 100644
--- a/libgo/go/net/cgo_linux.go
+++ b/libgo/go/net/cgo_linux.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,!netgo
+// +build !android,cgo,!netgo
package net
diff --git a/libgo/go/net/cgo_unix_test.go b/libgo/go/net/cgo_unix_test.go
new file mode 100644
index 0000000000..33566ce9c2
--- /dev/null
+++ b/libgo/go/net/cgo_unix_test.go
@@ -0,0 +1,24 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build cgo,!netgo
+// +build darwin dragonfly freebsd linux netbsd openbsd
+
+package net
+
+import "testing"
+
+func TestCgoLookupIP(t *testing.T) {
+ host := "localhost"
+ _, err, ok := cgoLookupIP(host)
+ if !ok {
+ t.Errorf("cgoLookupIP must not be a placeholder")
+ }
+ if err != nil {
+ t.Errorf("cgoLookupIP failed: %v", err)
+ }
+ if _, err := goLookupIP(host); err != nil {
+ t.Errorf("goLookupIP failed: %v", err)
+ }
+}
diff --git a/libgo/go/net/conn_test.go b/libgo/go/net/conn_test.go
index 98bd695499..9c9d1a8057 100644
--- a/libgo/go/net/conn_test.go
+++ b/libgo/go/net/conn_test.go
@@ -16,11 +16,11 @@ import (
var connTests = []struct {
net string
- addr func() string
+ addr string
}{
- {"tcp", func() string { return "127.0.0.1:0" }},
- {"unix", testUnixAddr},
- {"unixpacket", testUnixAddr},
+ {"tcp", "127.0.0.1:0"},
+ {"unix", testUnixAddr()},
+ {"unixpacket", testUnixAddr()},
}
// someTimeout is used just to test that net.Conn implementations
@@ -31,18 +31,21 @@ const someTimeout = 10 * time.Second
func TestConnAndListener(t *testing.T) {
for _, tt := range connTests {
switch tt.net {
- case "unix", "unixpacket":
+ case "unix":
switch runtime.GOOS {
- case "plan9", "windows":
+ case "nacl", "plan9", "windows":
continue
}
- if tt.net == "unixpacket" && runtime.GOOS != "linux" {
+ case "unixpacket":
+ switch runtime.GOOS {
+ case "android", "darwin", "nacl", "openbsd", "plan9", "windows":
+ continue
+ case "freebsd": // FreeBSD 8 doesn't support unixpacket
continue
}
}
- addr := tt.addr()
- ln, err := Listen(tt.net, addr)
+ ln, err := Listen(tt.net, tt.addr)
if err != nil {
t.Fatalf("Listen failed: %v", err)
}
@@ -52,8 +55,10 @@ func TestConnAndListener(t *testing.T) {
case "unix", "unixpacket":
os.Remove(addr)
}
- }(ln, tt.net, addr)
- ln.Addr()
+ }(ln, tt.net, tt.addr)
+ if ln.Addr().Network() != tt.net {
+ t.Fatalf("got %v; expected %v", ln.Addr().Network(), tt.net)
+ }
done := make(chan int)
go transponder(t, ln, done)
@@ -63,8 +68,9 @@ func TestConnAndListener(t *testing.T) {
t.Fatalf("Dial failed: %v", err)
}
defer c.Close()
- c.LocalAddr()
- c.RemoteAddr()
+ 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)
+ }
c.SetDeadline(time.Now().Add(someTimeout))
c.SetReadDeadline(time.Now().Add(someTimeout))
c.SetWriteDeadline(time.Now().Add(someTimeout))
@@ -96,8 +102,11 @@ func transponder(t *testing.T, ln Listener, done chan<- int) {
return
}
defer c.Close()
- c.LocalAddr()
- c.RemoteAddr()
+ 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))
diff --git a/libgo/go/net/dial.go b/libgo/go/net/dial.go
index 6304818bf1..e6f0436cdd 100644
--- a/libgo/go/net/dial.go
+++ b/libgo/go/net/dial.go
@@ -44,6 +44,12 @@ type Dialer struct {
// destination is a host name that has multiple address family
// DNS records.
DualStack bool
+
+ // KeepAlive specifies the keep-alive period for an active
+ // network connection.
+ // If zero, keep-alives are not enabled. Network protocols
+ // that do not support keep-alives ignore this field.
+ KeepAlive time.Duration
}
// Return either now+Timeout or Deadline, whichever comes first.
@@ -112,9 +118,8 @@ func resolveAddr(op, net, addr string, deadline time.Time) (netaddr, error) {
// "unixpacket".
//
// For TCP and UDP networks, addresses have the form host:port.
-// If host is a literal IPv6 address or host name, it must be enclosed
-// in square brackets as in "[::1]:80", "[ipv6-host]:http" or
-// "[ipv6-host%zone]:80".
+// If host is a literal IPv6 address it must be enclosed
+// in square brackets as in "[::1]:80" or "[ipv6-host%zone]:80".
// The functions JoinHostPort and SplitHostPort manipulate addresses
// in this form.
//
@@ -162,9 +167,19 @@ func (d *Dialer) Dial(network, address string) (Conn, error) {
return dialMulti(network, address, d.LocalAddr, ras, deadline)
}
}
- return dial(network, ra.toAddr(), dialer, d.deadline())
+ c, err := dial(network, ra.toAddr(), dialer, d.deadline())
+ if d.KeepAlive > 0 && err == nil {
+ if tc, ok := c.(*TCPConn); ok {
+ tc.SetKeepAlive(true)
+ tc.SetKeepAlivePeriod(d.KeepAlive)
+ testHookSetKeepAlive()
+ }
+ }
+ return c, err
}
+var testHookSetKeepAlive = func() {} // changed by dial_test.go
+
// 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
@@ -172,7 +187,6 @@ func (d *Dialer) Dial(network, address string) (Conn, error) {
func dialMulti(net, addr string, la Addr, ras addrList, deadline time.Time) (Conn, error) {
type racer struct {
Conn
- Addr
error
}
// Sig controls the flow of dial results on lane. It passes a
@@ -184,7 +198,7 @@ func dialMulti(net, addr string, la Addr, ras addrList, deadline time.Time) (Con
go func(ra Addr) {
c, err := dialSingle(net, addr, la, ra, deadline)
if _, ok := <-sig; ok {
- lane <- racer{c, ra, err}
+ lane <- racer{c, err}
} else if err == nil {
// We have to return the resources
// that belong to the other
@@ -195,22 +209,18 @@ func dialMulti(net, addr string, la Addr, ras addrList, deadline time.Time) (Con
}(ra.toAddr())
}
defer close(sig)
- var failAddr Addr
lastErr := errTimeout
nracers := len(ras)
for nracers > 0 {
sig <- true
- select {
- case racer := <-lane:
- if racer.error == nil {
- return racer.Conn, nil
- }
- failAddr = racer.Addr
- lastErr = racer.error
- nracers--
+ racer := <-lane
+ if racer.error == nil {
+ return racer.Conn, nil
}
+ lastErr = racer.error
+ nracers--
}
- return nil, &OpError{Op: "dial", Net: net, Addr: failAddr, Err: lastErr}
+ return nil, lastErr
}
// dialSingle attempts to establish and returns a single connection to
diff --git a/libgo/go/net/dial_test.go b/libgo/go/net/dial_test.go
index 973e69dea5..42898d669f 100644
--- a/libgo/go/net/dial_test.go
+++ b/libgo/go/net/dial_test.go
@@ -58,7 +58,7 @@ func TestDialTimeout(t *testing.T) {
errc <- err
}()
}
- case "darwin", "windows":
+ 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.
@@ -119,6 +119,7 @@ func TestSelfConnect(t *testing.T) {
// TODO(brainman): do not know why it hangs.
t.Skip("skipping known-broken test on windows")
}
+
// Test that Dial does not honor self-connects.
// See the comment in DialTCP.
@@ -149,8 +150,12 @@ func TestSelfConnect(t *testing.T) {
for i := 0; i < n; i++ {
c, err := DialTimeout("tcp", addr, time.Millisecond)
if err == nil {
+ if c.LocalAddr().String() == addr {
+ t.Errorf("#%d: Dial %q self-connect", i, addr)
+ } else {
+ t.Logf("#%d: Dial %q succeeded - possibly racing with other listener", i, addr)
+ }
c.Close()
- t.Errorf("#%d: Dial %q succeeded", i, addr)
}
}
}
@@ -334,6 +339,8 @@ func numTCP() (ntcp, nopen, nclose int, err error) {
}
func TestDialMultiFDLeak(t *testing.T) {
+ t.Skip("flaky test - golang.org/issue/8764")
+
if !supportsIPv4 || !supportsIPv6 {
t.Skip("neither ipv4 nor ipv6 is supported")
}
@@ -425,60 +432,6 @@ func numFD() int {
panic("numFDs not implemented on " + runtime.GOOS)
}
-// Assert that a failed Dial attempt does not leak
-// runtime.PollDesc structures
-func TestDialFailPDLeak(t *testing.T) {
- if testing.Short() {
- t.Skip("skipping test in short mode")
- }
- if runtime.GOOS == "windows" && runtime.GOARCH == "386" {
- // Just skip the test because it takes too long.
- t.Skipf("skipping test on %q/%q", runtime.GOOS, runtime.GOARCH)
- }
-
- maxprocs := runtime.GOMAXPROCS(0)
- loops := 10 + maxprocs
- // 500 is enough to turn over the chunk of pollcache.
- // See allocPollDesc in runtime/netpoll.goc.
- const count = 500
- var old runtime.MemStats // used by sysdelta
- runtime.ReadMemStats(&old)
- sysdelta := func() uint64 {
- var new runtime.MemStats
- runtime.ReadMemStats(&new)
- delta := old.Sys - new.Sys
- old = new
- return delta
- }
- d := &Dialer{Timeout: time.Nanosecond} // don't bother TCP with handshaking
- failcount := 0
- for i := 0; i < loops; i++ {
- var wg sync.WaitGroup
- for i := 0; i < count; i++ {
- wg.Add(1)
- go func() {
- defer wg.Done()
- if c, err := d.Dial("tcp", "127.0.0.1:1"); err == nil {
- t.Error("dial should not succeed")
- c.Close()
- }
- }()
- }
- wg.Wait()
- if t.Failed() {
- t.FailNow()
- }
- if delta := sysdelta(); delta > 0 {
- failcount++
- }
- // there are always some allocations on the first loop
- if failcount > maxprocs+2 {
- t.Error("detected possible memory leak in runtime")
- t.FailNow()
- }
- }
-}
-
func TestDialer(t *testing.T) {
ln, err := Listen("tcp4", "127.0.0.1:0")
if err != nil {
@@ -514,6 +467,11 @@ func TestDialer(t *testing.T) {
}
func TestDialDualStackLocalhost(t *testing.T) {
+ switch runtime.GOOS {
+ case "nacl":
+ t.Skipf("skipping test on %q", runtime.GOOS)
+ }
+
if ips, err := LookupIP("localhost"); err != nil {
t.Fatalf("LookupIP failed: %v", err)
} else if len(ips) < 2 || !supportsIPv4 || !supportsIPv6 {
@@ -542,7 +500,7 @@ func TestDialDualStackLocalhost(t *testing.T) {
}
d := &Dialer{DualStack: true}
- for _ = range dss.lns {
+ for range dss.lns {
if c, err := d.Dial("tcp", "localhost:"+dss.port); err != nil {
t.Errorf("Dial failed: %v", err)
} else {
@@ -555,3 +513,36 @@ func TestDialDualStackLocalhost(t *testing.T) {
}
}
}
+
+func TestDialerKeepAlive(t *testing.T) {
+ ln := newLocalListener(t)
+ defer ln.Close()
+ defer func() {
+ testHookSetKeepAlive = func() {}
+ }()
+ go func() {
+ for {
+ c, err := ln.Accept()
+ if err != nil {
+ return
+ }
+ c.Close()
+ }
+ }()
+ for _, keepAlive := range []bool{false, true} {
+ got := false
+ testHookSetKeepAlive = func() { got = true }
+ var d Dialer
+ if keepAlive {
+ d.KeepAlive = 30 * time.Second
+ }
+ c, err := d.Dial("tcp", ln.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ c.Close()
+ if got != keepAlive {
+ t.Errorf("Dialer.KeepAlive = %v: SetKeepAlive called = %v, want %v", d.KeepAlive, got, !got)
+ }
+ }
+}
diff --git a/libgo/go/net/dialgoogle_test.go b/libgo/go/net/dialgoogle_test.go
index b4ebad0e0d..df5895afa7 100644
--- a/libgo/go/net/dialgoogle_test.go
+++ b/libgo/go/net/dialgoogle_test.go
@@ -104,31 +104,7 @@ var googleaddrsipv4 = []string{
"[::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:0:ffff::%d.%d.%d.%d]:80",
-}
-
-func TestDNSThreadLimit(t *testing.T) {
- if testing.Short() || !*testExternal {
- t.Skip("skipping test to avoid external network")
- }
-
- 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.
+ "[0:0:0:0::ffff:%d.%d.%d.%d]:80",
}
func TestDialGoogleIPv4(t *testing.T) {
diff --git a/libgo/go/net/dnsclient.go b/libgo/go/net/dnsclient.go
index 01db437294..e8014e4ffc 100644
--- a/libgo/go/net/dnsclient.go
+++ b/libgo/go/net/dnsclient.go
@@ -191,14 +191,12 @@ func (addrs byPriorityWeight) shuffleByWeight() {
}
for sum > 0 && len(addrs) > 1 {
s := 0
- n := rand.Intn(sum + 1)
+ n := rand.Intn(sum)
for i := range addrs {
s += int(addrs[i].Weight)
- if s >= n {
+ if s > n {
if i > 0 {
- t := addrs[i]
- copy(addrs[1:i+1], addrs[0:i])
- addrs[0] = t
+ addrs[0], addrs[i] = addrs[i], addrs[0]
}
break
}
diff --git a/libgo/go/net/dnsclient_test.go b/libgo/go/net/dnsclient_test.go
new file mode 100644
index 0000000000..435eb35506
--- /dev/null
+++ b/libgo/go/net/dnsclient_test.go
@@ -0,0 +1,69 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "math/rand"
+ "testing"
+)
+
+func checkDistribution(t *testing.T, data []*SRV, margin float64) {
+ sum := 0
+ for _, srv := range data {
+ sum += int(srv.Weight)
+ }
+
+ results := make(map[string]int)
+
+ count := 1000
+ for j := 0; j < count; j++ {
+ d := make([]*SRV, len(data))
+ copy(d, data)
+ byPriorityWeight(d).shuffleByWeight()
+ key := d[0].Target
+ results[key] = results[key] + 1
+ }
+
+ actual := results[data[0].Target]
+ expected := float64(count) * float64(data[0].Weight) / float64(sum)
+ diff := float64(actual) - expected
+ t.Logf("actual: %v diff: %v e: %v m: %v", actual, diff, expected, margin)
+ if diff < 0 {
+ diff = -diff
+ }
+ if diff > (expected * margin) {
+ t.Errorf("missed target weight: expected %v, %v", expected, actual)
+ }
+}
+
+func testUniformity(t *testing.T, size int, margin float64) {
+ rand.Seed(1)
+ data := make([]*SRV, size)
+ for i := 0; i < size; i++ {
+ data[i] = &SRV{Target: string('a' + i), Weight: 1}
+ }
+ checkDistribution(t, data, margin)
+}
+
+func TestUniformity(t *testing.T) {
+ testUniformity(t, 2, 0.05)
+ testUniformity(t, 3, 0.10)
+ testUniformity(t, 10, 0.20)
+ testWeighting(t, 0.05)
+}
+
+func testWeighting(t *testing.T, margin float64) {
+ rand.Seed(1)
+ data := []*SRV{
+ {Target: "a", Weight: 60},
+ {Target: "b", Weight: 30},
+ {Target: "c", Weight: 10},
+ }
+ checkDistribution(t, data, margin)
+}
+
+func TestWeighting(t *testing.T) {
+ testWeighting(t, 0.05)
+}
diff --git a/libgo/go/net/dnsclient_unix.go b/libgo/go/net/dnsclient_unix.go
index 16cf420dcd..7511083f79 100644
--- a/libgo/go/net/dnsclient_unix.go
+++ b/libgo/go/net/dnsclient_unix.go
@@ -2,13 +2,12 @@
// 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
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
// DNS client: see RFC 1035.
// Has to be linked into package net for Dial.
// TODO(rsc):
-// Check periodically whether /etc/resolv.conf has changed.
// Could potentially handle many outstanding lookups faster.
// Could have a small cache.
// Random UDP source port (net.Dial should do that for us).
@@ -17,124 +16,182 @@
package net
import (
+ "errors"
"io"
"math/rand"
+ "os"
"sync"
"time"
)
-// Send a request on the connection and hope for a reply.
-// Up to cfg.attempts attempts.
-func exchange(cfg *dnsConfig, c Conn, name string, qtype uint16) (*dnsMsg, error) {
- _, useTCP := c.(*TCPConn)
- if len(name) >= 256 {
- return nil, &DNSError{Err: "name too long", Name: name}
+// A dnsConn represents a DNS transport endpoint.
+type dnsConn interface {
+ Conn
+
+ // readDNSResponse reads a DNS response message from the DNS
+ // transport endpoint and returns the received DNS response
+ // message.
+ readDNSResponse() (*dnsMsg, error)
+
+ // writeDNSQuery writes a DNS query message to the DNS
+ // connection endpoint.
+ writeDNSQuery(*dnsMsg) error
+}
+
+func (c *UDPConn) readDNSResponse() (*dnsMsg, error) {
+ b := make([]byte, 512) // see RFC 1035
+ n, err := c.Read(b)
+ if err != nil {
+ return nil, err
}
- out := new(dnsMsg)
- out.id = uint16(rand.Int()) ^ uint16(time.Now().UnixNano())
- out.question = []dnsQuestion{
- {name, qtype, dnsClassINET},
+ msg := &dnsMsg{}
+ if !msg.Unpack(b[:n]) {
+ return nil, errors.New("cannot unmarshal DNS message")
}
- out.recursion_desired = true
- msg, ok := out.Pack()
+ return msg, nil
+}
+
+func (c *UDPConn) writeDNSQuery(msg *dnsMsg) error {
+ b, ok := msg.Pack()
if !ok {
- return nil, &DNSError{Err: "internal error - cannot pack message", Name: name}
+ return errors.New("cannot marshal DNS message")
+ }
+ if _, err := c.Write(b); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (c *TCPConn) readDNSResponse() (*dnsMsg, error) {
+ b := make([]byte, 1280) // 1280 is a reasonable initial size for IP over Ethernet, see RFC 4035
+ if _, err := io.ReadFull(c, b[:2]); err != nil {
+ return nil, err
+ }
+ l := int(b[0])<<8 | int(b[1])
+ if l > len(b) {
+ b = make([]byte, l)
+ }
+ n, err := io.ReadFull(c, b[:l])
+ if err != nil {
+ return nil, err
+ }
+ msg := &dnsMsg{}
+ if !msg.Unpack(b[:n]) {
+ return nil, errors.New("cannot unmarshal DNS message")
+ }
+ return msg, nil
+}
+
+func (c *TCPConn) writeDNSQuery(msg *dnsMsg) error {
+ b, ok := msg.Pack()
+ if !ok {
+ return errors.New("cannot marshal DNS message")
+ }
+ l := uint16(len(b))
+ b = append([]byte{byte(l >> 8), byte(l)}, b...)
+ if _, err := c.Write(b); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (d *Dialer) dialDNS(network, server string) (dnsConn, error) {
+ switch network {
+ case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6":
+ default:
+ return nil, UnknownNetworkError(network)
+ }
+ // Calling Dial here is scary -- we have to be sure not to
+ // dial a name that will require a DNS lookup, or Dial will
+ // call back here to translate it. The DNS config parser has
+ // already checked that all the cfg.servers[i] are IP
+ // addresses, which Dial will use without a DNS lookup.
+ c, err := d.Dial(network, server)
+ if err != nil {
+ return nil, err
}
- if useTCP {
- mlen := uint16(len(msg))
- msg = append([]byte{byte(mlen >> 8), byte(mlen)}, msg...)
+ switch network {
+ case "tcp", "tcp4", "tcp6":
+ return c.(*TCPConn), nil
+ case "udp", "udp4", "udp6":
+ return c.(*UDPConn), nil
+ }
+ panic("unreachable")
+}
+
+// exchange sends a query on the connection and hopes for a response.
+func exchange(server, name string, qtype uint16, timeout time.Duration) (*dnsMsg, error) {
+ d := Dialer{Timeout: timeout}
+ out := dnsMsg{
+ dnsMsgHdr: dnsMsgHdr{
+ recursion_desired: true,
+ },
+ question: []dnsQuestion{
+ {name, qtype, dnsClassINET},
+ },
}
- for attempt := 0; attempt < cfg.attempts; attempt++ {
- n, err := c.Write(msg)
+ for _, network := range []string{"udp", "tcp"} {
+ c, err := d.dialDNS(network, server)
if err != nil {
return nil, err
}
-
- if cfg.timeout == 0 {
- c.SetReadDeadline(noDeadline)
- } else {
- c.SetReadDeadline(time.Now().Add(time.Duration(cfg.timeout) * time.Second))
+ defer c.Close()
+ if timeout > 0 {
+ c.SetDeadline(time.Now().Add(timeout))
}
- buf := make([]byte, 2000)
- if useTCP {
- n, err = io.ReadFull(c, buf[:2])
- if err != nil {
- if e, ok := err.(Error); ok && e.Timeout() {
- continue
- }
- }
- mlen := int(buf[0])<<8 | int(buf[1])
- if mlen > len(buf) {
- buf = make([]byte, mlen)
- }
- n, err = io.ReadFull(c, buf[:mlen])
- } else {
- n, err = c.Read(buf)
+ out.id = uint16(rand.Int()) ^ uint16(time.Now().UnixNano())
+ if err := c.writeDNSQuery(&out); err != nil {
+ return nil, err
}
+ in, err := c.readDNSResponse()
if err != nil {
- if e, ok := err.(Error); ok && e.Timeout() {
- continue
- }
return nil, err
}
- buf = buf[:n]
- in := new(dnsMsg)
- if !in.Unpack(buf) || in.id != out.id {
+ if in.id != out.id {
+ return nil, errors.New("DNS message ID mismatch")
+ }
+ if in.truncated { // see RFC 5966
continue
}
return in, nil
}
- var server string
- if a := c.RemoteAddr(); a != nil {
- server = a.String()
- }
- return nil, &DNSError{Err: "no answer from server", Name: name, Server: server, IsTimeout: true}
+ return nil, errors.New("no answer from DNS server")
}
// Do a lookup for a single name, which must be rooted
// (otherwise answer will not find the answers).
-func tryOneName(cfg *dnsConfig, name string, qtype uint16) (cname string, addrs []dnsRR, err error) {
+func tryOneName(cfg *dnsConfig, name string, qtype uint16) (string, []dnsRR, error) {
if len(cfg.servers) == 0 {
return "", nil, &DNSError{Err: "no DNS servers", Name: name}
}
- for i := 0; i < len(cfg.servers); i++ {
- // Calling Dial here is scary -- we have to be sure
- // not to dial a name that will require a DNS lookup,
- // or Dial will call back here to translate it.
- // The DNS config parser has already checked that
- // all the cfg.servers[i] are IP addresses, which
- // Dial will use without a DNS lookup.
- server := cfg.servers[i] + ":53"
- c, cerr := Dial("udp", server)
- if cerr != nil {
- err = cerr
- continue
- }
- msg, merr := exchange(cfg, c, name, qtype)
- c.Close()
- if merr != nil {
- err = merr
- continue
- }
- if msg.truncated { // see RFC 5966
- c, cerr = Dial("tcp", server)
- if cerr != nil {
- err = cerr
+ if len(name) >= 256 {
+ return "", nil, &DNSError{Err: "DNS name too long", Name: name}
+ }
+ timeout := time.Duration(cfg.timeout) * time.Second
+ var lastErr error
+ for i := 0; i < cfg.attempts; i++ {
+ for _, server := range cfg.servers {
+ server = JoinHostPort(server, "53")
+ msg, err := exchange(server, name, qtype, timeout)
+ if err != nil {
+ lastErr = &DNSError{
+ Err: err.Error(),
+ Name: name,
+ Server: server,
+ }
+ if nerr, ok := err.(Error); ok && nerr.Timeout() {
+ lastErr.(*DNSError).IsTimeout = true
+ }
continue
}
- msg, merr = exchange(cfg, c, name, qtype)
- c.Close()
- if merr != nil {
- err = merr
- continue
+ cname, addrs, err := answer(name, server, msg, qtype)
+ if err == nil || err.(*DNSError).Err == noSuchHost {
+ return cname, addrs, err
}
- }
- cname, addrs, err = answer(name, server, msg, qtype)
- if err == nil || err.(*DNSError).Err == noSuchHost {
- break
+ lastErr = err
}
}
- return
+ return "", nil, lastErr
}
func convertRR_A(records []dnsRR) []IP {
@@ -156,61 +213,116 @@ func convertRR_AAAA(records []dnsRR) []IP {
return addrs
}
-var cfg *dnsConfig
-var dnserr error
+var cfg struct {
+ ch chan struct{}
+ mu sync.RWMutex // protects dnsConfig and dnserr
+ dnsConfig *dnsConfig
+ dnserr error
+}
+var onceLoadConfig sync.Once
-func loadConfig() { cfg, dnserr = dnsReadConfig() }
+// Assume dns config file is /etc/resolv.conf here
+func loadDefaultConfig() {
+ loadConfig("/etc/resolv.conf", 5*time.Second, nil)
+}
-var onceLoadConfig sync.Once
+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:
+ }
+
+ // 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}
}
- onceLoadConfig.Do(loadConfig)
- if dnserr != nil || cfg == nil {
- err = dnserr
+ onceLoadConfig.Do(loadDefaultConfig)
+
+ select {
+ case cfg.ch <- struct{}{}:
+ default:
+ }
+
+ cfg.mu.RLock()
+ defer cfg.mu.RUnlock()
+
+ if cfg.dnserr != nil || cfg.dnsConfig == nil {
+ err = cfg.dnserr
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.ndots {
+ if rooted || count(name, '.') >= cfg.dnsConfig.ndots {
rname := name
if !rooted {
rname += "."
}
// Can try as ordinary name.
- cname, addrs, err = tryOneName(cfg, rname, qtype)
- if err == nil {
+ cname, addrs, err = tryOneName(cfg.dnsConfig, rname, qtype)
+ if rooted || err == nil {
return
}
}
- if rooted {
- return
- }
// Otherwise, try suffixes.
- for i := 0; i < len(cfg.search); i++ {
- rname := name + "." + cfg.search[i]
+ for i := 0; i < len(cfg.dnsConfig.search); i++ {
+ rname := name + "." + cfg.dnsConfig.search[i]
if rname[len(rname)-1] != '.' {
rname += "."
}
- cname, addrs, err = tryOneName(cfg, rname, qtype)
+ cname, addrs, err = tryOneName(cfg.dnsConfig, rname, qtype)
if err == nil {
return
}
}
- // Last ditch effort: try unsuffixed.
- rname := name
- if !rooted {
- rname += "."
- }
- cname, addrs, err = tryOneName(cfg, rname, qtype)
- if err == nil {
- return
+ // 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)
+ if err == nil {
+ return
+ }
}
+
if e, ok := err.(*DNSError); ok {
// Show original name passed to lookup, not suffixed one.
// In general we might have tried many suffixes; showing
@@ -232,11 +344,6 @@ func goLookupHost(name string) (addrs []string, err error) {
if len(addrs) > 0 {
return
}
- onceLoadConfig.Do(loadConfig)
- if dnserr != nil || cfg == nil {
- err = dnserr
- return
- }
ips, err := goLookupIP(name)
if err != nil {
return
@@ -267,36 +374,36 @@ func goLookupIP(name string) (addrs []IP, err error) {
return
}
}
- onceLoadConfig.Do(loadConfig)
- if dnserr != nil || cfg == nil {
- err = dnserr
- return
- }
- var records []dnsRR
- var cname string
- var err4, err6 error
- cname, records, err4 = lookup(name, dnsTypeA)
- addrs = convertRR_A(records)
- if cname != "" {
- name = cname
- }
- _, records, err6 = lookup(name, dnsTypeAAAA)
- if err4 != nil && err6 == nil {
- // Ignore A error because AAAA lookup succeeded.
- err4 = nil
+ type racer struct {
+ qtype uint16
+ rrs []dnsRR
+ error
}
- if err6 != nil && len(addrs) > 0 {
- // Ignore AAAA error because A lookup succeeded.
- err6 = nil
+ 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)
}
- if err4 != nil {
- return nil, err4
+ var lastErr error
+ for range qtypes {
+ racer := <-lane
+ if racer.error != nil {
+ lastErr = racer.error
+ continue
+ }
+ switch racer.qtype {
+ case dnsTypeA:
+ addrs = append(addrs, convertRR_A(racer.rrs)...)
+ case dnsTypeAAAA:
+ addrs = append(addrs, convertRR_AAAA(racer.rrs)...)
+ }
}
- if err6 != nil {
- return nil, err6
+ if len(addrs) == 0 && lastErr != nil {
+ return nil, lastErr
}
-
- addrs = append(addrs, convertRR_AAAA(records)...)
return addrs, nil
}
@@ -307,11 +414,6 @@ 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) {
- onceLoadConfig.Do(loadConfig)
- if dnserr != nil || cfg == nil {
- err = dnserr
- return
- }
_, rr, err := lookup(name, dnsTypeCNAME)
if err != nil {
return
diff --git a/libgo/go/net/dnsclient_unix_test.go b/libgo/go/net/dnsclient_unix_test.go
index 47dcb563bc..1167c26b39 100644
--- a/libgo/go/net/dnsclient_unix_test.go
+++ b/libgo/go/net/dnsclient_unix_test.go
@@ -2,26 +2,245 @@
// 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
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package net
import (
+ "io"
+ "io/ioutil"
+ "os"
+ "path"
+ "reflect"
"testing"
+ "time"
)
-func TestTCPLookup(t *testing.T) {
+var dnsTransportFallbackTests = []struct {
+ server string
+ name string
+ qtype uint16
+ timeout int
+ rcode int
+}{
+ // Querying "com." with qtype=255 usually makes an answer
+ // which requires more than 512 bytes.
+ {"8.8.8.8:53", "com.", dnsTypeALL, 2, dnsRcodeSuccess},
+ {"8.8.4.4:53", "com.", dnsTypeALL, 4, dnsRcodeSuccess},
+}
+
+func TestDNSTransportFallback(t *testing.T) {
+ if testing.Short() || !*testExternal {
+ t.Skip("skipping test to avoid external network")
+ }
+
+ for _, tt := range dnsTransportFallbackTests {
+ timeout := time.Duration(tt.timeout) * time.Second
+ msg, err := exchange(tt.server, tt.name, tt.qtype, timeout)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ switch msg.rcode {
+ case tt.rcode, dnsRcodeServerFailure:
+ default:
+ t.Errorf("got %v from %v; want %v", msg.rcode, tt.server, tt.rcode)
+ continue
+ }
+ }
+}
+
+// See RFC 6761 for further information about the reserved, pseudo
+// domain names.
+var specialDomainNameTests = []struct {
+ name string
+ qtype uint16
+ rcode int
+}{
+ // Name resoltion APIs and libraries should not recongnize 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
+ // 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.
+ {"localhost.", dnsTypeALL, dnsRcodeNameError},
+ {"invalid.", dnsTypeALL, dnsRcodeNameError},
+}
+
+func TestSpecialDomainName(t *testing.T) {
if testing.Short() || !*testExternal {
t.Skip("skipping test to avoid external network")
}
- c, err := Dial("tcp", "8.8.8.8:53")
+
+ server := "8.8.8.8:53"
+ for _, tt := range specialDomainNameTests {
+ msg, err := exchange(server, tt.name, tt.qtype, 0)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ switch msg.rcode {
+ case tt.rcode, dnsRcodeServerFailure:
+ default:
+ t.Errorf("got %v from %v; want %v", msg.rcode, server, tt.rcode)
+ continue
+ }
+ }
+}
+
+type resolvConfTest struct {
+ *testing.T
+ dir string
+ path string
+ started bool
+ quitc chan chan struct{}
+}
+
+func newResolvConfTest(t *testing.T) *resolvConfTest {
+ dir, err := ioutil.TempDir("", "resolvConfTest")
if err != nil {
- t.Fatalf("Dial failed: %v", err)
+ t.Fatalf("could not create temp dir: %v", err)
}
- defer c.Close()
- cfg := &dnsConfig{timeout: 10, attempts: 3}
- _, err = exchange(cfg, c, "com.", dnsTypeALL)
+
+ // Disable the default loadConfig
+ onceLoadConfig.Do(func() {})
+
+ r := &resolvConfTest{
+ T: t,
+ dir: dir,
+ path: path.Join(dir, "resolv.conf"),
+ quitc: make(chan chan struct{}),
+ }
+
+ return r
+}
+
+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)
if err != nil {
- t.Fatalf("exchange failed: %v", err)
+ r.Fatalf("failed to create temp file %s: %v", r.path, err)
+ }
+ if _, err := io.WriteString(f, s); err != nil {
+ f.Close()
+ r.Fatalf("failed to write temp file: %v", 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
+ }
+}
+
+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 (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 TestReloadResolvConfFail(t *testing.T) {
+ if testing.Short() || !*testExternal {
+ t.Skip("skipping test to avoid external network")
+ }
+
+ r := newResolvConfTest(t)
+ defer r.Close()
+
+ // resolv.conf.tmp does not exist yet
+ r.Start()
+ if _, err := goLookupIP("golang.org"); err == nil {
+ t.Fatal("goLookupIP(missing) succeeded")
+ }
+
+ r.SetConf("nameserver 8.8.8.8")
+ if _, err := goLookupIP("golang.org"); err != nil {
+ t.Fatalf("goLookupIP(missing; good) failed: %v", err)
+ }
+
+ // 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)
+ }
+}
+
+func TestReloadResolvConfChange(t *testing.T) {
+ if testing.Short() || !*testExternal {
+ t.Skip("skipping test to 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)
+ }
+ r.WantServers([]string{"8.8.8.8"})
+
+ // 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)
+ }
+
+ // 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) {
+ for i := 0; i < b.N; i++ {
+ goLookupIP("www.example.com")
+ }
+}
+
+func BenchmarkGoLookupIPNoSuchHost(b *testing.B) {
+ 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
+ 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 2f0f6c031f..66ab7c4dd3 100644
--- a/libgo/go/net/dnsconfig_unix.go
+++ b/libgo/go/net/dnsconfig_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
// Read system DNS config from /etc/resolv.conf
@@ -20,19 +20,17 @@ type dnsConfig struct {
// 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.
-// We assume it's in resolv.conf anyway.
-func dnsReadConfig() (*dnsConfig, error) {
- file, err := open("/etc/resolv.conf")
+func dnsReadConfig(filename string) (*dnsConfig, error) {
+ file, err := open(filename)
if err != nil {
return nil, &DNSConfigError{err}
}
- conf := new(dnsConfig)
- conf.servers = make([]string, 3)[0:0] // small, but the standard limit
- conf.search = make([]string, 0)
- conf.ndots = 1
- conf.timeout = 5
- conf.attempts = 2
- conf.rotate = false
+ defer file.close()
+ conf := &dnsConfig{
+ ndots: 1,
+ timeout: 5,
+ attempts: 2,
+ }
for line, ok := file.readLine(); ok; line, ok = file.readLine() {
f := getFields(line)
if len(f) < 1 {
@@ -40,30 +38,20 @@ func dnsReadConfig() (*dnsConfig, error) {
}
switch f[0] {
case "nameserver": // add one name server
- a := conf.servers
- n := len(a)
- if len(f) > 1 && n < cap(a) {
+ if len(f) > 1 && len(conf.servers) < 3 { // small, but the standard limit
// One more check: make sure server name is
// just an IP address. Otherwise we need DNS
// to look it up.
- name := f[1]
- switch len(ParseIP(name)) {
- case 16:
- name = "[" + name + "]"
- fallthrough
- case 4:
- a = a[0 : n+1]
- a[n] = name
- conf.servers = a
+ if parseIPv4(f[1]) != nil {
+ conf.servers = append(conf.servers, f[1])
+ } else if ip, _ := parseIPv6(f[1], true); ip != nil {
+ conf.servers = append(conf.servers, f[1])
}
}
case "domain": // set search path to just this domain
if len(f) > 1 {
- conf.search = make([]string, 1)
- conf.search[0] = f[1]
- } else {
- conf.search = make([]string, 0)
+ conf.search = []string{f[1]}
}
case "search": // set search path to given servers
@@ -76,19 +64,19 @@ func dnsReadConfig() (*dnsConfig, error) {
for i := 1; i < len(f); i++ {
s := f[i]
switch {
- case len(s) >= 6 && s[0:6] == "ndots:":
+ case hasPrefix(s, "ndots:"):
n, _, _ := dtoi(s, 6)
if n < 1 {
n = 1
}
conf.ndots = n
- case len(s) >= 8 && s[0:8] == "timeout:":
+ case hasPrefix(s, "timeout:"):
n, _, _ := dtoi(s, 8)
if n < 1 {
n = 1
}
conf.timeout = n
- case len(s) >= 8 && s[0:9] == "attempts:":
+ case hasPrefix(s, "attempts:"):
n, _, _ := dtoi(s, 9)
if n < 1 {
n = 1
@@ -100,7 +88,9 @@ func dnsReadConfig() (*dnsConfig, error) {
}
}
}
- file.close()
-
return conf, nil
}
+
+func hasPrefix(s, prefix string) bool {
+ return len(s) >= len(prefix) && s[:len(prefix)] == prefix
+}
diff --git a/libgo/go/net/dnsconfig_unix_test.go b/libgo/go/net/dnsconfig_unix_test.go
new file mode 100644
index 0000000000..94fb0c32e2
--- /dev/null
+++ b/libgo/go/net/dnsconfig_unix_test.go
@@ -0,0 +1,69 @@
+// 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 netbsd openbsd solaris
+
+package net
+
+import (
+ "reflect"
+ "testing"
+)
+
+var dnsReadConfigTests = []struct {
+ name string
+ conf 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,
+ },
+ },
+ {
+ name: "testdata/domain-resolv.conf",
+ conf: dnsConfig{
+ servers: []string{"8.8.8.8"},
+ search: []string{"localdomain"},
+ ndots: 1,
+ timeout: 5,
+ attempts: 2,
+ },
+ },
+ {
+ name: "testdata/search-resolv.conf",
+ conf: dnsConfig{
+ servers: []string{"8.8.8.8"},
+ search: []string{"test", "invalid"},
+ ndots: 1,
+ timeout: 5,
+ attempts: 2,
+ },
+ },
+ {
+ name: "testdata/empty-resolv.conf",
+ conf: dnsConfig{
+ ndots: 1,
+ timeout: 5,
+ attempts: 2,
+ },
+ },
+}
+
+func TestDNSReadConfig(t *testing.T) {
+ for _, tt := range dnsReadConfigTests {
+ conf, err := dnsReadConfig(tt.name)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !reflect.DeepEqual(conf, &tt.conf) {
+ t.Errorf("got %v; want %v", conf, &tt.conf)
+ }
+ }
+}
diff --git a/libgo/go/net/fd_mutex_test.go b/libgo/go/net/fd_mutex_test.go
index 8383084b7a..c34ec59b99 100644
--- a/libgo/go/net/fd_mutex_test.go
+++ b/libgo/go/net/fd_mutex_test.go
@@ -63,7 +63,8 @@ func TestMutexCloseUnblock(t *testing.T) {
for i := 0; i < 4; i++ {
go func() {
if mu.RWLock(true) {
- t.Fatal("broken")
+ t.Error("broken")
+ return
}
c <- true
}()
@@ -138,36 +139,44 @@ func TestMutexStress(t *testing.T) {
switch r.Intn(3) {
case 0:
if !mu.Incref() {
- t.Fatal("broken")
+ t.Error("broken")
+ return
}
if mu.Decref() {
- t.Fatal("broken")
+ t.Error("broken")
+ return
}
case 1:
if !mu.RWLock(true) {
- t.Fatal("broken")
+ t.Error("broken")
+ return
}
// Ensure that it provides mutual exclusion for readers.
if readState[0] != readState[1] {
- t.Fatal("broken")
+ t.Error("broken")
+ return
}
readState[0]++
readState[1]++
if mu.RWUnlock(true) {
- t.Fatal("broken")
+ t.Error("broken")
+ return
}
case 2:
if !mu.RWLock(false) {
- t.Fatal("broken")
+ t.Error("broken")
+ return
}
// Ensure that it provides mutual exclusion for writers.
if writeState[0] != writeState[1] {
- t.Fatal("broken")
+ t.Error("broken")
+ return
}
writeState[0]++
writeState[1]++
if mu.RWUnlock(false) {
- t.Fatal("broken")
+ t.Error("broken")
+ return
}
}
}
diff --git a/libgo/go/net/fd_plan9.go b/libgo/go/net/fd_plan9.go
index acc8294021..5fe8effc29 100644
--- a/libgo/go/net/fd_plan9.go
+++ b/libgo/go/net/fd_plan9.go
@@ -13,12 +13,23 @@ import (
// Network file descritor.
type netFD struct {
- proto, name, dir string
- ctl, data *os.File
- laddr, raddr Addr
+ // locking/lifetime of sysfd + serialize access to Read and Write methods
+ fdmu fdMutex
+
+ // immutable until Close
+ proto string
+ n string
+ dir string
+ ctl, data *os.File
+ laddr, raddr Addr
}
+var (
+ netdir string // default network
+)
+
func sysInit() {
+ netdir = "/net"
}
func dial(net string, ra Addr, dialer func(time.Time) (Conn, error), deadline time.Time) (Conn, error) {
@@ -27,16 +38,99 @@ 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 {
- return &netFD{proto, name, "/net/" + proto + "/" + name, ctl, data, laddr, raddr}
+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 (fd *netFD) init() error {
+ // stub for future fd.pd.Init(fd)
+ return nil
+}
+
+func (fd *netFD) name() string {
+ var ls, rs string
+ if fd.laddr != nil {
+ ls = fd.laddr.String()
+ }
+ if fd.raddr != nil {
+ rs = fd.raddr.String()
+ }
+ return fd.proto + ":" + ls + "->" + rs
}
func (fd *netFD) ok() bool { return fd != nil && fd.ctl != nil }
+func (fd *netFD) destroy() {
+ if !fd.ok() {
+ return
+ }
+ err := fd.ctl.Close()
+ if fd.data != nil {
+ if err1 := fd.data.Close(); err1 != nil && err == nil {
+ err = err1
+ }
+ }
+ fd.ctl = nil
+ fd.data = nil
+}
+
+// Add a reference to this fd.
+// Returns an error if the fd cannot be used.
+func (fd *netFD) incref() error {
+ if !fd.fdmu.Incref() {
+ return errClosing
+ }
+ return nil
+}
+
+// Remove a reference to this FD and close if we've been asked to do so
+// (and there are no references left).
+func (fd *netFD) decref() {
+ if fd.fdmu.Decref() {
+ fd.destroy()
+ }
+}
+
+// Add a reference to this fd and lock for reading.
+// Returns an error if the fd cannot be used.
+func (fd *netFD) readLock() error {
+ if !fd.fdmu.RWLock(true) {
+ return errClosing
+ }
+ return nil
+}
+
+// Unlock for reading and remove a reference to this FD.
+func (fd *netFD) readUnlock() {
+ if fd.fdmu.RWUnlock(true) {
+ fd.destroy()
+ }
+}
+
+// Add a reference to this fd and lock for writing.
+// Returns an error if the fd cannot be used.
+func (fd *netFD) writeLock() error {
+ if !fd.fdmu.RWLock(false) {
+ return errClosing
+ }
+ return nil
+}
+
+// Unlock for writing and remove a reference to this FD.
+func (fd *netFD) writeUnlock() {
+ if fd.fdmu.RWUnlock(false) {
+ fd.destroy()
+ }
+}
+
func (fd *netFD) Read(b []byte) (n int, err error) {
if !fd.ok() || fd.data == nil {
return 0, syscall.EINVAL
}
+ if err := fd.readLock(); err != nil {
+ return 0, err
+ }
+ defer fd.readUnlock()
n, err = fd.data.Read(b)
if fd.proto == "udp" && err == io.EOF {
n = 0
@@ -49,17 +143,21 @@ func (fd *netFD) Write(b []byte) (n int, err error) {
if !fd.ok() || fd.data == nil {
return 0, syscall.EINVAL
}
+ if err := fd.writeLock(); err != nil {
+ return 0, err
+ }
+ defer fd.writeUnlock()
return fd.data.Write(b)
}
-func (fd *netFD) CloseRead() error {
+func (fd *netFD) closeRead() error {
if !fd.ok() {
return syscall.EINVAL
}
return syscall.EPLAN9
}
-func (fd *netFD) CloseWrite() error {
+func (fd *netFD) closeWrite() error {
if !fd.ok() {
return syscall.EINVAL
}
@@ -67,6 +165,9 @@ func (fd *netFD) CloseWrite() error {
}
func (fd *netFD) Close() error {
+ if !fd.fdmu.IncrefAndClose() {
+ return errClosing
+ }
if !fd.ok() {
return syscall.EINVAL
}
diff --git a/libgo/go/net/fd_poll_nacl.go b/libgo/go/net/fd_poll_nacl.go
new file mode 100644
index 0000000000..a3701f8764
--- /dev/null
+++ b/libgo/go/net/fd_poll_nacl.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 net
+
+import (
+ "syscall"
+ "time"
+)
+
+type pollDesc struct {
+ fd *netFD
+ closing bool
+}
+
+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 {
+ pd.closing = true
+ if pd.fd != nil {
+ syscall.StopIO(pd.fd.sysfd)
+ }
+ return false
+}
+
+func (pd *pollDesc) Prepare(mode int) error {
+ if pd.closing {
+ return errClosing
+ }
+ return nil
+}
+
+func (pd *pollDesc) PrepareRead() error { return pd.Prepare('r') }
+
+func (pd *pollDesc) PrepareWrite() error { return pd.Prepare('w') }
+
+func (pd *pollDesc) Wait(mode int) error {
+ if pd.closing {
+ return errClosing
+ }
+ return errTimeout
+}
+
+func (pd *pollDesc) WaitRead() error { return pd.Wait('r') }
+
+func (pd *pollDesc) WaitWrite() error { return pd.Wait('w') }
+
+func (pd *pollDesc) WaitCanceled(mode int) {}
+
+func (pd *pollDesc) WaitCanceledRead() {}
+
+func (pd *pollDesc) WaitCanceledWrite() {}
+
+func (fd *netFD) setDeadline(t time.Time) error {
+ return setDeadlineImpl(fd, t, 'r'+'w')
+}
+
+func (fd *netFD) setReadDeadline(t time.Time) error {
+ return setDeadlineImpl(fd, t, 'r')
+}
+
+func (fd *netFD) setWriteDeadline(t time.Time) error {
+ return setDeadlineImpl(fd, t, 'w')
+}
+
+func setDeadlineImpl(fd *netFD, t time.Time, mode int) error {
+ d := t.UnixNano()
+ if t.IsZero() {
+ d = 0
+ }
+ if err := fd.incref(); err != nil {
+ return err
+ }
+ switch mode {
+ case 'r':
+ syscall.SetReadDeadline(fd.sysfd, d)
+ case 'w':
+ syscall.SetWriteDeadline(fd.sysfd, d)
+ case 'r' + 'w':
+ syscall.SetReadDeadline(fd.sysfd, d)
+ syscall.SetWriteDeadline(fd.sysfd, d)
+ }
+ fd.decref()
+ return nil
+}
diff --git a/libgo/go/net/fd_poll_runtime.go b/libgo/go/net/fd_poll_runtime.go
index e2b2768864..2bddc836c7 100644
--- a/libgo/go/net/fd_poll_runtime.go
+++ b/libgo/go/net/fd_poll_runtime.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 netbsd openbsd windows
+// +build darwin dragonfly freebsd linux netbsd openbsd windows solaris
package net
@@ -12,6 +12,9 @@ import (
"time"
)
+// runtimeNano returns the current value of the runtime clock in nanoseconds.
+func runtimeNano() int64
+
func runtime_pollServerInit()
func runtime_pollOpen(fd uintptr) (uintptr, int)
func runtime_pollClose(ctx uintptr)
@@ -128,7 +131,7 @@ func (fd *netFD) setWriteDeadline(t time.Time) error {
}
func setDeadlineImpl(fd *netFD, t time.Time, mode int) error {
- d := t.UnixNano()
+ d := runtimeNano() + int64(t.Sub(time.Now()))
if t.IsZero() {
d = 0
}
diff --git a/libgo/go/net/fd_unix.go b/libgo/go/net/fd_unix.go
index a89303e37e..7a97faeba3 100644
--- a/libgo/go/net/fd_unix.go
+++ b/libgo/go/net/fd_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 netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package net
@@ -68,36 +68,64 @@ func (fd *netFD) name() string {
return fd.net + ":" + ls + "->" + rs
}
-func (fd *netFD) connect(la, ra syscall.Sockaddr) error {
+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.
- if err := fd.pd.PrepareWrite(); err != nil {
- return err
- }
- for {
- err := syscall.Connect(fd.sysfd, ra)
- if err == nil || err == syscall.EISCONN {
- break
+ switch err := syscall.Connect(fd.sysfd, ra); err {
+ case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
+ case nil, syscall.EISCONN:
+ if !deadline.IsZero() && deadline.Before(time.Now()) {
+ return errTimeout
}
-
+ if err := fd.init(); err != nil {
+ return err
+ }
+ return nil
+ case syscall.EINVAL:
// On Solaris we can see EINVAL if the socket has
// 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.
- if runtime.GOOS == "solaris" && err == syscall.EINVAL {
- break
+ if runtime.GOOS == "solaris" {
+ return nil
}
-
- if err != syscall.EINPROGRESS && err != syscall.EALREADY && err != syscall.EINTR {
+ fallthrough
+ default:
+ return err
+ }
+ if err := fd.init(); err != nil {
+ return err
+ }
+ if !deadline.IsZero() {
+ fd.setWriteDeadline(deadline)
+ defer fd.setWriteDeadline(noDeadline)
+ }
+ for {
+ // Performing multiple connect system calls on a
+ // non-blocking socket under Unix variants does not
+ // necessarily result in earlier errors being
+ // returned. Instead, once runtime-integrated network
+ // poller tells us that the socket is ready, get the
+ // SO_ERROR socket option to see if the connection
+ // succeeded or failed. See issue 7474 for further
+ // details.
+ if err := fd.pd.WaitWrite(); err != nil {
return err
}
- if err = fd.pd.WaitWrite(); err != nil {
+ nerr, err := syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
+ if err != nil {
+ return 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 nil
}
func (fd *netFD) destroy() {
@@ -190,11 +218,11 @@ func (fd *netFD) shutdown(how int) error {
return nil
}
-func (fd *netFD) CloseRead() error {
+func (fd *netFD) closeRead() error {
return fd.shutdown(syscall.SHUT_RD)
}
-func (fd *netFD) CloseWrite() error {
+func (fd *netFD) closeWrite() error {
return fd.shutdown(syscall.SHUT_WR)
}
@@ -225,7 +253,7 @@ func (fd *netFD) Read(p []byte) (n int, err error) {
return
}
-func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
+func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
if err := fd.readLock(); err != nil {
return 0, nil, err
}
@@ -252,7 +280,7 @@ func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
return
}
-func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
+func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
if err := fd.readLock(); err != nil {
return 0, 0, 0, nil, err
}
@@ -323,7 +351,7 @@ func (fd *netFD) Write(p []byte) (nn int, err error) {
return nn, err
}
-func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
+func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
if err := fd.writeLock(); err != nil {
return 0, err
}
@@ -348,7 +376,7 @@ func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
return
}
-func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
+func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
if err := fd.writeLock(); err != nil {
return 0, 0, err
}
@@ -357,7 +385,7 @@ func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob
return 0, 0, &OpError{"write", fd.net, fd.raddr, err}
}
for {
- err = syscall.Sendmsg(fd.sysfd, p, oob, sa, 0)
+ n, err = syscall.SendmsgN(fd.sysfd, p, oob, sa, 0)
if err == syscall.EAGAIN {
if err = fd.pd.WaitWrite(); err == nil {
continue
@@ -366,7 +394,6 @@ func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob
break
}
if err == nil {
- n = len(p)
oobn = len(oob)
} else {
err = &OpError{"write", fd.net, fd.raddr, err}
@@ -374,7 +401,7 @@ func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob
return
}
-func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (netfd *netFD, err error) {
+func (fd *netFD) accept() (netfd *netFD, err error) {
if err := fd.readLock(); err != nil {
return nil, err
}
@@ -411,7 +438,7 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (netfd *netFD, err e
return nil, err
}
lsa, _ := syscall.Getsockname(netfd.sysfd)
- netfd.setAddr(toAddr(lsa), toAddr(rsa))
+ netfd.setAddr(netfd.addrFunc()(lsa), netfd.addrFunc()(rsa))
return netfd, nil
}
@@ -465,7 +492,6 @@ 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 {
- syscall.ForkLock.RUnlock()
return nil, &OpError{"dup", fd.net, fd.laddr, err}
}
diff --git a/libgo/go/net/fd_unix_test.go b/libgo/go/net/fd_unix_test.go
index 65d3e69a76..fe8e8ff6a8 100644
--- a/libgo/go/net/fd_unix_test.go
+++ b/libgo/go/net/fd_unix_test.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 netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package net
diff --git a/libgo/go/net/fd_windows.go b/libgo/go/net/fd_windows.go
index 630fc5e6f7..f3a534a1de 100644
--- a/libgo/go/net/fd_windows.go
+++ b/libgo/go/net/fd_windows.go
@@ -119,7 +119,7 @@ func (o *operation) InitBuf(buf []byte) {
o.buf.Len = uint32(len(buf))
o.buf.Buf = nil
if len(buf) != 0 {
- o.buf.Buf = (*byte)(unsafe.Pointer(&buf[0]))
+ o.buf.Buf = &buf[0]
}
}
@@ -294,6 +294,18 @@ func (fd *netFD) init() error {
fd.skipSyncNotif = true
}
}
+ // Disable SIO_UDP_CONNRESET behavior.
+ // http://support.microsoft.com/kb/263823
+ switch fd.net {
+ case "udp", "udp4", "udp6":
+ ret := uint32(0)
+ flag := uint32(0)
+ size := uint32(unsafe.Sizeof(flag))
+ err := syscall.WSAIoctl(fd.sysfd, syscall.SIO_UDP_CONNRESET, (*byte)(unsafe.Pointer(&flag)), size, nil, 0, &ret, nil, 0)
+ if err != nil {
+ return os.NewSyscallError("WSAIoctl", err)
+ }
+ }
fd.rop.mode = 'r'
fd.wop.mode = 'w'
fd.rop.fd = fd
@@ -313,10 +325,17 @@ func (fd *netFD) setAddr(laddr, raddr Addr) {
runtime.SetFinalizer(fd, (*netFD).Close)
}
-func (fd *netFD) connect(la, ra syscall.Sockaddr) error {
+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.
+ if err := fd.init(); err != nil {
+ return err
+ }
+ if !deadline.IsZero() {
+ fd.setWriteDeadline(deadline)
+ defer fd.setWriteDeadline(noDeadline)
+ }
if !canUseConnectEx(fd.net) {
return syscall.Connect(fd.sysfd, ra)
}
@@ -431,11 +450,11 @@ func (fd *netFD) shutdown(how int) error {
return nil
}
-func (fd *netFD) CloseRead() error {
+func (fd *netFD) closeRead() error {
return fd.shutdown(syscall.SHUT_RD)
}
-func (fd *netFD) CloseWrite() error {
+func (fd *netFD) closeWrite() error {
return fd.shutdown(syscall.SHUT_WR)
}
@@ -458,7 +477,7 @@ func (fd *netFD) Read(buf []byte) (int, error) {
return n, err
}
-func (fd *netFD) ReadFrom(buf []byte) (n int, sa syscall.Sockaddr, err error) {
+func (fd *netFD) readFrom(buf []byte) (n int, sa syscall.Sockaddr, err error) {
if len(buf) == 0 {
return 0, nil, nil
}
@@ -497,7 +516,7 @@ func (fd *netFD) Write(buf []byte) (int, error) {
})
}
-func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (int, error) {
+func (fd *netFD) writeTo(buf []byte, sa syscall.Sockaddr) (int, error) {
if len(buf) == 0 {
return 0, nil
}
@@ -513,7 +532,7 @@ func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (int, error) {
})
}
-func (fd *netFD) acceptOne(toAddr func(syscall.Sockaddr) Addr, rawsa []syscall.RawSockaddrAny, o *operation) (*netFD, error) {
+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 {
@@ -552,7 +571,7 @@ func (fd *netFD) acceptOne(toAddr func(syscall.Sockaddr) Addr, rawsa []syscall.R
return netfd, nil
}
-func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (*netFD, error) {
+func (fd *netFD) accept() (*netFD, error) {
if err := fd.readLock(); err != nil {
return nil, err
}
@@ -563,7 +582,7 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (*netFD, error) {
var err error
var rawsa [2]syscall.RawSockaddrAny
for {
- netfd, err = fd.acceptOne(toAddr, rawsa[:], o)
+ netfd, err = fd.acceptOne(rawsa[:], o)
if err == nil {
break
}
@@ -596,7 +615,7 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (*netFD, error) {
lsa, _ := lrsa.Sockaddr()
rsa, _ := rrsa.Sockaddr()
- netfd.setAddr(toAddr(lsa), toAddr(rsa))
+ netfd.setAddr(netfd.addrFunc()(lsa), netfd.addrFunc()(rsa))
return netfd, nil
}
@@ -628,10 +647,10 @@ func (fd *netFD) dup() (*os.File, error) {
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) {
+func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
return 0, 0, 0, nil, errNoSupport
}
-func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
+func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
return 0, 0, errNoSupport
}
diff --git a/libgo/go/net/file_plan9.go b/libgo/go/net/file_plan9.go
index f6ee1c29e0..068f0881dd 100644
--- a/libgo/go/net/file_plan9.go
+++ b/libgo/go/net/file_plan9.go
@@ -43,7 +43,7 @@ func newFileFD(f *os.File) (net *netFD, err error) {
}
comp := splitAtBytes(path, "/")
n := len(comp)
- if n < 3 || comp[0] != "net" {
+ if n < 3 || comp[0][0:3] != "net" {
return nil, syscall.EPLAN9
}
@@ -58,7 +58,7 @@ func newFileFD(f *os.File) (net *netFD, err error) {
}
defer close(fd)
- dir := "/net/" + comp[n-2]
+ dir := netdir + "/" + comp[n-2]
ctl = os.NewFile(uintptr(fd), dir+"/"+file)
ctl.Seek(0, 0)
var buf [16]byte
@@ -71,19 +71,19 @@ func newFileFD(f *os.File) (net *netFD, err error) {
if len(comp) < 4 {
return nil, errors.New("could not find control file for connection")
}
- dir := "/net/" + comp[1] + "/" + name
+ dir := netdir + "/" + comp[1] + "/" + name
ctl, err = os.OpenFile(dir+"/ctl", os.O_RDWR, 0)
if err != nil {
return nil, err
}
defer close(int(ctl.Fd()))
}
- dir := "/net/" + comp[1] + "/" + name
+ dir := netdir + "/" + comp[1] + "/" + name
laddr, err := readPlan9Addr(comp[1], dir+"/local")
if err != nil {
return nil, err
}
- return newFD(comp[1], name, ctl, nil, laddr, nil), nil
+ return newFD(comp[1], name, ctl, nil, laddr, nil)
}
func newFileConn(f *os.File) (c Conn, err error) {
diff --git a/libgo/go/net/file_stub.go b/libgo/go/net/file_stub.go
new file mode 100644
index 0000000000..4281072ef9
--- /dev/null
+++ b/libgo/go/net/file_stub.go
@@ -0,0 +1,38 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build nacl
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+// FileConn returns a copy of the network connection corresponding to
+// the open file f. It is the caller's responsibility to close f when
+// finished. Closing c does not affect f, and closing f does not
+// affect c.
+func FileConn(f *os.File) (c Conn, err error) {
+ return nil, syscall.ENOPROTOOPT
+
+}
+
+// FileListener returns a copy of the network listener corresponding
+// to the open file f. It is the caller's responsibility to close l
+// when finished. Closing l does not affect f, and closing f does not
+// affect l.
+func FileListener(f *os.File) (l Listener, err error) {
+ return nil, syscall.ENOPROTOOPT
+
+}
+
+// FilePacketConn returns a copy of the packet network connection
+// corresponding to the open file f. It is the caller's
+// responsibility to close f when finished. Closing c does not affect
+// f, and closing f does not affect c.
+func FilePacketConn(f *os.File) (c PacketConn, err error) {
+ return nil, syscall.ENOPROTOOPT
+}
diff --git a/libgo/go/net/file_test.go b/libgo/go/net/file_test.go
index acaf188510..6fab06a9c6 100644
--- a/libgo/go/net/file_test.go
+++ b/libgo/go/net/file_test.go
@@ -89,7 +89,7 @@ var fileListenerTests = []struct {
func TestFileListener(t *testing.T) {
switch runtime.GOOS {
- case "windows":
+ case "nacl", "windows":
t.Skipf("skipping test on %q", runtime.GOOS)
}
@@ -174,12 +174,14 @@ var filePacketConnTests = []struct {
{net: "udp6", addr: "[::1]", ipv6: true},
+ {net: "ip4:icmp", addr: "127.0.0.1"},
+
{net: "unixgram", addr: "@gotest3/net", linux: true},
}
func TestFilePacketConn(t *testing.T) {
switch runtime.GOOS {
- case "plan9", "windows":
+ case "nacl", "plan9", "windows":
t.Skipf("skipping test on %q", runtime.GOOS)
}
@@ -187,6 +189,10 @@ func TestFilePacketConn(t *testing.T) {
if skipServerTest(tt.net, "unixgram", tt.addr, tt.ipv6, false, tt.linux) {
continue
}
+ if os.Getuid() != 0 && tt.net == "ip4:icmp" {
+ t.Log("skipping test; must be root")
+ continue
+ }
testFilePacketConnListen(t, tt.net, tt.addr)
switch tt.addr {
case "", "0.0.0.0", "[::ffff:0.0.0.0]", "[::]":
diff --git a/libgo/go/net/file_unix.go b/libgo/go/net/file_unix.go
index 8fe1b0eb03..214a4196c8 100644
--- a/libgo/go/net/file_unix.go
+++ b/libgo/go/net/file_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package net
@@ -129,6 +129,8 @@ func FilePacketConn(f *os.File) (c PacketConn, err error) {
switch fd.laddr.(type) {
case *UDPAddr:
return newUDPConn(fd), nil
+ case *IPAddr:
+ return newIPConn(fd), nil
case *UnixAddr:
return newUnixConn(fd), nil
}
diff --git a/libgo/go/net/hosts.go b/libgo/go/net/hosts.go
index e6674ba341..9400503e41 100644
--- a/libgo/go/net/hosts.go
+++ b/libgo/go/net/hosts.go
@@ -51,7 +51,7 @@ func readHosts() {
}
}
// Update the data cache.
- hosts.expire = time.Now().Add(cacheMaxAge)
+ hosts.expire = now.Add(cacheMaxAge)
hosts.path = hp
hosts.byName = hs
hosts.byAddr = is
diff --git a/libgo/go/net/hosts_test.go b/libgo/go/net/hosts_test.go
index b07ed0baa9..2fe358e079 100644
--- a/libgo/go/net/hosts_test.go
+++ b/libgo/go/net/hosts_test.go
@@ -41,7 +41,7 @@ func TestLookupStaticHost(t *testing.T) {
if len(ips) != len(tt.ips) {
t.Errorf("# of hosts = %v; want %v",
len(ips), len(tt.ips))
- return
+ continue
}
for k, v := range ips {
if tt.ips[k].String() != v {
diff --git a/libgo/go/net/http/cgi/host.go b/libgo/go/net/http/cgi/host.go
index d27cc4dc9a..ec95a972c1 100644
--- a/libgo/go/net/http/cgi/host.go
+++ b/libgo/go/net/http/cgi/host.go
@@ -214,12 +214,17 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
internalError(err)
return
}
+ if hook := testHookStartProcess; hook != nil {
+ hook(cmd.Process)
+ }
defer cmd.Wait()
defer stdoutRead.Close()
linebody := bufio.NewReaderSize(stdoutRead, 1024)
headers := make(http.Header)
statusCode := 0
+ headerLines := 0
+ sawBlankLine := false
for {
line, isPrefix, err := linebody.ReadLine()
if isPrefix {
@@ -236,8 +241,10 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
return
}
if len(line) == 0 {
+ sawBlankLine = true
break
}
+ headerLines++
parts := strings.SplitN(string(line), ":", 2)
if len(parts) < 2 {
h.printf("cgi: bogus header line: %s", string(line))
@@ -263,6 +270,11 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
headers.Add(header, val)
}
}
+ if headerLines == 0 || !sawBlankLine {
+ rw.WriteHeader(http.StatusInternalServerError)
+ h.printf("cgi: no headers")
+ return
+ }
if loc := headers.Get("Location"); loc != "" {
if strings.HasPrefix(loc, "/") && h.PathLocationHandler != nil {
@@ -274,6 +286,12 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
}
}
+ if statusCode == 0 && headers.Get("Content-Type") == "" {
+ rw.WriteHeader(http.StatusInternalServerError)
+ h.printf("cgi: missing required Content-Type in headers")
+ return
+ }
+
if statusCode == 0 {
statusCode = http.StatusOK
}
@@ -292,6 +310,13 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
_, err = io.Copy(rw, linebody)
if err != nil {
h.printf("cgi: copy error: %v", err)
+ // And kill the child CGI process so we don't hang on
+ // the deferred cmd.Wait above if the error was just
+ // the client (rw) going away. If it was a read error
+ // (because the child died itself), then the extra
+ // kill of an already-dead process is harmless (the PID
+ // won't be reused until the Wait above).
+ cmd.Process.Kill()
}
}
@@ -348,3 +373,5 @@ func upperCaseAndUnderscore(r rune) rune {
// TODO: other transformations in spec or practice?
return r
}
+
+var testHookStartProcess func(*os.Process) // nil except for some tests
diff --git a/libgo/go/net/http/cgi/matryoshka_test.go b/libgo/go/net/http/cgi/matryoshka_test.go
index e1a78c8f62..18c4803e71 100644
--- a/libgo/go/net/http/cgi/matryoshka_test.go
+++ b/libgo/go/net/http/cgi/matryoshka_test.go
@@ -9,15 +9,25 @@
package cgi
import (
+ "bytes"
+ "errors"
"fmt"
+ "io"
"net/http"
+ "net/http/httptest"
"os"
+ "runtime"
"testing"
+ "time"
)
// 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")
+ }
+
h := &Handler{
Path: os.Args[0],
Root: "/test.go",
@@ -51,8 +61,88 @@ func TestHostingOurselves(t *testing.T) {
}
}
-// Test that a child handler only writing headers works.
+type customWriterRecorder struct {
+ w io.Writer
+ *httptest.ResponseRecorder
+}
+
+func (r *customWriterRecorder) Write(p []byte) (n int, err error) {
+ return r.w.Write(p)
+}
+
+type limitWriter struct {
+ w io.Writer
+ n int
+}
+
+func (w *limitWriter) Write(p []byte) (n int, err error) {
+ if len(p) > w.n {
+ p = p[:w.n]
+ }
+ if len(p) > 0 {
+ n, err = w.w.Write(p)
+ w.n -= n
+ }
+ if w.n == 0 {
+ err = errors.New("past write limit")
+ }
+ return
+}
+
+// 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")
+ }
+
+ defer func() { testHookStartProcess = nil }()
+ proc := make(chan *os.Process, 1)
+ testHookStartProcess = func(p *os.Process) {
+ proc <- p
+ }
+
+ h := &Handler{
+ Path: os.Args[0],
+ Root: "/test.go",
+ Args: []string{"-test.run=TestBeChildCGIProcess"},
+ }
+ req, _ := http.NewRequest("GET", "http://example.com/test.cgi?write-forever=1", nil)
+ rec := httptest.NewRecorder()
+ var out bytes.Buffer
+ const writeLen = 50 << 10
+ rw := &customWriterRecorder{&limitWriter{&out, writeLen}, rec}
+
+ donec := make(chan bool, 1)
+ go func() {
+ h.ServeHTTP(rw, req)
+ donec <- true
+ }()
+
+ select {
+ case <-donec:
+ if out.Len() != writeLen || out.Bytes()[0] != 'a' {
+ t.Errorf("unexpected output: %q", out.Bytes())
+ }
+ case <-time.After(5 * time.Second):
+ t.Errorf("timeout. ServeHTTP hung and didn't kill the child process?")
+ select {
+ case p := <-proc:
+ p.Kill()
+ t.Logf("killed process")
+ default:
+ t.Logf("didn't kill process")
+ }
+ }
+}
+
+// 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")
+ }
+
h := &Handler{
Path: os.Args[0],
Root: "/test.go",
@@ -67,18 +157,63 @@ func TestChildOnlyHeaders(t *testing.T) {
}
}
+// golang.org/issue/7198
+func Test500WithNoHeaders(t *testing.T) { want500Test(t, "/immediate-disconnect") }
+func Test500WithNoContentType(t *testing.T) { want500Test(t, "/no-content-type") }
+func Test500WithEmptyHeaders(t *testing.T) { want500Test(t, "/empty-headers") }
+
+func want500Test(t *testing.T, path string) {
+ h := &Handler{
+ Path: os.Args[0],
+ Root: "/test.go",
+ Args: []string{"-test.run=TestBeChildCGIProcess"},
+ }
+ expectedMap := map[string]string{
+ "_body": "",
+ }
+ replay := runCgiTest(t, h, "GET "+path+" HTTP/1.0\nHost: example.com\n\n", expectedMap)
+ if replay.Code != 500 {
+ t.Errorf("Got code %d; want 500", replay.Code)
+ }
+}
+
+type neverEnding byte
+
+func (b neverEnding) Read(p []byte) (n int, err error) {
+ for i := range p {
+ p[i] = byte(b)
+ }
+ return len(p), nil
+}
+
// Note: not actually a test.
func TestBeChildCGIProcess(t *testing.T) {
if os.Getenv("REQUEST_METHOD") == "" {
// Not in a CGI environment; skipping test.
return
}
+ switch os.Getenv("REQUEST_URI") {
+ case "/immediate-disconnect":
+ os.Exit(0)
+ case "/no-content-type":
+ fmt.Printf("Content-Length: 6\n\nHello\n")
+ os.Exit(0)
+ case "/empty-headers":
+ fmt.Printf("\nHello")
+ os.Exit(0)
+ }
Serve(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("X-Test-Header", "X-Test-Value")
req.ParseForm()
if req.FormValue("no-body") == "1" {
return
}
+ if req.FormValue("write-forever") == "1" {
+ io.Copy(rw, neverEnding('a'))
+ for {
+ time.Sleep(5 * time.Second) // hang forever, until killed
+ }
+ }
fmt.Fprintf(rw, "test=Hello CGI-in-CGI\n")
for k, vv := range req.Form {
for _, v := range vv {
diff --git a/libgo/go/net/http/chunked.go b/libgo/go/net/http/chunked.go
deleted file mode 100644
index 91db017245..0000000000
--- a/libgo/go/net/http/chunked.go
+++ /dev/null
@@ -1,183 +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.
-
-// The wire protocol for HTTP's "chunked" Transfer-Encoding.
-
-// This code is duplicated in httputil/chunked.go.
-// Please make any changes in both files.
-
-package http
-
-import (
- "bufio"
- "errors"
- "fmt"
- "io"
-)
-
-const maxLineLength = 4096 // assumed <= bufio.defaultBufSize
-
-var ErrLineTooLong = errors.New("header line too long")
-
-// newChunkedReader returns a new chunkedReader that translates the data read from r
-// out of HTTP "chunked" format before returning it.
-// The chunkedReader returns io.EOF when the final 0-length chunk is read.
-//
-// newChunkedReader is not needed by normal applications. The http package
-// automatically decodes chunking when reading response bodies.
-func newChunkedReader(r io.Reader) io.Reader {
- br, ok := r.(*bufio.Reader)
- if !ok {
- br = bufio.NewReader(r)
- }
- return &chunkedReader{r: br}
-}
-
-type chunkedReader struct {
- r *bufio.Reader
- n uint64 // unread bytes in chunk
- err error
- buf [2]byte
-}
-
-func (cr *chunkedReader) beginChunk() {
- // chunk-size CRLF
- var line []byte
- line, cr.err = readLine(cr.r)
- if cr.err != nil {
- return
- }
- cr.n, cr.err = parseHexUint(line)
- if cr.err != nil {
- return
- }
- if cr.n == 0 {
- cr.err = io.EOF
- }
-}
-
-func (cr *chunkedReader) Read(b []uint8) (n int, err error) {
- if cr.err != nil {
- return 0, cr.err
- }
- if cr.n == 0 {
- cr.beginChunk()
- if cr.err != nil {
- return 0, cr.err
- }
- }
- if uint64(len(b)) > cr.n {
- b = b[0:cr.n]
- }
- n, cr.err = cr.r.Read(b)
- cr.n -= uint64(n)
- if cr.n == 0 && cr.err == nil {
- // end of chunk (CRLF)
- if _, cr.err = io.ReadFull(cr.r, cr.buf[:]); cr.err == nil {
- if cr.buf[0] != '\r' || cr.buf[1] != '\n' {
- cr.err = errors.New("malformed chunked encoding")
- }
- }
- }
- return n, cr.err
-}
-
-// Read a line of bytes (up to \n) from b.
-// Give up if the line exceeds maxLineLength.
-// The returned bytes are a pointer into storage in
-// the bufio, so they are only valid until the next bufio read.
-func readLine(b *bufio.Reader) (p []byte, err error) {
- if p, err = b.ReadSlice('\n'); err != nil {
- // We always know when EOF is coming.
- // If the caller asked for a line, there should be a line.
- if err == io.EOF {
- err = io.ErrUnexpectedEOF
- } else if err == bufio.ErrBufferFull {
- err = ErrLineTooLong
- }
- return nil, err
- }
- if len(p) >= maxLineLength {
- return nil, ErrLineTooLong
- }
- return trimTrailingWhitespace(p), nil
-}
-
-func trimTrailingWhitespace(b []byte) []byte {
- for len(b) > 0 && isASCIISpace(b[len(b)-1]) {
- b = b[:len(b)-1]
- }
- return b
-}
-
-func isASCIISpace(b byte) bool {
- return b == ' ' || b == '\t' || b == '\n' || b == '\r'
-}
-
-// newChunkedWriter returns a new chunkedWriter that translates writes into HTTP
-// "chunked" format before writing them to w. Closing the returned chunkedWriter
-// sends the final 0-length chunk that marks the end of the stream.
-//
-// newChunkedWriter is not needed by normal applications. The http
-// package adds chunking automatically if handlers don't set a
-// Content-Length header. Using newChunkedWriter inside a handler
-// would result in double chunking or chunking with a Content-Length
-// length, both of which are wrong.
-func newChunkedWriter(w io.Writer) io.WriteCloser {
- return &chunkedWriter{w}
-}
-
-// Writing to chunkedWriter translates to writing in HTTP chunked Transfer
-// Encoding wire format to the underlying Wire chunkedWriter.
-type chunkedWriter struct {
- Wire io.Writer
-}
-
-// Write the contents of data as one chunk to Wire.
-// NOTE: Note that the corresponding chunk-writing procedure in Conn.Write has
-// a bug since it does not check for success of io.WriteString
-func (cw *chunkedWriter) Write(data []byte) (n int, err error) {
-
- // Don't send 0-length data. It looks like EOF for chunked encoding.
- if len(data) == 0 {
- return 0, nil
- }
-
- if _, err = fmt.Fprintf(cw.Wire, "%x\r\n", len(data)); err != nil {
- return 0, err
- }
- if n, err = cw.Wire.Write(data); err != nil {
- return
- }
- if n != len(data) {
- err = io.ErrShortWrite
- return
- }
- _, err = io.WriteString(cw.Wire, "\r\n")
-
- return
-}
-
-func (cw *chunkedWriter) Close() error {
- _, err := io.WriteString(cw.Wire, "0\r\n")
- return err
-}
-
-func parseHexUint(v []byte) (n uint64, err error) {
- for _, b := range v {
- n <<= 4
- switch {
- case '0' <= b && b <= '9':
- b = b - '0'
- case 'a' <= b && b <= 'f':
- b = b - 'a' + 10
- case 'A' <= b && b <= 'F':
- b = b - 'A' + 10
- default:
- return 0, errors.New("invalid byte in chunk length")
- }
- n |= uint64(b)
- }
- return
-}
diff --git a/libgo/go/net/http/chunked_test.go b/libgo/go/net/http/chunked_test.go
deleted file mode 100644
index 0b18c7b55e..0000000000
--- a/libgo/go/net/http/chunked_test.go
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This code is duplicated in httputil/chunked_test.go.
-// Please make any changes in both files.
-
-package http
-
-import (
- "bytes"
- "fmt"
- "io"
- "io/ioutil"
- "runtime"
- "testing"
-)
-
-func TestChunk(t *testing.T) {
- var b bytes.Buffer
-
- w := newChunkedWriter(&b)
- const chunk1 = "hello, "
- const chunk2 = "world! 0123456789abcdef"
- w.Write([]byte(chunk1))
- w.Write([]byte(chunk2))
- w.Close()
-
- if g, e := b.String(), "7\r\nhello, \r\n17\r\nworld! 0123456789abcdef\r\n0\r\n"; g != e {
- t.Fatalf("chunk writer wrote %q; want %q", g, e)
- }
-
- r := newChunkedReader(&b)
- data, err := ioutil.ReadAll(r)
- if err != nil {
- t.Logf(`data: "%s"`, data)
- t.Fatalf("ReadAll from reader: %v", err)
- }
- if g, e := string(data), chunk1+chunk2; g != e {
- t.Errorf("chunk reader read %q; want %q", g, e)
- }
-}
-
-func TestChunkReaderAllocs(t *testing.T) {
- // temporarily set GOMAXPROCS to 1 as we are testing memory allocations
- defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
- var buf bytes.Buffer
- w := newChunkedWriter(&buf)
- a, b, c := []byte("aaaaaa"), []byte("bbbbbbbbbbbb"), []byte("cccccccccccccccccccccccc")
- w.Write(a)
- w.Write(b)
- w.Write(c)
- w.Close()
-
- r := newChunkedReader(&buf)
- readBuf := make([]byte, len(a)+len(b)+len(c)+1)
-
- var ms runtime.MemStats
- runtime.ReadMemStats(&ms)
- m0 := ms.Mallocs
-
- n, err := io.ReadFull(r, readBuf)
-
- runtime.ReadMemStats(&ms)
- mallocs := ms.Mallocs - m0
- if mallocs > 1 {
- t.Errorf("%d mallocs; want <= 1", mallocs)
- }
-
- if n != len(readBuf)-1 {
- t.Errorf("read %d bytes; want %d", n, len(readBuf)-1)
- }
- if err != io.ErrUnexpectedEOF {
- t.Errorf("read error = %v; want ErrUnexpectedEOF", err)
- }
-}
-
-func TestParseHexUint(t *testing.T) {
- for i := uint64(0); i <= 1234; i++ {
- line := []byte(fmt.Sprintf("%x", i))
- got, err := parseHexUint(line)
- if err != nil {
- t.Fatalf("on %d: %v", i, err)
- }
- if got != i {
- t.Errorf("for input %q = %d; want %d", line, got, i)
- }
- }
- _, err := parseHexUint([]byte("bogus"))
- if err == nil {
- t.Error("expected error on bogus input")
- }
-}
diff --git a/libgo/go/net/http/client.go b/libgo/go/net/http/client.go
index 22f2e865cf..ce884d1f07 100644
--- a/libgo/go/net/http/client.go
+++ b/libgo/go/net/http/client.go
@@ -14,9 +14,12 @@ import (
"errors"
"fmt"
"io"
+ "io/ioutil"
"log"
"net/url"
"strings"
+ "sync"
+ "time"
)
// A Client is an HTTP client. Its zero value (DefaultClient) is a
@@ -52,6 +55,20 @@ type Client struct {
// If Jar is nil, cookies are not sent in requests and ignored
// in responses.
Jar CookieJar
+
+ // Timeout specifies a time limit for requests made by this
+ // Client. The timeout includes connection time, any
+ // redirects, and reading the response body. The timer remains
+ // running after Get, Head, Post, or Do return and will
+ // interrupt reading of the Response.Body.
+ //
+ // A Timeout of zero means no timeout.
+ //
+ // The Client's Transport must support the CancelRequest
+ // method or Client will return errors when attempting to make
+ // a request with Get, Head, Post, or Do. Client's default
+ // Transport (DefaultTransport) supports CancelRequest.
+ Timeout time.Duration
}
// DefaultClient is the default Client and is used by Get, Head, and Post.
@@ -74,8 +91,9 @@ type RoundTripper interface {
// authentication, or cookies.
//
// RoundTrip should not modify the request, except for
- // consuming and closing the Body. The request's URL and
- // Header fields are guaranteed to be initialized.
+ // consuming and closing the Body, including on errors. The
+ // request's URL and Header fields are guaranteed to be
+ // initialized.
RoundTrip(*Request) (*Response, error)
}
@@ -83,6 +101,30 @@ type RoundTripper interface {
// return true if the string includes a port.
func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") }
+// refererForURL returns a referer without any authentication info or
+// an empty string if lastReq scheme is https and newReq scheme is http.
+func refererForURL(lastReq, newReq *url.URL) string {
+ // https://tools.ietf.org/html/rfc7231#section-5.5.2
+ // "Clients SHOULD NOT include a Referer header field in a
+ // (non-secure) HTTP request if the referring page was
+ // transferred with a secure protocol."
+ if lastReq.Scheme == "https" && newReq.Scheme == "http" {
+ return ""
+ }
+ referer := lastReq.String()
+ if lastReq.User != nil {
+ // This is not very efficient, but is the best we can
+ // do without:
+ // - introducing a new method on URL
+ // - creating a race condition
+ // - copying the URL struct manually, which would cause
+ // maintenance problems down the line
+ auth := lastReq.User.String() + "@"
+ referer = strings.Replace(referer, auth, "", 1)
+ }
+ return referer
+}
+
// Used in Send to implement io.ReadCloser by bundling together the
// bufio.Reader through which we read the response, and the underlying
// network connection.
@@ -97,7 +139,7 @@ func (c *Client) send(req *Request) (*Response, error) {
req.AddCookie(cookie)
}
}
- resp, err := send(req, c.Transport)
+ resp, err := send(req, c.transport())
if err != nil {
return nil, err
}
@@ -123,6 +165,9 @@ func (c *Client) send(req *Request) (*Response, error) {
// (typically Transport) may not be able to re-use a persistent TCP
// connection to the server for a subsequent "keep-alive" request.
//
+// The request Body, if non-nil, will be closed by the underlying
+// Transport, even on errors.
+//
// Generally Get, Post, or PostForm will be used instead of Do.
func (c *Client) Do(req *Request) (resp *Response, err error) {
if req.Method == "GET" || req.Method == "HEAD" {
@@ -134,22 +179,28 @@ func (c *Client) Do(req *Request) (resp *Response, err error) {
return c.send(req)
}
+func (c *Client) transport() RoundTripper {
+ if c.Transport != nil {
+ return c.Transport
+ }
+ return DefaultTransport
+}
+
// send issues an HTTP request.
// Caller should close resp.Body when done reading from it.
func send(req *Request, t RoundTripper) (resp *Response, err error) {
if t == nil {
- t = DefaultTransport
- if t == nil {
- err = errors.New("http: no Client.Transport or DefaultTransport")
- return
- }
+ req.closeBody()
+ return nil, errors.New("http: no Client.Transport or DefaultTransport")
}
if req.URL == nil {
+ req.closeBody()
return nil, errors.New("http: nil Request.URL")
}
if req.RequestURI != "" {
+ req.closeBody()
return nil, errors.New("http: Request.RequestURI can't be set in client requests.")
}
@@ -257,37 +308,59 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo
var via []*Request
if ireq.URL == nil {
+ ireq.closeBody()
return nil, errors.New("http: nil Request.URL")
}
+ var reqmu sync.Mutex // guards req
req := ireq
+
+ var timer *time.Timer
+ if c.Timeout > 0 {
+ type canceler interface {
+ CancelRequest(*Request)
+ }
+ tr, ok := c.transport().(canceler)
+ if !ok {
+ 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() {
+ reqmu.Lock()
+ defer reqmu.Unlock()
+ tr.CancelRequest(req)
+ })
+ }
+
urlStr := "" // next relative or absolute URL to fetch (after first request)
redirectFailed := false
for redirect := 0; ; redirect++ {
if redirect != 0 {
- req = new(Request)
- req.Method = ireq.Method
+ nreq := new(Request)
+ nreq.Method = ireq.Method
if ireq.Method == "POST" || ireq.Method == "PUT" {
- req.Method = "GET"
+ nreq.Method = "GET"
}
- req.Header = make(Header)
- req.URL, err = base.Parse(urlStr)
+ nreq.Header = make(Header)
+ nreq.URL, err = base.Parse(urlStr)
if err != nil {
break
}
if len(via) > 0 {
// Add the Referer header.
lastReq := via[len(via)-1]
- if lastReq.URL.Scheme != "https" {
- req.Header.Set("Referer", lastReq.URL.String())
+ if ref := refererForURL(lastReq.URL, nreq.URL); ref != "" {
+ nreq.Header.Set("Referer", ref)
}
- err = redirectChecker(req, via)
+ err = redirectChecker(nreq, via)
if err != nil {
redirectFailed = true
break
}
}
+ reqmu.Lock()
+ req = nreq
+ reqmu.Unlock()
}
urlStr = req.URL.String()
@@ -296,6 +369,12 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo
}
if shouldRedirect(resp.StatusCode) {
+ // Read the body if small so underlying TCP connection will be re-used.
+ // No need to check for errors: if it fails, Transport won't reuse it anyway.
+ const maxBodySlurpSize = 2 << 10
+ if resp.ContentLength == -1 || resp.ContentLength <= maxBodySlurpSize {
+ io.CopyN(ioutil.Discard, resp.Body, maxBodySlurpSize)
+ }
resp.Body.Close()
if urlStr = resp.Header.Get("Location"); urlStr == "" {
err = errors.New(fmt.Sprintf("%d response missing Location header", resp.StatusCode))
@@ -305,7 +384,10 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo
via = append(via, req)
continue
}
- return
+ if timer != nil {
+ resp.Body = &cancelTimerBody{timer, resp.Body}
+ }
+ return resp, nil
}
method := ireq.Method
@@ -349,7 +431,7 @@ 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
-// body is successfully written to the server.
+// request.
func (c *Client) Post(url string, bodyType string, body io.Reader) (resp *Response, err error) {
req, err := NewRequest("POST", url, body)
if err != nil {
@@ -408,3 +490,22 @@ func (c *Client) Head(url string) (resp *Response, err error) {
}
return c.doFollowingRedirects(req, shouldRedirectGet)
}
+
+type cancelTimerBody struct {
+ t *time.Timer
+ rc io.ReadCloser
+}
+
+func (b *cancelTimerBody) Read(p []byte) (n int, err error) {
+ n, err = b.rc.Read(p)
+ if err == io.EOF {
+ b.t.Stop()
+ }
+ return
+}
+
+func (b *cancelTimerBody) Close() error {
+ err := b.rc.Close()
+ b.t.Stop()
+ return err
+}
diff --git a/libgo/go/net/http/client_test.go b/libgo/go/net/http/client_test.go
index 997d04151c..56b6563c48 100644
--- a/libgo/go/net/http/client_test.go
+++ b/libgo/go/net/http/client_test.go
@@ -15,14 +15,18 @@ import (
"fmt"
"io"
"io/ioutil"
+ "log"
"net"
. "net/http"
"net/http/httptest"
"net/url"
+ "reflect"
+ "sort"
"strconv"
"strings"
"sync"
"testing"
+ "time"
)
var robotsTxtHandler = HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -54,6 +58,13 @@ func pedanticReadAll(r io.Reader) (b []byte, err error) {
}
}
+type chanWriter chan string
+
+func (w chanWriter) Write(p []byte) (n int, err error) {
+ w <- string(p)
+ return len(p), nil
+}
+
func TestClient(t *testing.T) {
defer afterTest(t)
ts := httptest.NewServer(robotsTxtHandler)
@@ -373,24 +384,6 @@ func (j *TestJar) Cookies(u *url.URL) []*Cookie {
return j.perURL[u.Host]
}
-func TestRedirectCookiesOnRequest(t *testing.T) {
- defer afterTest(t)
- var ts *httptest.Server
- ts = httptest.NewServer(echoCookiesRedirectHandler)
- defer ts.Close()
- c := &Client{}
- req, _ := NewRequest("GET", ts.URL, nil)
- req.AddCookie(expectedCookies[0])
- // TODO: Uncomment when an implementation of a RFC6265 cookie jar lands.
- _ = c
- // resp, _ := c.Do(req)
- // matchReturnedCookies(t, expectedCookies, resp.Cookies())
-
- req, _ = NewRequest("GET", ts.URL, nil)
- // resp, _ = c.Do(req)
- // matchReturnedCookies(t, expectedCookies[1:], resp.Cookies())
-}
-
func TestRedirectCookiesJar(t *testing.T) {
defer afterTest(t)
var ts *httptest.Server
@@ -410,8 +403,8 @@ func TestRedirectCookiesJar(t *testing.T) {
}
func matchReturnedCookies(t *testing.T, expected, given []*Cookie) {
- t.Logf("Received cookies: %v", given)
if len(given) != len(expected) {
+ t.Logf("Received cookies: %v", given)
t.Errorf("Expected %d cookies, got %d", len(expected), len(given))
}
for _, ec := range expected {
@@ -582,6 +575,8 @@ func TestClientInsecureTransport(t *testing.T) {
ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
w.Write([]byte("Hello"))
}))
+ errc := make(chanWriter, 10) // but only expecting 1
+ ts.Config.ErrorLog = log.New(errc, "", 0)
defer ts.Close()
// TODO(bradfitz): add tests for skipping hostname checks too?
@@ -603,6 +598,16 @@ func TestClientInsecureTransport(t *testing.T) {
res.Body.Close()
}
}
+
+ select {
+ case v := <-errc:
+ if !strings.Contains(v, "TLS handshake error") {
+ t.Errorf("expected an error log message containing 'TLS handshake error'; got %q", v)
+ }
+ case <-time.After(5 * time.Second):
+ t.Errorf("timeout waiting for logged error")
+ }
+
}
func TestClientErrorWithRequestURI(t *testing.T) {
@@ -653,6 +658,8 @@ func TestClientWithIncorrectTLSServerName(t *testing.T) {
defer afterTest(t)
ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
defer ts.Close()
+ errc := make(chanWriter, 10) // but only expecting 1
+ ts.Config.ErrorLog = log.New(errc, "", 0)
trans := newTLSTransport(t, ts)
trans.TLSClientConfig.ServerName = "badserver"
@@ -664,6 +671,14 @@ func TestClientWithIncorrectTLSServerName(t *testing.T) {
if !strings.Contains(err.Error(), "127.0.0.1") || !strings.Contains(err.Error(), "badserver") {
t.Errorf("wanted error mentioning 127.0.0.1 and badserver; got error: %v", err)
}
+ select {
+ case v := <-errc:
+ if !strings.Contains(v, "TLS handshake error") {
+ t.Errorf("expected an error log message containing 'TLS handshake error'; got %q", v)
+ }
+ case <-time.After(5 * time.Second):
+ t.Errorf("timeout waiting for logged error")
+ }
}
// Test for golang.org/issue/5829; the Transport should respect TLSClientConfig.ServerName
@@ -696,6 +711,33 @@ func TestTransportUsesTLSConfigServerName(t *testing.T) {
res.Body.Close()
}
+func TestResponseSetsTLSConnectionState(t *testing.T) {
+ defer afterTest(t)
+ ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Write([]byte("Hello"))
+ }))
+ defer ts.Close()
+
+ tr := newTLSTransport(t, ts)
+ tr.TLSClientConfig.CipherSuites = []uint16{tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA}
+ tr.Dial = func(netw, addr string) (net.Conn, error) {
+ return net.Dial(netw, ts.Listener.Addr().String())
+ }
+ defer tr.CloseIdleConnections()
+ c := &Client{Transport: tr}
+ res, err := c.Get("https://example.com/")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+ if res.TLS == nil {
+ t.Fatal("Response didn't set TLS Connection State.")
+ }
+ if got, want := res.TLS.CipherSuite, tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA; got != want {
+ t.Errorf("TLS Cipher Suite = %d; want %d", got, want)
+ }
+}
+
// Verify Response.ContentLength is populated. http://golang.org/issue/4126
func TestClientHeadContentLength(t *testing.T) {
defer afterTest(t)
@@ -799,3 +841,235 @@ func TestBasicAuth(t *testing.T) {
t.Errorf("Invalid auth %q", auth)
}
}
+
+func TestClientTimeout(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping in short mode")
+ }
+ defer afterTest(t)
+ sawRoot := make(chan bool, 1)
+ sawSlow := make(chan bool, 1)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ if r.URL.Path == "/" {
+ sawRoot <- true
+ Redirect(w, r, "/slow", StatusFound)
+ return
+ }
+ if r.URL.Path == "/slow" {
+ w.Write([]byte("Hello"))
+ w.(Flusher).Flush()
+ sawSlow <- true
+ time.Sleep(2 * time.Second)
+ return
+ }
+ }))
+ defer ts.Close()
+ const timeout = 500 * time.Millisecond
+ c := &Client{
+ Timeout: timeout,
+ }
+
+ res, err := c.Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ select {
+ case <-sawRoot:
+ // good.
+ default:
+ t.Fatal("handler never got / request")
+ }
+
+ select {
+ case <-sawSlow:
+ // good.
+ default:
+ t.Fatal("handler never got /slow request")
+ }
+
+ errc := make(chan error, 1)
+ go func() {
+ _, err := ioutil.ReadAll(res.Body)
+ errc <- err
+ res.Body.Close()
+ }()
+
+ const failTime = timeout * 2
+ select {
+ case err := <-errc:
+ if err == nil {
+ t.Error("expected error from ReadAll")
+ }
+ // Expected error.
+ case <-time.After(failTime):
+ t.Errorf("timeout after %v waiting for timeout of %v", failTime, timeout)
+ }
+}
+
+func TestClientRedirectEatsBody(t *testing.T) {
+ defer afterTest(t)
+ saw := make(chan string, 2)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ saw <- r.RemoteAddr
+ if r.URL.Path == "/" {
+ Redirect(w, r, "/foo", StatusFound) // which includes a body
+ }
+ }))
+ defer ts.Close()
+
+ res, err := Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, err = ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Fatal(err)
+ }
+ res.Body.Close()
+
+ var first string
+ select {
+ case first = <-saw:
+ default:
+ t.Fatal("server didn't see a request")
+ }
+
+ var second string
+ select {
+ case second = <-saw:
+ default:
+ t.Fatal("server didn't see a second request")
+ }
+
+ if first != second {
+ t.Fatal("server saw different client ports before & after the redirect")
+ }
+}
+
+// eofReaderFunc is an io.Reader that runs itself, and then returns io.EOF.
+type eofReaderFunc func()
+
+func (f eofReaderFunc) Read(p []byte) (n int, err error) {
+ f()
+ return 0, io.EOF
+}
+
+func TestClientTrailers(t *testing.T) {
+ defer afterTest(t)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header().Set("Connection", "close")
+ w.Header().Set("Trailer", "Server-Trailer-A, Server-Trailer-B")
+ w.Header().Add("Trailer", "Server-Trailer-C")
+
+ var decl []string
+ for k := range r.Trailer {
+ decl = append(decl, k)
+ }
+ sort.Strings(decl)
+
+ slurp, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ t.Errorf("Server reading request body: %v", err)
+ }
+ if string(slurp) != "foo" {
+ t.Errorf("Server read request body %q; want foo", slurp)
+ }
+ if r.Trailer == nil {
+ io.WriteString(w, "nil Trailer")
+ } else {
+ fmt.Fprintf(w, "decl: %v, vals: %s, %s",
+ decl,
+ r.Trailer.Get("Client-Trailer-A"),
+ 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()
+ }))
+ defer ts.Close()
+
+ var req *Request
+ req, _ = NewRequest("POST", ts.URL, io.MultiReader(
+ eofReaderFunc(func() {
+ req.Trailer["Client-Trailer-A"] = []string{"valuea"}
+ }),
+ strings.NewReader("foo"),
+ eofReaderFunc(func() {
+ req.Trailer["Client-Trailer-B"] = []string{"valueb"}
+ }),
+ ))
+ req.Trailer = Header{
+ "Client-Trailer-A": nil, // to be set later
+ "Client-Trailer-B": nil, // to be set later
+ }
+ req.ContentLength = -1
+ res, err := DefaultClient.Do(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := wantBody(res, err, "decl: [Client-Trailer-A Client-Trailer-B], vals: valuea, valueb"); err != nil {
+ t.Error(err)
+ }
+ want := Header{
+ "Server-Trailer-A": []string{"valuea"},
+ "Server-Trailer-B": nil,
+ "Server-Trailer-C": []string{"valuec"},
+ }
+ if !reflect.DeepEqual(res.Trailer, want) {
+ t.Errorf("Response trailers = %#v; want %#v", res.Trailer, want)
+ }
+}
+
+func TestReferer(t *testing.T) {
+ tests := []struct {
+ lastReq, newReq string // from -> to URLs
+ want string
+ }{
+ // don't send user:
+ {"http://gopher@test.com", "http://link.com", "http://test.com"},
+ {"https://gopher@test.com", "https://link.com", "https://test.com"},
+
+ // don't send a user and password:
+ {"http://gopher:go@test.com", "http://link.com", "http://test.com"},
+ {"https://gopher:go@test.com", "https://link.com", "https://test.com"},
+
+ // nothing to do:
+ {"http://test.com", "http://link.com", "http://test.com"},
+ {"https://test.com", "https://link.com", "https://test.com"},
+
+ // https to http doesn't send a referer:
+ {"https://test.com", "http://link.com", ""},
+ {"https://gopher:go@test.com", "http://link.com", ""},
+ }
+ for _, tt := range tests {
+ l, err := url.Parse(tt.lastReq)
+ if err != nil {
+ t.Fatal(err)
+ }
+ n, err := url.Parse(tt.newReq)
+ if err != nil {
+ t.Fatal(err)
+ }
+ r := ExportRefererForURL(l, n)
+ if r != tt.want {
+ t.Errorf("refererForURL(%q, %q) = %q; want %q", tt.lastReq, tt.newReq, r, tt.want)
+ }
+ }
+}
diff --git a/libgo/go/net/http/cookie.go b/libgo/go/net/http/cookie.go
index 8b01c508eb..a0d0fdbbd0 100644
--- a/libgo/go/net/http/cookie.go
+++ b/libgo/go/net/http/cookie.go
@@ -56,7 +56,7 @@ func readSetCookies(h Header) []*Cookie {
if !isCookieNameValid(name) {
continue
}
- value, success := parseCookieValue(value)
+ value, success := parseCookieValue(value, true)
if !success {
continue
}
@@ -76,11 +76,7 @@ func readSetCookies(h Header) []*Cookie {
attr, val = attr[:j], attr[j+1:]
}
lowerAttr := strings.ToLower(attr)
- parseCookieValueFn := parseCookieValue
- if lowerAttr == "expires" {
- parseCookieValueFn = parseCookieExpiresValue
- }
- val, success = parseCookieValueFn(val)
+ val, success = parseCookieValue(val, false)
if !success {
c.Unparsed = append(c.Unparsed, parts[i])
continue
@@ -94,7 +90,6 @@ func readSetCookies(h Header) []*Cookie {
continue
case "domain":
c.Domain = val
- // TODO: Add domain parsing
continue
case "max-age":
secs, err := strconv.Atoi(val)
@@ -121,7 +116,6 @@ func readSetCookies(h Header) []*Cookie {
continue
case "path":
c.Path = val
- // TODO: Add path parsing
continue
}
c.Unparsed = append(c.Unparsed, parts[i])
@@ -211,7 +205,7 @@ func readCookies(h Header, filter string) []*Cookie {
if filter != "" && filter != name {
continue
}
- val, success := parseCookieValue(val)
+ val, success := parseCookieValue(val, true)
if !success {
continue
}
@@ -300,12 +294,23 @@ func sanitizeCookieName(n string) string {
// ; US-ASCII characters excluding CTLs,
// ; whitespace DQUOTE, comma, semicolon,
// ; and backslash
+// 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.
func sanitizeCookieValue(v string) string {
- return sanitizeOrWarn("Cookie.Value", validCookieValueByte, v)
+ v = sanitizeOrWarn("Cookie.Value", validCookieValueByte, v)
+ if len(v) == 0 {
+ return v
+ }
+ if v[0] == ' ' || v[0] == ',' || v[len(v)-1] == ' ' || v[len(v)-1] == ',' {
+ return `"` + v + `"`
+ }
+ return v
}
func validCookieValueByte(b byte) bool {
- return 0x20 < b && b < 0x7f && b != '"' && b != ',' && b != ';' && b != '\\'
+ return 0x20 <= b && b < 0x7f && b != '"' && b != ';' && b != '\\'
}
// path-av = "Path=" path-value
@@ -340,38 +345,13 @@ func sanitizeOrWarn(fieldName string, valid func(byte) bool, v string) string {
return string(buf)
}
-func unquoteCookieValue(v string) string {
- if len(v) > 1 && v[0] == '"' && v[len(v)-1] == '"' {
- return v[1 : len(v)-1]
- }
- return v
-}
-
-func isCookieByte(c byte) bool {
- switch {
- case c == 0x21, 0x23 <= c && c <= 0x2b, 0x2d <= c && c <= 0x3a,
- 0x3c <= c && c <= 0x5b, 0x5d <= c && c <= 0x7e:
- return true
+func parseCookieValue(raw string, allowDoubleQuote bool) (string, bool) {
+ // Strip the quotes, if present.
+ if allowDoubleQuote && len(raw) > 1 && raw[0] == '"' && raw[len(raw)-1] == '"' {
+ raw = raw[1 : len(raw)-1]
}
- return false
-}
-
-func isCookieExpiresByte(c byte) (ok bool) {
- return isCookieByte(c) || c == ',' || c == ' '
-}
-
-func parseCookieValue(raw string) (string, bool) {
- return parseCookieValueUsing(raw, isCookieByte)
-}
-
-func parseCookieExpiresValue(raw string) (string, bool) {
- return parseCookieValueUsing(raw, isCookieExpiresByte)
-}
-
-func parseCookieValueUsing(raw string, validByte func(byte) bool) (string, bool) {
- raw = unquoteCookieValue(raw)
for i := 0; i < len(raw); i++ {
- if !validByte(raw[i]) {
+ if !validCookieValueByte(raw[i]) {
return "", false
}
}
diff --git a/libgo/go/net/http/cookie_test.go b/libgo/go/net/http/cookie_test.go
index 11b01cc571..98dc2fade0 100644
--- a/libgo/go/net/http/cookie_test.go
+++ b/libgo/go/net/http/cookie_test.go
@@ -5,9 +5,13 @@
package http
import (
+ "bytes"
"encoding/json"
"fmt"
+ "log"
+ "os"
"reflect"
+ "strings"
"testing"
"time"
)
@@ -48,15 +52,61 @@ var writeSetCookiesTests = []struct {
&Cookie{Name: "cookie-8", Value: "eight", Domain: "::1"},
"cookie-8=eight",
},
+ // The "special" cookies have values containing commas or spaces which
+ // are disallowed by RFC 6265 but are common in the wild.
+ {
+ &Cookie{Name: "special-1", Value: "a z"},
+ `special-1=a z`,
+ },
+ {
+ &Cookie{Name: "special-2", Value: " z"},
+ `special-2=" z"`,
+ },
+ {
+ &Cookie{Name: "special-3", Value: "a "},
+ `special-3="a "`,
+ },
+ {
+ &Cookie{Name: "special-4", Value: " "},
+ `special-4=" "`,
+ },
+ {
+ &Cookie{Name: "special-5", Value: "a,z"},
+ `special-5=a,z`,
+ },
+ {
+ &Cookie{Name: "special-6", Value: ",z"},
+ `special-6=",z"`,
+ },
+ {
+ &Cookie{Name: "special-7", Value: "a,"},
+ `special-7="a,"`,
+ },
+ {
+ &Cookie{Name: "special-8", Value: ","},
+ `special-8=","`,
+ },
+ {
+ &Cookie{Name: "empty-value", Value: ""},
+ `empty-value=`,
+ },
}
func TestWriteSetCookies(t *testing.T) {
+ defer log.SetOutput(os.Stderr)
+ var logbuf bytes.Buffer
+ log.SetOutput(&logbuf)
+
for i, tt := range writeSetCookiesTests {
if g, e := tt.Cookie.String(), tt.Raw; g != e {
t.Errorf("Test %d, expecting:\n%s\nGot:\n%s\n", i, e, g)
continue
}
}
+
+ if got, sub := logbuf.String(), "dropping domain attribute"; !strings.Contains(got, sub) {
+ t.Errorf("Expected substring %q in log output. Got:\n%s", sub, got)
+ }
}
type headerOnlyResponseWriter Header
@@ -166,6 +216,40 @@ var readSetCookiesTests = []struct {
Raw: "ASP.NET_SessionId=foo; path=/; HttpOnly",
}},
},
+ // Make sure we can properly read back the Set-Cookie headers we create
+ // for values containing spaces or commas:
+ {
+ Header{"Set-Cookie": {`special-1=a z`}},
+ []*Cookie{{Name: "special-1", Value: "a z", Raw: `special-1=a z`}},
+ },
+ {
+ Header{"Set-Cookie": {`special-2=" z"`}},
+ []*Cookie{{Name: "special-2", Value: " z", Raw: `special-2=" z"`}},
+ },
+ {
+ Header{"Set-Cookie": {`special-3="a "`}},
+ []*Cookie{{Name: "special-3", Value: "a ", Raw: `special-3="a "`}},
+ },
+ {
+ Header{"Set-Cookie": {`special-4=" "`}},
+ []*Cookie{{Name: "special-4", Value: " ", Raw: `special-4=" "`}},
+ },
+ {
+ Header{"Set-Cookie": {`special-5=a,z`}},
+ []*Cookie{{Name: "special-5", Value: "a,z", Raw: `special-5=a,z`}},
+ },
+ {
+ Header{"Set-Cookie": {`special-6=",z"`}},
+ []*Cookie{{Name: "special-6", Value: ",z", Raw: `special-6=",z"`}},
+ },
+ {
+ Header{"Set-Cookie": {`special-7=a,`}},
+ []*Cookie{{Name: "special-7", Value: "a,", Raw: `special-7=a,`}},
+ },
+ {
+ Header{"Set-Cookie": {`special-8=","`}},
+ []*Cookie{{Name: "special-8", Value: ",", Raw: `special-8=","`}},
+ },
// TODO(bradfitz): users have reported seeing this in the
// wild, but do browsers handle it? RFC 6265 just says "don't
@@ -229,6 +313,14 @@ var readCookiesTests = []struct {
{Name: "c2", Value: "v2"},
},
},
+ {
+ Header{"Cookie": {`Cookie-1="v$1"; c2="v2"`}},
+ "",
+ []*Cookie{
+ {Name: "Cookie-1", Value: "v$1"},
+ {Name: "c2", Value: "v2"},
+ },
+ },
}
func TestReadCookies(t *testing.T) {
@@ -243,23 +335,64 @@ func TestReadCookies(t *testing.T) {
}
}
+func TestSetCookieDoubleQuotes(t *testing.T) {
+ res := &Response{Header: Header{}}
+ res.Header.Add("Set-Cookie", `quoted0=none; max-age=30`)
+ res.Header.Add("Set-Cookie", `quoted1="cookieValue"; max-age=31`)
+ res.Header.Add("Set-Cookie", `quoted2=cookieAV; max-age="32"`)
+ res.Header.Add("Set-Cookie", `quoted3="both"; max-age="33"`)
+ got := res.Cookies()
+ want := []*Cookie{
+ {Name: "quoted0", Value: "none", MaxAge: 30},
+ {Name: "quoted1", Value: "cookieValue", MaxAge: 31},
+ {Name: "quoted2", Value: "cookieAV"},
+ {Name: "quoted3", Value: "both"},
+ }
+ if len(got) != len(want) {
+ t.Fatal("got %d cookies, want %d", len(got), len(want))
+ }
+ for i, w := range want {
+ g := got[i]
+ if g.Name != w.Name || g.Value != w.Value || g.MaxAge != w.MaxAge {
+ t.Errorf("cookie #%d:\ngot %v\nwant %v", i, g, w)
+ }
+ }
+}
+
func TestCookieSanitizeValue(t *testing.T) {
+ defer log.SetOutput(os.Stderr)
+ var logbuf bytes.Buffer
+ log.SetOutput(&logbuf)
+
tests := []struct {
in, want string
}{
{"foo", "foo"},
- {"foo bar", "foobar"},
+ {"foo;bar", "foobar"},
+ {"foo\\bar", "foobar"},
+ {"foo\"bar", "foobar"},
{"\x00\x7e\x7f\x80", "\x7e"},
{`"withquotes"`, "withquotes"},
+ {"a z", "a z"},
+ {" z", `" z"`},
+ {"a ", `"a "`},
}
for _, tt := range tests {
if got := sanitizeCookieValue(tt.in); got != tt.want {
t.Errorf("sanitizeCookieValue(%q) = %q; want %q", tt.in, got, tt.want)
}
}
+
+ if got, sub := logbuf.String(), "dropping invalid bytes"; !strings.Contains(got, sub) {
+ t.Errorf("Expected substring %q in log output. Got:\n%s", sub, got)
+ }
}
func TestCookieSanitizePath(t *testing.T) {
+ defer log.SetOutput(os.Stderr)
+ var logbuf bytes.Buffer
+ log.SetOutput(&logbuf)
+
tests := []struct {
in, want string
}{
@@ -272,4 +405,8 @@ func TestCookieSanitizePath(t *testing.T) {
t.Errorf("sanitizeCookiePath(%q) = %q; want %q", tt.in, got, tt.want)
}
}
+
+ if got, sub := logbuf.String(), "dropping invalid bytes"; !strings.Contains(got, sub) {
+ t.Errorf("Expected substring %q in log output. Got:\n%s", sub, got)
+ }
}
diff --git a/libgo/go/net/http/cookiejar/jar.go b/libgo/go/net/http/cookiejar/jar.go
index 389ab58e41..0e0fac9286 100644
--- a/libgo/go/net/http/cookiejar/jar.go
+++ b/libgo/go/net/http/cookiejar/jar.go
@@ -30,7 +30,7 @@ import (
// set a cookie for bar.com.
//
// A public suffix list implementation is in the package
-// code.google.com/p/go.net/publicsuffix.
+// golang.org/x/net/publicsuffix.
type PublicSuffixList interface {
// PublicSuffix returns the public suffix of domain.
//
diff --git a/libgo/go/net/http/export_test.go b/libgo/go/net/http/export_test.go
index 22b7f27968..87b6c0773a 100644
--- a/libgo/go/net/http/export_test.go
+++ b/libgo/go/net/http/export_test.go
@@ -9,6 +9,7 @@ package http
import (
"net"
+ "net/url"
"time"
)
@@ -21,7 +22,7 @@ var ExportAppendTime = appendTime
func (t *Transport) NumPendingRequestsForTesting() int {
t.reqMu.Lock()
defer t.reqMu.Unlock()
- return len(t.reqConn)
+ return len(t.reqCanceler)
}
func (t *Transport) IdleConnKeysForTesting() (keys []string) {
@@ -32,7 +33,7 @@ func (t *Transport) IdleConnKeysForTesting() (keys []string) {
return
}
for key := range t.idleConn {
- keys = append(keys, key)
+ keys = append(keys, key.String())
}
return
}
@@ -43,11 +44,12 @@ func (t *Transport) IdleConnCountForTesting(cacheKey string) int {
if t.idleConn == nil {
return 0
}
- conns, ok := t.idleConn[cacheKey]
- if !ok {
- return 0
+ for k, conns := range t.idleConn {
+ if k.String() == cacheKey {
+ return len(conns)
+ }
}
- return len(conns)
+ return 0
}
func (t *Transport) IdleConnChMapSizeForTesting() int {
@@ -56,6 +58,26 @@ func (t *Transport) IdleConnChMapSizeForTesting() int {
return len(t.idleConnCh)
}
+func (t *Transport) IsIdleForTesting() bool {
+ t.idleMu.Lock()
+ defer t.idleMu.Unlock()
+ return t.wantIdle
+}
+
+func (t *Transport) RequestIdleConnChForTesting() {
+ t.getIdleConnCh(connectMethod{nil, "http", "example.com"})
+}
+
+func (t *Transport) PutIdleTestConn() bool {
+ c, _ := net.Pipe()
+ return t.putIdleConn(&persistConn{
+ t: t,
+ conn: c, // dummy
+ closech: make(chan struct{}), // so it can be closed
+ cacheKey: connectMethodKey{"", "http", "example.com"},
+ })
+}
+
func NewTestTimeoutHandler(handler Handler, ch <-chan time.Time) Handler {
f := func() <-chan time.Time {
return ch
@@ -63,4 +85,24 @@ func NewTestTimeoutHandler(handler Handler, ch <-chan time.Time) Handler {
return &timeoutHandler{handler, f, ""}
}
+func ResetCachedEnvironment() {
+ httpProxyEnv.reset()
+ httpsProxyEnv.reset()
+ noProxyEnv.reset()
+}
+
var DefaultUserAgent = defaultUserAgent
+
+func ExportRefererForURL(lastReq, newReq *url.URL) string {
+ return refererForURL(lastReq, newReq)
+}
+
+// SetPendingDialHooks sets the hooks that run before and after handling
+// pending dials.
+func SetPendingDialHooks(before, after func()) {
+ prePendingDial, postPendingDial = before, after
+}
+
+var ExportServerNewConn = (*Server).newConn
+
+var ExportCloseWriteAndWait = (*conn).closeWriteAndWait
diff --git a/libgo/go/net/http/fcgi/child.go b/libgo/go/net/http/fcgi/child.go
index 60b794e077..a3beaa33a8 100644
--- a/libgo/go/net/http/fcgi/child.go
+++ b/libgo/go/net/http/fcgi/child.go
@@ -16,6 +16,7 @@ import (
"net/http/cgi"
"os"
"strings"
+ "sync"
"time"
)
@@ -126,8 +127,10 @@ func (r *response) Close() error {
}
type child struct {
- conn *conn
- handler http.Handler
+ conn *conn
+ handler http.Handler
+
+ mu sync.Mutex // protects requests:
requests map[uint16]*request // keyed by request ID
}
@@ -157,7 +160,9 @@ var errCloseConn = errors.New("fcgi: connection should be closed")
var emptyBody = ioutil.NopCloser(strings.NewReader(""))
func (c *child) handleRecord(rec *record) error {
+ c.mu.Lock()
req, ok := c.requests[rec.h.Id]
+ c.mu.Unlock()
if !ok && rec.h.Type != typeBeginRequest && rec.h.Type != typeGetValues {
// The spec says to ignore unknown request IDs.
return nil
@@ -179,7 +184,10 @@ func (c *child) handleRecord(rec *record) error {
c.conn.writeEndRequest(rec.h.Id, 0, statusUnknownRole)
return nil
}
- c.requests[rec.h.Id] = newRequest(rec.h.Id, br.flags)
+ req = newRequest(rec.h.Id, br.flags)
+ c.mu.Lock()
+ c.requests[rec.h.Id] = req
+ c.mu.Unlock()
return nil
case typeParams:
// NOTE(eds): Technically a key-value pair can straddle the boundary
@@ -220,7 +228,9 @@ func (c *child) handleRecord(rec *record) error {
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.keepConn {
// connection will close upon return
@@ -247,6 +257,9 @@ func (c *child) serveRequest(req *request, body io.ReadCloser) {
c.handler.ServeHTTP(r, httpReq)
}
r.Close()
+ c.mu.Lock()
+ delete(c.requests, req.reqId)
+ c.mu.Unlock()
c.conn.writeEndRequest(req.reqId, 0, statusRequestComplete)
// Consume the entire body, so the host isn't still writing to
diff --git a/libgo/go/net/http/fs.go b/libgo/go/net/http/fs.go
index 8b32ca1d0e..e322f710a5 100644
--- a/libgo/go/net/http/fs.go
+++ b/libgo/go/net/http/fs.go
@@ -13,6 +13,7 @@ import (
"mime"
"mime/multipart"
"net/textproto"
+ "net/url"
"os"
"path"
"path/filepath"
@@ -21,8 +22,12 @@ import (
"time"
)
-// A Dir implements http.FileSystem using the native file
-// system restricted to a specific directory tree.
+// A Dir implements FileSystem using the native file system restricted to a
+// specific directory tree.
+//
+// While the FileSystem.Open method takes '/'-separated paths, a Dir's string
+// value is a filename on the native file system, not a URL, so it is separated
+// by filepath.Separator, which isn't necessarily '/'.
//
// An empty Dir is treated as ".".
type Dir string
@@ -52,12 +57,14 @@ type FileSystem interface {
// A File is returned by a FileSystem's Open method and can be
// served by the FileServer implementation.
+//
+// The methods should behave the same as those on an *os.File.
type File interface {
- Close() error
- Stat() (os.FileInfo, error)
+ io.Closer
+ io.Reader
Readdir(count int) ([]os.FileInfo, error)
- Read([]byte) (int, error)
Seek(offset int64, whence int) (int64, error)
+ Stat() (os.FileInfo, error)
}
func dirList(w ResponseWriter, f File) {
@@ -73,8 +80,11 @@ func dirList(w ResponseWriter, f File) {
if d.IsDir() {
name += "/"
}
- // TODO htmlescape
- fmt.Fprintf(w, "<a href=\"%s\">%s</a>\n", name, name)
+ // name may contain '?' or '#', which must be escaped to remain
+ // part of the URL path, and not indicate the start of a query
+ // string or fragment.
+ url := url.URL{Path: name}
+ fmt.Fprintf(w, "<a href=\"%s\">%s</a>\n", url.String(), htmlReplacer.Replace(name))
}
}
fmt.Fprintf(w, "</pre>\n")
@@ -133,7 +143,7 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time,
if checkLastModified(w, r, modtime) {
return
}
- rangeReq, done := checkETag(w, r)
+ rangeReq, done := checkETag(w, r, modtime)
if done {
return
}
@@ -206,12 +216,6 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time,
code = StatusPartialContent
w.Header().Set("Content-Range", ra.contentRange(size))
case len(ranges) > 1:
- for _, ra := range ranges {
- if ra.start > size {
- Error(w, err.Error(), StatusRequestedRangeNotSatisfiable)
- return
- }
- }
sendSize = rangesMIMESize(ranges, ctype, size)
code = StatusPartialContent
@@ -275,11 +279,14 @@ func checkLastModified(w ResponseWriter, r *Request, modtime time.Time) bool {
}
// checkETag implements If-None-Match and If-Range checks.
-// The ETag must have been previously set in the ResponseWriter's headers.
+//
+// The ETag or modtime must have been previously set in the
+// ResponseWriter's headers. The modtime is only compared at second
+// granularity and may be the zero value to mean unknown.
//
// The return value is the effective request "Range" header to use and
// whether this request is now considered done.
-func checkETag(w ResponseWriter, r *Request) (rangeReq string, done bool) {
+func checkETag(w ResponseWriter, r *Request, modtime time.Time) (rangeReq string, done bool) {
etag := w.Header().get("Etag")
rangeReq = r.Header.get("Range")
@@ -290,11 +297,17 @@ func checkETag(w ResponseWriter, r *Request) (rangeReq string, done bool) {
// We only support ETag versions.
// The caller must have set the ETag on the response already.
if ir := r.Header.get("If-Range"); ir != "" && ir != etag {
- // TODO(bradfitz): handle If-Range requests with Last-Modified
- // times instead of ETags? I'd rather not, at least for
- // now. That seems like a bug/compromise in the RFC 2616, and
- // I've never heard of anybody caring about that (yet).
- rangeReq = ""
+ // The If-Range value is typically the ETag value, but it may also be
+ // the modtime date. See golang.org/issue/8367.
+ timeMatches := false
+ if !modtime.IsZero() {
+ if t, err := ParseTime(ir); err == nil && t.Unix() == modtime.Unix() {
+ timeMatches = true
+ }
+ }
+ if !timeMatches {
+ rangeReq = ""
+ }
}
if inm := r.Header.get("If-None-Match"); inm != "" {
@@ -372,7 +385,7 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec
// use contents of index.html for directory, if present
if d.IsDir() {
- index := name + indexPage
+ index := strings.TrimSuffix(name, "/") + indexPage
ff, err := fs.Open(index)
if err == nil {
defer ff.Close()
@@ -394,7 +407,7 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec
return
}
- // serverContent will check modification time
+ // serveContent will check modification time
sizeFunc := func() (int64, error) { return d.Size(), nil }
serveContent(w, r, d.Name(), d.ModTime(), sizeFunc, f)
}
@@ -521,7 +534,7 @@ func (w *countingWriter) Write(p []byte) (n int, err error) {
return len(p), nil
}
-// rangesMIMESize returns the nunber of bytes it takes to encode the
+// rangesMIMESize returns the number of bytes it takes to encode the
// provided ranges as a multipart response.
func rangesMIMESize(ranges []httpRange, contentType string, contentSize int64) (encSize int64) {
var w countingWriter
diff --git a/libgo/go/net/http/fs_test.go b/libgo/go/net/http/fs_test.go
index dd3e9fefea..2ddd4ca5fe 100644
--- a/libgo/go/net/http/fs_test.go
+++ b/libgo/go/net/http/fs_test.go
@@ -227,6 +227,54 @@ func TestFileServerCleans(t *testing.T) {
}
}
+func TestFileServerEscapesNames(t *testing.T) {
+ defer afterTest(t)
+ const dirListPrefix = "<pre>\n"
+ const dirListSuffix = "\n</pre>\n"
+ tests := []struct {
+ name, escaped string
+ }{
+ {`simple_name`, `<a href="simple_name">simple_name</a>`},
+ {`"'<>&`, `<a href="%22%27%3C%3E&">&#34;&#39;&lt;&gt;&amp;</a>`},
+ {`?foo=bar#baz`, `<a href="%3Ffoo=bar%23baz">?foo=bar#baz</a>`},
+ {`<combo>?foo`, `<a href="%3Ccombo%3E%3Ffoo">&lt;combo&gt;?foo</a>`},
+ }
+
+ // We put each test file in its own directory in the fakeFS so we can look at it in isolation.
+ fs := make(fakeFS)
+ for i, test := range tests {
+ testFile := &fakeFileInfo{basename: test.name}
+ fs[fmt.Sprintf("/%d", i)] = &fakeFileInfo{
+ dir: true,
+ modtime: time.Unix(1000000000, 0).UTC(),
+ ents: []*fakeFileInfo{testFile},
+ }
+ fs[fmt.Sprintf("/%d/%s", i, test.name)] = testFile
+ }
+
+ ts := httptest.NewServer(FileServer(&fs))
+ defer ts.Close()
+ for i, test := range tests {
+ url := fmt.Sprintf("%s/%d", ts.URL, i)
+ res, err := Get(url)
+ if err != nil {
+ t.Fatalf("test %q: Get: %v", test.name, err)
+ }
+ b, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Fatalf("test %q: read Body: %v", test.name, err)
+ }
+ s := string(b)
+ if !strings.HasPrefix(s, dirListPrefix) || !strings.HasSuffix(s, dirListSuffix) {
+ t.Errorf("test %q: listing dir, full output is %q, want prefix %q and suffix %q", test.name, s, dirListPrefix, dirListSuffix)
+ }
+ if trimmed := strings.TrimSuffix(strings.TrimPrefix(s, dirListPrefix), dirListSuffix); trimmed != test.escaped {
+ t.Errorf("test %q: listing dir, filename escaped to %q, want %q", test.name, trimmed, test.escaped)
+ }
+ res.Body.Close()
+ }
+}
+
func mustRemoveAll(dir string) {
err := os.RemoveAll(dir)
if err != nil {
@@ -457,8 +505,9 @@ func (f *fakeFileInfo) Mode() os.FileMode {
type fakeFile struct {
io.ReadSeeker
- fi *fakeFileInfo
- path string // as opened
+ fi *fakeFileInfo
+ path string // as opened
+ entpos int
}
func (f *fakeFile) Close() error { return nil }
@@ -468,10 +517,20 @@ func (f *fakeFile) Readdir(count int) ([]os.FileInfo, error) {
return nil, os.ErrInvalid
}
var fis []os.FileInfo
- for _, fi := range f.fi.ents {
- fis = append(fis, fi)
+
+ limit := f.entpos + count
+ if count <= 0 || limit > len(f.fi.ents) {
+ limit = len(f.fi.ents)
+ }
+ for ; f.entpos < limit; f.entpos++ {
+ fis = append(fis, f.fi.ents[f.entpos])
+ }
+
+ if len(fis) == 0 && count > 0 {
+ return fis, io.EOF
+ } else {
+ return fis, nil
}
- return fis, nil
}
type fakeFS map[string]*fakeFileInfo
@@ -480,7 +539,6 @@ func (fs fakeFS) Open(name string) (File, error) {
name = path.Clean(name)
f, ok := fs[name]
if !ok {
- println("fake filesystem didn't find file", name)
return nil, os.ErrNotExist
}
return &fakeFile{ReadSeeker: strings.NewReader(f.contents), fi: f, path: name}, nil
@@ -663,6 +721,28 @@ func TestServeContent(t *testing.T) {
wantStatus: 200,
wantContentType: "text/css; charset=utf-8",
},
+ "range_with_modtime": {
+ file: "testdata/style.css",
+ modtime: time.Date(2014, 6, 25, 17, 12, 18, 0 /* nanos */, time.UTC),
+ reqHeader: map[string]string{
+ "Range": "bytes=0-4",
+ "If-Range": "Wed, 25 Jun 2014 17:12:18 GMT",
+ },
+ wantStatus: StatusPartialContent,
+ wantContentType: "text/css; charset=utf-8",
+ wantLastMod: "Wed, 25 Jun 2014 17:12:18 GMT",
+ },
+ "range_with_modtime_nanos": {
+ file: "testdata/style.css",
+ modtime: time.Date(2014, 6, 25, 17, 12, 18, 123 /* nanos */, time.UTC),
+ reqHeader: map[string]string{
+ "Range": "bytes=0-4",
+ "If-Range": "Wed, 25 Jun 2014 17:12:18 GMT",
+ },
+ wantStatus: StatusPartialContent,
+ wantContentType: "text/css; charset=utf-8",
+ wantLastMod: "Wed, 25 Jun 2014 17:12:18 GMT",
+ },
}
for testName, tt := range tests {
var content io.ReadSeeker
@@ -802,4 +882,41 @@ func TestLinuxSendfileChild(*testing.T) {
}
}
+func TestFileServerCleanPath(t *testing.T) {
+ tests := []struct {
+ path string
+ wantCode int
+ wantOpen []string
+ }{
+ {"/", 200, []string{"/", "/index.html"}},
+ {"/dir", 301, []string{"/dir"}},
+ {"/dir/", 200, []string{"/dir", "/dir/index.html"}},
+ }
+ for _, tt := range tests {
+ var log []string
+ rr := httptest.NewRecorder()
+ req, _ := NewRequest("GET", "http://foo.localhost"+tt.path, nil)
+ FileServer(fileServerCleanPathDir{&log}).ServeHTTP(rr, req)
+ if !reflect.DeepEqual(log, tt.wantOpen) {
+ t.Logf("For %s: Opens = %q; want %q", tt.path, log, tt.wantOpen)
+ }
+ if rr.Code != tt.wantCode {
+ t.Logf("For %s: Response code = %d; want %d", tt.path, rr.Code, tt.wantCode)
+ }
+ }
+}
+
+type fileServerCleanPathDir struct {
+ log *[]string
+}
+
+func (d fileServerCleanPathDir) Open(path string) (File, error) {
+ *(d.log) = append(*(d.log), path)
+ if path == "/" || path == "/dir" || path == "/dir/" {
+ // Just return back something that's a directory.
+ return Dir(".").Open(".")
+ }
+ return nil, os.ErrNotExist
+}
+
type panicOnSeek struct{ io.ReadSeeker }
diff --git a/libgo/go/net/http/header.go b/libgo/go/net/http/header.go
index ca1ae07c25..153b94370f 100644
--- a/libgo/go/net/http/header.go
+++ b/libgo/go/net/http/header.go
@@ -9,9 +9,12 @@ import (
"net/textproto"
"sort"
"strings"
+ "sync"
"time"
)
+var raceEnabled = false // set by race.go
+
// A Header represents the key-value pairs in an HTTP header.
type Header map[string][]string
@@ -114,18 +117,15 @@ func (s *headerSorter) Len() int { return len(s.kvs) }
func (s *headerSorter) Swap(i, j int) { s.kvs[i], s.kvs[j] = s.kvs[j], s.kvs[i] }
func (s *headerSorter) Less(i, j int) bool { return s.kvs[i].key < s.kvs[j].key }
-// TODO: convert this to a sync.Cache (issue 4720)
-var headerSorterCache = make(chan *headerSorter, 8)
+var headerSorterPool = sync.Pool{
+ New: func() interface{} { return new(headerSorter) },
+}
// sortedKeyValues returns h's keys sorted in the returned kvs
// slice. The headerSorter used to sort is also returned, for possible
// return to headerSorterCache.
func (h Header) sortedKeyValues(exclude map[string]bool) (kvs []keyValues, hs *headerSorter) {
- select {
- case hs = <-headerSorterCache:
- default:
- hs = new(headerSorter)
- }
+ hs = headerSorterPool.Get().(*headerSorter)
if cap(hs.kvs) < len(h) {
hs.kvs = make([]keyValues, 0, len(h))
}
@@ -159,10 +159,7 @@ func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error {
}
}
}
- select {
- case headerSorterCache <- sorter:
- default:
- }
+ headerSorterPool.Put(sorter)
return nil
}
diff --git a/libgo/go/net/http/header_test.go b/libgo/go/net/http/header_test.go
index 2c896c5ad2..299576ba8c 100644
--- a/libgo/go/net/http/header_test.go
+++ b/libgo/go/net/http/header_test.go
@@ -192,9 +192,12 @@ func BenchmarkHeaderWriteSubset(b *testing.B) {
}
}
-func TestHeaderWriteSubsetMallocs(t *testing.T) {
+func TestHeaderWriteSubsetAllocs(t *testing.T) {
if testing.Short() {
- t.Skip("skipping malloc count in short mode")
+ t.Skip("skipping alloc test in short mode")
+ }
+ if raceEnabled {
+ t.Skip("skipping test under race detector")
}
t.Skip("Skipping alloc count test on gccgo")
if runtime.GOMAXPROCS(0) > 1 {
@@ -205,6 +208,6 @@ func TestHeaderWriteSubsetMallocs(t *testing.T) {
testHeader.WriteSubset(&buf, nil)
})
if n > 0 {
- t.Errorf("mallocs = %g; want 0", n)
+ t.Errorf("allocs = %g; want 0", n)
}
}
diff --git a/libgo/go/net/http/httptest/server.go b/libgo/go/net/http/httptest/server.go
index 7f265552f5..789e7bf41e 100644
--- a/libgo/go/net/http/httptest/server.go
+++ b/libgo/go/net/http/httptest/server.go
@@ -203,7 +203,7 @@ func (h *waitGroupHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// localhostCert is a PEM-encoded TLS cert with SAN IPs
// "127.0.0.1" and "[::1]", expiring at the last second of 2049 (the end
// of ASN.1 time).
-// generated from src/pkg/crypto/tls:
+// 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
var localhostCert = []byte(`-----BEGIN CERTIFICATE-----
MIIBdzCCASOgAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD
diff --git a/libgo/go/net/http/httputil/chunked_test.go b/libgo/go/net/http/httputil/chunked_test.go
deleted file mode 100644
index a06bffad5b..0000000000
--- a/libgo/go/net/http/httputil/chunked_test.go
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This code is a duplicate of ../chunked_test.go with these edits:
-// s/newChunked/NewChunked/g
-// s/package http/package httputil/
-// Please make any changes in both files.
-
-package httputil
-
-import (
- "bytes"
- "fmt"
- "io"
- "io/ioutil"
- "runtime"
- "testing"
-)
-
-func TestChunk(t *testing.T) {
- var b bytes.Buffer
-
- w := NewChunkedWriter(&b)
- const chunk1 = "hello, "
- const chunk2 = "world! 0123456789abcdef"
- w.Write([]byte(chunk1))
- w.Write([]byte(chunk2))
- w.Close()
-
- if g, e := b.String(), "7\r\nhello, \r\n17\r\nworld! 0123456789abcdef\r\n0\r\n"; g != e {
- t.Fatalf("chunk writer wrote %q; want %q", g, e)
- }
-
- r := NewChunkedReader(&b)
- data, err := ioutil.ReadAll(r)
- if err != nil {
- t.Logf(`data: "%s"`, data)
- t.Fatalf("ReadAll from reader: %v", err)
- }
- if g, e := string(data), chunk1+chunk2; g != e {
- t.Errorf("chunk reader read %q; want %q", g, e)
- }
-}
-
-func TestChunkReaderAllocs(t *testing.T) {
- // temporarily set GOMAXPROCS to 1 as we are testing memory allocations
- defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
- var buf bytes.Buffer
- w := NewChunkedWriter(&buf)
- a, b, c := []byte("aaaaaa"), []byte("bbbbbbbbbbbb"), []byte("cccccccccccccccccccccccc")
- w.Write(a)
- w.Write(b)
- w.Write(c)
- w.Close()
-
- r := NewChunkedReader(&buf)
- readBuf := make([]byte, len(a)+len(b)+len(c)+1)
-
- var ms runtime.MemStats
- runtime.ReadMemStats(&ms)
- m0 := ms.Mallocs
-
- n, err := io.ReadFull(r, readBuf)
-
- runtime.ReadMemStats(&ms)
- mallocs := ms.Mallocs - m0
- if mallocs > 1 {
- t.Errorf("%d mallocs; want <= 1", mallocs)
- }
-
- if n != len(readBuf)-1 {
- t.Errorf("read %d bytes; want %d", n, len(readBuf)-1)
- }
- if err != io.ErrUnexpectedEOF {
- t.Errorf("read error = %v; want ErrUnexpectedEOF", err)
- }
-}
-
-func TestParseHexUint(t *testing.T) {
- for i := uint64(0); i <= 1234; i++ {
- line := []byte(fmt.Sprintf("%x", i))
- got, err := parseHexUint(line)
- if err != nil {
- t.Fatalf("on %d: %v", i, err)
- }
- if got != i {
- t.Errorf("for input %q = %d; want %d", line, got, i)
- }
- }
- _, err := parseHexUint([]byte("bogus"))
- if err == nil {
- t.Error("expected error on bogus input")
- }
-}
diff --git a/libgo/go/net/http/httputil/dump.go b/libgo/go/net/http/httputil/dump.go
index 265499fb00..ac8f103f9b 100644
--- a/libgo/go/net/http/httputil/dump.go
+++ b/libgo/go/net/http/httputil/dump.go
@@ -7,6 +7,7 @@ package httputil
import (
"bufio"
"bytes"
+ "errors"
"fmt"
"io"
"io/ioutil"
@@ -29,7 +30,7 @@ func drainBody(b io.ReadCloser) (r1, r2 io.ReadCloser, err error) {
if err = b.Close(); err != nil {
return nil, nil, err
}
- return ioutil.NopCloser(&buf), ioutil.NopCloser(bytes.NewBuffer(buf.Bytes())), nil
+ return ioutil.NopCloser(&buf), ioutil.NopCloser(bytes.NewReader(buf.Bytes())), nil
}
// dumpConn is a net.Conn which writes to Writer and reads from Reader
@@ -94,14 +95,23 @@ func DumpRequestOut(req *http.Request, body bool) ([]byte, error) {
// with a dummy response.
var buf bytes.Buffer // records the output
pr, pw := io.Pipe()
+ defer pr.Close()
+ defer pw.Close()
dr := &delegateReader{c: make(chan io.Reader)}
// Wait for the request before replying with a dummy response:
go func() {
- http.ReadRequest(bufio.NewReader(pr))
+ req, err := http.ReadRequest(bufio.NewReader(pr))
+ if err == nil {
+ // Ensure all the body is read; otherwise
+ // we'll get a partial dump.
+ io.Copy(ioutil.Discard, req.Body)
+ req.Body.Close()
+ }
dr.c <- strings.NewReader("HTTP/1.1 204 No Content\r\n\r\n")
}()
t := &http.Transport{
+ DisableKeepAlives: true,
Dial: func(net, addr string) (net.Conn, error) {
return &dumpConn{io.MultiWriter(&buf, pw), dr}, nil
},
@@ -230,14 +240,31 @@ func DumpRequest(req *http.Request, body bool) (dump []byte, err error) {
return
}
+// errNoBody is a sentinel error value used by failureToReadBody so we can detect
+// that the lack of body was intentional.
+var errNoBody = errors.New("sentinel error value")
+
+// failureToReadBody is a io.ReadCloser that just returns errNoBody on
+// Read. It's swapped in when we don't actually want to consume the
+// body, but need a non-nil one, and want to distinguish the error
+// from reading the dummy body.
+type failureToReadBody struct{}
+
+func (failureToReadBody) Read([]byte) (int, error) { return 0, errNoBody }
+func (failureToReadBody) Close() error { return nil }
+
+var emptyBody = ioutil.NopCloser(strings.NewReader(""))
+
// DumpResponse is like DumpRequest but dumps a response.
func DumpResponse(resp *http.Response, body bool) (dump []byte, err error) {
var b bytes.Buffer
save := resp.Body
savecl := resp.ContentLength
- if !body || resp.Body == nil {
- resp.Body = nil
- resp.ContentLength = 0
+
+ if !body {
+ resp.Body = failureToReadBody{}
+ } else if resp.Body == nil {
+ resp.Body = emptyBody
} else {
save, resp.Body, err = drainBody(resp.Body)
if err != nil {
@@ -245,11 +272,13 @@ func DumpResponse(resp *http.Response, body bool) (dump []byte, err error) {
}
}
err = resp.Write(&b)
+ if err == errNoBody {
+ err = nil
+ }
resp.Body = save
resp.ContentLength = savecl
if err != nil {
- return
+ return nil, err
}
- dump = b.Bytes()
- return
+ return b.Bytes(), nil
}
diff --git a/libgo/go/net/http/httputil/dump_test.go b/libgo/go/net/http/httputil/dump_test.go
index 987a820487..024ee5a86f 100644
--- a/libgo/go/net/http/httputil/dump_test.go
+++ b/libgo/go/net/http/httputil/dump_test.go
@@ -11,6 +11,8 @@ import (
"io/ioutil"
"net/http"
"net/url"
+ "runtime"
+ "strings"
"testing"
)
@@ -109,9 +111,34 @@ var dumpTests = []dumpTest{
NoBody: true,
},
+
+ // Request with Body > 8196 (default buffer size)
+ {
+ Req: http.Request{
+ Method: "POST",
+ URL: &url.URL{
+ Scheme: "http",
+ Host: "post.tld",
+ Path: "/",
+ },
+ ContentLength: 8193,
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ },
+
+ Body: bytes.Repeat([]byte("a"), 8193),
+
+ WantDumpOut: "POST / HTTP/1.1\r\n" +
+ "Host: post.tld\r\n" +
+ "User-Agent: Go 1.1 package http\r\n" +
+ "Content-Length: 8193\r\n" +
+ "Accept-Encoding: gzip\r\n\r\n" +
+ strings.Repeat("a", 8193),
+ },
}
func TestDumpRequest(t *testing.T) {
+ numg0 := runtime.NumGoroutine()
for i, tt := range dumpTests {
setBody := func() {
if tt.Body == nil {
@@ -119,9 +146,11 @@ func TestDumpRequest(t *testing.T) {
}
switch b := tt.Body.(type) {
case []byte:
- tt.Req.Body = ioutil.NopCloser(bytes.NewBuffer(b))
+ tt.Req.Body = ioutil.NopCloser(bytes.NewReader(b))
case func() io.ReadCloser:
tt.Req.Body = b()
+ default:
+ t.Fatalf("Test %d: unsupported Body of %T", i, tt.Body)
}
}
setBody()
@@ -155,6 +184,11 @@ func TestDumpRequest(t *testing.T) {
}
}
}
+ if dg := runtime.NumGoroutine() - numg0; dg > 4 {
+ buf := make([]byte, 4096)
+ buf = buf[:runtime.Stack(buf, true)]
+ t.Errorf("Unexpectedly large number of new goroutines: %d new: %s", dg, buf)
+ }
}
func chunk(s string) string {
@@ -176,3 +210,82 @@ func mustNewRequest(method, url string, body io.Reader) *http.Request {
}
return req
}
+
+var dumpResTests = []struct {
+ res *http.Response
+ body bool
+ want string
+}{
+ {
+ res: &http.Response{
+ Status: "200 OK",
+ StatusCode: 200,
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ ContentLength: 50,
+ Header: http.Header{
+ "Foo": []string{"Bar"},
+ },
+ Body: ioutil.NopCloser(strings.NewReader("foo")), // shouldn't be used
+ },
+ body: false, // to verify we see 50, not empty or 3.
+ want: `HTTP/1.1 200 OK
+Content-Length: 50
+Foo: Bar`,
+ },
+
+ {
+ res: &http.Response{
+ Status: "200 OK",
+ StatusCode: 200,
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ ContentLength: 3,
+ Body: ioutil.NopCloser(strings.NewReader("foo")),
+ },
+ body: true,
+ want: `HTTP/1.1 200 OK
+Content-Length: 3
+
+foo`,
+ },
+
+ {
+ res: &http.Response{
+ Status: "200 OK",
+ StatusCode: 200,
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ ContentLength: -1,
+ Body: ioutil.NopCloser(strings.NewReader("foo")),
+ TransferEncoding: []string{"chunked"},
+ },
+ body: true,
+ want: `HTTP/1.1 200 OK
+Transfer-Encoding: chunked
+
+3
+foo
+0`,
+ },
+}
+
+func TestDumpResponse(t *testing.T) {
+ for i, tt := range dumpResTests {
+ gotb, err := DumpResponse(tt.res, tt.body)
+ if err != nil {
+ t.Errorf("%d. DumpResponse = %v", i, err)
+ continue
+ }
+ got := string(gotb)
+ got = strings.TrimSpace(got)
+ got = strings.Replace(got, "\r", "", -1)
+
+ if got != tt.want {
+ t.Errorf("%d.\nDumpResponse got:\n%s\n\nWant:\n%s\n", i, got, tt.want)
+ }
+ }
+}
diff --git a/libgo/go/net/http/httputil/httputil.go b/libgo/go/net/http/httputil/httputil.go
new file mode 100644
index 0000000000..2e523e9e26
--- /dev/null
+++ b/libgo/go/net/http/httputil/httputil.go
@@ -0,0 +1,39 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package httputil provides HTTP utility functions, complementing the
+// more common ones in the net/http package.
+package httputil
+
+import (
+ "io"
+ "net/http/internal"
+)
+
+// NewChunkedReader returns a new chunkedReader that translates the data read from r
+// out of HTTP "chunked" format before returning it.
+// The chunkedReader returns io.EOF when the final 0-length chunk is read.
+//
+// NewChunkedReader is not needed by normal applications. The http package
+// automatically decodes chunking when reading response bodies.
+func NewChunkedReader(r io.Reader) io.Reader {
+ return internal.NewChunkedReader(r)
+}
+
+// NewChunkedWriter returns a new chunkedWriter that translates writes into HTTP
+// "chunked" format before writing them to w. Closing the returned chunkedWriter
+// sends the final 0-length chunk that marks the end of the stream.
+//
+// NewChunkedWriter is not needed by normal applications. The http
+// package adds chunking automatically if handlers don't set a
+// Content-Length header. Using NewChunkedWriter inside a handler
+// would result in double chunking or chunking with a Content-Length
+// length, both of which are wrong.
+func NewChunkedWriter(w io.Writer) io.WriteCloser {
+ return internal.NewChunkedWriter(w)
+}
+
+// ErrLineTooLong is returned when reading malformed chunked data
+// with lines that are too long.
+var ErrLineTooLong = internal.ErrLineTooLong
diff --git a/libgo/go/net/http/httputil/persist.go b/libgo/go/net/http/httputil/persist.go
index 507938acac..987bcc96ba 100644
--- a/libgo/go/net/http/httputil/persist.go
+++ b/libgo/go/net/http/httputil/persist.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 httputil provides HTTP utility functions, complementing the
-// more common ones in the net/http package.
package httputil
import (
@@ -33,8 +31,8 @@ var errClosed = errors.New("i/o operation on closed connection")
// i.e. requests can be read out of sync (but in the same order) while the
// respective responses are sent.
//
-// ServerConn is low-level and should not be needed by most applications.
-// See Server.
+// ServerConn is low-level and old. Applications should instead use Server
+// in the net/http package.
type ServerConn struct {
lk sync.Mutex // read-write protects the following fields
c net.Conn
@@ -47,8 +45,11 @@ type ServerConn struct {
pipe textproto.Pipeline
}
-// NewServerConn returns a new ServerConn reading and writing c. If r is not
+// NewServerConn returns a new ServerConn reading and writing c. If r is not
// nil, it is the buffer to use when reading c.
+//
+// ServerConn is low-level and old. Applications should instead use Server
+// in the net/http package.
func NewServerConn(c net.Conn, r *bufio.Reader) *ServerConn {
if r == nil {
r = bufio.NewReader(c)
@@ -223,8 +224,8 @@ func (sc *ServerConn) Write(req *http.Request, resp *http.Response) error {
// supports hijacking the connection calling Hijack to
// regain control of the underlying net.Conn and deal with it as desired.
//
-// ClientConn is low-level and should not be needed by most applications.
-// See Client.
+// ClientConn is low-level and old. Applications should instead use
+// Client or Transport in the net/http package.
type ClientConn struct {
lk sync.Mutex // read-write protects the following fields
c net.Conn
@@ -240,6 +241,9 @@ type ClientConn struct {
// NewClientConn returns a new ClientConn reading and writing c. If r is not
// nil, it is the buffer to use when reading c.
+//
+// ClientConn is low-level and old. Applications should use Client or
+// Transport in the net/http package.
func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
if r == nil {
r = bufio.NewReader(c)
@@ -254,6 +258,9 @@ func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
// NewProxyClientConn works like NewClientConn but writes Requests
// using Request's WriteProxy method.
+//
+// New code should not use NewProxyClientConn. See Client or
+// Transport in the net/http package instead.
func NewProxyClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
cc := NewClientConn(c, r)
cc.writeReq = (*http.Request).WriteProxy
diff --git a/libgo/go/net/http/httputil/reverseproxy.go b/libgo/go/net/http/httputil/reverseproxy.go
index 1990f64dbd..ab46370180 100644
--- a/libgo/go/net/http/httputil/reverseproxy.go
+++ b/libgo/go/net/http/httputil/reverseproxy.go
@@ -40,6 +40,12 @@ type ReverseProxy struct {
// response body.
// If zero, no periodic flushing is done.
FlushInterval time.Duration
+
+ // ErrorLog specifies an optional logger for errors
+ // that occur when attempting to proxy the request.
+ // If nil, logging goes to os.Stderr via the log package's
+ // standard logger.
+ ErrorLog *log.Logger
}
func singleJoiningSlash(a, b string) string {
@@ -138,12 +144,16 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
res, err := transport.RoundTrip(outreq)
if err != nil {
- log.Printf("http: proxy error: %v", err)
+ p.logf("http: proxy error: %v", err)
rw.WriteHeader(http.StatusInternalServerError)
return
}
defer res.Body.Close()
+ for _, h := range hopHeaders {
+ res.Header.Del(h)
+ }
+
copyHeader(rw.Header(), res.Header)
rw.WriteHeader(res.StatusCode)
@@ -167,6 +177,14 @@ func (p *ReverseProxy) copyResponse(dst io.Writer, src io.Reader) {
io.Copy(dst, src)
}
+func (p *ReverseProxy) logf(format string, args ...interface{}) {
+ if p.ErrorLog != nil {
+ p.ErrorLog.Printf(format, args...)
+ } else {
+ log.Printf(format, args...)
+ }
+}
+
type writeFlusher interface {
io.Writer
http.Flusher
diff --git a/libgo/go/net/http/httputil/reverseproxy_test.go b/libgo/go/net/http/httputil/reverseproxy_test.go
index 1c0444ec48..e9539b44b6 100644
--- a/libgo/go/net/http/httputil/reverseproxy_test.go
+++ b/libgo/go/net/http/httputil/reverseproxy_test.go
@@ -16,6 +16,12 @@ import (
"time"
)
+const fakeHopHeader = "X-Fake-Hop-Header-For-Test"
+
+func init() {
+ hopHeaders = append(hopHeaders, fakeHopHeader)
+}
+
func TestReverseProxy(t *testing.T) {
const backendResponse = "I am the backend"
const backendStatus = 404
@@ -36,6 +42,10 @@ func TestReverseProxy(t *testing.T) {
t.Errorf("backend got Host header %q, want %q", g, e)
}
w.Header().Set("X-Foo", "bar")
+ w.Header().Set("Upgrade", "foo")
+ w.Header().Set(fakeHopHeader, "foo")
+ w.Header().Add("X-Multi-Value", "foo")
+ w.Header().Add("X-Multi-Value", "bar")
http.SetCookie(w, &http.Cookie{Name: "flavor", Value: "chocolateChip"})
w.WriteHeader(backendStatus)
w.Write([]byte(backendResponse))
@@ -64,6 +74,12 @@ func TestReverseProxy(t *testing.T) {
if g, e := res.Header.Get("X-Foo"), "bar"; g != e {
t.Errorf("got X-Foo %q; expected %q", g, e)
}
+ if c := res.Header.Get(fakeHopHeader); c != "" {
+ t.Errorf("got %s header value %q", fakeHopHeader, c)
+ }
+ if g, e := len(res.Header["X-Multi-Value"]), 2; g != e {
+ t.Errorf("got %d X-Multi-Value header values; expected %d", g, e)
+ }
if g, e := len(res.Header["Set-Cookie"]), 1; g != e {
t.Fatalf("got %d SetCookies, want %d", g, e)
}
diff --git a/libgo/go/net/http/httputil/chunked.go b/libgo/go/net/http/internal/chunked.go
index b66d409515..9294deb3e5 100644
--- a/libgo/go/net/http/httputil/chunked.go
+++ b/libgo/go/net/http/internal/chunked.go
@@ -4,15 +4,13 @@
// The wire protocol for HTTP's "chunked" Transfer-Encoding.
-// This code is a duplicate of ../chunked.go with these edits:
-// s/newChunked/NewChunked/g
-// s/package http/package httputil/
-// Please make any changes in both files.
-
-package httputil
+// Package internal contains HTTP internals shared by net/http and
+// net/http/httputil.
+package internal
import (
"bufio"
+ "bytes"
"errors"
"fmt"
"io"
@@ -59,26 +57,45 @@ func (cr *chunkedReader) beginChunk() {
}
}
-func (cr *chunkedReader) Read(b []uint8) (n int, err error) {
- if cr.err != nil {
- return 0, cr.err
+func (cr *chunkedReader) chunkHeaderAvailable() bool {
+ n := cr.r.Buffered()
+ if n > 0 {
+ peek, _ := cr.r.Peek(n)
+ return bytes.IndexByte(peek, '\n') >= 0
}
- if cr.n == 0 {
- cr.beginChunk()
- if cr.err != nil {
- return 0, cr.err
+ return false
+}
+
+func (cr *chunkedReader) Read(b []uint8) (n int, err error) {
+ for cr.err == nil {
+ if cr.n == 0 {
+ if n > 0 && !cr.chunkHeaderAvailable() {
+ // We've read enough. Don't potentially block
+ // reading a new chunk header.
+ break
+ }
+ cr.beginChunk()
+ continue
}
- }
- if uint64(len(b)) > cr.n {
- b = b[0:cr.n]
- }
- n, cr.err = cr.r.Read(b)
- cr.n -= uint64(n)
- if cr.n == 0 && cr.err == nil {
- // end of chunk (CRLF)
- if _, cr.err = io.ReadFull(cr.r, cr.buf[:]); cr.err == nil {
- if cr.buf[0] != '\r' || cr.buf[1] != '\n' {
- cr.err = errors.New("malformed chunked encoding")
+ if len(b) == 0 {
+ break
+ }
+ rbuf := b
+ if uint64(len(rbuf)) > cr.n {
+ rbuf = rbuf[:cr.n]
+ }
+ var n0 int
+ n0, cr.err = cr.r.Read(rbuf)
+ n += n0
+ b = b[n0:]
+ cr.n -= uint64(n0)
+ // If we're at the end of a chunk, read the next two
+ // bytes to verify they are "\r\n".
+ if cr.n == 0 && cr.err == nil {
+ if _, cr.err = io.ReadFull(cr.r, cr.buf[:2]); cr.err == nil {
+ if cr.buf[0] != '\r' || cr.buf[1] != '\n' {
+ cr.err = errors.New("malformed chunked encoding")
+ }
}
}
}
@@ -123,7 +140,7 @@ func isASCIISpace(b byte) bool {
//
// NewChunkedWriter is not needed by normal applications. The http
// package adds chunking automatically if handlers don't set a
-// Content-Length header. Using NewChunkedWriter inside a handler
+// Content-Length header. Using newChunkedWriter inside a handler
// would result in double chunking or chunking with a Content-Length
// length, both of which are wrong.
func NewChunkedWriter(w io.Writer) io.WriteCloser {
diff --git a/libgo/go/net/http/internal/chunked_test.go b/libgo/go/net/http/internal/chunked_test.go
new file mode 100644
index 0000000000..ebc626ea9d
--- /dev/null
+++ b/libgo/go/net/http/internal/chunked_test.go
@@ -0,0 +1,156 @@
+// 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 internal
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "strings"
+ "testing"
+)
+
+func TestChunk(t *testing.T) {
+ var b bytes.Buffer
+
+ w := NewChunkedWriter(&b)
+ const chunk1 = "hello, "
+ const chunk2 = "world! 0123456789abcdef"
+ w.Write([]byte(chunk1))
+ w.Write([]byte(chunk2))
+ w.Close()
+
+ if g, e := b.String(), "7\r\nhello, \r\n17\r\nworld! 0123456789abcdef\r\n0\r\n"; g != e {
+ t.Fatalf("chunk writer wrote %q; want %q", g, e)
+ }
+
+ r := NewChunkedReader(&b)
+ data, err := ioutil.ReadAll(r)
+ if err != nil {
+ t.Logf(`data: "%s"`, data)
+ t.Fatalf("ReadAll from reader: %v", err)
+ }
+ if g, e := string(data), chunk1+chunk2; g != e {
+ t.Errorf("chunk reader read %q; want %q", g, e)
+ }
+}
+
+func TestChunkReadMultiple(t *testing.T) {
+ // Bunch of small chunks, all read together.
+ {
+ var b bytes.Buffer
+ w := NewChunkedWriter(&b)
+ w.Write([]byte("foo"))
+ w.Write([]byte("bar"))
+ w.Close()
+
+ r := NewChunkedReader(&b)
+ buf := make([]byte, 10)
+ n, err := r.Read(buf)
+ if n != 6 || err != io.EOF {
+ t.Errorf("Read = %d, %v; want 6, EOF", n, err)
+ }
+ buf = buf[:n]
+ if string(buf) != "foobar" {
+ t.Errorf("Read = %q; want %q", buf, "foobar")
+ }
+ }
+
+ // One big chunk followed by a little chunk, but the small bufio.Reader size
+ // should prevent the second chunk header from being read.
+ {
+ var b bytes.Buffer
+ w := NewChunkedWriter(&b)
+ // fillBufChunk is 11 bytes + 3 bytes header + 2 bytes footer = 16 bytes,
+ // the same as the bufio ReaderSize below (the minimum), so even
+ // though we're going to try to Read with a buffer larger enough to also
+ // receive "foo", the second chunk header won't be read yet.
+ const fillBufChunk = "0123456789a"
+ const shortChunk = "foo"
+ w.Write([]byte(fillBufChunk))
+ w.Write([]byte(shortChunk))
+ w.Close()
+
+ r := NewChunkedReader(bufio.NewReaderSize(&b, 16))
+ buf := make([]byte, len(fillBufChunk)+len(shortChunk))
+ n, err := r.Read(buf)
+ if n != len(fillBufChunk) || err != nil {
+ t.Errorf("Read = %d, %v; want %d, nil", n, err, len(fillBufChunk))
+ }
+ buf = buf[:n]
+ if string(buf) != fillBufChunk {
+ t.Errorf("Read = %q; want %q", buf, fillBufChunk)
+ }
+
+ n, err = r.Read(buf)
+ if n != len(shortChunk) || err != io.EOF {
+ t.Errorf("Read = %d, %v; want %d, EOF", n, err, len(shortChunk))
+ }
+ }
+
+ // And test that we see an EOF chunk, even though our buffer is already full:
+ {
+ r := NewChunkedReader(bufio.NewReader(strings.NewReader("3\r\nfoo\r\n0\r\n")))
+ buf := make([]byte, 3)
+ n, err := r.Read(buf)
+ if n != 3 || err != io.EOF {
+ t.Errorf("Read = %d, %v; want 3, EOF", n, err)
+ }
+ if string(buf) != "foo" {
+ t.Errorf("buf = %q; want foo", buf)
+ }
+ }
+}
+
+func TestChunkReaderAllocs(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping in short mode")
+ }
+ var buf bytes.Buffer
+ w := NewChunkedWriter(&buf)
+ a, b, c := []byte("aaaaaa"), []byte("bbbbbbbbbbbb"), []byte("cccccccccccccccccccccccc")
+ w.Write(a)
+ w.Write(b)
+ w.Write(c)
+ w.Close()
+
+ readBuf := make([]byte, len(a)+len(b)+len(c)+1)
+ byter := bytes.NewReader(buf.Bytes())
+ bufr := bufio.NewReader(byter)
+ mallocs := testing.AllocsPerRun(100, func() {
+ byter.Seek(0, 0)
+ bufr.Reset(byter)
+ r := NewChunkedReader(bufr)
+ n, err := io.ReadFull(r, readBuf)
+ if n != len(readBuf)-1 {
+ t.Fatalf("read %d bytes; want %d", n, len(readBuf)-1)
+ }
+ if err != io.ErrUnexpectedEOF {
+ t.Fatalf("read error = %v; want ErrUnexpectedEOF", err)
+ }
+ })
+ if mallocs > 1.5 {
+ t.Errorf("mallocs = %v; want 1", mallocs)
+ }
+}
+
+func TestParseHexUint(t *testing.T) {
+ for i := uint64(0); i <= 1234; i++ {
+ line := []byte(fmt.Sprintf("%x", i))
+ got, err := parseHexUint(line)
+ if err != nil {
+ t.Fatalf("on %d: %v", i, err)
+ }
+ if got != i {
+ t.Errorf("for input %q = %d; want %d", line, got, i)
+ }
+ }
+ _, err := parseHexUint([]byte("bogus"))
+ if err == nil {
+ t.Error("expected error on bogus input")
+ }
+}
diff --git a/libgo/go/net/http/z_last_test.go b/libgo/go/net/http/main_test.go
index 5a0cc11984..b8c71fd19f 100644
--- a/libgo/go/net/http/z_last_test.go
+++ b/libgo/go/net/http/main_test.go
@@ -5,7 +5,9 @@
package http_test
import (
+ "fmt"
"net/http"
+ "os"
"runtime"
"sort"
"strings"
@@ -13,6 +15,14 @@ import (
"time"
)
+func TestMain(m *testing.M) {
+ v := m.Run()
+ if v == 0 && goroutineLeaked() {
+ os.Exit(1)
+ }
+ os.Exit(v)
+}
+
func interestingGoroutines() (gs []string) {
buf := make([]byte, 2<<20)
buf = buf[:runtime.Stack(buf, true)]
@@ -30,6 +40,7 @@ func interestingGoroutines() (gs []string) {
// These only show up with GOTRACEBACK=2; Issue 5005 (comment 28)
strings.Contains(stack, "runtime.goexit") ||
strings.Contains(stack, "created by runtime.gc") ||
+ strings.Contains(stack, "net/http_test.interestingGoroutines") ||
strings.Contains(stack, "runtime.MHeap_Scavenger") {
continue
}
@@ -40,10 +51,10 @@ func interestingGoroutines() (gs []string) {
}
// Verify the other tests didn't leave any goroutines running.
-// This is in a file named z_last_test.go so it sorts at the end.
-func TestGoroutinesRunning(t *testing.T) {
+func goroutineLeaked() bool {
if testing.Short() {
- t.Skip("not counting goroutines for leakage in -short mode")
+ // not counting goroutines for leakage in -short mode
+ return false
}
gs := interestingGoroutines()
@@ -54,13 +65,14 @@ func TestGoroutinesRunning(t *testing.T) {
n++
}
- t.Logf("num goroutines = %d", n)
- if n > 0 {
- t.Error("Too many goroutines.")
- for stack, count := range stackCount {
- t.Logf("%d instances of:\n%s", count, stack)
- }
+ if n == 0 {
+ return false
+ }
+ fmt.Fprintf(os.Stderr, "Too many goroutines running after net/http test(s).\n")
+ for stack, count := range stackCount {
+ fmt.Fprintf(os.Stderr, "%d instances of:\n%s\n", count, stack)
}
+ return true
}
func afterTest(t *testing.T) {
diff --git a/libgo/go/net/http/pprof/pprof.go b/libgo/go/net/http/pprof/pprof.go
index 0c7548e3ef..a23f1bc4bc 100644
--- a/libgo/go/net/http/pprof/pprof.go
+++ b/libgo/go/net/http/pprof/pprof.go
@@ -162,6 +162,10 @@ func (name handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Unknown profile: %s\n", name)
return
}
+ gc, _ := strconv.Atoi(r.FormValue("gc"))
+ if name == "heap" && gc > 0 {
+ runtime.GC()
+ }
p.WriteTo(w, debug)
return
}
diff --git a/libgo/go/net/http/proxy_test.go b/libgo/go/net/http/proxy_test.go
index 449ccaeea7..b6aed3792b 100644
--- a/libgo/go/net/http/proxy_test.go
+++ b/libgo/go/net/http/proxy_test.go
@@ -35,12 +35,8 @@ var UseProxyTests = []struct {
}
func TestUseProxy(t *testing.T) {
- oldenv := os.Getenv("NO_PROXY")
- defer os.Setenv("NO_PROXY", oldenv)
-
- no_proxy := "foobar.com, .barbaz.net"
- os.Setenv("NO_PROXY", no_proxy)
-
+ ResetProxyEnv()
+ os.Setenv("NO_PROXY", "foobar.com, .barbaz.net")
for _, test := range UseProxyTests {
if useProxy(test.host+":80") != test.match {
t.Errorf("useProxy(%v) = %v, want %v", test.host, !test.match, test.match)
@@ -71,8 +67,15 @@ func TestCacheKeys(t *testing.T) {
proxy = u
}
cm := connectMethod{proxy, tt.scheme, tt.addr}
- if cm.String() != tt.key {
- t.Fatalf("{%q, %q, %q} cache key %q; want %q", tt.proxy, tt.scheme, tt.addr, cm.String(), tt.key)
+ if got := cm.key().String(); got != tt.key {
+ t.Fatalf("{%q, %q, %q} cache key = %q; want %q", tt.proxy, tt.scheme, tt.addr, got, tt.key)
}
}
}
+
+func ResetProxyEnv() {
+ for _, v := range []string{"HTTP_PROXY", "http_proxy", "NO_PROXY", "no_proxy"} {
+ os.Setenv(v, "")
+ }
+ ResetCachedEnvironment()
+}
diff --git a/libgo/go/net/http/race.go b/libgo/go/net/http/race.go
new file mode 100644
index 0000000000..766503967c
--- /dev/null
+++ b/libgo/go/net/http/race.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 race
+
+package http
+
+func init() {
+ raceEnabled = true
+}
diff --git a/libgo/go/net/http/readrequest_test.go b/libgo/go/net/http/readrequest_test.go
index ffdd6a892d..e930d99af6 100644
--- a/libgo/go/net/http/readrequest_test.go
+++ b/libgo/go/net/http/readrequest_test.go
@@ -11,6 +11,7 @@ import (
"io"
"net/url"
"reflect"
+ "strings"
"testing"
)
@@ -295,14 +296,39 @@ var reqTests = []reqTest{
noTrailer,
noError,
},
+
+ // Connection: close. golang.org/issue/8261
+ {
+ "GET / HTTP/1.1\r\nHost: issue8261.com\r\nConnection: close\r\n\r\n",
+ &Request{
+ Method: "GET",
+ URL: &url.URL{
+ Path: "/",
+ },
+ Header: Header{
+ // This wasn't removed from Go 1.0 to
+ // Go 1.3, so locking it in that we
+ // keep this:
+ "Connection": []string{"close"},
+ },
+ Host: "issue8261.com",
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Close: true,
+ RequestURI: "/",
+ },
+
+ noBody,
+ noTrailer,
+ noError,
+ },
}
func TestReadRequest(t *testing.T) {
for i := range reqTests {
tt := &reqTests[i]
- var braw bytes.Buffer
- braw.WriteString(tt.Raw)
- req, err := ReadRequest(bufio.NewReader(&braw))
+ req, err := ReadRequest(bufio.NewReader(strings.NewReader(tt.Raw)))
if err != nil {
if err.Error() != tt.Error {
t.Errorf("#%d: error %q, want error %q", i, err.Error(), tt.Error)
@@ -311,21 +337,22 @@ func TestReadRequest(t *testing.T) {
}
rbody := req.Body
req.Body = nil
- diff(t, fmt.Sprintf("#%d Request", i), req, tt.Req)
+ testName := fmt.Sprintf("Test %d (%q)", i, tt.Raw)
+ diff(t, testName, req, tt.Req)
var bout bytes.Buffer
if rbody != nil {
_, err := io.Copy(&bout, rbody)
if err != nil {
- t.Fatalf("#%d. copying body: %v", i, err)
+ t.Fatalf("%s: copying body: %v", testName, err)
}
rbody.Close()
}
body := bout.String()
if body != tt.Body {
- t.Errorf("#%d: Body = %q want %q", i, body, tt.Body)
+ t.Errorf("%s: Body = %q want %q", testName, body, tt.Body)
}
if !reflect.DeepEqual(tt.Trailer, req.Trailer) {
- t.Errorf("#%d. Trailers differ.\n got: %v\nwant: %v", i, req.Trailer, tt.Trailer)
+ t.Errorf("%s: Trailers differ.\n got: %v\nwant: %v", testName, req.Trailer, tt.Trailer)
}
}
}
diff --git a/libgo/go/net/http/request.go b/libgo/go/net/http/request.go
index 57b5d09484..487eebcb84 100644
--- a/libgo/go/net/http/request.go
+++ b/libgo/go/net/http/request.go
@@ -10,6 +10,7 @@ import (
"bufio"
"bytes"
"crypto/tls"
+ "encoding/base64"
"errors"
"fmt"
"io"
@@ -20,6 +21,7 @@ import (
"net/url"
"strconv"
"strings"
+ "sync"
)
const (
@@ -68,18 +70,31 @@ var reqWriteExcludeHeader = map[string]bool{
// A Request represents an HTTP request received by a server
// or to be sent by a client.
+//
+// The field semantics differ slightly between client and server
+// usage. In addition to the notes on the fields below, see the
+// documentation for Request.Write and RoundTripper.
type Request struct {
- Method string // GET, POST, PUT, etc.
+ // Method specifies the HTTP method (GET, POST, PUT, etc.).
+ // For client requests an empty string means GET.
+ Method string
- // URL is created from the URI supplied on the Request-Line
- // as stored in RequestURI.
+ // URL specifies either the URI being requested (for server
+ // requests) or the URL to access (for client requests).
+ //
+ // For server requests the URL is parsed from the URI
+ // supplied on the Request-Line as stored in RequestURI. For
+ // most requests, fields other than Path and RawQuery will be
+ // empty. (See RFC 2616, Section 5.1.2)
//
- // For most requests, fields other than Path and RawQuery
- // will be empty. (See RFC 2616, Section 5.1.2)
+ // For client requests, the URL's Host specifies the server to
+ // connect to, while the Request's Host field optionally
+ // specifies the Host header value to send in the HTTP
+ // request.
URL *url.URL
// The protocol version for incoming requests.
- // Outgoing requests always use HTTP/1.1.
+ // Client requests always use HTTP/1.1.
Proto string // "HTTP/1.0"
ProtoMajor int // 1
ProtoMinor int // 0
@@ -103,15 +118,20 @@ type Request struct {
// The request parser implements this by canonicalizing the
// name, making the first character and any characters
// following a hyphen uppercase and the rest lowercase.
+ //
+ // For client requests certain headers are automatically
+ // added and may override values in Header.
+ //
+ // See the documentation for the Request.Write method.
Header Header
// Body is the request's body.
//
- // For client requests, a nil body means the request has no
+ // For client requests a nil body means the request has no
// body, such as a GET request. The HTTP Client's Transport
// is responsible for calling the Close method.
//
- // For server requests, the Request Body is always non-nil
+ // For server requests the Request Body is always non-nil
// but will return EOF immediately when no body is present.
// The Server will close the request body. The ServeHTTP
// Handler does not need to.
@@ -121,7 +141,7 @@ type Request struct {
// The value -1 indicates that the length is unknown.
// Values >= 0 indicate that the given number of bytes may
// be read from Body.
- // For outgoing requests, a value of 0 means unknown if Body is not nil.
+ // For client requests, a value of 0 means unknown if Body is not nil.
ContentLength int64
// TransferEncoding lists the transfer encodings from outermost to
@@ -132,13 +152,18 @@ type Request struct {
TransferEncoding []string
// Close indicates whether to close the connection after
- // replying to this request.
+ // replying to this request (for servers) or after sending
+ // the request (for clients).
Close bool
- // The host on which the URL is sought.
- // Per RFC 2616, this is either the value of the Host: header
- // or the host name given in the URL itself.
+ // For server requests Host specifies the host on which the
+ // URL is sought. Per RFC 2616, this is either the value of
+ // the "Host" header or the host name given in the URL itself.
// It may be of the form "host:port".
+ //
+ // For client requests Host optionally overrides the Host
+ // header to send. If empty, the Request.Write method uses
+ // the value of URL.Host.
Host string
// Form contains the parsed form data, including both the URL
@@ -158,12 +183,24 @@ type Request struct {
// The HTTP client ignores MultipartForm and uses Body instead.
MultipartForm *multipart.Form
- // Trailer maps trailer keys to values. Like for Header, if the
- // response has multiple trailer lines with the same key, they will be
- // concatenated, delimited by commas.
- // For server requests, Trailer is only populated after Body has been
- // closed or fully consumed.
- // Trailer support is only partially complete.
+ // Trailer specifies additional headers that are sent after the request
+ // body.
+ //
+ // For server requests the Trailer map initially contains only the
+ // trailer keys, with nil values. (The client declares which trailers it
+ // will later send.) While the handler is reading from Body, it must
+ // not reference Trailer. After reading from Body returns EOF, Trailer
+ // can be read again and will contain non-nil values, if they were sent
+ // by the client.
+ //
+ // For client requests Trailer must be initialized to a map containing
+ // the trailer keys to later send. The values may be nil or their final
+ // values. The ContentLength must be 0 or -1, to send a chunked request.
+ // After the HTTP request is sent the map values can be updated while
+ // the request body is read. Once the body returns EOF, the caller must
+ // not mutate Trailer.
+ //
+ // Few HTTP clients, servers, or proxies support HTTP trailers.
Trailer Header
// RemoteAddr allows HTTP servers and other software to record
@@ -354,10 +391,16 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) err
w = bw
}
- fmt.Fprintf(w, "%s %s HTTP/1.1\r\n", valueOrDefault(req.Method, "GET"), ruri)
+ _, err := fmt.Fprintf(w, "%s %s HTTP/1.1\r\n", valueOrDefault(req.Method, "GET"), ruri)
+ if err != nil {
+ return err
+ }
// Header lines
- fmt.Fprintf(w, "Host: %s\r\n", host)
+ _, err = fmt.Fprintf(w, "Host: %s\r\n", host)
+ if err != nil {
+ return err
+ }
// Use the defaultUserAgent unless the Header contains one, which
// may be blank to not send the header.
@@ -368,7 +411,10 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) err
}
}
if userAgent != "" {
- fmt.Fprintf(w, "User-Agent: %s\r\n", userAgent)
+ _, err = fmt.Fprintf(w, "User-Agent: %s\r\n", userAgent)
+ if err != nil {
+ return err
+ }
}
// Process Body,ContentLength,Close,Trailer
@@ -381,7 +427,6 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) err
return err
}
- // TODO: split long values? (If so, should share code with Conn.Write)
err = req.Header.WriteSubset(w, reqWriteExcludeHeader)
if err != nil {
return err
@@ -394,7 +439,10 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) err
}
}
- io.WriteString(w, "\r\n")
+ _, err = io.WriteString(w, "\r\n")
+ if err != nil {
+ return err
+ }
// Write body and trailer
err = tw.WriteBody(w)
@@ -474,6 +522,35 @@ func NewRequest(method, urlStr string, body io.Reader) (*Request, error) {
return req, nil
}
+// BasicAuth returns the username and password provided in the request's
+// Authorization header, if the request uses HTTP Basic Authentication.
+// See RFC 2617, Section 2.
+func (r *Request) BasicAuth() (username, password string, ok bool) {
+ auth := r.Header.Get("Authorization")
+ if auth == "" {
+ return
+ }
+ return parseBasicAuth(auth)
+}
+
+// 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 ") {
+ return
+ }
+ c, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(auth, "Basic "))
+ if err != nil {
+ return
+ }
+ cs := string(c)
+ s := strings.IndexByte(cs, ':')
+ if s < 0 {
+ return
+ }
+ return cs[:s], cs[s+1:], true
+}
+
// SetBasicAuth sets the request's Authorization header to use HTTP
// Basic Authentication with the provided username and password.
//
@@ -494,25 +571,20 @@ func parseRequestLine(line string) (method, requestURI, proto string, ok bool) {
return line[:s1], line[s1+1 : s2], line[s2+1:], true
}
-// TODO(bradfitz): use a sync.Cache when available
-var textprotoReaderCache = make(chan *textproto.Reader, 4)
+var textprotoReaderPool sync.Pool
func newTextprotoReader(br *bufio.Reader) *textproto.Reader {
- select {
- case r := <-textprotoReaderCache:
- r.R = br
- return r
- default:
- return textproto.NewReader(br)
+ if v := textprotoReaderPool.Get(); v != nil {
+ tr := v.(*textproto.Reader)
+ tr.R = br
+ return tr
}
+ return textproto.NewReader(br)
}
func putTextprotoReader(r *textproto.Reader) {
r.R = nil
- select {
- case textprotoReaderCache <- r:
- default:
- }
+ textprotoReaderPool.Put(r)
}
// ReadRequest reads and parses a request from b.
@@ -588,37 +660,12 @@ func ReadRequest(b *bufio.Reader) (req *Request, err error) {
fixPragmaCacheControl(req.Header)
- // TODO: Parse specific header values:
- // Accept
- // Accept-Encoding
- // Accept-Language
- // Authorization
- // Cache-Control
- // Connection
- // Date
- // Expect
- // From
- // If-Match
- // If-Modified-Since
- // If-None-Match
- // If-Range
- // If-Unmodified-Since
- // Max-Forwards
- // Proxy-Authorization
- // Referer [sic]
- // TE (transfer-codings)
- // Trailer
- // Transfer-Encoding
- // Upgrade
- // User-Agent
- // Via
- // Warning
-
err = readTransfer(req, b)
if err != nil {
return nil, err
}
+ req.Close = shouldClose(req.ProtoMajor, req.ProtoMinor, req.Header, false)
return req, nil
}
@@ -677,6 +724,11 @@ func parsePostForm(r *Request) (vs url.Values, err error) {
return
}
ct := r.Header.Get("Content-Type")
+ // RFC 2616, section 7.2.1 - empty type
+ // SHOULD be treated as application/octet-stream
+ if ct == "" {
+ ct = "application/octet-stream"
+ }
ct, _, err = mime.ParseMediaType(ct)
switch {
case ct == "application/x-www-form-urlencoded":
@@ -707,7 +759,7 @@ func parsePostForm(r *Request) (vs url.Values, err error) {
// orders to call too many functions here.
// Clean this up and write more tests.
// request_test.go contains the start of this,
- // in TestRequestMultipartCallOrder.
+ // in TestParseMultipartFormOrder and others.
}
return
}
@@ -727,7 +779,7 @@ func parsePostForm(r *Request) (vs url.Values, err error) {
func (r *Request) ParseForm() error {
var err error
if r.PostForm == nil {
- if r.Method == "POST" || r.Method == "PUT" {
+ if r.Method == "POST" || r.Method == "PUT" || r.Method == "PATCH" {
r.PostForm, err = parsePostForm(r)
}
if r.PostForm == nil {
@@ -780,9 +832,7 @@ func (r *Request) ParseMultipartForm(maxMemory int64) error {
}
mr, err := r.multipartReader()
- if err == ErrNotMultipart {
- return nil
- } else if err != nil {
+ if err != nil {
return err
}
@@ -800,8 +850,10 @@ func (r *Request) ParseMultipartForm(maxMemory int64) error {
// FormValue returns the first value for the named component of the query.
// POST and PUT body parameters take precedence over URL query string values.
-// FormValue calls ParseMultipartForm and ParseForm if necessary.
-// To access multiple values of the same key use ParseForm.
+// FormValue calls ParseMultipartForm and ParseForm if necessary and ignores
+// any errors returned by these functions.
+// To access multiple values of the same key, call ParseForm and
+// then inspect Request.Form directly.
func (r *Request) FormValue(key string) string {
if r.Form == nil {
r.ParseMultipartForm(defaultMaxMemory)
@@ -814,7 +866,8 @@ func (r *Request) FormValue(key string) string {
// PostFormValue returns the first value for the named component of the POST
// or PUT request body. URL query parameters are ignored.
-// PostFormValue calls ParseMultipartForm and ParseForm if necessary.
+// PostFormValue calls ParseMultipartForm and ParseForm if necessary and ignores
+// any errors returned by these functions.
func (r *Request) PostFormValue(key string) string {
if r.PostForm == nil {
r.ParseMultipartForm(defaultMaxMemory)
@@ -860,3 +913,9 @@ func (r *Request) wantsHttp10KeepAlive() bool {
func (r *Request) wantsClose() bool {
return hasToken(r.Header.get("Connection"), "close")
}
+
+func (r *Request) closeBody() {
+ if r.Body != nil {
+ r.Body.Close()
+ }
+}
diff --git a/libgo/go/net/http/request_test.go b/libgo/go/net/http/request_test.go
index 89303c3360..759ea4e8b5 100644
--- a/libgo/go/net/http/request_test.go
+++ b/libgo/go/net/http/request_test.go
@@ -7,6 +7,7 @@ package http_test
import (
"bufio"
"bytes"
+ "encoding/base64"
"fmt"
"io"
"io/ioutil"
@@ -60,6 +61,37 @@ func TestPostQuery(t *testing.T) {
}
}
+func TestPatchQuery(t *testing.T) {
+ req, _ := NewRequest("PATCH", "http://www.google.com/search?q=foo&q=bar&both=x&prio=1&empty=not",
+ strings.NewReader("z=post&both=y&prio=2&empty="))
+ req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
+
+ if q := req.FormValue("q"); q != "foo" {
+ t.Errorf(`req.FormValue("q") = %q, want "foo"`, q)
+ }
+ if z := req.FormValue("z"); z != "post" {
+ t.Errorf(`req.FormValue("z") = %q, want "post"`, z)
+ }
+ if bq, found := req.PostForm["q"]; found {
+ t.Errorf(`req.PostForm["q"] = %q, want no entry in map`, bq)
+ }
+ if bz := req.PostFormValue("z"); bz != "post" {
+ t.Errorf(`req.PostFormValue("z") = %q, want "post"`, bz)
+ }
+ if qs := req.Form["q"]; !reflect.DeepEqual(qs, []string{"foo", "bar"}) {
+ t.Errorf(`req.Form["q"] = %q, want ["foo", "bar"]`, qs)
+ }
+ if both := req.Form["both"]; !reflect.DeepEqual(both, []string{"y", "x"}) {
+ t.Errorf(`req.Form["both"] = %q, want ["y", "x"]`, both)
+ }
+ if prio := req.FormValue("prio"); prio != "2" {
+ t.Errorf(`req.FormValue("prio") = %q, want "2" (from body)`, prio)
+ }
+ if empty := req.FormValue("empty"); empty != "" {
+ t.Errorf(`req.FormValue("empty") = %q, want "" (from body)`, empty)
+ }
+}
+
type stringMap map[string][]string
type parseContentTypeTest struct {
shouldError bool
@@ -68,8 +100,9 @@ type parseContentTypeTest struct {
var parseContentTypeTests = []parseContentTypeTest{
{false, stringMap{"Content-Type": {"text/plain"}}},
- // Non-existent keys are not placed. The value nil is illegal.
- {true, stringMap{}},
+ // Empty content type is legal - shoult be treated as
+ // application/octet-stream (RFC 2616, section 7.2.1)
+ {false, stringMap{}},
{true, stringMap{"Content-Type": {"text/plain; boundary="}}},
{false, stringMap{"Content-Type": {"application/unknown"}}},
}
@@ -79,7 +112,7 @@ func TestParseFormUnknownContentType(t *testing.T) {
req := &Request{
Method: "POST",
Header: Header(test.contentType),
- Body: ioutil.NopCloser(bytes.NewBufferString("body")),
+ Body: ioutil.NopCloser(strings.NewReader("body")),
}
err := req.ParseForm()
switch {
@@ -122,7 +155,25 @@ func TestMultipartReader(t *testing.T) {
req.Header = Header{"Content-Type": {"text/plain"}}
multipart, err = req.MultipartReader()
if multipart != nil {
- t.Errorf("unexpected multipart for text/plain")
+ t.Error("unexpected multipart for text/plain")
+ }
+}
+
+func TestParseMultipartForm(t *testing.T) {
+ req := &Request{
+ Method: "POST",
+ Header: Header{"Content-Type": {`multipart/form-data; boundary="foo123"`}},
+ Body: ioutil.NopCloser(new(bytes.Buffer)),
+ }
+ err := req.ParseMultipartForm(25)
+ if err == nil {
+ t.Error("expected multipart EOF, got nil")
+ }
+
+ req.Header = Header{"Content-Type": {"text/plain"}}
+ err = req.ParseMultipartForm(25)
+ if err != ErrNotMultipart {
+ t.Error("expected ErrNotMultipart for text/plain")
}
}
@@ -188,25 +239,72 @@ func TestMultipartRequestAuto(t *testing.T) {
validateTestMultipartContents(t, req, true)
}
-func TestEmptyMultipartRequest(t *testing.T) {
- // Test that FormValue and FormFile automatically invoke
- // ParseMultipartForm and return the right values.
- req, err := NewRequest("GET", "/", nil)
- if err != nil {
- t.Errorf("NewRequest err = %q", err)
- }
+func TestMissingFileMultipartRequest(t *testing.T) {
+ // Test that FormFile returns an error if
+ // the named file is missing.
+ req := newTestMultipartRequest(t)
testMissingFile(t, req)
}
-func TestRequestMultipartCallOrder(t *testing.T) {
+// Test that FormValue invokes ParseMultipartForm.
+func TestFormValueCallsParseMultipartForm(t *testing.T) {
+ req, _ := NewRequest("POST", "http://www.google.com/", strings.NewReader("z=post"))
+ req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
+ if req.Form != nil {
+ t.Fatal("Unexpected request Form, want nil")
+ }
+ req.FormValue("z")
+ if req.Form == nil {
+ t.Fatal("ParseMultipartForm not called by FormValue")
+ }
+}
+
+// Test that FormFile invokes ParseMultipartForm.
+func TestFormFileCallsParseMultipartForm(t *testing.T) {
req := newTestMultipartRequest(t)
- _, err := req.MultipartReader()
- if err != nil {
+ if req.Form != nil {
+ t.Fatal("Unexpected request Form, want nil")
+ }
+ req.FormFile("")
+ if req.Form == nil {
+ t.Fatal("ParseMultipartForm not called by FormFile")
+ }
+}
+
+// Test that ParseMultipartForm errors if called
+// after MultipartReader on the same request.
+func TestParseMultipartFormOrder(t *testing.T) {
+ req := newTestMultipartRequest(t)
+ if _, err := req.MultipartReader(); err != nil {
t.Fatalf("MultipartReader: %v", err)
}
- err = req.ParseMultipartForm(1024)
- if err == nil {
- t.Errorf("expected an error from ParseMultipartForm after call to MultipartReader")
+ if err := req.ParseMultipartForm(1024); err == nil {
+ t.Fatal("expected an error from ParseMultipartForm after call to MultipartReader")
+ }
+}
+
+// Test that MultipartReader errors if called
+// after ParseMultipartForm on the same request.
+func TestMultipartReaderOrder(t *testing.T) {
+ req := newTestMultipartRequest(t)
+ if err := req.ParseMultipartForm(25); err != nil {
+ t.Fatalf("ParseMultipartForm: %v", err)
+ }
+ defer req.MultipartForm.RemoveAll()
+ if _, err := req.MultipartReader(); err == nil {
+ t.Fatal("expected an error from MultipartReader after call to ParseMultipartForm")
+ }
+}
+
+// Test that FormFile errors if called after
+// MultipartReader on the same request.
+func TestFormFileOrder(t *testing.T) {
+ req := newTestMultipartRequest(t)
+ if _, err := req.MultipartReader(); err != nil {
+ t.Fatalf("MultipartReader: %v", err)
+ }
+ if _, _, err := req.FormFile(""); err == nil {
+ t.Fatal("expected an error from FormFile after call to MultipartReader")
}
}
@@ -299,6 +397,75 @@ func TestParseHTTPVersion(t *testing.T) {
}
}
+type getBasicAuthTest struct {
+ username, password string
+ ok bool
+}
+
+type parseBasicAuthTest getBasicAuthTest
+
+type basicAuthCredentialsTest struct {
+ username, password string
+}
+
+var getBasicAuthTests = []struct {
+ username, password string
+ ok bool
+}{
+ {"Aladdin", "open sesame", true},
+ {"Aladdin", "open:sesame", true},
+ {"", "", true},
+}
+
+func TestGetBasicAuth(t *testing.T) {
+ for _, tt := range getBasicAuthTests {
+ r, _ := NewRequest("GET", "http://example.com/", nil)
+ r.SetBasicAuth(tt.username, tt.password)
+ username, password, ok := r.BasicAuth()
+ if ok != tt.ok || username != tt.username || password != tt.password {
+ t.Errorf("BasicAuth() = %#v, want %#v", getBasicAuthTest{username, password, ok},
+ getBasicAuthTest{tt.username, tt.password, tt.ok})
+ }
+ }
+ // Unauthenticated request.
+ r, _ := NewRequest("GET", "http://example.com/", nil)
+ username, password, ok := r.BasicAuth()
+ if ok {
+ t.Errorf("expected false from BasicAuth when the request is unauthenticated")
+ }
+ want := basicAuthCredentialsTest{"", ""}
+ if username != want.username || password != want.password {
+ t.Errorf("expected credentials: %#v when the request is unauthenticated, got %#v",
+ want, basicAuthCredentialsTest{username, password})
+ }
+}
+
+var parseBasicAuthTests = []struct {
+ header, username, password string
+ ok bool
+}{
+ {"Basic " + base64.StdEncoding.EncodeToString([]byte("Aladdin:open sesame")), "Aladdin", "open sesame", true},
+ {"Basic " + base64.StdEncoding.EncodeToString([]byte("Aladdin:open:sesame")), "Aladdin", "open:sesame", true},
+ {"Basic " + base64.StdEncoding.EncodeToString([]byte(":")), "", "", true},
+ {"Basic" + base64.StdEncoding.EncodeToString([]byte("Aladdin:open sesame")), "", "", false},
+ {base64.StdEncoding.EncodeToString([]byte("Aladdin:open sesame")), "", "", false},
+ {"Basic ", "", "", false},
+ {"Basic Aladdin:open sesame", "", "", false},
+ {`Digest username="Aladdin"`, "", "", false},
+}
+
+func TestParseBasicAuth(t *testing.T) {
+ for _, tt := range parseBasicAuthTests {
+ r, _ := NewRequest("GET", "http://example.com/", nil)
+ r.Header.Set("Authorization", tt.header)
+ username, password, ok := r.BasicAuth()
+ if ok != tt.ok || username != tt.username || password != tt.password {
+ t.Errorf("BasicAuth() = %#v, want %#v", getBasicAuthTest{username, password, ok},
+ getBasicAuthTest{tt.username, tt.password, tt.ok})
+ }
+ }
+}
+
type logWrites struct {
t *testing.T
dst *[]string
@@ -343,7 +510,7 @@ func testMissingFile(t *testing.T, req *Request) {
}
func newTestMultipartRequest(t *testing.T) *Request {
- b := bytes.NewBufferString(strings.Replace(message, "\n", "\r\n", -1))
+ b := strings.NewReader(strings.Replace(message, "\n", "\r\n", -1))
req, err := NewRequest("POST", "/", b)
if err != nil {
t.Fatal("NewRequest:", err)
diff --git a/libgo/go/net/http/requestwrite_test.go b/libgo/go/net/http/requestwrite_test.go
index b27b1f7ce3..7a6bd58786 100644
--- a/libgo/go/net/http/requestwrite_test.go
+++ b/libgo/go/net/http/requestwrite_test.go
@@ -280,7 +280,7 @@ var reqWriteTests = []reqWriteTest{
ContentLength: 10, // but we're going to send only 5 bytes
},
Body: []byte("12345"),
- WantError: errors.New("http: Request.ContentLength=10 with Body length 5"),
+ WantError: errors.New("http: ContentLength=10 with Body length 5"),
},
// Request with a ContentLength of 4 but an 8 byte body.
@@ -294,7 +294,7 @@ var reqWriteTests = []reqWriteTest{
ContentLength: 4, // but we're going to try to send 8 bytes
},
Body: []byte("12345678"),
- WantError: errors.New("http: Request.ContentLength=4 with Body length 8"),
+ WantError: errors.New("http: ContentLength=4 with Body length 8"),
},
// Request with a 5 ContentLength and nil body.
@@ -310,6 +310,46 @@ var reqWriteTests = []reqWriteTest{
WantError: errors.New("http: Request.ContentLength=5 with nil Body"),
},
+ // Request with a 0 ContentLength and a body with 1 byte content and an error.
+ {
+ Req: Request{
+ Method: "POST",
+ URL: mustParseURL("/"),
+ Host: "example.com",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ ContentLength: 0, // as if unset by user
+ },
+
+ Body: func() io.ReadCloser {
+ err := errors.New("Custom reader error")
+ errReader := &errorReader{err}
+ return ioutil.NopCloser(io.MultiReader(strings.NewReader("x"), errReader))
+ },
+
+ WantError: errors.New("Custom reader error"),
+ },
+
+ // Request with a 0 ContentLength and a body without content and an error.
+ {
+ Req: Request{
+ Method: "POST",
+ URL: mustParseURL("/"),
+ Host: "example.com",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ ContentLength: 0, // as if unset by user
+ },
+
+ Body: func() io.ReadCloser {
+ err := errors.New("Custom reader error")
+ errReader := &errorReader{err}
+ return ioutil.NopCloser(errReader)
+ },
+
+ WantError: errors.New("Custom reader error"),
+ },
+
// Verify that DumpRequest preserves the HTTP version number, doesn't add a Host,
// and doesn't add a User-Agent.
{
@@ -427,7 +467,7 @@ func TestRequestWrite(t *testing.T) {
}
switch b := tt.Body.(type) {
case []byte:
- tt.Req.Body = ioutil.NopCloser(bytes.NewBuffer(b))
+ tt.Req.Body = ioutil.NopCloser(bytes.NewReader(b))
case func() io.ReadCloser:
tt.Req.Body = b()
}
@@ -523,3 +563,61 @@ func mustParseURL(s string) *url.URL {
}
return u
}
+
+type writerFunc func([]byte) (int, error)
+
+func (f writerFunc) Write(p []byte) (int, error) { return f(p) }
+
+// TestRequestWriteError tests the Write err != nil checks in (*Request).write.
+func TestRequestWriteError(t *testing.T) {
+ failAfter, writeCount := 0, 0
+ errFail := errors.New("fake write failure")
+
+ // w is the buffered io.Writer to write the request to. It
+ // fails exactly once on its Nth Write call, as controlled by
+ // failAfter. It also tracks the number of calls in
+ // writeCount.
+ w := struct {
+ io.ByteWriter // to avoid being wrapped by a bufio.Writer
+ io.Writer
+ }{
+ nil,
+ writerFunc(func(p []byte) (n int, err error) {
+ writeCount++
+ if failAfter == 0 {
+ err = errFail
+ }
+ failAfter--
+ return len(p), err
+ }),
+ }
+
+ req, _ := NewRequest("GET", "http://example.com/", nil)
+ const writeCalls = 4 // number of Write calls in current implementation
+ sawGood := false
+ for n := 0; n <= writeCalls+2; n++ {
+ failAfter = n
+ writeCount = 0
+ err := req.Write(w)
+ var wantErr error
+ if n < writeCalls {
+ wantErr = errFail
+ }
+ if err != wantErr {
+ t.Errorf("for fail-after %d Writes, err = %v; want %v", n, err, wantErr)
+ continue
+ }
+ if err == nil {
+ sawGood = true
+ if writeCount != writeCalls {
+ t.Fatalf("writeCalls constant is outdated in test")
+ }
+ }
+ if writeCount > writeCalls || writeCount > n+1 {
+ t.Errorf("for fail-after %d, saw unexpectedly high (%d) write calls", n, writeCount)
+ }
+ }
+ if !sawGood {
+ t.Fatalf("writeCalls constant is outdated in test")
+ }
+}
diff --git a/libgo/go/net/http/response.go b/libgo/go/net/http/response.go
index 35d0ba3bb1..5d2c39080e 100644
--- a/libgo/go/net/http/response.go
+++ b/libgo/go/net/http/response.go
@@ -8,6 +8,8 @@ package http
import (
"bufio"
+ "bytes"
+ "crypto/tls"
"errors"
"io"
"net/textproto"
@@ -45,7 +47,8 @@ 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-lengthed body.
+ // a zero-length body. It is the caller's responsibility to
+ // close Body.
//
// The Body is automatically dechunked if the server replied
// with a "chunked" Transfer-Encoding.
@@ -74,6 +77,12 @@ type Response struct {
// Request's Body is nil (having already been consumed).
// This is only populated for Client requests.
Request *Request
+
+ // TLS contains information about the TLS connection on which the
+ // response was received. It is nil for unencrypted responses.
+ // The pointer is shared between responses and should not be
+ // modified.
+ TLS *tls.ConnectionState
}
// Cookies parses and returns the cookies set in the Set-Cookie headers.
@@ -141,6 +150,9 @@ func ReadResponse(r *bufio.Reader, req *Request) (*Response, error) {
// Parse the response headers.
mimeHeader, err := tp.ReadMIMEHeader()
if err != nil {
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
return nil, err
}
resp.Header = Header(mimeHeader)
@@ -187,8 +199,8 @@ 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.
func (r *Response) Write(w io.Writer) error {
-
// Status line
text := r.Status
if text == "" {
@@ -201,10 +213,45 @@ func (r *Response) Write(w io.Writer) error {
protoMajor, protoMinor := strconv.Itoa(r.ProtoMajor), strconv.Itoa(r.ProtoMinor)
statusCode := strconv.Itoa(r.StatusCode) + " "
text = strings.TrimPrefix(text, statusCode)
- io.WriteString(w, "HTTP/"+protoMajor+"."+protoMinor+" "+statusCode+text+"\r\n")
+ if _, err := io.WriteString(w, "HTTP/"+protoMajor+"."+protoMinor+" "+statusCode+text+"\r\n"); err != nil {
+ return err
+ }
+
+ // Clone it, so we can modify r1 as needed.
+ r1 := new(Response)
+ *r1 = *r
+ if r1.ContentLength == 0 && r1.Body != nil {
+ // Is it actually 0 length? Or just unknown?
+ var buf [1]byte
+ n, err := r1.Body.Read(buf[:])
+ if err != nil && err != io.EOF {
+ return err
+ }
+ if n == 0 {
+ // Reset it to a known zero reader, in case underlying one
+ // is unhappy being read repeatedly.
+ r1.Body = eofReader
+ } else {
+ r1.ContentLength = -1
+ r1.Body = struct {
+ io.Reader
+ io.Closer
+ }{
+ io.MultiReader(bytes.NewReader(buf[:1]), r.Body),
+ r.Body,
+ }
+ }
+ }
+ // If we're sending a non-chunked HTTP/1.1 response without a
+ // content-length, the only way to do that is the old HTTP/1.0
+ // way, by noting the EOF with a connection close, so we need
+ // to set Close.
+ if r1.ContentLength == -1 && !r1.Close && r1.ProtoAtLeast(1, 1) && !chunked(r1.TransferEncoding) {
+ r1.Close = true
+ }
// Process Body,ContentLength,Close,Trailer
- tw, err := newTransferWriter(r)
+ tw, err := newTransferWriter(r1)
if err != nil {
return err
}
@@ -219,8 +266,19 @@ func (r *Response) Write(w io.Writer) error {
return err
}
+ // contentLengthAlreadySent may have been already sent for
+ // POST/PUT requests, even if zero length. See Issue 8180.
+ contentLengthAlreadySent := tw.shouldSendContentLength()
+ if r1.ContentLength == 0 && !chunked(r1.TransferEncoding) && !contentLengthAlreadySent {
+ if _, err := io.WriteString(w, "Content-Length: 0\r\n"); err != nil {
+ return err
+ }
+ }
+
// End-of-header
- io.WriteString(w, "\r\n")
+ if _, err := io.WriteString(w, "\r\n"); err != nil {
+ return err
+ }
// Write body and trailer
err = tw.WriteBody(w)
diff --git a/libgo/go/net/http/response_test.go b/libgo/go/net/http/response_test.go
index 5044306a87..06e940d9ab 100644
--- a/libgo/go/net/http/response_test.go
+++ b/libgo/go/net/http/response_test.go
@@ -12,8 +12,10 @@ import (
"fmt"
"io"
"io/ioutil"
+ "net/http/internal"
"net/url"
"reflect"
+ "regexp"
"strings"
"testing"
)
@@ -28,6 +30,10 @@ func dummyReq(method string) *Request {
return &Request{Method: method}
}
+func dummyReq11(method string) *Request {
+ return &Request{Method: method, Proto: "HTTP/1.1", ProtoMajor: 1, ProtoMinor: 1}
+}
+
var respTests = []respTest{
// Unchunked response without Content-Length.
{
@@ -371,6 +377,34 @@ some body`,
"Body here\n",
},
+
+ // 206 Partial Content. golang.org/issue/8923
+ {
+ "HTTP/1.1 206 Partial Content\r\n" +
+ "Content-Type: text/plain; charset=utf-8\r\n" +
+ "Accept-Ranges: bytes\r\n" +
+ "Content-Range: bytes 0-5/1862\r\n" +
+ "Content-Length: 6\r\n\r\n" +
+ "foobar",
+
+ Response{
+ Status: "206 Partial Content",
+ StatusCode: 206,
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Request: dummyReq("GET"),
+ Header: Header{
+ "Accept-Ranges": []string{"bytes"},
+ "Content-Length": []string{"6"},
+ "Content-Type": []string{"text/plain; charset=utf-8"},
+ "Content-Range": []string{"bytes 0-5/1862"},
+ },
+ ContentLength: 6,
+ },
+
+ "foobar",
+ },
}
func TestReadResponse(t *testing.T) {
@@ -406,8 +440,7 @@ func TestWriteResponse(t *testing.T) {
t.Errorf("#%d: %v", i, err)
continue
}
- bout := bytes.NewBuffer(nil)
- err = resp.Write(bout)
+ err = resp.Write(ioutil.Discard)
if err != nil {
t.Errorf("#%d: %v", i, err)
continue
@@ -447,7 +480,7 @@ func TestReadResponseCloseInMiddle(t *testing.T) {
}
var wr io.Writer = &buf
if test.chunked {
- wr = newChunkedWriter(wr)
+ wr = internal.NewChunkedWriter(wr)
}
if test.compressed {
buf.WriteString("Content-Encoding: gzip\r\n")
@@ -506,6 +539,9 @@ func TestReadResponseCloseInMiddle(t *testing.T) {
rest, err := ioutil.ReadAll(bufr)
checkErr(err, "ReadAll on remainder")
if e, g := "Next Request Here", string(rest); e != g {
+ g = regexp.MustCompile(`(xx+)`).ReplaceAllStringFunc(g, func(match string) string {
+ return fmt.Sprintf("x(repeated x%d)", len(match))
+ })
fatalf("remainder = %q, expected %q", g, e)
}
}
@@ -615,6 +651,15 @@ func TestResponseContentLengthShortBody(t *testing.T) {
}
}
+func TestReadResponseUnexpectedEOF(t *testing.T) {
+ br := bufio.NewReader(strings.NewReader("HTTP/1.1 301 Moved Permanently\r\n" +
+ "Location: http://example.com"))
+ _, err := ReadResponse(br, nil)
+ if err != io.ErrUnexpectedEOF {
+ t.Errorf("ReadResponse = %v; want io.ErrUnexpectedEOF", err)
+ }
+}
+
func TestNeedsSniff(t *testing.T) {
// needsSniff returns true with an empty response.
r := &response{}
diff --git a/libgo/go/net/http/responsewrite_test.go b/libgo/go/net/http/responsewrite_test.go
index 5c10e2161c..585b13b850 100644
--- a/libgo/go/net/http/responsewrite_test.go
+++ b/libgo/go/net/http/responsewrite_test.go
@@ -7,6 +7,7 @@ package http
import (
"bytes"
"io/ioutil"
+ "strings"
"testing"
)
@@ -25,7 +26,7 @@ func TestResponseWrite(t *testing.T) {
ProtoMinor: 0,
Request: dummyReq("GET"),
Header: Header{},
- Body: ioutil.NopCloser(bytes.NewBufferString("abcdef")),
+ Body: ioutil.NopCloser(strings.NewReader("abcdef")),
ContentLength: 6,
},
@@ -41,13 +42,113 @@ func TestResponseWrite(t *testing.T) {
ProtoMinor: 0,
Request: dummyReq("GET"),
Header: Header{},
- Body: ioutil.NopCloser(bytes.NewBufferString("abcdef")),
+ Body: ioutil.NopCloser(strings.NewReader("abcdef")),
ContentLength: -1,
},
"HTTP/1.0 200 OK\r\n" +
"\r\n" +
"abcdef",
},
+ // HTTP/1.1 response with unknown length and Connection: close
+ {
+ Response{
+ StatusCode: 200,
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Request: dummyReq("GET"),
+ Header: Header{},
+ Body: ioutil.NopCloser(strings.NewReader("abcdef")),
+ ContentLength: -1,
+ Close: true,
+ },
+ "HTTP/1.1 200 OK\r\n" +
+ "Connection: close\r\n" +
+ "\r\n" +
+ "abcdef",
+ },
+ // HTTP/1.1 response with unknown length and not setting connection: close
+ {
+ Response{
+ StatusCode: 200,
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Request: dummyReq11("GET"),
+ Header: Header{},
+ Body: ioutil.NopCloser(strings.NewReader("abcdef")),
+ ContentLength: -1,
+ Close: false,
+ },
+ "HTTP/1.1 200 OK\r\n" +
+ "Connection: close\r\n" +
+ "\r\n" +
+ "abcdef",
+ },
+ // HTTP/1.1 response with unknown length and not setting connection: close, but
+ // setting chunked.
+ {
+ Response{
+ StatusCode: 200,
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Request: dummyReq11("GET"),
+ Header: Header{},
+ Body: ioutil.NopCloser(strings.NewReader("abcdef")),
+ ContentLength: -1,
+ TransferEncoding: []string{"chunked"},
+ Close: false,
+ },
+ "HTTP/1.1 200 OK\r\n" +
+ "Transfer-Encoding: chunked\r\n\r\n" +
+ "6\r\nabcdef\r\n0\r\n\r\n",
+ },
+ // HTTP/1.1 response 0 content-length, and nil body
+ {
+ Response{
+ StatusCode: 200,
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Request: dummyReq11("GET"),
+ Header: Header{},
+ Body: nil,
+ ContentLength: 0,
+ Close: false,
+ },
+ "HTTP/1.1 200 OK\r\n" +
+ "Content-Length: 0\r\n" +
+ "\r\n",
+ },
+ // HTTP/1.1 response 0 content-length, and non-nil empty body
+ {
+ Response{
+ StatusCode: 200,
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Request: dummyReq11("GET"),
+ Header: Header{},
+ Body: ioutil.NopCloser(strings.NewReader("")),
+ ContentLength: 0,
+ Close: false,
+ },
+ "HTTP/1.1 200 OK\r\n" +
+ "Content-Length: 0\r\n" +
+ "\r\n",
+ },
+ // HTTP/1.1 response 0 content-length, and non-nil non-empty body
+ {
+ Response{
+ StatusCode: 200,
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Request: dummyReq11("GET"),
+ Header: Header{},
+ Body: ioutil.NopCloser(strings.NewReader("foo")),
+ ContentLength: 0,
+ Close: false,
+ },
+ "HTTP/1.1 200 OK\r\n" +
+ "Connection: close\r\n" +
+ "\r\nfoo",
+ },
// HTTP/1.1, chunked coding; empty trailer; close
{
Response{
@@ -56,7 +157,7 @@ func TestResponseWrite(t *testing.T) {
ProtoMinor: 1,
Request: dummyReq("GET"),
Header: Header{},
- Body: ioutil.NopCloser(bytes.NewBufferString("abcdef")),
+ Body: ioutil.NopCloser(strings.NewReader("abcdef")),
ContentLength: 6,
TransferEncoding: []string{"chunked"},
Close: true,
@@ -90,6 +191,22 @@ func TestResponseWrite(t *testing.T) {
"Foo: Bar Baz\r\n" +
"\r\n",
},
+
+ // Want a single Content-Length header. Fixing issue 8180 where
+ // there were two.
+ {
+ Response{
+ StatusCode: StatusOK,
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Request: &Request{Method: "POST"},
+ Header: Header{},
+ ContentLength: 0,
+ TransferEncoding: nil,
+ Body: nil,
+ },
+ "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
+ },
}
for i := range respWriteTests {
diff --git a/libgo/go/net/http/serve_test.go b/libgo/go/net/http/serve_test.go
index 8961cf491f..6bd168d3de 100644
--- a/libgo/go/net/http/serve_test.go
+++ b/libgo/go/net/http/serve_test.go
@@ -15,6 +15,7 @@ import (
"io"
"io/ioutil"
"log"
+ "math/rand"
"net"
. "net/http"
"net/http/httptest"
@@ -419,7 +420,7 @@ func TestServeMuxHandlerRedirects(t *testing.T) {
func TestMuxRedirectLeadingSlashes(t *testing.T) {
paths := []string{"//foo.txt", "///foo.txt", "/../../foo.txt"}
for _, path := range paths {
- req, err := ReadRequest(bufio.NewReader(bytes.NewBufferString("GET " + path + " HTTP/1.1\r\nHost: test\r\n\r\n")))
+ req, err := ReadRequest(bufio.NewReader(strings.NewReader("GET " + path + " HTTP/1.1\r\nHost: test\r\n\r\n")))
if err != nil {
t.Errorf("%s", err)
}
@@ -441,6 +442,9 @@ func TestMuxRedirectLeadingSlashes(t *testing.T) {
}
func TestServerTimeouts(t *testing.T) {
+ if runtime.GOOS == "plan9" {
+ t.Skip("skipping test; see http://golang.org/issue/7237")
+ }
defer afterTest(t)
reqNum := 0
ts := httptest.NewUnstartedServer(HandlerFunc(func(res ResponseWriter, req *Request) {
@@ -517,6 +521,9 @@ func TestServerTimeouts(t *testing.T) {
// shouldn't cause a handler to block forever on reads (next HTTP
// request) that will never happen.
func TestOnlyWriteTimeout(t *testing.T) {
+ if runtime.GOOS == "plan9" {
+ t.Skip("skipping test; see http://golang.org/issue/7237")
+ }
defer afterTest(t)
var conn net.Conn
var afterTimeoutErrc = make(chan error, 1)
@@ -771,6 +778,35 @@ func TestChunkedResponseHeaders(t *testing.T) {
}
}
+func TestIdentityResponseHeaders(t *testing.T) {
+ defer afterTest(t)
+ log.SetOutput(ioutil.Discard) // is noisy otherwise
+ defer log.SetOutput(os.Stderr)
+
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header().Set("Transfer-Encoding", "identity")
+ w.(Flusher).Flush()
+ fmt.Fprintf(w, "I am an identity response.")
+ }))
+ defer ts.Close()
+
+ res, err := Get(ts.URL)
+ if err != nil {
+ t.Fatalf("Get error: %v", err)
+ }
+ defer res.Body.Close()
+
+ if g, e := res.TransferEncoding, []string(nil); !reflect.DeepEqual(g, e) {
+ t.Errorf("expected TransferEncoding of %v; got %v", e, g)
+ }
+ if _, haveCL := res.Header["Content-Length"]; haveCL {
+ t.Errorf("Unexpected Content-Length")
+ }
+ if !res.Close {
+ t.Errorf("expected Connection: close; got %v", res.Close)
+ }
+}
+
// Test304Responses verifies that 304s don't declare that they're
// chunking in their response headers and aren't allowed to produce
// output.
@@ -840,9 +876,14 @@ func TestHeadResponses(t *testing.T) {
}
func TestTLSHandshakeTimeout(t *testing.T) {
+ if runtime.GOOS == "plan9" {
+ t.Skip("skipping test; see http://golang.org/issue/7237")
+ }
defer afterTest(t)
ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
+ errc := make(chanWriter, 10) // but only expecting 1
ts.Config.ReadTimeout = 250 * time.Millisecond
+ ts.Config.ErrorLog = log.New(errc, "", 0)
ts.StartTLS()
defer ts.Close()
conn, err := net.Dial("tcp", ts.Listener.Addr().String())
@@ -857,6 +898,14 @@ func TestTLSHandshakeTimeout(t *testing.T) {
t.Errorf("Read = %d, %v; want an error and no bytes", n, err)
}
})
+ select {
+ case v := <-errc:
+ if !strings.Contains(v, "timeout") && !strings.Contains(v, "TLS handshake") {
+ t.Errorf("expected a TLS handshake timeout error; got %q", v)
+ }
+ case <-time.After(5 * time.Second):
+ t.Errorf("timeout waiting for logged error")
+ }
}
func TestTLSServer(t *testing.T) {
@@ -869,6 +918,7 @@ func TestTLSServer(t *testing.T) {
}
}
}))
+ ts.Config.ErrorLog = log.New(ioutil.Discard, "", 0)
defer ts.Close()
// Connect an idle TCP connection to this server before we run
@@ -913,31 +963,50 @@ func TestTLSServer(t *testing.T) {
}
type serverExpectTest struct {
- contentLength int // of request body
+ contentLength int // of request body
+ chunked bool
expectation string // e.g. "100-continue"
readBody bool // whether handler should read the body (if false, sends StatusUnauthorized)
expectedResponse string // expected substring in first line of http response
}
+func expectTest(contentLength int, expectation string, readBody bool, expectedResponse string) serverExpectTest {
+ return serverExpectTest{
+ contentLength: contentLength,
+ expectation: expectation,
+ readBody: readBody,
+ expectedResponse: expectedResponse,
+ }
+}
+
var serverExpectTests = []serverExpectTest{
// Normal 100-continues, case-insensitive.
- {100, "100-continue", true, "100 Continue"},
- {100, "100-cOntInUE", true, "100 Continue"},
+ expectTest(100, "100-continue", true, "100 Continue"),
+ expectTest(100, "100-cOntInUE", true, "100 Continue"),
// No 100-continue.
- {100, "", true, "200 OK"},
+ expectTest(100, "", true, "200 OK"),
// 100-continue but requesting client to deny us,
// so it never reads the body.
- {100, "100-continue", false, "401 Unauthorized"},
+ expectTest(100, "100-continue", false, "401 Unauthorized"),
// Likewise without 100-continue:
- {100, "", false, "401 Unauthorized"},
+ expectTest(100, "", false, "401 Unauthorized"),
// Non-standard expectations are failures
- {0, "a-pony", false, "417 Expectation Failed"},
+ expectTest(0, "a-pony", false, "417 Expectation Failed"),
- // Expect-100 requested but no body
- {0, "100-continue", true, "400 Bad Request"},
+ // Expect-100 requested but no body (is apparently okay: Issue 7625)
+ expectTest(0, "100-continue", true, "200 OK"),
+ // Expect-100 requested but handler doesn't read the body
+ expectTest(0, "100-continue", false, "401 Unauthorized"),
+ // Expect-100 continue with no body, but a chunked body.
+ {
+ expectation: "100-continue",
+ readBody: true,
+ chunked: true,
+ expectedResponse: "100 Continue",
+ },
}
// Tests that the server responds to the "Expect" request header
@@ -966,21 +1035,38 @@ func TestServerExpect(t *testing.T) {
// Only send the body immediately if we're acting like an HTTP client
// that doesn't send 100-continue expectations.
- writeBody := test.contentLength > 0 && strings.ToLower(test.expectation) != "100-continue"
+ writeBody := test.contentLength != 0 && strings.ToLower(test.expectation) != "100-continue"
go func() {
+ contentLen := fmt.Sprintf("Content-Length: %d", test.contentLength)
+ if test.chunked {
+ contentLen = "Transfer-Encoding: chunked"
+ }
_, err := fmt.Fprintf(conn, "POST /?readbody=%v HTTP/1.1\r\n"+
"Connection: close\r\n"+
- "Content-Length: %d\r\n"+
+ "%s\r\n"+
"Expect: %s\r\nHost: foo\r\n\r\n",
- test.readBody, test.contentLength, test.expectation)
+ test.readBody, contentLen, test.expectation)
if err != nil {
t.Errorf("On test %#v, error writing request headers: %v", test, err)
return
}
if writeBody {
+ var targ io.WriteCloser = struct {
+ io.Writer
+ io.Closer
+ }{
+ conn,
+ ioutil.NopCloser(nil),
+ }
+ if test.chunked {
+ targ = httputil.NewChunkedWriter(conn)
+ }
body := strings.Repeat("A", test.contentLength)
- _, err = fmt.Fprint(conn, body)
+ _, err = fmt.Fprint(targ, body)
+ if err == nil {
+ err = targ.Close()
+ }
if err != nil {
if !test.readBody {
// Server likely already hung up on us.
@@ -1132,6 +1218,82 @@ func TestTimeoutHandler(t *testing.T) {
}
}
+// See issues 8209 and 8414.
+func TestTimeoutHandlerRace(t *testing.T) {
+ defer afterTest(t)
+
+ delayHi := HandlerFunc(func(w ResponseWriter, r *Request) {
+ ms, _ := strconv.Atoi(r.URL.Path[1:])
+ if ms == 0 {
+ ms = 1
+ }
+ for i := 0; i < ms; i++ {
+ w.Write([]byte("hi"))
+ time.Sleep(time.Millisecond)
+ }
+ })
+
+ ts := httptest.NewServer(TimeoutHandler(delayHi, 20*time.Millisecond, ""))
+ defer ts.Close()
+
+ var wg sync.WaitGroup
+ gate := make(chan bool, 10)
+ n := 50
+ if testing.Short() {
+ n = 10
+ gate = make(chan bool, 3)
+ }
+ for i := 0; i < n; i++ {
+ gate <- true
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ defer func() { <-gate }()
+ res, err := Get(fmt.Sprintf("%s/%d", ts.URL, rand.Intn(50)))
+ if err == nil {
+ io.Copy(ioutil.Discard, res.Body)
+ res.Body.Close()
+ }
+ }()
+ }
+ wg.Wait()
+}
+
+// See issues 8209 and 8414.
+func TestTimeoutHandlerRaceHeader(t *testing.T) {
+ defer afterTest(t)
+
+ delay204 := HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.WriteHeader(204)
+ })
+
+ ts := httptest.NewServer(TimeoutHandler(delay204, time.Nanosecond, ""))
+ defer ts.Close()
+
+ var wg sync.WaitGroup
+ gate := make(chan bool, 50)
+ n := 500
+ if testing.Short() {
+ n = 10
+ }
+ for i := 0; i < n; i++ {
+ gate <- true
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ defer func() { <-gate }()
+ res, err := Get(ts.URL)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ defer res.Body.Close()
+ io.Copy(ioutil.Discard, res.Body)
+ }()
+ }
+ wg.Wait()
+}
+
// Verifies we don't path.Clean() on the wrong parts in redirects.
func TestRedirectMunging(t *testing.T) {
req, _ := NewRequest("GET", "http://example.com/", nil)
@@ -1414,6 +1576,9 @@ func TestRequestBodyLimit(t *testing.T) {
// TestClientWriteShutdown tests that if the client shuts down the write
// 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")
+ }
defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
defer ts.Close()
@@ -1934,6 +2099,31 @@ func TestWriteAfterHijack(t *testing.T) {
}
}
+func TestDoubleHijack(t *testing.T) {
+ req := reqBytes("GET / HTTP/1.1\nHost: golang.org")
+ var buf bytes.Buffer
+ conn := &rwTestConn{
+ Reader: bytes.NewReader(req),
+ Writer: &buf,
+ closec: make(chan bool, 1),
+ }
+ handler := HandlerFunc(func(rw ResponseWriter, r *Request) {
+ conn, _, err := rw.(Hijacker).Hijack()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ _, _, err = rw.(Hijacker).Hijack()
+ if err == nil {
+ t.Errorf("got err = nil; want err != nil")
+ }
+ conn.Close()
+ })
+ ln := &oneConnListener{conn: conn}
+ go Serve(ln, handler)
+ <-conn.closec
+}
+
// http://code.google.com/p/go/issues/detail?id=5955
// Note that this does not test the "request too large"
// exit path from the http server. This is intentional;
@@ -2037,31 +2227,160 @@ func TestServerReaderFromOrder(t *testing.T) {
}
}
-// Issue 6157
-func TestNoContentTypeOnNotModified(t *testing.T) {
+// Issue 6157, Issue 6685
+func TestCodesPreventingContentTypeAndBody(t *testing.T) {
+ for _, code := range []int{StatusNotModified, StatusNoContent, StatusContinue} {
+ ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) {
+ if r.URL.Path == "/header" {
+ w.Header().Set("Content-Length", "123")
+ }
+ w.WriteHeader(code)
+ if r.URL.Path == "/more" {
+ w.Write([]byte("stuff"))
+ }
+ }))
+ for _, req := range []string{
+ "GET / HTTP/1.0",
+ "GET /header HTTP/1.0",
+ "GET /more HTTP/1.0",
+ "GET / HTTP/1.1",
+ "GET /header HTTP/1.1",
+ "GET /more HTTP/1.1",
+ } {
+ got := ht.rawResponse(req)
+ wantStatus := fmt.Sprintf("%d %s", code, StatusText(code))
+ if !strings.Contains(got, wantStatus) {
+ t.Errorf("Code %d: Wanted %q Modified for %q: %s", code, wantStatus, req, got)
+ } else if strings.Contains(got, "Content-Length") {
+ t.Errorf("Code %d: Got a Content-Length from %q: %s", code, req, got)
+ } else if strings.Contains(got, "stuff") {
+ t.Errorf("Code %d: Response contains a body from %q: %s", code, req, got)
+ }
+ }
+ }
+}
+
+func TestContentTypeOkayOn204(t *testing.T) {
ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) {
- if r.URL.Path == "/header" {
- w.Header().Set("Content-Length", "123")
+ w.Header().Set("Content-Length", "123") // suppressed
+ w.Header().Set("Content-Type", "foo/bar")
+ w.WriteHeader(204)
+ }))
+ got := ht.rawResponse("GET / HTTP/1.1")
+ if !strings.Contains(got, "Content-Type: foo/bar") {
+ t.Errorf("Response = %q; want Content-Type: foo/bar", got)
+ }
+ if strings.Contains(got, "Content-Length: 123") {
+ t.Errorf("Response = %q; don't want a Content-Length", got)
+ }
+}
+
+// Issue 6995
+// A server Handler can receive a Request, and then turn around and
+// give a copy of that Request.Body out to the Transport (e.g. any
+// proxy). So then two people own that Request.Body (both the server
+// and the http client), and both think they can close it on failure.
+// Therefore, all incoming server requests Bodies need to be thread-safe.
+func TestTransportAndServerSharedBodyRace(t *testing.T) {
+ defer afterTest(t)
+
+ const bodySize = 1 << 20
+
+ unblockBackend := make(chan bool)
+ backend := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
+ io.CopyN(rw, req.Body, bodySize/2)
+ <-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
}
- w.WriteHeader(StatusNotModified)
- if r.URL.Path == "/more" {
- w.Write([]byte("stuff"))
+ req2, _ := NewRequest("POST", backend.URL, req.Body)
+ req2.ContentLength = bodySize
+
+ bresp, err := DefaultClient.Do(req2)
+ if err != nil {
+ t.Errorf("Proxy outbound request: %v", err)
+ return
+ }
+ _, err = io.CopyN(ioutil.Discard, bresp.Body, bodySize/4)
+ if err != nil {
+ t.Errorf("Proxy copy error: %v", err)
+ return
}
+ backendRespc <- bresp // to close later
+
+ // Try to cause a race: Both the DefaultTransport and the proxy handler's Server
+ // will try to read/close req.Body (aka req2.Body)
+ DefaultTransport.(*Transport).CancelRequest(req2)
+ rw.Write([]byte("OK"))
}))
- for _, req := range []string{
- "GET / HTTP/1.0",
- "GET /header HTTP/1.0",
- "GET /more HTTP/1.0",
- "GET / HTTP/1.1",
- "GET /header HTTP/1.1",
- "GET /more HTTP/1.1",
- } {
- got := ht.rawResponse(req)
- if !strings.Contains(got, "304 Not Modified") {
- t.Errorf("Non-304 Not Modified for %q: %s", req, got)
- } else if strings.Contains(got, "Content-Length") {
- t.Errorf("Got a Content-Length from %q: %s", req, got)
+ defer proxy.Close()
+
+ req, _ := NewRequest("POST", proxy.URL, io.LimitReader(neverEnding('a'), bodySize))
+ res, err := DefaultClient.Do(req)
+ if err != nil {
+ t.Fatalf("Original request: %v", err)
+ }
+
+ // Cleanup, so we don't leak goroutines.
+ res.Body.Close()
+ close(unblockBackend)
+ (<-backendRespc).Body.Close()
+}
+
+// Test that a hanging Request.Body.Read from another goroutine can't
+// cause the Handler goroutine's Request.Body.Close to block.
+func TestRequestBodyCloseDoesntBlock(t *testing.T) {
+ t.Skipf("Skipping known issue; see golang.org/issue/7121")
+ if testing.Short() {
+ t.Skip("skipping in -short mode")
+ }
+ defer afterTest(t)
+
+ readErrCh := make(chan error, 1)
+ errCh := make(chan error, 2)
+
+ server := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
+ go func(body io.Reader) {
+ _, err := body.Read(make([]byte, 100))
+ readErrCh <- err
+ }(req.Body)
+ time.Sleep(500 * time.Millisecond)
+ }))
+ defer server.Close()
+
+ closeConn := make(chan bool)
+ defer close(closeConn)
+ go func() {
+ conn, err := net.Dial("tcp", server.Listener.Addr().String())
+ if err != nil {
+ errCh <- err
+ return
+ }
+ defer conn.Close()
+ _, err = conn.Write([]byte("POST / HTTP/1.1\r\nConnection: close\r\nHost: foo\r\nContent-Length: 100000\r\n\r\n"))
+ if err != nil {
+ errCh <- err
+ return
+ }
+ // And now just block, making the server block on our
+ // 100000 bytes of body that will never arrive.
+ <-closeConn
+ }()
+ select {
+ case err := <-readErrCh:
+ if err == nil {
+ t.Error("Read was nil. Expected error.")
}
+ case err := <-errCh:
+ t.Error(err)
+ case <-time.After(5 * time.Second):
+ t.Error("timeout")
}
}
@@ -2074,8 +2393,8 @@ func TestResponseWriterWriteStringAllocs(t *testing.T) {
w.Write([]byte("Hello world"))
}
}))
- before := testing.AllocsPerRun(25, func() { ht.rawResponse("GET / HTTP/1.0") })
- after := testing.AllocsPerRun(25, func() { ht.rawResponse("GET /s HTTP/1.0") })
+ 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)
}
@@ -2094,6 +2413,350 @@ func TestAppendTime(t *testing.T) {
}
}
+func TestServerConnState(t *testing.T) {
+ defer afterTest(t)
+ handler := map[string]func(w ResponseWriter, r *Request){
+ "/": func(w ResponseWriter, r *Request) {
+ fmt.Fprintf(w, "Hello.")
+ },
+ "/close": func(w ResponseWriter, r *Request) {
+ w.Header().Set("Connection", "close")
+ fmt.Fprintf(w, "Hello.")
+ },
+ "/hijack": func(w ResponseWriter, r *Request) {
+ c, _, _ := w.(Hijacker).Hijack()
+ c.Write([]byte("HTTP/1.0 200 OK\r\nConnection: close\r\n\r\nHello."))
+ c.Close()
+ },
+ "/hijack-panic": func(w ResponseWriter, r *Request) {
+ c, _, _ := w.(Hijacker).Hijack()
+ c.Write([]byte("HTTP/1.0 200 OK\r\nConnection: close\r\n\r\nHello."))
+ c.Close()
+ panic("intentional panic")
+ },
+ }
+ ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ handler[r.URL.Path](w, r)
+ }))
+ defer ts.Close()
+
+ var mu sync.Mutex // guard stateLog and connID
+ var stateLog = map[int][]ConnState{}
+ var connID = map[net.Conn]int{}
+
+ ts.Config.ErrorLog = log.New(ioutil.Discard, "", 0)
+ ts.Config.ConnState = func(c net.Conn, state ConnState) {
+ if c == nil {
+ t.Errorf("nil conn seen in state %s", state)
+ return
+ }
+ mu.Lock()
+ defer mu.Unlock()
+ id, ok := connID[c]
+ if !ok {
+ id = len(connID) + 1
+ connID[c] = id
+ }
+ stateLog[id] = append(stateLog[id], state)
+ }
+ ts.Start()
+
+ mustGet(t, ts.URL+"/")
+ mustGet(t, ts.URL+"/close")
+
+ mustGet(t, ts.URL+"/")
+ mustGet(t, ts.URL+"/", "Connection", "close")
+
+ mustGet(t, ts.URL+"/hijack")
+ mustGet(t, ts.URL+"/hijack-panic")
+
+ // New->Closed
+ {
+ c, err := net.Dial("tcp", ts.Listener.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ c.Close()
+ }
+
+ // New->Active->Closed
+ {
+ c, err := net.Dial("tcp", ts.Listener.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ if _, err := io.WriteString(c, "BOGUS REQUEST\r\n\r\n"); err != nil {
+ t.Fatal(err)
+ }
+ c.Close()
+ }
+
+ // New->Idle->Closed
+ {
+ c, err := net.Dial("tcp", ts.Listener.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ if _, err := io.WriteString(c, "GET / HTTP/1.1\r\nHost: foo\r\n\r\n"); err != nil {
+ t.Fatal(err)
+ }
+ res, err := ReadResponse(bufio.NewReader(c), nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if _, err := io.Copy(ioutil.Discard, res.Body); err != nil {
+ t.Fatal(err)
+ }
+ c.Close()
+ }
+
+ want := map[int][]ConnState{
+ 1: {StateNew, StateActive, StateIdle, StateActive, StateClosed},
+ 2: {StateNew, StateActive, StateIdle, StateActive, StateClosed},
+ 3: {StateNew, StateActive, StateHijacked},
+ 4: {StateNew, StateActive, StateHijacked},
+ 5: {StateNew, StateClosed},
+ 6: {StateNew, StateActive, StateClosed},
+ 7: {StateNew, StateActive, StateIdle, StateClosed},
+ }
+ logString := func(m map[int][]ConnState) string {
+ var b bytes.Buffer
+ for id, l := range m {
+ fmt.Fprintf(&b, "Conn %d: ", id)
+ for _, s := range l {
+ fmt.Fprintf(&b, "%s ", s)
+ }
+ b.WriteString("\n")
+ }
+ return b.String()
+ }
+
+ for i := 0; i < 5; i++ {
+ time.Sleep(time.Duration(i) * 50 * time.Millisecond)
+ mu.Lock()
+ match := reflect.DeepEqual(stateLog, want)
+ mu.Unlock()
+ if match {
+ return
+ }
+ }
+
+ mu.Lock()
+ t.Errorf("Unexpected events.\nGot log: %s\n Want: %s\n", logString(stateLog), logString(want))
+ mu.Unlock()
+}
+
+func mustGet(t *testing.T, url string, headers ...string) {
+ req, err := NewRequest("GET", url, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for len(headers) > 0 {
+ req.Header.Add(headers[0], headers[1])
+ headers = headers[2:]
+ }
+ res, err := DefaultClient.Do(req)
+ if err != nil {
+ t.Errorf("Error fetching %s: %v", url, err)
+ return
+ }
+ _, err = ioutil.ReadAll(res.Body)
+ defer res.Body.Close()
+ if err != nil {
+ t.Errorf("Error reading %s: %v", url, err)
+ }
+}
+
+func TestServerKeepAlivesEnabled(t *testing.T) {
+ defer afterTest(t)
+ ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
+ ts.Config.SetKeepAlivesEnabled(false)
+ ts.Start()
+ defer ts.Close()
+ res, err := Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+ if !res.Close {
+ t.Errorf("Body.Close == false; want true")
+ }
+}
+
+// golang.org/issue/7856
+func TestServerEmptyBodyRace(t *testing.T) {
+ defer afterTest(t)
+ var n int32
+ ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
+ atomic.AddInt32(&n, 1)
+ }))
+ defer ts.Close()
+ var wg sync.WaitGroup
+ const reqs = 20
+ for i := 0; i < reqs; i++ {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ res, err := Get(ts.URL)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ defer res.Body.Close()
+ _, err = io.Copy(ioutil.Discard, res.Body)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ }()
+ }
+ wg.Wait()
+ if got := atomic.LoadInt32(&n); got != reqs {
+ t.Errorf("handler ran %d times; want %d", got, reqs)
+ }
+}
+
+func TestServerConnStateNew(t *testing.T) {
+ sawNew := false // if the test is buggy, we'll race on this variable.
+ srv := &Server{
+ ConnState: func(c net.Conn, state ConnState) {
+ if state == StateNew {
+ sawNew = true // testing that this write isn't racy
+ }
+ },
+ Handler: HandlerFunc(func(w ResponseWriter, r *Request) {}), // irrelevant
+ }
+ srv.Serve(&oneConnListener{
+ conn: &rwTestConn{
+ Reader: strings.NewReader("GET / HTTP/1.1\r\nHost: foo\r\n\r\n"),
+ Writer: ioutil.Discard,
+ },
+ })
+ if !sawNew { // testing that this read isn't racy
+ t.Error("StateNew not seen")
+ }
+}
+
+type closeWriteTestConn struct {
+ rwTestConn
+ didCloseWrite bool
+}
+
+func (c *closeWriteTestConn) CloseWrite() error {
+ c.didCloseWrite = true
+ return nil
+}
+
+func TestCloseWrite(t *testing.T) {
+ var srv Server
+ var testConn closeWriteTestConn
+ c, err := ExportServerNewConn(&srv, &testConn)
+ if err != nil {
+ t.Fatal(err)
+ }
+ ExportCloseWriteAndWait(c)
+ if !testConn.didCloseWrite {
+ t.Error("didn't see CloseWrite call")
+ }
+}
+
+// This verifies that a handler can Flush and then Hijack.
+//
+// An similar test crashed once during development, but it was only
+// testing this tangentially and temporarily until another TODO was
+// fixed.
+//
+// So add an explicit test for this.
+func TestServerFlushAndHijack(t *testing.T) {
+ defer afterTest(t)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ io.WriteString(w, "Hello, ")
+ w.(Flusher).Flush()
+ conn, buf, _ := w.(Hijacker).Hijack()
+ buf.WriteString("6\r\nworld!\r\n0\r\n\r\n")
+ if err := buf.Flush(); err != nil {
+ t.Error(err)
+ }
+ if err := conn.Close(); err != nil {
+ t.Error(err)
+ }
+ }))
+ defer ts.Close()
+ res, err := Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+ all, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if want := "Hello, world!"; string(all) != want {
+ t.Errorf("Got %q; want %q", all, want)
+ }
+}
+
+// golang.org/issue/8534 -- the Server shouldn't reuse a connection
+// for keep-alive after it's seen any Write error (e.g. a timeout) on
+// that net.Conn.
+//
+// To test, verify we don't timeout or see fewer unique client
+// addresses (== unique connections) than requests.
+func TestServerKeepAliveAfterWriteError(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping in -short mode")
+ }
+ defer afterTest(t)
+ const numReq = 3
+ addrc := make(chan string, numReq)
+ ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ addrc <- r.RemoteAddr
+ time.Sleep(500 * time.Millisecond)
+ w.(Flusher).Flush()
+ }))
+ ts.Config.WriteTimeout = 250 * time.Millisecond
+ ts.Start()
+ defer ts.Close()
+
+ errc := make(chan error, numReq)
+ go func() {
+ defer close(errc)
+ for i := 0; i < numReq; i++ {
+ res, err := Get(ts.URL)
+ if res != nil {
+ res.Body.Close()
+ }
+ errc <- err
+ }
+ }()
+
+ timeout := time.NewTimer(numReq * 2 * time.Second) // 4x overkill
+ defer timeout.Stop()
+ addrSeen := map[string]bool{}
+ numOkay := 0
+ for {
+ select {
+ case v := <-addrc:
+ addrSeen[v] = true
+ case err, ok := <-errc:
+ if !ok {
+ if len(addrSeen) != numReq {
+ t.Errorf("saw %d unique client addresses; want %d", len(addrSeen), numReq)
+ }
+ if numOkay != 0 {
+ t.Errorf("got %d successful client requests; want 0", numOkay)
+ }
+ return
+ }
+ if err == nil {
+ numOkay++
+ }
+ case <-timeout.C:
+ t.Fatal("timeout waiting for requests to complete")
+ }
+ }
+}
+
func BenchmarkClientServer(b *testing.B) {
b.ReportAllocs()
b.StopTimer()
@@ -2109,6 +2772,7 @@ func BenchmarkClientServer(b *testing.B) {
b.Fatal("Get:", err)
}
all, err := ioutil.ReadAll(res.Body)
+ res.Body.Close()
if err != nil {
b.Fatal("ReadAll:", err)
}
@@ -2122,48 +2786,60 @@ func BenchmarkClientServer(b *testing.B) {
}
func BenchmarkClientServerParallel4(b *testing.B) {
- benchmarkClientServerParallel(b, 4)
+ benchmarkClientServerParallel(b, 4, false)
}
func BenchmarkClientServerParallel64(b *testing.B) {
- benchmarkClientServerParallel(b, 64)
+ benchmarkClientServerParallel(b, 64, false)
+}
+
+func BenchmarkClientServerParallelTLS4(b *testing.B) {
+ benchmarkClientServerParallel(b, 4, true)
}
-func benchmarkClientServerParallel(b *testing.B, conc int) {
+func BenchmarkClientServerParallelTLS64(b *testing.B) {
+ benchmarkClientServerParallel(b, 64, true)
+}
+
+func benchmarkClientServerParallel(b *testing.B, parallelism int, useTLS bool) {
b.ReportAllocs()
- b.StopTimer()
- ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, r *Request) {
+ ts := httptest.NewUnstartedServer(HandlerFunc(func(rw ResponseWriter, r *Request) {
fmt.Fprintf(rw, "Hello world.\n")
}))
+ if useTLS {
+ ts.StartTLS()
+ } else {
+ ts.Start()
+ }
defer ts.Close()
- b.StartTimer()
-
- numProcs := runtime.GOMAXPROCS(-1) * conc
- var wg sync.WaitGroup
- wg.Add(numProcs)
- n := int32(b.N)
- for p := 0; p < numProcs; p++ {
- go func() {
- for atomic.AddInt32(&n, -1) >= 0 {
- res, err := Get(ts.URL)
- if err != nil {
- b.Logf("Get: %v", err)
- continue
- }
- all, err := ioutil.ReadAll(res.Body)
- if err != nil {
- b.Logf("ReadAll: %v", err)
- continue
- }
- body := string(all)
- if body != "Hello world.\n" {
- panic("Got body: " + body)
- }
+ b.ResetTimer()
+ b.SetParallelism(parallelism)
+ b.RunParallel(func(pb *testing.PB) {
+ noVerifyTransport := &Transport{
+ TLSClientConfig: &tls.Config{
+ InsecureSkipVerify: true,
+ },
+ }
+ defer noVerifyTransport.CloseIdleConnections()
+ client := &Client{Transport: noVerifyTransport}
+ for pb.Next() {
+ res, err := client.Get(ts.URL)
+ if err != nil {
+ b.Logf("Get: %v", err)
+ continue
}
- wg.Done()
- }()
- }
- wg.Wait()
+ all, err := ioutil.ReadAll(res.Body)
+ res.Body.Close()
+ if err != nil {
+ b.Logf("ReadAll: %v", err)
+ continue
+ }
+ body := string(all)
+ if body != "Hello world.\n" {
+ panic("Got body: " + body)
+ }
+ }
+ })
}
// A benchmark for profiling the server without the HTTP client code.
@@ -2188,6 +2864,7 @@ func BenchmarkServer(b *testing.B) {
log.Panicf("Get: %v", err)
}
all, err := ioutil.ReadAll(res.Body)
+ res.Body.Close()
if err != nil {
log.Panicf("ReadAll: %v", err)
}
@@ -2391,3 +3068,28 @@ Host: golang.org
b.Errorf("b.N=%d but handled %d", b.N, handled)
}
}
+
+func BenchmarkServerHijack(b *testing.B) {
+ b.ReportAllocs()
+ req := reqBytes(`GET / HTTP/1.1
+Host: golang.org
+`)
+ h := HandlerFunc(func(w ResponseWriter, r *Request) {
+ conn, _, err := w.(Hijacker).Hijack()
+ if err != nil {
+ panic(err)
+ }
+ conn.Close()
+ })
+ conn := &rwTestConn{
+ Writer: ioutil.Discard,
+ closec: make(chan bool, 1),
+ }
+ ln := &oneConnListener{conn: conn}
+ for i := 0; i < b.N; i++ {
+ conn.Reader = bytes.NewReader(req)
+ ln.conn = conn
+ Serve(ln, h)
+ <-conn.closec
+ }
+}
diff --git a/libgo/go/net/http/server.go b/libgo/go/net/http/server.go
index 0e46863d5a..008d5aa7a7 100644
--- a/libgo/go/net/http/server.go
+++ b/libgo/go/net/http/server.go
@@ -22,6 +22,7 @@ import (
"strconv"
"strings"
"sync"
+ "sync/atomic"
"time"
)
@@ -41,6 +42,12 @@ var (
// and then return. Returning signals that the request is finished
// and that the HTTP server can move on to the next request on
// the connection.
+//
+// If ServeHTTP panics, the server (the caller of ServeHTTP) assumes
+// that the effect of the panic was isolated to the active request.
+// It recovers the panic, logs a stack trace to the server error log,
+// and hangs up the connection.
+//
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
@@ -107,6 +114,8 @@ type conn struct {
remoteAddr string // network address of remote side
server *Server // the Server on which the connection arrived
rwc net.Conn // i/o connection
+ w io.Writer // checkConnErrorWriter's copy of wrc, not zeroed on Hijack
+ werr error // any errors writing to w
sr liveSwitchReader // where the LimitReader reads from; usually the rwc
lr *io.LimitedReader // io.LimitReader(sr)
buf *bufio.ReadWriter // buffered(lr,rwc), reading from bufio->limitReader->sr->rwc
@@ -138,6 +147,7 @@ func (c *conn) hijack() (rwc net.Conn, buf *bufio.ReadWriter, err error) {
buf = c.buf
c.rwc = nil
c.buf = nil
+ c.setState(rwc, StateHijacked)
return
}
@@ -424,67 +434,64 @@ func (srv *Server) newConn(rwc net.Conn) (c *conn, err error) {
c.remoteAddr = rwc.RemoteAddr().String()
c.server = srv
c.rwc = rwc
+ c.w = rwc
if debugServerConnections {
c.rwc = newLoggingConn("server", c.rwc)
}
c.sr = liveSwitchReader{r: c.rwc}
c.lr = io.LimitReader(&c.sr, noLimit).(*io.LimitedReader)
br := newBufioReader(c.lr)
- bw := newBufioWriterSize(c.rwc, 4<<10)
+ bw := newBufioWriterSize(checkConnErrorWriter{c}, 4<<10)
c.buf = bufio.NewReadWriter(br, bw)
return c, nil
}
-// TODO: use a sync.Cache instead
var (
- bufioReaderCache = make(chan *bufio.Reader, 4)
- bufioWriterCache2k = make(chan *bufio.Writer, 4)
- bufioWriterCache4k = make(chan *bufio.Writer, 4)
+ bufioReaderPool sync.Pool
+ bufioWriter2kPool sync.Pool
+ bufioWriter4kPool sync.Pool
)
-func bufioWriterCache(size int) chan *bufio.Writer {
+func bufioWriterPool(size int) *sync.Pool {
switch size {
case 2 << 10:
- return bufioWriterCache2k
+ return &bufioWriter2kPool
case 4 << 10:
- return bufioWriterCache4k
+ return &bufioWriter4kPool
}
return nil
}
func newBufioReader(r io.Reader) *bufio.Reader {
- select {
- case p := <-bufioReaderCache:
- p.Reset(r)
- return p
- default:
- return bufio.NewReader(r)
+ if v := bufioReaderPool.Get(); v != nil {
+ br := v.(*bufio.Reader)
+ br.Reset(r)
+ return br
}
+ return bufio.NewReader(r)
}
func putBufioReader(br *bufio.Reader) {
br.Reset(nil)
- select {
- case bufioReaderCache <- br:
- default:
- }
+ bufioReaderPool.Put(br)
}
func newBufioWriterSize(w io.Writer, size int) *bufio.Writer {
- select {
- case p := <-bufioWriterCache(size):
- p.Reset(w)
- return p
- default:
- return bufio.NewWriterSize(w, size)
+ pool := bufioWriterPool(size)
+ if pool != nil {
+ if v := pool.Get(); v != nil {
+ bw := v.(*bufio.Writer)
+ bw.Reset(w)
+ return bw
+ }
}
+ return bufio.NewWriterSize(w, size)
}
func putBufioWriter(bw *bufio.Writer) {
bw.Reset(nil)
- select {
- case bufioWriterCache(bw.Available()) <- bw:
- default:
+ if pool := bufioWriterPool(bw.Available()); pool != nil {
+ pool.Put(bw)
}
}
@@ -500,6 +507,10 @@ func (srv *Server) maxHeaderBytes() int {
return DefaultMaxHeaderBytes
}
+func (srv *Server) initialLimitedReaderSize() int64 {
+ return int64(srv.maxHeaderBytes()) + 4096 // bufio slop
+}
+
// wrapper around io.ReaderCloser which on first read, sends an
// HTTP/1.1 100 Continue header
type expectContinueReader struct {
@@ -570,7 +581,7 @@ func (c *conn) readRequest() (w *response, err error) {
}()
}
- c.lr.N = int64(c.server.maxHeaderBytes()) + 4096 /* bufio slop */
+ c.lr.N = c.server.initialLimitedReaderSize()
var req *Request
if req, err = ReadRequest(c.buf.Reader); err != nil {
if c.lr.N == 0 {
@@ -618,11 +629,11 @@ const maxPostHandlerReadBytes = 256 << 10
func (w *response) WriteHeader(code int) {
if w.conn.hijacked() {
- log.Print("http: response.WriteHeader on hijacked connection")
+ w.conn.server.logf("http: response.WriteHeader on hijacked connection")
return
}
if w.wroteHeader {
- log.Print("http: multiple response.WriteHeader calls")
+ w.conn.server.logf("http: multiple response.WriteHeader calls")
return
}
w.wroteHeader = true
@@ -637,7 +648,7 @@ func (w *response) WriteHeader(code int) {
if err == nil && v >= 0 {
w.contentLength = v
} else {
- log.Printf("http: invalid Content-Length of %q", cl)
+ w.conn.server.logf("http: invalid Content-Length of %q", cl)
w.handlerHeader.Del("Content-Length")
}
}
@@ -707,6 +718,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
cw.wroteHeader = true
w := cw.res
+ keepAlivesEnabled := w.conn.server.doKeepAlives()
isHEAD := w.req.Method == "HEAD"
// header is written out to w.conn.buf below. Depending on the
@@ -739,7 +751,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
// response header and this is our first (and last) write, set
// it, even to zero. This helps HTTP/1.0 clients keep their
// "keep-alive" connections alive.
- // Exceptions: 304 responses never get Content-Length, and if
+ // Exceptions: 304/204/1xx responses never get Content-Length, and if
// it was a HEAD request, we don't know the difference between
// 0 actual bytes and 0 bytes because the handler noticed it
// was a HEAD request and chose not to write anything. So for
@@ -747,14 +759,14 @@ 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 && w.status != StatusNotModified && header.get("Content-Length") == "" && (!isHEAD || len(p) > 0) {
+ if w.handlerDone && 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)
}
// If this was an HTTP/1.0 request with keep-alive and we sent a
// Content-Length back, we can make this a keep-alive response ...
- if w.req.wantsHttp10KeepAlive() {
+ if w.req.wantsHttp10KeepAlive() && keepAlivesEnabled {
sentLength := header.get("Content-Length") != ""
if sentLength && header.get("Connection") == "keep-alive" {
w.closeAfterReply = false
@@ -773,7 +785,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
w.closeAfterReply = true
}
- if header.get("Connection") == "close" {
+ if header.get("Connection") == "close" || !keepAlivesEnabled {
w.closeAfterReply = true
}
@@ -796,18 +808,16 @@ func (cw *chunkWriter) writeHeader(p []byte) {
}
code := w.status
- if code == StatusNotModified {
- // Must not have body.
- // RFC 2616 section 10.3.5: "the response MUST NOT include other entity-headers"
- for _, k := range []string{"Content-Type", "Content-Length", "Transfer-Encoding"} {
- delHeader(k)
- }
- } else {
+ if bodyAllowedForStatus(code) {
// If no content type, apply sniffing algorithm to body.
_, haveType := header["Content-Type"]
if !haveType {
setHeader.contentType = DetectContentType(p)
}
+ } else {
+ for _, k := range suppressedHeaders(code) {
+ delHeader(k)
+ }
}
if _, ok := header["Date"]; !ok {
@@ -819,26 +829,33 @@ func (cw *chunkWriter) writeHeader(p []byte) {
if hasCL && hasTE && te != "identity" {
// TODO: return an error if WriteHeader gets a return parameter
// For now just ignore the Content-Length.
- log.Printf("http: WriteHeader called with both Transfer-Encoding of %q and a Content-Length of %d",
+ w.conn.server.logf("http: WriteHeader called with both Transfer-Encoding of %q and a Content-Length of %d",
te, w.contentLength)
delHeader("Content-Length")
hasCL = false
}
- if w.req.Method == "HEAD" || code == StatusNotModified {
+ if w.req.Method == "HEAD" || !bodyAllowedForStatus(code) {
// do nothing
} else if code == StatusNoContent {
delHeader("Transfer-Encoding")
} else if hasCL {
delHeader("Transfer-Encoding")
} else if w.req.ProtoAtLeast(1, 1) {
- // HTTP/1.1 or greater: use chunked transfer encoding
- // to avoid closing the connection at EOF.
- // TODO: this blows away any custom or stacked Transfer-Encoding they
- // might have set. Deal with that as need arises once we have a valid
- // use case.
- cw.chunking = true
- setHeader.transferEncoding = "chunked"
+ // HTTP/1.1 or greater: Transfer-Encoding has been set to identity, and no
+ // content-length has been provided. The connection must be closed after the
+ // reply is written, and no chunking is to be done. This is the setup
+ // recommended in the Server-Sent Events candidate recommendation 11,
+ // section 8.
+ if hasTE && te == "identity" {
+ cw.chunking = false
+ w.closeAfterReply = true
+ } else {
+ // HTTP/1.1 or greater: use chunked transfer encoding
+ // to avoid closing the connection at EOF.
+ cw.chunking = true
+ setHeader.transferEncoding = "chunked"
+ }
} else {
// HTTP version < 1.1: cannot do chunked transfer
// encoding and we don't know the Content-Length so
@@ -855,7 +872,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
return
}
- if w.closeAfterReply && !hasToken(cw.header.get("Connection"), "close") {
+ if w.closeAfterReply && (!keepAlivesEnabled || !hasToken(cw.header.get("Connection"), "close")) {
delHeader("Connection")
if w.req.ProtoAtLeast(1, 1) {
setHeader.connection = "close"
@@ -919,7 +936,7 @@ func (w *response) bodyAllowed() bool {
if !w.wroteHeader {
panic("")
}
- return w.status != StatusNotModified
+ return bodyAllowedForStatus(w.status)
}
// The Life Of A Write is like this:
@@ -942,8 +959,10 @@ func (w *response) bodyAllowed() bool {
// 2. (*response).w, a *bufio.Writer of bufferBeforeChunkingSize bytes
// 3. chunkWriter.Writer (whose writeHeader finalizes Content-Length/Type)
// and which writes the chunk headers, if needed.
-// 4. conn.buf, a bufio.Writer of default (4kB) bytes
-// 5. the rwc, the net.Conn.
+// 4. conn.buf, a bufio.Writer of default (4kB) bytes, writing to ->
+// 5. checkConnErrorWriter{c}, which notes any non-nil error on Write
+// and populates c.werr with it if so. but otherwise writes to:
+// 6. the rwc, the net.Conn.
//
// TODO(bradfitz): short-circuit some of the buffering when the
// initial header contains both a Content-Type and Content-Length.
@@ -965,7 +984,7 @@ func (w *response) WriteString(data string) (n int, err error) {
// either dataB or dataS is non-zero.
func (w *response) write(lenData int, dataB []byte, dataS string) (n int, err error) {
if w.conn.hijacked() {
- log.Print("http: response.Write on hijacked connection")
+ w.conn.server.logf("http: response.Write on hijacked connection")
return 0, ErrHijacked
}
if !w.wroteHeader {
@@ -1001,11 +1020,10 @@ func (w *response) finishRequest() {
w.cw.close()
w.conn.buf.Flush()
- // Close the body, unless we're about to close the whole TCP connection
- // anyway.
- if !w.closeAfterReply {
- w.req.Body.Close()
- }
+ // Close the body (regardless of w.closeAfterReply) so we can
+ // re-use its bufio.Reader later safely.
+ w.req.Body.Close()
+
if w.req.MultipartForm != nil {
w.req.MultipartForm.RemoveAll()
}
@@ -1014,6 +1032,12 @@ func (w *response) finishRequest() {
// Did not write enough. Avoid getting out of sync.
w.closeAfterReply = true
}
+
+ // There was some error writing to the underlying connection
+ // during the request, so don't re-use this conn.
+ if w.conn.werr != nil {
+ w.closeAfterReply = true
+ }
}
func (w *response) Flush() {
@@ -1058,15 +1082,21 @@ func (c *conn) close() {
// This timeout is somewhat arbitrary (~latency around the planet).
const rstAvoidanceDelay = 500 * time.Millisecond
+type closeWriter interface {
+ CloseWrite() error
+}
+
+var _ closeWriter = (*net.TCPConn)(nil)
+
// closeWrite flushes any outstanding data and sends a FIN packet (if
// client is connected via TCP), signalling that we're done. We then
-// pause for a bit, hoping the client processes it before `any
+// pause for a bit, hoping the client processes it before any
// subsequent RST.
//
// See http://golang.org/issue/3595
func (c *conn) closeWriteAndWait() {
c.finalFlush()
- if tcp, ok := c.rwc.(*net.TCPConn); ok {
+ if tcp, ok := c.rwc.(closeWriter); ok {
tcp.CloseWrite()
}
time.Sleep(rstAvoidanceDelay)
@@ -1084,17 +1114,25 @@ func validNPN(proto string) bool {
return true
}
+func (c *conn) setState(nc net.Conn, state ConnState) {
+ if hook := c.server.ConnState; hook != nil {
+ hook(nc, state)
+ }
+}
+
// Serve a new connection.
func (c *conn) serve() {
+ origConn := c.rwc // copy it before it's set nil on Close or Hijack
defer func() {
if err := recover(); err != nil {
- const size = 4096
+ const size = 64 << 10
buf := make([]byte, size)
buf = buf[:runtime.Stack(buf, false)]
- log.Printf("http: panic serving %v: %v\n%s", c.remoteAddr, err, buf)
+ c.server.logf("http: panic serving %v: %v\n%s", c.remoteAddr, err, buf)
}
if !c.hijacked() {
c.close()
+ c.setState(origConn, StateClosed)
}
}()
@@ -1106,6 +1144,7 @@ func (c *conn) serve() {
c.rwc.SetWriteDeadline(time.Now().Add(d))
}
if err := tlsConn.Handshake(); err != nil {
+ c.server.logf("http: TLS handshake error from %s: %v", c.rwc.RemoteAddr(), err)
return
}
c.tlsState = new(tls.ConnectionState)
@@ -1121,6 +1160,10 @@ func (c *conn) serve() {
for {
w, err := c.readRequest()
+ if c.lr.N != c.server.initialLimitedReaderSize() {
+ // If we read any bytes off the wire, we're active.
+ c.setState(c.rwc, StateActive)
+ }
if err != nil {
if err == errTooLarge {
// Their HTTP client may or may not be
@@ -1143,16 +1186,10 @@ func (c *conn) serve() {
// Expect 100 Continue support
req := w.req
if req.expectsContinue() {
- if req.ProtoAtLeast(1, 1) {
+ if req.ProtoAtLeast(1, 1) && req.ContentLength != 0 {
// Wrap the Body reader with one that replies on the connection
req.Body = &expectContinueReader{readCloser: req.Body, resp: w}
}
- if req.ContentLength == 0 {
- w.Header().Set("Connection", "close")
- w.WriteHeader(StatusBadRequest)
- w.finishRequest()
- break
- }
req.Header.Del("Expect")
} else if req.Header.get("Expect") != "" {
w.sendExpectationFailed()
@@ -1175,6 +1212,7 @@ func (c *conn) serve() {
}
break
}
+ c.setState(c.rwc, StateIdle)
}
}
@@ -1202,7 +1240,14 @@ func (w *response) Hijack() (rwc net.Conn, buf *bufio.ReadWriter, err error) {
if w.wroteHeader {
w.cw.flush()
}
- return w.conn.hijack()
+ // Release the bufioWriter that writes to the chunk writer, it is not
+ // used after a connection has been hijacked.
+ rwc, buf, err = w.conn.hijack()
+ if err == nil {
+ putBufioWriter(w.w)
+ w.w = nil
+ }
+ return rwc, buf, err
}
func (w *response) CloseNotify() <-chan bool {
@@ -1562,6 +1607,7 @@ func Serve(l net.Listener, handler Handler) error {
}
// A Server defines parameters for running an HTTP server.
+// The zero value for Server is a valid configuration.
type Server struct {
Addr string // TCP address to listen on, ":http" if empty
Handler Handler // handler to invoke, http.DefaultServeMux if nil
@@ -1578,6 +1624,66 @@ type Server struct {
// and RemoteAddr if not already set. The connection is
// automatically closed when the function returns.
TLSNextProto map[string]func(*Server, *tls.Conn, Handler)
+
+ // ConnState specifies an optional callback function that is
+ // called when a client connection changes state. See the
+ // ConnState type and associated constants for details.
+ ConnState func(net.Conn, ConnState)
+
+ // ErrorLog specifies an optional logger for errors accepting
+ // connections and unexpected behavior from handlers.
+ // If nil, logging goes to os.Stderr via the log package's
+ // standard logger.
+ ErrorLog *log.Logger
+
+ disableKeepAlives int32 // accessed atomically.
+}
+
+// A ConnState represents the state of a client connection to a server.
+// It's used by the optional Server.ConnState hook.
+type ConnState int
+
+const (
+ // StateNew represents a new connection that is expected to
+ // send a request immediately. Connections begin at this
+ // state and then transition to either StateActive or
+ // StateClosed.
+ StateNew ConnState = iota
+
+ // StateActive represents a connection that has read 1 or more
+ // bytes of a request. The Server.ConnState hook for
+ // StateActive fires before the request has entered a handler
+ // and doesn't fire again until the request has been
+ // handled. After the request is handled, the state
+ // transitions to StateClosed, StateHijacked, or StateIdle.
+ StateActive
+
+ // StateIdle represents a connection that has finished
+ // handling a request and is in the keep-alive state, waiting
+ // for a new request. Connections transition from StateIdle
+ // to either StateActive or StateClosed.
+ StateIdle
+
+ // StateHijacked represents a hijacked connection.
+ // This is a terminal state. It does not transition to StateClosed.
+ StateHijacked
+
+ // StateClosed represents a closed connection.
+ // This is a terminal state. Hijacked connections do not
+ // transition to StateClosed.
+ StateClosed
+)
+
+var stateName = map[ConnState]string{
+ StateNew: "new",
+ StateActive: "active",
+ StateIdle: "idle",
+ StateHijacked: "hijacked",
+ StateClosed: "closed",
+}
+
+func (c ConnState) String() string {
+ return stateName[c]
}
// serverHandler delegates to either the server's Handler or
@@ -1605,11 +1711,11 @@ func (srv *Server) ListenAndServe() error {
if addr == "" {
addr = ":http"
}
- l, e := net.Listen("tcp", addr)
- if e != nil {
- return e
+ ln, err := net.Listen("tcp", addr)
+ if err != nil {
+ return err
}
- return srv.Serve(l)
+ return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})
}
// Serve accepts incoming connections on the Listener l, creating a
@@ -1630,7 +1736,7 @@ func (srv *Server) Serve(l net.Listener) error {
if max := 1 * time.Second; tempDelay > max {
tempDelay = max
}
- log.Printf("http: Accept error: %v; retrying in %v", e, tempDelay)
+ srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay)
time.Sleep(tempDelay)
continue
}
@@ -1641,10 +1747,35 @@ func (srv *Server) Serve(l net.Listener) error {
if err != nil {
continue
}
+ c.setState(c.rwc, StateNew) // before Serve can return
go c.serve()
}
}
+func (s *Server) doKeepAlives() bool {
+ return atomic.LoadInt32(&s.disableKeepAlives) == 0
+}
+
+// SetKeepAlivesEnabled controls whether HTTP keep-alives are enabled.
+// 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) {
+ if v {
+ atomic.StoreInt32(&s.disableKeepAlives, 0)
+ } else {
+ atomic.StoreInt32(&s.disableKeepAlives, 1)
+ }
+}
+
+func (s *Server) logf(format string, args ...interface{}) {
+ if s.ErrorLog != nil {
+ s.ErrorLog.Printf(format, args...)
+ } else {
+ log.Printf(format, args...)
+ }
+}
+
// ListenAndServe listens on the TCP network address addr
// and then calls Serve with handler to handle requests
// on incoming connections. Handler is typically nil,
@@ -1739,12 +1870,12 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
return err
}
- conn, err := net.Listen("tcp", addr)
+ ln, err := net.Listen("tcp", addr)
if err != nil {
return err
}
- tlsListener := tls.NewListener(conn, config)
+ tlsListener := tls.NewListener(tcpKeepAliveListener{ln.(*net.TCPListener)}, config)
return srv.Serve(tlsListener)
}
@@ -1815,9 +1946,9 @@ func (tw *timeoutWriter) Header() Header {
func (tw *timeoutWriter) Write(p []byte) (int, error) {
tw.mu.Lock()
- timedOut := tw.timedOut
- tw.mu.Unlock()
- if timedOut {
+ defer tw.mu.Unlock()
+ tw.wroteHeader = true // implicitly at least
+ if tw.timedOut {
return 0, ErrHandlerTimeout
}
return tw.w.Write(p)
@@ -1825,15 +1956,32 @@ func (tw *timeoutWriter) Write(p []byte) (int, error) {
func (tw *timeoutWriter) WriteHeader(code int) {
tw.mu.Lock()
+ defer tw.mu.Unlock()
if tw.timedOut || tw.wroteHeader {
- tw.mu.Unlock()
return
}
tw.wroteHeader = true
- tw.mu.Unlock()
tw.w.WriteHeader(code)
}
+// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
+// connections. It's used by ListenAndServe and ListenAndServeTLS so
+// dead TCP connections (e.g. closing laptop mid-download) eventually
+// go away.
+type tcpKeepAliveListener struct {
+ *net.TCPListener
+}
+
+func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
+ tc, err := ln.AcceptTCP()
+ if err != nil {
+ return
+ }
+ tc.SetKeepAlive(true)
+ tc.SetKeepAlivePeriod(3 * time.Minute)
+ return tc, nil
+}
+
// globalOptionsHandler responds to "OPTIONS *" requests.
type globalOptionsHandler struct{}
@@ -1850,17 +1998,24 @@ func (globalOptionsHandler) ServeHTTP(w ResponseWriter, r *Request) {
}
}
+type eofReaderWithWriteTo struct{}
+
+func (eofReaderWithWriteTo) WriteTo(io.Writer) (int64, error) { return 0, nil }
+func (eofReaderWithWriteTo) Read([]byte) (int, error) { return 0, io.EOF }
+
// eofReader is a non-nil io.ReadCloser that always returns EOF.
-// It embeds a *strings.Reader so it still has a WriteTo method
-// and io.Copy won't need a buffer.
+// It has a WriteTo method so io.Copy won't need a buffer.
var eofReader = &struct {
- *strings.Reader
+ eofReaderWithWriteTo
io.Closer
}{
- strings.NewReader(""),
+ eofReaderWithWriteTo{},
ioutil.NopCloser(nil),
}
+// Verify that an io.Copy from an eofReader won't require a buffer.
+var _ io.WriterTo = eofReader
+
// initNPNRequest is an HTTP handler that initializes certain
// uninitialized fields in its *Request. Such partially-initialized
// Requests come from NPN protocol handlers.
@@ -1924,3 +2079,18 @@ func (c *loggingConn) Close() (err error) {
log.Printf("%s.Close() = %v", c.name, err)
return
}
+
+// checkConnErrorWriter writes to c.rwc and records any write errors to c.werr.
+// It only contains one field (and a pointer field at that), so it
+// fits in an interface value without an extra allocation.
+type checkConnErrorWriter struct {
+ c *conn
+}
+
+func (w checkConnErrorWriter) Write(p []byte) (n int, err error) {
+ n, err = w.c.w.Write(p) // c.w == c.rwc, except after a hijack, when rwc is nil.
+ if err != nil && w.c.werr == nil {
+ w.c.werr = err
+ }
+ return
+}
diff --git a/libgo/go/net/http/transfer.go b/libgo/go/net/http/transfer.go
index bacd83732d..520500330b 100644
--- a/libgo/go/net/http/transfer.go
+++ b/libgo/go/net/http/transfer.go
@@ -11,11 +11,26 @@ import (
"fmt"
"io"
"io/ioutil"
+ "net/http/internal"
"net/textproto"
+ "sort"
"strconv"
"strings"
+ "sync"
)
+// ErrLineTooLong is returned when reading request or response bodies
+// with malformed chunked encoding.
+var ErrLineTooLong = internal.ErrLineTooLong
+
+type errorReader struct {
+ err error
+}
+
+func (r *errorReader) Read(p []byte) (n int, err error) {
+ return 0, r.err
+}
+
// transferWriter inspects the fields of a user-supplied Request or Response,
// sanitizes them without changing the user object and provides methods for
// writing the respective header, body and trailer in wire format.
@@ -52,14 +67,17 @@ func newTransferWriter(r interface{}) (t *transferWriter, err error) {
if t.ContentLength == 0 {
// Test to see if it's actually zero or just unset.
var buf [1]byte
- n, _ := io.ReadFull(t.Body, buf[:])
- if n == 1 {
+ n, rerr := io.ReadFull(t.Body, buf[:])
+ if rerr != nil && rerr != io.EOF {
+ t.ContentLength = -1
+ 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.
// Stich the Body back together again, re-attaching our
// consumed byte.
t.ContentLength = -1
- t.Body = io.MultiReader(bytes.NewBuffer(buf[:]), t.Body)
+ t.Body = io.MultiReader(bytes.NewReader(buf[:]), t.Body)
} else {
// Body is actually empty.
t.Body = nil
@@ -131,11 +149,10 @@ func (t *transferWriter) shouldSendContentLength() bool {
return false
}
-func (t *transferWriter) WriteHeader(w io.Writer) (err error) {
+func (t *transferWriter) WriteHeader(w io.Writer) error {
if t.Close {
- _, err = io.WriteString(w, "Connection: close\r\n")
- if err != nil {
- return
+ if _, err := io.WriteString(w, "Connection: close\r\n"); err != nil {
+ return err
}
}
@@ -143,49 +160,50 @@ func (t *transferWriter) WriteHeader(w io.Writer) (err error) {
// function of the sanitized field triple (Body, ContentLength,
// TransferEncoding)
if t.shouldSendContentLength() {
- io.WriteString(w, "Content-Length: ")
- _, err = io.WriteString(w, strconv.FormatInt(t.ContentLength, 10)+"\r\n")
- if err != nil {
- return
+ if _, err := io.WriteString(w, "Content-Length: "); err != nil {
+ return err
+ }
+ if _, err := io.WriteString(w, strconv.FormatInt(t.ContentLength, 10)+"\r\n"); err != nil {
+ return err
}
} else if chunked(t.TransferEncoding) {
- _, err = io.WriteString(w, "Transfer-Encoding: chunked\r\n")
- if err != nil {
- return
+ if _, err := io.WriteString(w, "Transfer-Encoding: chunked\r\n"); err != nil {
+ return err
}
}
// Write Trailer header
if t.Trailer != nil {
- // TODO: At some point, there should be a generic mechanism for
- // writing long headers, using HTTP line splitting
- io.WriteString(w, "Trailer: ")
- needComma := false
+ keys := make([]string, 0, len(t.Trailer))
for k := range t.Trailer {
k = CanonicalHeaderKey(k)
switch k {
case "Transfer-Encoding", "Trailer", "Content-Length":
return &badStringError{"invalid Trailer key", k}
}
- if needComma {
- io.WriteString(w, ",")
+ keys = append(keys, k)
+ }
+ if len(keys) > 0 {
+ sort.Strings(keys)
+ // TODO: could do better allocation-wise here, but trailers are rare,
+ // so being lazy for now.
+ if _, err := io.WriteString(w, "Trailer: "+strings.Join(keys, ",")+"\r\n"); err != nil {
+ return err
}
- io.WriteString(w, k)
- needComma = true
}
- _, err = io.WriteString(w, "\r\n")
}
- return
+ return nil
}
-func (t *transferWriter) WriteBody(w io.Writer) (err error) {
+func (t *transferWriter) WriteBody(w io.Writer) error {
+ var err error
var ncopy int64
// Write body
if t.Body != nil {
if chunked(t.TransferEncoding) {
- cw := newChunkedWriter(w)
+ cw := internal.NewChunkedWriter(w)
_, err = io.Copy(cw, t.Body)
if err == nil {
err = cw.Close()
@@ -210,17 +228,22 @@ func (t *transferWriter) WriteBody(w io.Writer) (err error) {
}
if !t.ResponseToHEAD && t.ContentLength != -1 && t.ContentLength != ncopy {
- return fmt.Errorf("http: Request.ContentLength=%d with Body length %d",
+ return fmt.Errorf("http: ContentLength=%d with Body length %d",
t.ContentLength, ncopy)
}
// TODO(petar): Place trailer writer code here.
if chunked(t.TransferEncoding) {
+ // Write Trailer header
+ if t.Trailer != nil {
+ if err := t.Trailer.Write(w); err != nil {
+ return err
+ }
+ }
// Last chunk, empty trailer
_, err = io.WriteString(w, "\r\n")
}
-
- return
+ return err
}
type transferReader struct {
@@ -252,6 +275,22 @@ func bodyAllowedForStatus(status int) bool {
return true
}
+var (
+ suppressedHeaders304 = []string{"Content-Type", "Content-Length", "Transfer-Encoding"}
+ suppressedHeadersNoBody = []string{"Content-Length", "Transfer-Encoding"}
+)
+
+func suppressedHeaders(status int) []string {
+ switch {
+ case status == 304:
+ // RFC 2616 section 10.3.5: "the response MUST NOT include other entity-headers"
+ return suppressedHeaders304
+ case !bodyAllowedForStatus(status):
+ return suppressedHeadersNoBody
+ }
+ return nil
+}
+
// msg is *Request or *Response.
func readTransfer(msg interface{}, r *bufio.Reader) (err error) {
t := &transferReader{RequestMethod: "GET"}
@@ -264,7 +303,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) {
t.StatusCode = rr.StatusCode
t.ProtoMajor = rr.ProtoMajor
t.ProtoMinor = rr.ProtoMinor
- t.Close = shouldClose(t.ProtoMajor, t.ProtoMinor, t.Header)
+ t.Close = shouldClose(t.ProtoMajor, t.ProtoMinor, t.Header, true)
isResponse = true
if rr.Request != nil {
t.RequestMethod = rr.Request.Method
@@ -331,17 +370,17 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) {
if noBodyExpected(t.RequestMethod) {
t.Body = eofReader
} else {
- t.Body = &body{Reader: newChunkedReader(r), hdr: msg, r: r, closing: t.Close}
+ t.Body = &body{src: internal.NewChunkedReader(r), hdr: msg, r: r, closing: t.Close}
}
case realLength == 0:
t.Body = eofReader
case realLength > 0:
- t.Body = &body{Reader: io.LimitReader(r, realLength), closing: t.Close}
+ t.Body = &body{src: io.LimitReader(r, realLength), closing: t.Close}
default:
// realLength < 0, i.e. "Content-Length" not mentioned in header
if t.Close {
// Close semantics (i.e. HTTP/1.0)
- t.Body = &body{Reader: r, closing: t.Close}
+ t.Body = &body{src: r, closing: t.Close}
} else {
// Persistent connection (i.e. HTTP/1.1)
t.Body = eofReader
@@ -463,7 +502,7 @@ func fixLength(isResponse bool, status int, requestMethod string, header Header,
// Determine whether to hang up after sending a request and body, or
// receiving a response and body
// 'header' is the request headers
-func shouldClose(major, minor int, header Header) bool {
+func shouldClose(major, minor int, header Header, removeCloseHeader bool) bool {
if major < 1 {
return true
} else if major == 1 && minor == 0 {
@@ -475,7 +514,9 @@ func shouldClose(major, minor int, header Header) bool {
// TODO: Should split on commas, toss surrounding white space,
// and check each field.
if strings.ToLower(header.get("Connection")) == "close" {
- header.Del("Connection")
+ if removeCloseHeader {
+ header.Del("Connection")
+ }
return true
}
}
@@ -498,7 +539,7 @@ func fixTrailer(header Header, te []string) (Header, error) {
case "Transfer-Encoding", "Trailer", "Content-Length":
return nil, &badStringError{"bad trailer key", key}
}
- trailer.Del(key)
+ trailer[key] = nil
}
if len(trailer) == 0 {
return nil, nil
@@ -514,11 +555,13 @@ 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 {
- io.Reader
+ 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?
- closed bool
+
+ mu sync.Mutex // guards closed, and calls to Read and Close
+ closed bool
}
// ErrBodyReadAfterClose is returned when reading a Request or Response
@@ -528,10 +571,17 @@ type body struct {
var ErrBodyReadAfterClose = errors.New("http: invalid Read on closed Body")
func (b *body) Read(p []byte) (n int, err error) {
+ b.mu.Lock()
+ defer b.mu.Unlock()
if b.closed {
return 0, ErrBodyReadAfterClose
}
- n, err = b.Reader.Read(p)
+ return b.readLocked(p)
+}
+
+// Must hold b.mu.
+func (b *body) readLocked(p []byte) (n int, err error) {
+ n, err = b.src.Read(p)
if err == io.EOF {
// Chunked case. Read the trailer.
@@ -543,12 +593,23 @@ func (b *body) Read(p []byte) (n int, err error) {
} else {
// If the server declared the Content-Length, our body is a LimitedReader
// and we need to check whether this EOF arrived early.
- if lr, ok := b.Reader.(*io.LimitedReader); ok && lr.N > 0 {
+ if lr, ok := b.src.(*io.LimitedReader); ok && lr.N > 0 {
err = io.ErrUnexpectedEOF
}
}
}
+ // If we can return an EOF here along with the read data, do
+ // so. This is optional per the io.Reader contract, but doing
+ // so helps the HTTP transport code recycle its connection
+ // earlier (since it will see this EOF itself), even if the
+ // client doesn't do future reads or Close.
+ if err == nil && n > 0 {
+ if lr, ok := b.src.(*io.LimitedReader); ok && lr.N == 0 {
+ err = io.EOF
+ }
+ }
+
return n, err
}
@@ -610,14 +671,26 @@ func (b *body) readTrailer() error {
}
switch rr := b.hdr.(type) {
case *Request:
- rr.Trailer = Header(hdr)
+ mergeSetHeader(&rr.Trailer, Header(hdr))
case *Response:
- rr.Trailer = Header(hdr)
+ mergeSetHeader(&rr.Trailer, Header(hdr))
}
return nil
}
+func mergeSetHeader(dst *Header, src Header) {
+ if *dst == nil {
+ *dst = src
+ return
+ }
+ for k, vv := range src {
+ (*dst)[k] = vv
+ }
+}
+
func (b *body) Close() error {
+ b.mu.Lock()
+ defer b.mu.Unlock()
if b.closed {
return nil
}
@@ -629,12 +702,25 @@ func (b *body) Close() error {
default:
// Fully consume the body, which will also lead to us reading
// the trailer headers after the body, if present.
- _, err = io.Copy(ioutil.Discard, b)
+ _, err = io.Copy(ioutil.Discard, bodyLocked{b})
}
b.closed = true
return err
}
+// bodyLocked is a io.Reader reading from a *body when its mutex is
+// already held.
+type bodyLocked struct {
+ b *body
+}
+
+func (bl bodyLocked) Read(p []byte) (n int, err error) {
+ if bl.b.closed {
+ return 0, ErrBodyReadAfterClose
+ }
+ return bl.b.readLocked(p)
+}
+
// parseContentLength trims whitespace from s and returns -1 if no value
// is set, or the value if it's >= 0.
func parseContentLength(cl string) (int64, error) {
diff --git a/libgo/go/net/http/transfer_test.go b/libgo/go/net/http/transfer_test.go
index 8627a374c8..48cd540b9f 100644
--- a/libgo/go/net/http/transfer_test.go
+++ b/libgo/go/net/http/transfer_test.go
@@ -6,15 +6,16 @@ package http
import (
"bufio"
+ "io"
"strings"
"testing"
)
func TestBodyReadBadTrailer(t *testing.T) {
b := &body{
- Reader: strings.NewReader("foobar"),
- hdr: true, // force reading the trailer
- r: bufio.NewReader(strings.NewReader("")),
+ src: strings.NewReader("foobar"),
+ hdr: true, // force reading the trailer
+ r: bufio.NewReader(strings.NewReader("")),
}
buf := make([]byte, 7)
n, err := b.Read(buf[:3])
@@ -35,3 +36,29 @@ func TestBodyReadBadTrailer(t *testing.T) {
t.Errorf("final Read was successful (%q), expected error from trailer read", got)
}
}
+
+func TestFinalChunkedBodyReadEOF(t *testing.T) {
+ res, err := ReadResponse(bufio.NewReader(strings.NewReader(
+ "HTTP/1.1 200 OK\r\n"+
+ "Transfer-Encoding: chunked\r\n"+
+ "\r\n"+
+ "0a\r\n"+
+ "Body here\n\r\n"+
+ "09\r\n"+
+ "continued\r\n"+
+ "0\r\n"+
+ "\r\n")), nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ want := "Body here\ncontinued"
+ buf := make([]byte, len(want))
+ n, err := res.Body.Read(buf)
+ if n != len(want) || err != io.EOF {
+ t.Logf("body = %#v", res.Body)
+ t.Errorf("Read = %v, %v; want %d, EOF", n, err, len(want))
+ }
+ if string(buf) != want {
+ t.Errorf("buf = %q; want %q", buf, want)
+ }
+}
diff --git a/libgo/go/net/http/transport.go b/libgo/go/net/http/transport.go
index f6871afacd..782f7cd395 100644
--- a/libgo/go/net/http/transport.go
+++ b/libgo/go/net/http/transport.go
@@ -30,23 +30,33 @@ import (
// and caches them for reuse by subsequent calls. It uses HTTP proxies
// as directed by the $HTTP_PROXY and $NO_PROXY (or $http_proxy and
// $no_proxy) environment variables.
-var DefaultTransport RoundTripper = &Transport{Proxy: ProxyFromEnvironment}
+var DefaultTransport RoundTripper = &Transport{
+ Proxy: ProxyFromEnvironment,
+ Dial: (&net.Dialer{
+ Timeout: 30 * time.Second,
+ KeepAlive: 30 * time.Second,
+ }).Dial,
+ TLSHandshakeTimeout: 10 * time.Second,
+}
// DefaultMaxIdleConnsPerHost is the default value of Transport's
// MaxIdleConnsPerHost.
const DefaultMaxIdleConnsPerHost = 2
-// Transport is an implementation of RoundTripper that supports http,
-// https, and http proxies (for either http or https with CONNECT).
+// Transport is an implementation of RoundTripper that supports HTTP,
+// HTTPS, and HTTP proxies (for either HTTP or HTTPS with CONNECT).
// Transport can also cache connections for future re-use.
type Transport struct {
idleMu sync.Mutex
- idleConn map[string][]*persistConn
- idleConnCh map[string]chan *persistConn
- reqMu sync.Mutex
- reqConn map[*Request]*persistConn
- altMu sync.RWMutex
- altProto map[string]RoundTripper // nil or map of URI scheme => RoundTripper
+ wantIdle bool // user has requested to close all idle conns
+ idleConn map[connectMethodKey][]*persistConn
+ idleConnCh map[connectMethodKey]chan *persistConn
+
+ reqMu sync.Mutex
+ reqCanceler map[*Request]func()
+
+ altMu sync.RWMutex
+ altProto map[string]RoundTripper // nil or map of URI scheme => RoundTripper
// Proxy specifies a function to return a proxy for a given
// Request. If the function returns a non-nil error, the
@@ -54,15 +64,30 @@ type Transport struct {
// If Proxy is nil or returns a nil *URL, no proxy is used.
Proxy func(*Request) (*url.URL, error)
- // Dial specifies the dial function for creating TCP
- // connections.
+ // Dial specifies the dial function for creating unencrypted
+ // TCP connections.
// If Dial is nil, net.Dial is used.
Dial func(network, addr string) (net.Conn, error)
+ // DialTLS specifies an optional dial function for creating
+ // TLS connections for non-proxied HTTPS requests.
+ //
+ // If DialTLS is nil, Dial and TLSClientConfig are used.
+ //
+ // If DialTLS is set, the Dial hook is not used for HTTPS
+ // requests and the TLSClientConfig and TLSHandshakeTimeout
+ // are ignored. The returned net.Conn is assumed to already be
+ // past the TLS handshake.
+ DialTLS func(network, addr string) (net.Conn, error)
+
// TLSClientConfig specifies the TLS configuration to use with
// tls.Client. If nil, the default configuration is used.
TLSClientConfig *tls.Config
+ // TLSHandshakeTimeout specifies the maximum amount of time waiting to
+ // wait for a TLS handshake. Zero means no timeout.
+ TLSHandshakeTimeout time.Duration
+
// DisableKeepAlives, if true, prevents re-use of TCP connections
// between different HTTP requests.
DisableKeepAlives bool
@@ -94,12 +119,28 @@ type Transport struct {
// ProxyFromEnvironment returns the URL of the proxy to use for a
// given request, as indicated by the environment variables
-// $HTTP_PROXY and $NO_PROXY (or $http_proxy and $no_proxy).
-// An error is returned if the proxy environment is invalid.
+// HTTP_PROXY, HTTPS_PROXY and NO_PROXY (or the lowercase versions
+// thereof). HTTPS_PROXY takes precedence over HTTP_PROXY for https
+// requests.
+//
+// The environment values may be either a complete URL or a
+// "host[:port]", in which case the "http" scheme is assumed.
+// An error is returned if the value is a different form.
+//
// A nil URL and nil error are returned if no proxy is defined in the
-// environment, or a proxy should not be used for the given request.
+// environment, or a proxy should not be used for the given request,
+// as defined by NO_PROXY.
+//
+// As a special case, if req.URL.Host is "localhost" (with or without
+// a port number), then a nil URL and nil error will be returned.
func ProxyFromEnvironment(req *Request) (*url.URL, error) {
- proxy := getenvEitherCase("HTTP_PROXY")
+ var proxy string
+ if req.URL.Scheme == "https" {
+ proxy = httpsProxyEnv.Get()
+ }
+ if proxy == "" {
+ proxy = httpProxyEnv.Get()
+ }
if proxy == "" {
return nil, nil
}
@@ -149,9 +190,11 @@ func (tr *transportRequest) extraHeaders() Header {
// and redirects), see Get, Post, and the Client type.
func (t *Transport) RoundTrip(req *Request) (resp *Response, err error) {
if req.URL == nil {
+ req.closeBody()
return nil, errors.New("http: nil Request.URL")
}
if req.Header == nil {
+ req.closeBody()
return nil, errors.New("http: nil Request.Header")
}
if req.URL.Scheme != "http" && req.URL.Scheme != "https" {
@@ -162,16 +205,19 @@ func (t *Transport) RoundTrip(req *Request) (resp *Response, err error) {
}
t.altMu.RUnlock()
if rt == nil {
+ req.closeBody()
return nil, &badStringError{"unsupported protocol scheme", req.URL.Scheme}
}
return rt.RoundTrip(req)
}
if req.URL.Host == "" {
+ req.closeBody()
return nil, errors.New("http: no Host in request URL")
}
treq := &transportRequest{Request: req}
cm, err := t.connectMethodForRequest(treq)
if err != nil {
+ req.closeBody()
return nil, err
}
@@ -179,8 +225,10 @@ func (t *Transport) RoundTrip(req *Request) (resp *Response, err error) {
// host (for http or https), the http proxy, or the http proxy
// pre-CONNECTed to https server. In any case, we'll be ready
// to send it requests.
- pconn, err := t.getConn(cm)
+ pconn, err := t.getConn(req, cm)
if err != nil {
+ t.setReqCanceler(req, nil)
+ req.closeBody()
return nil, err
}
@@ -217,10 +265,8 @@ func (t *Transport) CloseIdleConnections() {
m := t.idleConn
t.idleConn = nil
t.idleConnCh = nil
+ t.wantIdle = true
t.idleMu.Unlock()
- if m == nil {
- return
- }
for _, conns := range m {
for _, pconn := range conns {
pconn.close()
@@ -232,10 +278,10 @@ func (t *Transport) CloseIdleConnections() {
// connection.
func (t *Transport) CancelRequest(req *Request) {
t.reqMu.Lock()
- pc := t.reqConn[req]
+ cancel := t.reqCanceler[req]
t.reqMu.Unlock()
- if pc != nil {
- pc.conn.Close()
+ if cancel != nil {
+ cancel()
}
}
@@ -243,26 +289,54 @@ func (t *Transport) CancelRequest(req *Request) {
// Private implementation past this point.
//
-func getenvEitherCase(k string) string {
- if v := os.Getenv(strings.ToUpper(k)); v != "" {
- return v
+var (
+ httpProxyEnv = &envOnce{
+ names: []string{"HTTP_PROXY", "http_proxy"},
+ }
+ httpsProxyEnv = &envOnce{
+ names: []string{"HTTPS_PROXY", "https_proxy"},
}
- return os.Getenv(strings.ToLower(k))
+ noProxyEnv = &envOnce{
+ names: []string{"NO_PROXY", "no_proxy"},
+ }
+)
+
+// envOnce looks up an environment variable (optionally by multiple
+// names) once. It mitigates expensive lookups on some platforms
+// (e.g. Windows).
+type envOnce struct {
+ names []string
+ once sync.Once
+ val string
+}
+
+func (e *envOnce) Get() string {
+ e.once.Do(e.init)
+ return e.val
}
-func (t *Transport) connectMethodForRequest(treq *transportRequest) (*connectMethod, error) {
- cm := &connectMethod{
- targetScheme: treq.URL.Scheme,
- targetAddr: canonicalAddr(treq.URL),
+func (e *envOnce) init() {
+ for _, n := range e.names {
+ e.val = os.Getenv(n)
+ if e.val != "" {
+ return
+ }
}
+}
+
+// reset is used by tests
+func (e *envOnce) reset() {
+ e.once = sync.Once{}
+ e.val = ""
+}
+
+func (t *Transport) connectMethodForRequest(treq *transportRequest) (cm connectMethod, err error) {
+ cm.targetScheme = treq.URL.Scheme
+ cm.targetAddr = canonicalAddr(treq.URL)
if t.Proxy != nil {
- var err error
cm.proxyURL, err = t.Proxy(treq.Request)
- if err != nil {
- return nil, err
- }
}
- return cm, nil
+ return cm, err
}
// proxyAuth returns the Proxy-Authorization header to set
@@ -315,8 +389,13 @@ func (t *Transport) putIdleConn(pconn *persistConn) bool {
delete(t.idleConnCh, key)
}
}
+ if t.wantIdle {
+ t.idleMu.Unlock()
+ pconn.close()
+ return false
+ }
if t.idleConn == nil {
- t.idleConn = make(map[string][]*persistConn)
+ t.idleConn = make(map[connectMethodKey][]*persistConn)
}
if len(t.idleConn[key]) >= max {
t.idleMu.Unlock()
@@ -336,15 +415,16 @@ func (t *Transport) putIdleConn(pconn *persistConn) bool {
// getIdleConnCh returns a channel to receive and return idle
// persistent connection for the given connectMethod.
// It may return nil, if persistent connections are not being used.
-func (t *Transport) getIdleConnCh(cm *connectMethod) chan *persistConn {
+func (t *Transport) getIdleConnCh(cm connectMethod) chan *persistConn {
if t.DisableKeepAlives {
return nil
}
key := cm.key()
t.idleMu.Lock()
defer t.idleMu.Unlock()
+ t.wantIdle = false
if t.idleConnCh == nil {
- t.idleConnCh = make(map[string]chan *persistConn)
+ t.idleConnCh = make(map[connectMethodKey]chan *persistConn)
}
ch, ok := t.idleConnCh[key]
if !ok {
@@ -354,7 +434,7 @@ func (t *Transport) getIdleConnCh(cm *connectMethod) chan *persistConn {
return ch
}
-func (t *Transport) getIdleConn(cm *connectMethod) (pconn *persistConn) {
+func (t *Transport) getIdleConn(cm connectMethod) (pconn *persistConn) {
key := cm.key()
t.idleMu.Lock()
defer t.idleMu.Unlock()
@@ -373,7 +453,7 @@ func (t *Transport) getIdleConn(cm *connectMethod) (pconn *persistConn) {
// 2 or more cached connections; pop last
// TODO: queue?
pconn = pconns[len(pconns)-1]
- t.idleConn[key] = pconns[0 : len(pconns)-1]
+ t.idleConn[key] = pconns[:len(pconns)-1]
}
if !pconn.isBroken() {
return
@@ -381,16 +461,16 @@ func (t *Transport) getIdleConn(cm *connectMethod) (pconn *persistConn) {
}
}
-func (t *Transport) setReqConn(r *Request, pc *persistConn) {
+func (t *Transport) setReqCanceler(r *Request, fn func()) {
t.reqMu.Lock()
defer t.reqMu.Unlock()
- if t.reqConn == nil {
- t.reqConn = make(map[*Request]*persistConn)
+ if t.reqCanceler == nil {
+ t.reqCanceler = make(map[*Request]func())
}
- if pc != nil {
- t.reqConn[r] = pc
+ if fn != nil {
+ t.reqCanceler[r] = fn
} else {
- delete(t.reqConn, r)
+ delete(t.reqCanceler, r)
}
}
@@ -401,11 +481,14 @@ func (t *Transport) dial(network, addr string) (c net.Conn, err error) {
return net.Dial(network, addr)
}
+// Testing hooks:
+var prePendingDial, postPendingDial func()
+
// getConn dials and creates a new persistConn to the target as
// specified in the connectMethod. This includes doing a proxy CONNECT
// and/or setting up TLS. If this doesn't return an error, the persistConn
// is ready to write requests to.
-func (t *Transport) getConn(cm *connectMethod) (*persistConn, error) {
+func (t *Transport) getConn(req *Request, cm connectMethod) (*persistConn, error) {
if pc := t.getIdleConn(cm); pc != nil {
return pc, nil
}
@@ -415,6 +498,24 @@ func (t *Transport) getConn(cm *connectMethod) (*persistConn, error) {
err error
}
dialc := make(chan dialRes)
+
+ handlePendingDial := func() {
+ if prePendingDial != nil {
+ prePendingDial()
+ }
+ go func() {
+ if v := <-dialc; v.err == nil {
+ t.putIdleConn(v.pc)
+ }
+ if postPendingDial != nil {
+ postPendingDial()
+ }
+ }()
+ }
+
+ cancelc := make(chan struct{})
+ t.setReqCanceler(req, func() { close(cancelc) })
+
go func() {
pc, err := t.dialConn(cm)
dialc <- dialRes{pc, err}
@@ -431,53 +532,65 @@ func (t *Transport) getConn(cm *connectMethod) (*persistConn, error) {
// else's dial that they didn't use.
// But our dial is still going, so give it away
// when it finishes:
- go func() {
- if v := <-dialc; v.err == nil {
- t.putIdleConn(v.pc)
- }
- }()
+ handlePendingDial()
return pc, nil
+ case <-cancelc:
+ handlePendingDial()
+ return nil, errors.New("net/http: request canceled while waiting for connection")
}
}
-func (t *Transport) dialConn(cm *connectMethod) (*persistConn, error) {
- conn, err := t.dial("tcp", cm.addr())
- if err != nil {
- if cm.proxyURL != nil {
- err = fmt.Errorf("http: error connecting to proxy %s: %v", cm.proxyURL, err)
- }
- return nil, err
- }
-
- pa := cm.proxyAuth()
-
+func (t *Transport) dialConn(cm connectMethod) (*persistConn, error) {
pconn := &persistConn{
- t: t,
- cacheKey: cm.key(),
- conn: conn,
- reqch: make(chan requestAndChan, 50),
- writech: make(chan writeRequest, 50),
- closech: make(chan struct{}),
+ t: t,
+ cacheKey: cm.key(),
+ reqch: make(chan requestAndChan, 1),
+ writech: make(chan writeRequest, 1),
+ closech: make(chan struct{}),
+ writeErrCh: make(chan error, 1),
+ }
+ tlsDial := t.DialTLS != nil && cm.targetScheme == "https" && cm.proxyURL == nil
+ if tlsDial {
+ var err error
+ pconn.conn, err = t.DialTLS("tcp", cm.addr())
+ if err != nil {
+ return nil, err
+ }
+ if tc, ok := pconn.conn.(*tls.Conn); ok {
+ cs := tc.ConnectionState()
+ pconn.tlsState = &cs
+ }
+ } else {
+ conn, err := t.dial("tcp", cm.addr())
+ if err != nil {
+ if cm.proxyURL != nil {
+ err = fmt.Errorf("http: error connecting to proxy %s: %v", cm.proxyURL, err)
+ }
+ return nil, err
+ }
+ pconn.conn = conn
}
+ // Proxy setup.
switch {
case cm.proxyURL == nil:
- // Do nothing.
+ // Do nothing. Not using a proxy.
case cm.targetScheme == "http":
pconn.isProxy = true
- if pa != "" {
+ if pa := cm.proxyAuth(); pa != "" {
pconn.mutateHeaderFunc = func(h Header) {
h.Set("Proxy-Authorization", pa)
}
}
case cm.targetScheme == "https":
+ conn := pconn.conn
connectReq := &Request{
Method: "CONNECT",
URL: &url.URL{Opaque: cm.targetAddr},
Host: cm.targetAddr,
Header: make(Header),
}
- if pa != "" {
+ if pa := cm.proxyAuth(); pa != "" {
connectReq.Header.Set("Proxy-Authorization", pa)
}
connectReq.Write(conn)
@@ -498,7 +611,7 @@ func (t *Transport) dialConn(cm *connectMethod) (*persistConn, error) {
}
}
- if cm.targetScheme == "https" {
+ if cm.targetScheme == "https" && !tlsDial {
// Initiate TLS and check remote host name against certificate.
cfg := t.TLSClientConfig
if cfg == nil || cfg.ServerName == "" {
@@ -511,19 +624,38 @@ func (t *Transport) dialConn(cm *connectMethod) (*persistConn, error) {
cfg = &clone
}
}
- conn = tls.Client(conn, cfg)
- if err = conn.(*tls.Conn).Handshake(); err != nil {
+ plainConn := pconn.conn
+ tlsConn := tls.Client(plainConn, cfg)
+ errc := make(chan error, 2)
+ var timer *time.Timer // for canceling TLS handshake
+ if d := t.TLSHandshakeTimeout; d != 0 {
+ timer = time.AfterFunc(d, func() {
+ errc <- tlsHandshakeTimeoutError{}
+ })
+ }
+ go func() {
+ err := tlsConn.Handshake()
+ if timer != nil {
+ timer.Stop()
+ }
+ errc <- err
+ }()
+ if err := <-errc; err != nil {
+ plainConn.Close()
return nil, err
}
if !cfg.InsecureSkipVerify {
- if err = conn.(*tls.Conn).VerifyHostname(cfg.ServerName); err != nil {
+ if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil {
+ plainConn.Close()
return nil, err
}
}
- pconn.conn = conn
+ cs := tlsConn.ConnectionState()
+ pconn.tlsState = &cs
+ pconn.conn = tlsConn
}
- pconn.br = bufio.NewReader(pconn.conn)
+ pconn.br = bufio.NewReader(noteEOFReader{pconn.conn, &pconn.sawEOF})
pconn.bw = bufio.NewWriter(pconn.conn)
go pconn.readLoop()
go pconn.writeLoop()
@@ -550,7 +682,7 @@ func useProxy(addr string) bool {
}
}
- no_proxy := getenvEitherCase("NO_PROXY")
+ no_proxy := noProxyEnv.Get()
if no_proxy == "*" {
return false
}
@@ -590,8 +722,8 @@ func useProxy(addr string) bool {
//
// Cache key form Description
// ----------------- -------------------------
-// ||http|foo.com http directly to server, no proxy
-// ||https|foo.com https directly to server, no proxy
+// |http|foo.com http directly to server, no proxy
+// |https|foo.com https directly to server, no proxy
// http://proxy.com|https|foo.com http to proxy, then CONNECT to foo.com
// http://proxy.com|http http to proxy, http to anywhere after that
//
@@ -603,20 +735,20 @@ type connectMethod struct {
targetAddr string // Not used if proxy + http targetScheme (4th example in table)
}
-func (ck *connectMethod) key() string {
- return ck.String() // TODO: use a struct type instead
-}
-
-func (ck *connectMethod) String() string {
+func (cm *connectMethod) key() connectMethodKey {
proxyStr := ""
- targetAddr := ck.targetAddr
- if ck.proxyURL != nil {
- proxyStr = ck.proxyURL.String()
- if ck.targetScheme == "http" {
+ targetAddr := cm.targetAddr
+ if cm.proxyURL != nil {
+ proxyStr = cm.proxyURL.String()
+ if cm.targetScheme == "http" {
targetAddr = ""
}
}
- return strings.Join([]string{proxyStr, ck.targetScheme, targetAddr}, "|")
+ return connectMethodKey{
+ proxy: proxyStr,
+ scheme: cm.targetScheme,
+ addr: targetAddr,
+ }
}
// addr returns the first hop "host:port" to which we need to TCP connect.
@@ -637,22 +769,41 @@ func (cm *connectMethod) tlsHost() string {
return h
}
+// connectMethodKey is the map key version of connectMethod, with a
+// stringified proxy URL (or the empty string) instead of a pointer to
+// a URL.
+type connectMethodKey struct {
+ proxy, scheme, addr string
+}
+
+func (k connectMethodKey) String() string {
+ // Only used by tests.
+ return fmt.Sprintf("%s|%s|%s", k.proxy, k.scheme, k.addr)
+}
+
// persistConn wraps a connection, usually a persistent one
// (but may be used for non-keep-alive requests as well)
type persistConn struct {
t *Transport
- cacheKey string // its connectMethod.String()
+ cacheKey connectMethodKey
conn net.Conn
- closed bool // whether conn has been closed
+ tlsState *tls.ConnectionState
br *bufio.Reader // from conn
+ sawEOF bool // whether we've seen EOF from conn; owned by readLoop
bw *bufio.Writer // to conn
reqch chan requestAndChan // written by roundTrip; read by readLoop
writech chan writeRequest // written by roundTrip; read by writeLoop
- closech chan struct{} // broadcast close when readLoop (TCP connection) closes
+ closech chan struct{} // closed when conn closed
isProxy bool
+ // writeErrCh passes the request write error (usually nil)
+ // from the writeLoop goroutine to the readLoop which passes
+ // it off to the res.Body reader, which then uses it to decide
+ // whether or not a connection can be reused. Issue 7569.
+ writeErrCh chan error
- lk sync.Mutex // guards following 3 fields
+ lk sync.Mutex // guards following fields
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.
// mutateHeaderFunc is an optional func to modify extra
// headers on each outbound request before it's written. (the
@@ -660,6 +811,7 @@ type persistConn struct {
mutateHeaderFunc func(Header)
}
+// isBroken reports whether this connection is in a known broken state.
func (pc *persistConn) isBroken() bool {
pc.lk.Lock()
b := pc.broken
@@ -667,6 +819,10 @@ func (pc *persistConn) isBroken() bool {
return b
}
+func (pc *persistConn) cancelRequest() {
+ pc.conn.Close()
+}
+
var remoteSideClosedFunc func(error) bool // or nil to use default
func remoteSideClosed(err error) bool {
@@ -680,7 +836,6 @@ func remoteSideClosed(err error) bool {
}
func (pc *persistConn) readLoop() {
- defer close(pc.closech)
alive := true
for alive {
@@ -688,12 +843,14 @@ func (pc *persistConn) readLoop() {
pc.lk.Lock()
if pc.numExpectedResponses == 0 {
- pc.closeLocked()
- pc.lk.Unlock()
- if len(pb) > 0 {
- log.Printf("Unsolicited response received on idle HTTP channel starting with %q; err=%v",
- string(pb), err)
+ if !pc.closed {
+ pc.closeLocked()
+ if len(pb) > 0 {
+ log.Printf("Unsolicited response received on idle HTTP channel starting with %q; err=%v",
+ string(pb), err)
+ }
}
+ pc.lk.Unlock()
return
}
pc.lk.Unlock()
@@ -712,6 +869,11 @@ func (pc *persistConn) readLoop() {
resp, err = ReadResponse(pc.br, rc.req)
}
}
+
+ if resp != nil {
+ resp.TLS = pc.tlsState
+ }
+
hasBody := resp != nil && rc.req.Method != "HEAD" && resp.ContentLength != 0
if err != nil {
@@ -721,13 +883,7 @@ func (pc *persistConn) readLoop() {
resp.Header.Del("Content-Encoding")
resp.Header.Del("Content-Length")
resp.ContentLength = -1
- gzReader, zerr := gzip.NewReader(resp.Body)
- if zerr != nil {
- pc.close()
- err = zerr
- } else {
- resp.Body = &readerAndCloser{gzReader, resp.Body}
- }
+ resp.Body = &gzipReader{body: resp.Body}
}
resp.Body = &bodyEOFSignal{body: resp.Body}
}
@@ -750,24 +906,18 @@ func (pc *persistConn) readLoop() {
return nil
}
resp.Body.(*bodyEOFSignal).fn = func(err error) {
- alive1 := alive
- if err != nil {
- alive1 = false
- }
- if alive1 && !pc.t.putIdleConn(pc) {
- alive1 = false
- }
- if !alive1 || pc.isBroken() {
- pc.close()
- }
- waitForBodyRead <- alive1
+ waitForBodyRead <- alive &&
+ err == nil &&
+ !pc.sawEOF &&
+ pc.wroteRequest() &&
+ pc.t.putIdleConn(pc)
}
}
if alive && !hasBody {
- if !pc.t.putIdleConn(pc) {
- alive = false
- }
+ alive = !pc.sawEOF &&
+ pc.wroteRequest() &&
+ pc.t.putIdleConn(pc)
}
rc.ch <- responseAndError{resp, err}
@@ -775,10 +925,14 @@ func (pc *persistConn) readLoop() {
// Wait for the just-returned response body to be fully consumed
// before we race and peek on the underlying bufio reader.
if waitForBodyRead != nil {
- alive = <-waitForBodyRead
+ select {
+ case alive = <-waitForBodyRead:
+ case <-pc.closech:
+ alive = false
+ }
}
- pc.t.setReqConn(rc.req, nil)
+ pc.t.setReqCanceler(rc.req, nil)
if !alive {
pc.close()
@@ -800,14 +954,44 @@ func (pc *persistConn) writeLoop() {
}
if err != nil {
pc.markBroken()
+ wr.req.Request.closeBody()
}
- wr.ch <- err
+ pc.writeErrCh <- err // to the body reader, which might recycle us
+ wr.ch <- err // to the roundTrip function
case <-pc.closech:
return
}
}
}
+// wroteRequest is a check before recycling a connection that the previous write
+// (from writeLoop above) happened and was successful.
+func (pc *persistConn) wroteRequest() bool {
+ select {
+ case err := <-pc.writeErrCh:
+ // Common case: the write happened well before the response, so
+ // avoid creating a timer.
+ return err == nil
+ default:
+ // Rare case: the request was written in writeLoop above but
+ // before it could send to pc.writeErrCh, the reader read it
+ // all, processed it, and called us here. In this case, give the
+ // write goroutine a bit of time to finish its send.
+ //
+ // Less rare case: We also get here in the legitimate case of
+ // Issue 7569, where the writer is still writing (or stalled),
+ // but the server has already replied. In this case, we don't
+ // want to wait too long, and we want to return false so this
+ // connection isn't re-used.
+ select {
+ case err := <-pc.writeErrCh:
+ return err == nil
+ case <-time.After(50 * time.Millisecond):
+ return false
+ }
+ }
+}
+
type responseAndError struct {
res *Response
err error
@@ -832,8 +1016,20 @@ type writeRequest struct {
ch chan<- error
}
+type httpError struct {
+ err string
+ timeout bool
+}
+
+func (e *httpError) Error() string { return e.err }
+func (e *httpError) Timeout() bool { return e.timeout }
+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"}
+
func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err error) {
- pc.t.setReqConn(req.Request, pc)
+ pc.t.setReqCanceler(req.Request, pc.cancelRequest)
pc.lk.Lock()
pc.numExpectedResponses++
headerFn := pc.mutateHeaderFunc
@@ -844,11 +1040,14 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err
}
// Ask for a compressed version if the caller didn't set their
- // own value for Accept-Encoding. We only attempted to
+ // own value for Accept-Encoding. We only attempt to
// uncompress the gzip stream if we were the layer that
// requested it.
requestedGzip := false
- if !pc.t.DisableCompression && req.Header.Get("Accept-Encoding") == "" && req.Method != "HEAD" {
+ if !pc.t.DisableCompression &&
+ req.Header.Get("Accept-Encoding") == "" &&
+ req.Header.Get("Range") == "" &&
+ req.Method != "HEAD" {
// Request gzip only, not deflate. Deflate is ambiguous and
// not as universally supported anyway.
// See: http://www.gzip.org/zlib/zlib_faq.html#faq38
@@ -857,6 +1056,10 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err
// due to a bug in nginx:
// http://trac.nginx.org/nginx/ticket/358
// http://golang.org/issue/5522
+ //
+ // We don't request gzip if the request is for a range, since
+ // auto-decoding a portion of a gzipped document will just fail
+ // anyway. See http://golang.org/issue/8923
requestedGzip = true
req.extraHeaders().Set("Accept-Encoding", "gzip")
}
@@ -902,11 +1105,11 @@ WaitResponse:
pconnDeadCh = nil // avoid spinning
failTicker = time.After(100 * time.Millisecond) // arbitrary time to wait for resc
case <-failTicker:
- re = responseAndError{err: errors.New("net/http: transport closed before response was received")}
+ re = responseAndError{err: errClosed}
break WaitResponse
case <-respHeaderTimer:
pc.close()
- re = responseAndError{err: errors.New("net/http: timeout awaiting response headers")}
+ re = responseAndError{err: errTimeout}
break WaitResponse
case re = <-resc:
break WaitResponse
@@ -918,7 +1121,7 @@ WaitResponse:
pc.lk.Unlock()
if re.err != nil {
- pc.t.setReqConn(req.Request, nil)
+ pc.t.setReqCanceler(req.Request, nil)
}
return re.res, re.err
}
@@ -943,6 +1146,7 @@ func (pc *persistConn) closeLocked() {
if !pc.closed {
pc.conn.Close()
pc.closed = true
+ close(pc.closech)
}
pc.mutateHeaderFunc = nil
}
@@ -1025,7 +1229,47 @@ func (es *bodyEOFSignal) condfn(err error) {
es.fn = nil
}
+// gzipReader wraps a response body so it can lazily
+// call gzip.NewReader on the first call to Read
+type gzipReader struct {
+ body io.ReadCloser // underlying Response.Body
+ zr io.Reader // lazily-initialized gzip reader
+}
+
+func (gz *gzipReader) Read(p []byte) (n int, err error) {
+ if gz.zr == nil {
+ gz.zr, err = gzip.NewReader(gz.body)
+ if err != nil {
+ return 0, err
+ }
+ }
+ return gz.zr.Read(p)
+}
+
+func (gz *gzipReader) Close() error {
+ return gz.body.Close()
+}
+
type readerAndCloser struct {
io.Reader
io.Closer
}
+
+type tlsHandshakeTimeoutError struct{}
+
+func (tlsHandshakeTimeoutError) Timeout() bool { return true }
+func (tlsHandshakeTimeoutError) Temporary() bool { return true }
+func (tlsHandshakeTimeoutError) Error() string { return "net/http: TLS handshake timeout" }
+
+type noteEOFReader struct {
+ r io.Reader
+ sawEOF *bool
+}
+
+func (nr noteEOFReader) Read(p []byte) (n int, err error) {
+ n, err = nr.r.Read(p)
+ if err == io.EOF {
+ *nr.sawEOF = true
+ }
+ return
+}
diff --git a/libgo/go/net/http/transport_test.go b/libgo/go/net/http/transport_test.go
index e4df30a98d..defa633708 100644
--- a/libgo/go/net/http/transport_test.go
+++ b/libgo/go/net/http/transport_test.go
@@ -11,9 +11,12 @@ import (
"bytes"
"compress/gzip"
"crypto/rand"
+ "crypto/tls"
+ "errors"
"fmt"
"io"
"io/ioutil"
+ "log"
"net"
"net/http"
. "net/http"
@@ -54,21 +57,21 @@ func (c *testCloseConn) Close() error {
// been closed.
type testConnSet struct {
t *testing.T
+ mu sync.Mutex // guards closed and list
closed map[net.Conn]bool
list []net.Conn // in order created
- mutex sync.Mutex
}
func (tcs *testConnSet) insert(c net.Conn) {
- tcs.mutex.Lock()
- defer tcs.mutex.Unlock()
+ tcs.mu.Lock()
+ defer tcs.mu.Unlock()
tcs.closed[c] = false
tcs.list = append(tcs.list, c)
}
func (tcs *testConnSet) remove(c net.Conn) {
- tcs.mutex.Lock()
- defer tcs.mutex.Unlock()
+ tcs.mu.Lock()
+ defer tcs.mu.Unlock()
tcs.closed[c] = true
}
@@ -91,11 +94,19 @@ func makeTestDial(t *testing.T) (*testConnSet, func(n, addr string) (net.Conn, e
}
func (tcs *testConnSet) check(t *testing.T) {
- tcs.mutex.Lock()
- defer tcs.mutex.Unlock()
-
- for i, c := range tcs.list {
- if !tcs.closed[c] {
+ tcs.mu.Lock()
+ defer tcs.mu.Unlock()
+ for i := 4; i >= 0; i-- {
+ for i, c := range tcs.list {
+ if tcs.closed[c] {
+ continue
+ }
+ if i != 0 {
+ tcs.mu.Unlock()
+ time.Sleep(50 * time.Millisecond)
+ tcs.mu.Lock()
+ continue
+ }
t.Errorf("TCP connection #%d, %p (of %d total) was not closed", i+1, c, len(tcs.list))
}
}
@@ -271,6 +282,58 @@ func TestTransportIdleCacheKeys(t *testing.T) {
}
}
+// Tests that the HTTP transport re-uses connections when a client
+// reads to the end of a response Body without closing it.
+func TestTransportReadToEndReusesConn(t *testing.T) {
+ defer afterTest(t)
+ const msg = "foobar"
+
+ var addrSeen map[string]int
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ addrSeen[r.RemoteAddr]++
+ if r.URL.Path == "/chunked/" {
+ w.WriteHeader(200)
+ w.(http.Flusher).Flush()
+ } else {
+ w.Header().Set("Content-Type", strconv.Itoa(len(msg)))
+ w.WriteHeader(200)
+ }
+ w.Write([]byte(msg))
+ }))
+ defer ts.Close()
+
+ buf := make([]byte, len(msg))
+
+ for pi, path := range []string{"/content-length/", "/chunked/"} {
+ wantLen := []int{len(msg), -1}[pi]
+ addrSeen = make(map[string]int)
+ for i := 0; i < 3; i++ {
+ res, err := http.Get(ts.URL + path)
+ if err != nil {
+ t.Errorf("Get %s: %v", path, err)
+ continue
+ }
+ // We want to close this body eventually (before the
+ // defer afterTest at top runs), but not before the
+ // len(addrSeen) check at the bottom of this test,
+ // since Closing this early in the loop would risk
+ // making connections be re-used for the wrong reason.
+ defer res.Body.Close()
+
+ if res.ContentLength != int64(wantLen) {
+ t.Errorf("%s res.ContentLength = %d; want %d", path, res.ContentLength, wantLen)
+ }
+ n, err := res.Body.Read(buf)
+ if n != len(msg) || err != io.EOF {
+ t.Errorf("%s Read = %v, %v; want %d, EOF", path, n, err, len(msg))
+ }
+ }
+ if len(addrSeen) != 1 {
+ t.Errorf("for %s, server saw %d distinct client addresses; want 1", path, len(addrSeen))
+ }
+ }
+}
+
func TestTransportMaxPerHostIdleConns(t *testing.T) {
defer afterTest(t)
resch := make(chan string)
@@ -295,10 +358,11 @@ func TestTransportMaxPerHostIdleConns(t *testing.T) {
resp, err := c.Get(ts.URL)
if err != nil {
t.Error(err)
+ return
}
- _, err = ioutil.ReadAll(resp.Body)
- if err != nil {
- t.Fatalf("ReadAll: %v", err)
+ if _, err := ioutil.ReadAll(resp.Body); err != nil {
+ t.Errorf("ReadAll: %v", err)
+ return
}
donech <- true
}
@@ -739,8 +803,38 @@ func TestTransportGzipRecursive(t *testing.T) {
}
}
+// golang.org/issue/7750: request fails when server replies with
+// a short gzip body
+func TestTransportGzipShort(t *testing.T) {
+ defer afterTest(t)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header().Set("Content-Encoding", "gzip")
+ w.Write([]byte{0x1f, 0x8b})
+ }))
+ defer ts.Close()
+
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+ c := &Client{Transport: tr}
+ res, err := c.Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+ _, err = ioutil.ReadAll(res.Body)
+ if err == nil {
+ t.Fatal("Expect an error from reading a body.")
+ }
+ if err != io.ErrUnexpectedEOF {
+ t.Errorf("ReadAll error = %v; want io.ErrUnexpectedEOF", err)
+ }
+}
+
// 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")
+ }
defer afterTest(t)
gotReqCh := make(chan bool)
unblockCh := make(chan bool)
@@ -798,8 +892,8 @@ func TestTransportPersistConnLeak(t *testing.T) {
// We expect 0 or 1 extra goroutine, empirically. Allow up to 5.
// Previously we were leaking one per numReq.
- t.Logf("goroutine growth: %d -> %d -> %d (delta: %d)", n0, nhigh, nfinal, growth)
if int(growth) > 5 {
+ t.Logf("goroutine growth: %d -> %d -> %d (delta: %d)", n0, nhigh, nfinal, growth)
t.Error("too many new goroutines")
}
}
@@ -807,6 +901,9 @@ func TestTransportPersistConnLeak(t *testing.T) {
// golang.org/issue/4531: Transport leaks goroutines when
// request.ContentLength is explicitly short
func TestTransportPersistConnLeakShortBody(t *testing.T) {
+ if runtime.GOOS == "plan9" {
+ t.Skip("skipping test; see http://golang.org/issue/7237")
+ }
defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
}))
@@ -966,20 +1063,18 @@ func TestTransportConcurrency(t *testing.T) {
var wg sync.WaitGroup
wg.Add(numReqs)
- tr := &Transport{
- Dial: func(netw, addr string) (c net.Conn, err error) {
- // Due to the Transport's "socket late
- // binding" (see idleConnCh in transport.go),
- // the numReqs HTTP requests below can finish
- // with a dial still outstanding. So count
- // our dials as work too so the leak checker
- // doesn't complain at us.
- wg.Add(1)
- defer wg.Done()
- return net.Dial(netw, addr)
- },
- }
+ // Due to the Transport's "socket late binding" (see
+ // idleConnCh in transport.go), the numReqs HTTP requests
+ // below can finish with a dial still outstanding. To keep
+ // the leak checker happy, keep track of pending dials and
+ // wait for them to finish (and be closed or returned to the
+ // idle pool) before we close idle connections.
+ SetPendingDialHooks(func() { wg.Add(1) }, wg.Done)
+ defer SetPendingDialHooks(nil, nil)
+
+ tr := &Transport{}
defer tr.CloseIdleConnections()
+
c := &Client{Transport: tr}
reqs := make(chan string)
defer close(reqs)
@@ -1014,6 +1109,9 @@ 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")
+ }
defer afterTest(t)
const debug = false
mux := NewServeMux()
@@ -1075,6 +1173,9 @@ 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")
+ }
defer afterTest(t)
const debug = false
mux := NewServeMux()
@@ -1147,9 +1248,13 @@ func TestTransportResponseHeaderTimeout(t *testing.T) {
if testing.Short() {
t.Skip("skipping timeout test in -short mode")
}
+ inHandler := make(chan bool, 1)
mux := NewServeMux()
- mux.HandleFunc("/fast", func(w ResponseWriter, r *Request) {})
+ mux.HandleFunc("/fast", func(w ResponseWriter, r *Request) {
+ inHandler <- true
+ })
mux.HandleFunc("/slow", func(w ResponseWriter, r *Request) {
+ inHandler <- true
time.Sleep(2 * time.Second)
})
ts := httptest.NewServer(mux)
@@ -1172,7 +1277,27 @@ func TestTransportResponseHeaderTimeout(t *testing.T) {
}
for i, tt := range tests {
res, err := c.Get(ts.URL + tt.path)
+ select {
+ case <-inHandler:
+ case <-time.After(5 * time.Second):
+ t.Errorf("never entered handler for test index %d, %s", i, tt.path)
+ continue
+ }
if err != nil {
+ uerr, ok := err.(*url.Error)
+ if !ok {
+ t.Errorf("error is not an url.Error; got: %#v", err)
+ continue
+ }
+ nerr, ok := uerr.Err.(net.Error)
+ if !ok {
+ t.Errorf("error does not satisfy net.Error interface; got: %#v", err)
+ continue
+ }
+ if !nerr.Timeout() {
+ t.Errorf("want timeout error; got: %q", nerr)
+ continue
+ }
if strings.Contains(err.Error(), tt.wantErr) {
continue
}
@@ -1243,6 +1368,60 @@ func TestTransportCancelRequest(t *testing.T) {
}
}
+func TestTransportCancelRequestInDial(t *testing.T) {
+ defer afterTest(t)
+ if testing.Short() {
+ t.Skip("skipping test in -short mode")
+ }
+ var logbuf bytes.Buffer
+ eventLog := log.New(&logbuf, "", 0)
+
+ unblockDial := make(chan bool)
+ defer close(unblockDial)
+
+ inDial := make(chan bool)
+ tr := &Transport{
+ Dial: func(network, addr string) (net.Conn, error) {
+ eventLog.Println("dial: blocking")
+ inDial <- true
+ <-unblockDial
+ return nil, errors.New("nope")
+ },
+ }
+ cl := &Client{Transport: tr}
+ gotres := make(chan bool)
+ req, _ := NewRequest("GET", "http://something.no-network.tld/", nil)
+ go func() {
+ _, err := cl.Do(req)
+ eventLog.Printf("Get = %v", err)
+ gotres <- true
+ }()
+
+ select {
+ case <-inDial:
+ case <-time.After(5 * time.Second):
+ t.Fatal("timeout; never saw blocking dial")
+ }
+
+ eventLog.Printf("canceling")
+ tr.CancelRequest(req)
+
+ select {
+ case <-gotres:
+ case <-time.After(5 * time.Second):
+ panic("hang. events are: " + logbuf.String())
+ }
+
+ got := logbuf.String()
+ want := `dial: blocking
+canceling
+Get = Get http://something.no-network.tld/: net/http: request canceled while waiting for connection
+`
+ if got != want {
+ t.Errorf("Got events:\n%s\nWant:\n%s", got, want)
+ }
+}
+
// 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.
@@ -1283,7 +1462,7 @@ func TestTransportCloseResponseBody(t *testing.T) {
t.Fatal(err)
}
if !bytes.Equal(buf, want) {
- t.Errorf("read %q; want %q", buf, want)
+ t.Fatalf("read %q; want %q", buf, want)
}
didClose := make(chan error, 1)
go func() {
@@ -1372,8 +1551,10 @@ func TestTransportSocketLateBinding(t *testing.T) {
dialGate := make(chan bool, 1)
tr := &Transport{
Dial: func(n, addr string) (net.Conn, error) {
- <-dialGate
- return net.Dial(n, addr)
+ if <-dialGate {
+ return net.Dial(n, addr)
+ }
+ return nil, errors.New("manually closed")
},
DisableKeepAlives: false,
}
@@ -1408,7 +1589,7 @@ func TestTransportSocketLateBinding(t *testing.T) {
t.Fatalf("/foo came from conn %q; /bar came from %q instead", fooAddr, barAddr)
}
barRes.Body.Close()
- dialGate <- true
+ dialGate <- false
}
// Issue 2184
@@ -1520,26 +1701,40 @@ Content-Length: %d
}
type proxyFromEnvTest struct {
- req string // URL to fetch; blank means "http://example.com"
- env string
- noenv string
+ req string // URL to fetch; blank means "http://example.com"
+
+ env string // HTTP_PROXY
+ httpsenv string // HTTPS_PROXY
+ noenv string // NO_RPXY
+
want string
wanterr error
}
func (t proxyFromEnvTest) String() string {
var buf bytes.Buffer
+ space := func() {
+ if buf.Len() > 0 {
+ buf.WriteByte(' ')
+ }
+ }
if t.env != "" {
fmt.Fprintf(&buf, "http_proxy=%q", t.env)
}
+ if t.httpsenv != "" {
+ space()
+ fmt.Fprintf(&buf, "https_proxy=%q", t.httpsenv)
+ }
if t.noenv != "" {
- fmt.Fprintf(&buf, " no_proxy=%q", t.noenv)
+ space()
+ fmt.Fprintf(&buf, "no_proxy=%q", t.noenv)
}
req := "http://example.com"
if t.req != "" {
req = t.req
}
- fmt.Fprintf(&buf, " req=%q", req)
+ space()
+ fmt.Fprintf(&buf, "req=%q", req)
return strings.TrimSpace(buf.String())
}
@@ -1550,7 +1745,15 @@ var proxyFromEnvTests = []proxyFromEnvTest{
{env: "https://cache.corp.example.com", want: "https://cache.corp.example.com"},
{env: "http://127.0.0.1:8080", want: "http://127.0.0.1:8080"},
{env: "https://127.0.0.1:8080", want: "https://127.0.0.1:8080"},
+
+ // Don't use secure for http
+ {req: "http://insecure.tld/", env: "http.proxy.tld", httpsenv: "secure.proxy.tld", want: "http://http.proxy.tld"},
+ // Use secure for https.
+ {req: "https://secure.tld/", env: "http.proxy.tld", httpsenv: "secure.proxy.tld", want: "http://secure.proxy.tld"},
+ {req: "https://secure.tld/", env: "http.proxy.tld", httpsenv: "https://secure.proxy.tld", want: "https://secure.proxy.tld"},
+
{want: "<nil>"},
+
{noenv: "example.com", req: "http://example.com/", env: "proxy", want: "<nil>"},
{noenv: ".example.com", req: "http://example.com/", env: "proxy", want: "<nil>"},
{noenv: "ample.com", req: "http://example.com/", env: "proxy", want: "http://proxy"},
@@ -1559,13 +1762,12 @@ var proxyFromEnvTests = []proxyFromEnvTest{
}
func TestProxyFromEnvironment(t *testing.T) {
- os.Setenv("HTTP_PROXY", "")
- os.Setenv("http_proxy", "")
- os.Setenv("NO_PROXY", "")
- os.Setenv("no_proxy", "")
+ ResetProxyEnv()
for _, tt := range proxyFromEnvTests {
os.Setenv("HTTP_PROXY", tt.env)
+ os.Setenv("HTTPS_PROXY", tt.httpsenv)
os.Setenv("NO_PROXY", tt.noenv)
+ ResetCachedEnvironment()
reqURL := tt.req
if reqURL == "" {
reqURL = "http://example.com"
@@ -1643,6 +1845,438 @@ func TestTransportClosesRequestBody(t *testing.T) {
}
}
+func TestTransportTLSHandshakeTimeout(t *testing.T) {
+ defer afterTest(t)
+ if testing.Short() {
+ t.Skip("skipping in short mode")
+ }
+ ln := newLocalListener(t)
+ defer ln.Close()
+ testdonec := make(chan struct{})
+ defer close(testdonec)
+
+ go func() {
+ c, err := ln.Accept()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ <-testdonec
+ c.Close()
+ }()
+
+ getdonec := make(chan struct{})
+ go func() {
+ defer close(getdonec)
+ tr := &Transport{
+ Dial: func(_, _ string) (net.Conn, error) {
+ return net.Dial("tcp", ln.Addr().String())
+ },
+ TLSHandshakeTimeout: 250 * time.Millisecond,
+ }
+ cl := &Client{Transport: tr}
+ _, err := cl.Get("https://dummy.tld/")
+ if err == nil {
+ t.Error("expected error")
+ return
+ }
+ ue, ok := err.(*url.Error)
+ if !ok {
+ t.Errorf("expected url.Error; got %#v", err)
+ return
+ }
+ ne, ok := ue.Err.(net.Error)
+ if !ok {
+ t.Errorf("expected net.Error; got %#v", err)
+ return
+ }
+ if !ne.Timeout() {
+ t.Errorf("expected timeout error; got %v", err)
+ }
+ if !strings.Contains(err.Error(), "handshake timeout") {
+ t.Errorf("expected 'handshake timeout' in error; got %v", err)
+ }
+ }()
+ select {
+ case <-getdonec:
+ case <-time.After(5 * time.Second):
+ t.Error("test timeout; TLS handshake hung?")
+ }
+}
+
+// Trying to repro golang.org/issue/3514
+func TestTLSServerClosesConnection(t *testing.T) {
+ defer afterTest(t)
+ if runtime.GOOS == "windows" {
+ t.Skip("skipping flaky test on Windows; golang.org/issue/7634")
+ }
+ closedc := make(chan bool, 1)
+ ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ if strings.Contains(r.URL.Path, "/keep-alive-then-die") {
+ conn, _, _ := w.(Hijacker).Hijack()
+ conn.Write([]byte("HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nfoo"))
+ conn.Close()
+ closedc <- true
+ return
+ }
+ fmt.Fprintf(w, "hello")
+ }))
+ defer ts.Close()
+ tr := &Transport{
+ TLSClientConfig: &tls.Config{
+ InsecureSkipVerify: true,
+ },
+ }
+ defer tr.CloseIdleConnections()
+ client := &Client{Transport: tr}
+
+ var nSuccess = 0
+ var errs []error
+ const trials = 20
+ for i := 0; i < trials; i++ {
+ tr.CloseIdleConnections()
+ res, err := client.Get(ts.URL + "/keep-alive-then-die")
+ if err != nil {
+ t.Fatal(err)
+ }
+ <-closedc
+ slurp, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if string(slurp) != "foo" {
+ t.Errorf("Got %q, want foo", slurp)
+ }
+
+ // Now try again and see if we successfully
+ // pick a new connection.
+ res, err = client.Get(ts.URL + "/")
+ if err != nil {
+ errs = append(errs, err)
+ continue
+ }
+ slurp, err = ioutil.ReadAll(res.Body)
+ if err != nil {
+ errs = append(errs, err)
+ continue
+ }
+ nSuccess++
+ }
+ if nSuccess > 0 {
+ t.Logf("successes = %d of %d", nSuccess, trials)
+ } else {
+ t.Errorf("All runs failed:")
+ }
+ for _, err := range errs {
+ t.Logf(" err: %v", err)
+ }
+}
+
+// byteFromChanReader is an io.Reader that reads a single byte at a
+// time from the channel. When the channel is closed, the reader
+// returns io.EOF.
+type byteFromChanReader chan byte
+
+func (c byteFromChanReader) Read(p []byte) (n int, err error) {
+ if len(p) == 0 {
+ return
+ }
+ b, ok := <-c
+ if !ok {
+ return 0, io.EOF
+ }
+ p[0] = b
+ return 1, nil
+}
+
+// Verifies that the Transport doesn't reuse a connection in the case
+// where the server replies before the request has been fully
+// written. We still honor that reply (see TestIssue3595), but don't
+// send future requests on the connection because it's then in a
+// questionable state.
+// golang.org/issue/7569
+func TestTransportNoReuseAfterEarlyResponse(t *testing.T) {
+ defer afterTest(t)
+ var sconn struct {
+ sync.Mutex
+ c net.Conn
+ }
+ var getOkay bool
+ closeConn := func() {
+ sconn.Lock()
+ defer sconn.Unlock()
+ if sconn.c != nil {
+ sconn.c.Close()
+ sconn.c = nil
+ if !getOkay {
+ t.Logf("Closed server connection")
+ }
+ }
+ }
+ defer closeConn()
+
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ if r.Method == "GET" {
+ io.WriteString(w, "bar")
+ return
+ }
+ conn, _, _ := w.(Hijacker).Hijack()
+ sconn.Lock()
+ sconn.c = conn
+ sconn.Unlock()
+ conn.Write([]byte("HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nfoo")) // keep-alive
+ go io.Copy(ioutil.Discard, conn)
+ }))
+ defer ts.Close()
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+ client := &Client{Transport: tr}
+
+ const bodySize = 256 << 10
+ finalBit := make(byteFromChanReader, 1)
+ req, _ := NewRequest("POST", ts.URL, io.MultiReader(io.LimitReader(neverEnding('x'), bodySize-1), finalBit))
+ req.ContentLength = bodySize
+ res, err := client.Do(req)
+ if err := wantBody(res, err, "foo"); err != nil {
+ t.Errorf("POST response: %v", err)
+ }
+ donec := make(chan bool)
+ go func() {
+ defer close(donec)
+ res, err = client.Get(ts.URL)
+ if err := wantBody(res, err, "bar"); err != nil {
+ t.Errorf("GET response: %v", err)
+ return
+ }
+ getOkay = true // suppress test noise
+ }()
+ time.AfterFunc(5*time.Second, closeConn)
+ select {
+ case <-donec:
+ finalBit <- 'x' // unblock the writeloop of the first Post
+ close(finalBit)
+ case <-time.After(7 * time.Second):
+ t.Fatal("timeout waiting for GET request to finish")
+ }
+}
+
+type errorReader struct {
+ err error
+}
+
+func (e errorReader) Read(p []byte) (int, error) { return 0, e.err }
+
+type closerFunc func() error
+
+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")
+ }
+ defer afterTest(t)
+ readBody := make(chan error, 1)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ _, err := ioutil.ReadAll(r.Body)
+ readBody <- err
+ }))
+ defer ts.Close()
+ fakeErr := errors.New("fake error")
+ didClose := make(chan bool, 1)
+ req, _ := NewRequest("POST", ts.URL, struct {
+ io.Reader
+ io.Closer
+ }{
+ io.MultiReader(io.LimitReader(neverEnding('x'), 1<<20), errorReader{fakeErr}),
+ closerFunc(func() error {
+ select {
+ case didClose <- true:
+ default:
+ }
+ return nil
+ }),
+ })
+ res, err := DefaultClient.Do(req)
+ if res != nil {
+ defer res.Body.Close()
+ }
+ if err == nil || !strings.Contains(err.Error(), fakeErr.Error()) {
+ t.Fatalf("Do error = %v; want something containing %q", err, fakeErr.Error())
+ }
+ select {
+ case err := <-readBody:
+ if err == nil {
+ t.Errorf("Unexpected success reading request body from handler; want 'unexpected EOF reading trailer'")
+ }
+ case <-time.After(5 * time.Second):
+ t.Error("timeout waiting for server handler to complete")
+ }
+ select {
+ case <-didClose:
+ default:
+ t.Errorf("didn't see Body.Close")
+ }
+}
+
+func TestTransportDialTLS(t *testing.T) {
+ var mu sync.Mutex // guards following
+ var gotReq, didDial bool
+
+ ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ mu.Lock()
+ gotReq = true
+ mu.Unlock()
+ }))
+ defer ts.Close()
+ tr := &Transport{
+ DialTLS: func(netw, addr string) (net.Conn, error) {
+ mu.Lock()
+ didDial = true
+ mu.Unlock()
+ c, err := tls.Dial(netw, addr, &tls.Config{
+ InsecureSkipVerify: true,
+ })
+ if err != nil {
+ return nil, err
+ }
+ return c, c.Handshake()
+ },
+ }
+ defer tr.CloseIdleConnections()
+ client := &Client{Transport: tr}
+ res, err := client.Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ res.Body.Close()
+ mu.Lock()
+ if !gotReq {
+ t.Error("didn't get request")
+ }
+ if !didDial {
+ t.Error("didn't use dial hook")
+ }
+}
+
+// Test for issue 8755
+// Ensure that if a proxy returns an error, it is exposed by RoundTrip
+func TestRoundTripReturnsProxyError(t *testing.T) {
+ badProxy := func(*http.Request) (*url.URL, error) {
+ return nil, errors.New("errorMessage")
+ }
+
+ tr := &Transport{Proxy: badProxy}
+
+ req, _ := http.NewRequest("GET", "http://example.com", nil)
+
+ _, err := tr.RoundTrip(req)
+
+ if err == nil {
+ t.Error("Expected proxy error to be returned by RoundTrip")
+ }
+}
+
+// tests that putting an idle conn after a call to CloseIdleConns does return it
+func TestTransportCloseIdleConnsThenReturn(t *testing.T) {
+ tr := &Transport{}
+ wantIdle := func(when string, n int) bool {
+ got := tr.IdleConnCountForTesting("|http|example.com") // key used by PutIdleTestConn
+ if got == n {
+ return true
+ }
+ t.Errorf("%s: idle conns = %d; want %d", when, got, n)
+ return false
+ }
+ wantIdle("start", 0)
+ if !tr.PutIdleTestConn() {
+ t.Fatal("put failed")
+ }
+ if !tr.PutIdleTestConn() {
+ t.Fatal("second put failed")
+ }
+ wantIdle("after put", 2)
+ tr.CloseIdleConnections()
+ if !tr.IsIdleForTesting() {
+ t.Error("should be idle after CloseIdleConnections")
+ }
+ wantIdle("after close idle", 0)
+ if tr.PutIdleTestConn() {
+ t.Fatal("put didn't fail")
+ }
+ wantIdle("after second put", 0)
+
+ tr.RequestIdleConnChForTesting() // should toggle the transport out of idle mode
+ if tr.IsIdleForTesting() {
+ t.Error("shouldn't be idle after RequestIdleConnChForTesting")
+ }
+ if !tr.PutIdleTestConn() {
+ t.Fatal("after re-activation")
+ }
+ wantIdle("after final put", 1)
+}
+
+// This tests that an client requesting a content range won't also
+// implicitly ask for gzip support. If they want that, they need to do it
+// on their own.
+// golang.org/issue/8923
+func TestTransportRangeAndGzip(t *testing.T) {
+ defer afterTest(t)
+ reqc := make(chan *Request, 1)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ reqc <- r
+ }))
+ defer ts.Close()
+
+ req, _ := NewRequest("GET", ts.URL, nil)
+ req.Header.Set("Range", "bytes=7-11")
+ res, err := DefaultClient.Do(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ select {
+ case r := <-reqc:
+ if strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
+ t.Error("Transport advertised gzip support in the Accept header")
+ }
+ if r.Header.Get("Range") == "" {
+ t.Error("no Range in request")
+ }
+ case <-time.After(10 * time.Second):
+ t.Fatal("timeout")
+ }
+ res.Body.Close()
+}
+
+func wantBody(res *http.Response, err error, want string) error {
+ if err != nil {
+ return err
+ }
+ slurp, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ return fmt.Errorf("error reading body: %v", err)
+ }
+ if string(slurp) != want {
+ return fmt.Errorf("body = %q; want %q", slurp, want)
+ }
+ if err := res.Body.Close(); err != nil {
+ return fmt.Errorf("body Close = %v", err)
+ }
+ return nil
+}
+
+func newLocalListener(t *testing.T) net.Listener {
+ ln, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ ln, err = net.Listen("tcp6", "[::1]:0")
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+ return ln
+}
+
type countCloseReader struct {
n *int
io.Reader
diff --git a/libgo/go/net/interface.go b/libgo/go/net/interface.go
index 0713e9cd6a..2e9f1ebc67 100644
--- a/libgo/go/net/interface.go
+++ b/libgo/go/net/interface.go
@@ -7,11 +7,11 @@ package net
import "errors"
var (
- errInvalidInterface = errors.New("net: invalid interface")
- errInvalidInterfaceIndex = errors.New("net: invalid interface index")
- errInvalidInterfaceName = errors.New("net: invalid interface name")
- errNoSuchInterface = errors.New("net: no such interface")
- errNoSuchMulticastInterface = errors.New("net: no such multicast interface")
+ errInvalidInterface = errors.New("invalid network interface")
+ errInvalidInterfaceIndex = errors.New("invalid network interface index")
+ errInvalidInterfaceName = errors.New("invalid network interface name")
+ errNoSuchInterface = errors.New("no such network interface")
+ errNoSuchMulticastInterface = errors.New("no such multicast network interface")
)
// Interface represents a mapping between network interface name
diff --git a/libgo/go/net/interface_linux.go b/libgo/go/net/interface_linux.go
index 1207c0f269..1115d0fc40 100644
--- a/libgo/go/net/interface_linux.go
+++ b/libgo/go/net/interface_linux.go
@@ -45,15 +45,41 @@ loop:
return ift, nil
}
+const (
+ // See linux/if_arp.h.
+ // Note that Linux doesn't support IPv4 over IPv6 tunneling.
+ sysARPHardwareIPv4IPv4 = 768 // IPv4 over IPv4 tunneling
+ sysARPHardwareIPv6IPv6 = 769 // IPv6 over IPv6 tunneling
+ sysARPHardwareIPv6IPv4 = 776 // IPv6 over IPv4 tunneling
+ sysARPHardwareGREIPv4 = 778 // any over GRE over IPv4 tunneling
+ sysARPHardwareGREIPv6 = 823 // any over GRE over IPv6 tunneling
+)
+
func newLink(ifim *syscall.IfInfomsg, attrs []syscall.NetlinkRouteAttr) *Interface {
ifi := &Interface{Index: int(ifim.Index), Flags: linkFlags(ifim.Flags)}
for _, a := range attrs {
switch a.Attr.Type {
case syscall.IFLA_ADDRESS:
+ // We never return any /32 or /128 IP address
+ // prefix on any IP tunnel interface as the
+ // hardware address.
+ switch len(a.Value) {
+ case IPv4len:
+ switch ifim.Type {
+ case sysARPHardwareIPv4IPv4, sysARPHardwareGREIPv4, sysARPHardwareIPv6IPv4:
+ continue
+ }
+ case IPv6len:
+ switch ifim.Type {
+ case sysARPHardwareIPv6IPv6, sysARPHardwareGREIPv6:
+ continue
+ }
+ }
var nonzero bool
for _, b := range a.Value {
if b != 0 {
nonzero = true
+ break
}
}
if nonzero {
@@ -147,19 +173,31 @@ loop:
}
func newAddr(ifi *Interface, ifam *syscall.IfAddrmsg, attrs []syscall.NetlinkRouteAttr) Addr {
- for _, a := range attrs {
- if ifi.Flags&FlagPointToPoint != 0 && a.Attr.Type == syscall.IFA_LOCAL ||
- ifi.Flags&FlagPointToPoint == 0 && a.Attr.Type == syscall.IFA_ADDRESS {
- switch ifam.Family {
- case syscall.AF_INET:
- return &IPNet{IP: IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3]), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv4len)}
- case syscall.AF_INET6:
- ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv6len)}
- copy(ifa.IP, a.Value[:])
- return ifa
+ 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
}
}
}
+ for _, a := range attrs {
+ if ipPointToPoint && a.Attr.Type == syscall.IFA_ADDRESS || !ipPointToPoint && a.Attr.Type == syscall.IFA_LOCAL {
+ continue
+ }
+ switch ifam.Family {
+ case syscall.AF_INET:
+ return &IPNet{IP: IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3]), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv4len)}
+ case syscall.AF_INET6:
+ ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv6len)}
+ copy(ifa.IP, a.Value[:])
+ return ifa
+ }
+ }
return nil
}
diff --git a/libgo/go/net/interface_stub.go b/libgo/go/net/interface_stub.go
index a4eb731da4..c38fb7f765 100644
--- a/libgo/go/net/interface_stub.go
+++ b/libgo/go/net/interface_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 plan9
+// +build nacl plan9 solaris
package net
diff --git a/libgo/go/net/ip.go b/libgo/go/net/ip.go
index fd6a7d4ee8..4a93e97b39 100644
--- a/libgo/go/net/ip.go
+++ b/libgo/go/net/ip.go
@@ -287,6 +287,7 @@ func (ip IP) String() string {
if j > i && j-i > e1-e0 {
e0 = i
e1 = j
+ i = j
}
}
// The symbol "::" MUST NOT be used to shorten just one 16 bit 0 field.
@@ -295,21 +296,23 @@ func (ip IP) String() string {
e1 = -1
}
+ const maxLen = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
+ b := make([]byte, 0, maxLen)
+
// Print with possible :: in place of run of zeros
- var s string
for i := 0; i < IPv6len; i += 2 {
if i == e0 {
- s += "::"
+ b = append(b, ':', ':')
i = e1
if i >= IPv6len {
break
}
} else if i > 0 {
- s += ":"
+ b = append(b, ':')
}
- s += itox((uint(p[i])<<8)|uint(p[i+1]), 1)
+ b = appendHex(b, (uint32(p[i])<<8)|uint32(p[i+1]))
}
- return s
+ return string(b)
}
// ipEmptyString is like ip.String except that it returns
@@ -419,14 +422,14 @@ func (m IPMask) Size() (ones, bits int) {
// String returns the hexadecimal form of m, with no punctuation.
func (m IPMask) String() string {
- s := ""
- for _, b := range m {
- s += itox(uint(b), 2)
- }
- if len(s) == 0 {
+ if len(m) == 0 {
return "<nil>"
}
- return s
+ buf := make([]byte, len(m)*2)
+ for i, b := range m {
+ buf[i*2], buf[i*2+1] = hexDigit[b>>4], hexDigit[b&0xf]
+ }
+ return string(buf)
}
func networkNumberAndMask(n *IPNet) (ip IP, m IPMask) {
@@ -623,6 +626,9 @@ func parseIPv6(s string, zoneAllowed bool) (ip IP, zone string) {
for k := ellipsis + n - 1; k >= ellipsis; k-- {
ip[k] = 0
}
+ } else if ellipsis >= 0 {
+ // Ellipsis must represent at least one 0 group.
+ return nil, zone
}
return ip, zone
}
@@ -643,11 +649,16 @@ func (e *ParseError) Error() string {
// If s is not a valid textual representation of an IP address,
// ParseIP returns nil.
func ParseIP(s string) IP {
- if ip := parseIPv4(s); ip != nil {
- return ip
+ for i := 0; i < len(s); i++ {
+ switch s[i] {
+ case '.':
+ return parseIPv4(s)
+ case ':':
+ ip, _ := parseIPv6(s, false)
+ return ip
+ }
}
- ip, _ := parseIPv6(s, false)
- return ip
+ return nil
}
// ParseCIDR parses s as a CIDR notation IP address and mask,
diff --git a/libgo/go/net/ip_test.go b/libgo/go/net/ip_test.go
index 26b53729b8..485ff51153 100644
--- a/libgo/go/net/ip_test.go
+++ b/libgo/go/net/ip_test.go
@@ -25,6 +25,7 @@ var parseIPTests = []struct {
{"fe80::1%lo0", nil},
{"fe80::1%911", nil},
{"", nil},
+ {"a1:a2:a3:a4::b1:b2:b3:b4", nil}, // Issue 6628
}
func TestParseIP(t *testing.T) {
@@ -43,6 +44,14 @@ func TestParseIP(t *testing.T) {
}
}
+func BenchmarkParseIP(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ for _, tt := range parseIPTests {
+ ParseIP(tt.in)
+ }
+ }
+}
+
// Issue 6339
func TestMarshalEmptyIP(t *testing.T) {
for _, in := range [][]byte{nil, []byte("")} {
@@ -90,6 +99,16 @@ func TestIPString(t *testing.T) {
}
}
+func BenchmarkIPString(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ for _, tt := range ipStringTests {
+ if tt.in != nil {
+ tt.in.String()
+ }
+ }
+ }
+}
+
var ipMaskTests = []struct {
in IP
mask IPMask
@@ -130,6 +149,14 @@ func TestIPMaskString(t *testing.T) {
}
}
+func BenchmarkIPMaskString(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ for _, tt := range ipMaskStringTests {
+ tt.in.String()
+ }
+ }
+}
+
var parseCIDRTests = []struct {
in string
ip IP
diff --git a/libgo/go/net/ipraw_test.go b/libgo/go/net/ipraw_test.go
index ea183f1d3e..92dc8dc569 100644
--- a/libgo/go/net/ipraw_test.go
+++ b/libgo/go/net/ipraw_test.go
@@ -68,6 +68,11 @@ func skipRawSocketTest(t *testing.T) (skip bool, skipmsg string) {
}
func TestResolveIPAddr(t *testing.T) {
+ switch runtime.GOOS {
+ case "nacl":
+ t.Skipf("skipping test on %q", runtime.GOOS)
+ }
+
for _, tt := range resolveIPAddrTests {
addr, err := ResolveIPAddr(tt.net, tt.litAddrOrName)
if err != tt.err {
@@ -247,7 +252,7 @@ var ipConnLocalNameTests = []struct {
func TestIPConnLocalName(t *testing.T) {
switch runtime.GOOS {
- case "plan9", "windows":
+ case "nacl", "plan9", "windows":
t.Skipf("skipping test on %q", runtime.GOOS)
default:
if os.Getuid() != 0 {
@@ -277,7 +282,7 @@ func TestIPConnRemoteName(t *testing.T) {
}
}
- raddr := &IPAddr{IP: IPv4(127, 0, 0, 10).To4()}
+ 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)
diff --git a/libgo/go/net/iprawsock_posix.go b/libgo/go/net/iprawsock_posix.go
index 7228532576..99b081ba8c 100644
--- a/libgo/go/net/iprawsock_posix.go
+++ b/libgo/go/net/iprawsock_posix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
package net
@@ -19,7 +19,7 @@ import (
// that you do not uses these methods if it is important to receive a
// full packet.
//
-// The Go 1 compatibliity guidelines make it impossible for us to
+// The Go 1 compatibility guidelines make it impossible for us to
// change the behavior of these methods; use Read or ReadMsgIP
// instead.
@@ -79,7 +79,7 @@ func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) {
// TODO(cw,rsc): consider using readv if we know the family
// type to avoid the header trim/copy
var addr *IPAddr
- n, sa, err := c.fd.ReadFrom(b)
+ n, sa, err := c.fd.readFrom(b)
switch sa := sa.(type) {
case *syscall.SockaddrInet4:
addr = &IPAddr{IP: sa.Addr[0:]}
@@ -112,7 +112,7 @@ func (c *IPConn) ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err
return 0, 0, 0, nil, syscall.EINVAL
}
var sa syscall.Sockaddr
- n, oobn, flags, sa, err = c.fd.ReadMsg(b, oob)
+ n, oobn, flags, sa, err = c.fd.readMsg(b, oob)
switch sa := sa.(type) {
case *syscall.SockaddrInet4:
addr = &IPAddr{IP: sa.Addr[0:]}
@@ -133,6 +133,9 @@ func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (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}
+ }
if addr == nil {
return 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress}
}
@@ -140,7 +143,7 @@ func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) {
if err != nil {
return 0, &OpError{"write", c.fd.net, addr, err}
}
- return c.fd.WriteTo(b, sa)
+ return c.fd.writeTo(b, sa)
}
// WriteTo implements the PacketConn WriteTo method.
@@ -162,6 +165,9 @@ func (c *IPConn) WriteMsgIP(b, oob []byte, addr *IPAddr) (n, oobn int, err error
if !c.ok() {
return 0, 0, syscall.EINVAL
}
+ if c.fd.isConnected {
+ return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: ErrWriteToConnected}
+ }
if addr == nil {
return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress}
}
@@ -169,7 +175,7 @@ func (c *IPConn) WriteMsgIP(b, oob []byte, addr *IPAddr) (n, oobn int, err error
if err != nil {
return 0, 0, &OpError{"write", c.fd.net, addr, err}
}
- return c.fd.WriteMsg(b, oob, sa)
+ return c.fd.writeMsg(b, oob, sa)
}
// DialIP connects to the remote address raddr on the network protocol
@@ -192,7 +198,7 @@ func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn,
if raddr == nil {
return nil, &OpError{Op: "dial", Net: netProto, Addr: nil, Err: errMissingAddress}
}
- fd, err := internetSocket(net, laddr, raddr, deadline, syscall.SOCK_RAW, proto, "dial", sockaddrToIP)
+ 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}
}
@@ -213,7 +219,7 @@ func ListenIP(netProto string, laddr *IPAddr) (*IPConn, error) {
default:
return nil, &OpError{Op: "listen", Net: netProto, Addr: laddr, Err: UnknownNetworkError(netProto)}
}
- fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_RAW, proto, "listen", sockaddrToIP)
+ 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}
}
diff --git a/libgo/go/net/ipsock.go b/libgo/go/net/ipsock.go
index 8b586ef7c3..dda8578030 100644
--- a/libgo/go/net/ipsock.go
+++ b/libgo/go/net/ipsock.go
@@ -16,7 +16,7 @@ var (
// networking functionality.
supportsIPv4 bool
- // supportsIPv6 reports whether the platfrom supports IPv6
+ // supportsIPv6 reports whether the platform supports IPv6
// networking functionality.
supportsIPv6 bool
@@ -207,7 +207,7 @@ missingBrackets:
}
func splitHostZone(s string) (host, zone string) {
- // The IPv6 scoped addressing zone identifer starts after the
+ // The IPv6 scoped addressing zone identifier starts after the
// last percent sign.
if i := last(s, '%'); i > 0 {
host, zone = s[:i], s[i+1:]
@@ -232,7 +232,7 @@ func JoinHostPort(host, port string) string {
// 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
-// mutiple address family records. The result contains at least one
+// 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) {
var (
diff --git a/libgo/go/net/ipsock_plan9.go b/libgo/go/net/ipsock_plan9.go
index fcec4164f4..94ceea31b0 100644
--- a/libgo/go/net/ipsock_plan9.go
+++ b/libgo/go/net/ipsock_plan9.go
@@ -12,19 +12,45 @@ import (
"syscall"
)
+func probe(filename, query string) bool {
+ var file *file
+ var err error
+ if file, err = open(filename); err != nil {
+ return false
+ }
+
+ r := false
+ for line, ok := file.readLine(); ok && !r; line, ok = file.readLine() {
+ f := getFields(line)
+ if len(f) < 3 {
+ continue
+ }
+ for i := 0; i < len(f); i++ {
+ if query == f[i] {
+ r = true
+ break
+ }
+ }
+ }
+ file.close()
+ return r
+}
+
func probeIPv4Stack() bool {
- // TODO(mikio): implement this when Plan 9 supports IPv6-only
- // kernel.
- return true
+ return probe(netdir+"/iproute", "4i")
}
// probeIPv6Stack returns two boolean values. If the first boolean
// value is true, kernel supports basic IPv6 functionality. If the
// second boolean value is true, kernel supports IPv6 IPv4-mapping.
func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
- // TODO(mikio): implement this once Plan 9 gets an IPv6
- // protocol stack implementation.
- return false, false
+ // Plan 9 uses IPv6 natively, see ip(3).
+ r := probe(netdir+"/iproute", "6i")
+ v := false
+ if r {
+ v = probe(netdir+"/iproute", "4i")
+ }
+ return r, v
}
// parsePlan9Addr parses address of the form [ip!]port (e.g. 127.0.0.1!80).
@@ -34,12 +60,12 @@ 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("net: parsing IP failed")
+ return nil, 0, errors.New("parsing IP failed")
}
}
p, _, ok := dtoi(s[i+1:], 0)
if !ok {
- return nil, 0, errors.New("net: parsing port failed")
+ return nil, 0, errors.New("parsing port failed")
}
if p < 0 || p > 0xFFFF {
return nil, 0, &AddrError{"invalid port", string(p)}
@@ -133,18 +159,18 @@ func dialPlan9(net string, laddr, raddr Addr) (fd *netFD, err error) {
f.Close()
return nil, &OpError{"dial", f.Name(), raddr, err}
}
- data, err := os.OpenFile("/net/"+proto+"/"+name+"/data", os.O_RDWR, 0)
+ data, err := os.OpenFile(netdir+"/"+proto+"/"+name+"/data", os.O_RDWR, 0)
if err != nil {
f.Close()
return nil, &OpError{"dial", net, raddr, err}
}
- laddr, err = readPlan9Addr(proto, "/net/"+proto+"/"+name+"/local")
+ laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
if err != nil {
data.Close()
f.Close()
return nil, &OpError{"dial", proto, raddr, err}
}
- return newFD(proto, name, f, data, laddr, raddr), nil
+ return newFD(proto, name, f, data, laddr, raddr)
}
func listenPlan9(net string, laddr Addr) (fd *netFD, err error) {
@@ -158,20 +184,24 @@ func listenPlan9(net string, laddr Addr) (fd *netFD, err error) {
f.Close()
return nil, &OpError{"announce", proto, laddr, err}
}
- laddr, err = readPlan9Addr(proto, "/net/"+proto+"/"+name+"/local")
+ laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
if err != nil {
f.Close()
return nil, &OpError{Op: "listen", Net: net, Err: err}
}
- return newFD(proto, name, f, nil, laddr, nil), nil
+ return newFD(proto, name, f, nil, laddr, nil)
}
-func (l *netFD) netFD() *netFD {
- return newFD(l.proto, l.name, l.ctl, l.data, l.laddr, l.raddr)
+func (l *netFD) netFD() (*netFD, error) {
+ return newFD(l.proto, l.n, l.ctl, l.data, l.laddr, l.raddr)
}
func (l *netFD) acceptPlan9() (fd *netFD, err error) {
defer func() { netErr(err) }()
+ if err := l.readLock(); err != nil {
+ return nil, err
+ }
+ defer l.readUnlock()
f, err := os.Open(l.dir + "/listen")
if err != nil {
return nil, &OpError{"accept", l.dir + "/listen", l.laddr, err}
@@ -183,16 +213,16 @@ func (l *netFD) acceptPlan9() (fd *netFD, err error) {
return nil, &OpError{"accept", l.dir + "/listen", l.laddr, err}
}
name := string(buf[:n])
- data, err := os.OpenFile("/net/"+l.proto+"/"+name+"/data", os.O_RDWR, 0)
+ data, err := os.OpenFile(netdir+"/"+l.proto+"/"+name+"/data", os.O_RDWR, 0)
if err != nil {
f.Close()
return nil, &OpError{"accept", l.proto, l.laddr, err}
}
- raddr, err := readPlan9Addr(l.proto, "/net/"+l.proto+"/"+name+"/remote")
+ raddr, err := readPlan9Addr(l.proto, netdir+"/"+l.proto+"/"+name+"/remote")
if err != nil {
data.Close()
f.Close()
return nil, &OpError{"accept", l.proto, l.laddr, err}
}
- return newFD(l.proto, name, f, data, l.laddr, raddr), nil
+ return newFD(l.proto, name, f, data, l.laddr, raddr)
}
diff --git a/libgo/go/net/ipsock_posix.go b/libgo/go/net/ipsock_posix.go
index a83e525617..f9ebe40a21 100644
--- a/libgo/go/net/ipsock_posix.go
+++ b/libgo/go/net/ipsock_posix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
// Internet protocol family sockets for POSIX
@@ -40,12 +40,13 @@ func probeIPv4Stack() bool {
func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
var probes = []struct {
laddr TCPAddr
+ value int
ok bool
}{
// IPv6 communication capability
- {TCPAddr{IP: ParseIP("::1")}, false},
+ {laddr: TCPAddr{IP: ParseIP("::1")}, value: 1},
// IPv6 IPv4-mapped address communication capability
- {TCPAddr{IP: IPv4(127, 0, 0, 1)}, false},
+ {laddr: TCPAddr{IP: IPv4(127, 0, 0, 1)}, value: 0},
}
for i := range probes {
@@ -54,7 +55,7 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
continue
}
defer closesocket(s)
- syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
+ syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, probes[i].value)
sa, err := probes[i].laddr.sockaddr(syscall.AF_INET6)
if err != nil {
continue
@@ -131,9 +132,9 @@ func favoriteAddrFamily(net string, laddr, raddr sockaddr, mode string) (family
// Internet sockets (TCP, UDP, IP)
-func internetSocket(net string, laddr, raddr sockaddr, deadline time.Time, sotype, proto int, mode string, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) {
+func internetSocket(net string, laddr, raddr sockaddr, deadline time.Time, sotype, proto int, mode string) (fd *netFD, err error) {
family, ipv6only := favoriteAddrFamily(net, laddr, raddr, mode)
- return socket(net, family, sotype, proto, ipv6only, laddr, raddr, deadline, toAddr)
+ return socket(net, family, sotype, proto, ipv6only, laddr, raddr, deadline)
}
func ipToSockaddr(family int, ip IP, port int, zone string) (syscall.Sockaddr, error) {
diff --git a/libgo/go/net/lookup.go b/libgo/go/net/lookup.go
index 20f20578cd..aeffe6c9b7 100644
--- a/libgo/go/net/lookup.go
+++ b/libgo/go/net/lookup.go
@@ -40,10 +40,16 @@ func lookupIPMerge(host string) (addrs []IP, err error) {
addrsi, err, shared := lookupGroup.Do(host, func() (interface{}, error) {
return 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) {
if err != nil {
return nil, err
}
- addrs = addrsi.([]IP)
+ addrs := addrsi.([]IP)
if shared {
clone := make([]IP, len(addrs))
copy(clone, addrs)
@@ -52,41 +58,40 @@ func lookupIPMerge(host string) (addrs []IP, err error) {
return addrs, nil
}
+// lookupIPDeadline looks up a hostname with a deadline.
func lookupIPDeadline(host string, deadline time.Time) (addrs []IP, err error) {
if deadline.IsZero() {
return lookupIPMerge(host)
}
- // TODO(bradfitz): consider pushing the deadline down into the
- // name resolution functions. But that involves fixing it for
- // the native Go resolver, cgo, Windows, etc.
- //
- // In the meantime, just use a goroutine. Most users affected
- // by http://golang.org/issue/2631 are due to TCP connections
- // to unresponsive hosts, not DNS.
+ // We could push the deadline down into the name resolution
+ // functions. However, the most commonly used implementation
+ // calls getaddrinfo, which has no timeout.
+
timeout := deadline.Sub(time.Now())
if timeout <= 0 {
- err = errTimeout
- return
+ return nil, errTimeout
}
t := time.NewTimer(timeout)
defer t.Stop()
- type res struct {
- addrs []IP
- err error
- }
- resc := make(chan res, 1)
- go func() {
- a, err := lookupIPMerge(host)
- resc <- res{a, err}
- }()
+
+ ch := lookupGroup.DoChan(host, func() (interface{}, error) {
+ return lookupIP(host)
+ })
+
select {
case <-t.C:
- err = errTimeout
- case r := <-resc:
- addrs, err = r.addrs, r.err
+ // The DNS lookup timed out for some reason. Force
+ // future requests to start the DNS lookup again
+ // rather than waiting for the current lookup to
+ // complete. See issue 8602.
+ lookupGroup.Forget(host)
+
+ return nil, errTimeout
+
+ case r := <-ch:
+ return lookupIPReturn(r.v, r.err, r.shared)
}
- return
}
// LookupPort looks up the port for the given network and service.
diff --git a/libgo/go/net/lookup_plan9.go b/libgo/go/net/lookup_plan9.go
index f1204a99f7..b80ac10e0d 100644
--- a/libgo/go/net/lookup_plan9.go
+++ b/libgo/go/net/lookup_plan9.go
@@ -16,6 +16,10 @@ func query(filename, query string, bufSize int) (res []string, err error) {
}
defer file.Close()
+ _, err = file.Seek(0, 0)
+ if err != nil {
+ return
+ }
_, err = file.WriteString(query)
if err != nil {
return
@@ -45,7 +49,7 @@ func queryCS(net, host, service string) (res []string, err error) {
if host == "" {
host = "*"
}
- return query("/net/cs", net+"!"+host+"!"+service, 128)
+ return query(netdir+"/cs", net+"!"+host+"!"+service, 128)
}
func queryCS1(net string, ip IP, port int) (clone, dest string, err error) {
@@ -59,20 +63,41 @@ func queryCS1(net string, ip IP, port int) (clone, dest string, err error) {
}
f := getFields(lines[0])
if len(f) < 2 {
- return "", "", errors.New("net: bad response from ndb/cs")
+ return "", "", errors.New("bad response from ndb/cs")
}
clone, dest = f[0], f[1]
return
}
func queryDNS(addr string, typ string) (res []string, err error) {
- return query("/net/dns", addr+" "+typ, 1024)
+ return query(netdir+"/dns", addr+" "+typ, 1024)
+}
+
+// toLower returns a lower-case version of in. Restricting us to
+// ASCII is sufficient to handle the IP protocol names and allow
+// us to not depend on the strings and unicode packages.
+func toLower(in string) string {
+ for _, c := range in {
+ if 'A' <= c && c <= 'Z' {
+ // Has upper case; need to fix.
+ out := []byte(in)
+ for i := 0; i < len(in); i++ {
+ c := in[i]
+ if 'A' <= c && c <= 'Z' {
+ c += 'a' - 'A'
+ }
+ out[i] = c
+ }
+ return string(out)
+ }
+ }
+ return in
}
// lookupProtocol looks up IP protocol name and returns
// the corresponding protocol number.
func lookupProtocol(name string) (proto int, err error) {
- lines, err := query("/net/cs", "!protocol="+name, 128)
+ lines, err := query(netdir+"/cs", "!protocol="+toLower(name), 128)
if err != nil {
return 0, err
}
@@ -92,12 +117,13 @@ func lookupProtocol(name string) (proto int, err error) {
}
func lookupHost(host string) (addrs []string, err error) {
- // Use /net/cs instead of /net/dns because cs knows about
+ // Use netdir/cs instead of netdir/dns because cs knows about
// host names in local network (e.g. from /lib/ndb/local)
- lines, err := queryCS("tcp", host, "1")
+ lines, err := queryCS("net", host, "1")
if err != nil {
return
}
+loop:
for _, line := range lines {
f := getFields(line)
if len(f) < 2 {
@@ -110,6 +136,12 @@ func lookupHost(host string) (addrs []string, err error) {
if ParseIP(addr) == nil {
continue
}
+ // only return unique addresses
+ for _, a := range addrs {
+ if a == addr {
+ continue loop
+ }
+ }
addrs = append(addrs, addr)
}
return
@@ -167,7 +199,7 @@ func lookupCNAME(name string) (cname string, err error) {
return f[2] + ".", nil
}
}
- return "", errors.New("net: bad response from ndb/dns")
+ return "", errors.New("bad response from ndb/dns")
}
func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
diff --git a/libgo/go/net/lookup_stub.go b/libgo/go/net/lookup_stub.go
new file mode 100644
index 0000000000..502aafb270
--- /dev/null
+++ b/libgo/go/net/lookup_stub.go
@@ -0,0 +1,49 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build nacl
+
+package net
+
+import "syscall"
+
+func lookupProtocol(name string) (proto int, err error) {
+ return 0, syscall.ENOPROTOOPT
+}
+
+func lookupHost(host string) (addrs []string, err error) {
+ return nil, syscall.ENOPROTOOPT
+}
+
+func lookupIP(host string) (ips []IP, err error) {
+ return nil, syscall.ENOPROTOOPT
+}
+
+func lookupPort(network, service string) (port int, err error) {
+ return 0, syscall.ENOPROTOOPT
+}
+
+func lookupCNAME(name string) (cname string, err error) {
+ return "", syscall.ENOPROTOOPT
+}
+
+func lookupSRV(service, proto, name string) (cname string, srvs []*SRV, err error) {
+ return "", nil, syscall.ENOPROTOOPT
+}
+
+func lookupMX(name string) (mxs []*MX, err error) {
+ return nil, syscall.ENOPROTOOPT
+}
+
+func lookupNS(name string) (nss []*NS, err error) {
+ return nil, syscall.ENOPROTOOPT
+}
+
+func lookupTXT(name string) (txts []string, err error) {
+ return nil, syscall.ENOPROTOOPT
+}
+
+func lookupAddr(addr string) (ptrs []string, err error) {
+ return nil, syscall.ENOPROTOOPT
+}
diff --git a/libgo/go/net/lookup_test.go b/libgo/go/net/lookup_test.go
index 3355e46948..057e1322b9 100644
--- a/libgo/go/net/lookup_test.go
+++ b/libgo/go/net/lookup_test.go
@@ -15,87 +15,181 @@ import (
var testExternal = flag.Bool("external", true, "allow use of external networks during long test")
-func TestGoogleSRV(t *testing.T) {
+var lookupGoogleSRVTests = []struct {
+ service, proto, name string
+ cname, target string
+}{
+ {
+ "xmpp-server", "tcp", "google.com",
+ ".google.com", ".google.com",
+ },
+ {
+ "", "", "_xmpp-server._tcp.google.com", // non-standard back door
+ ".google.com", ".google.com",
+ },
+}
+
+func TestLookupGoogleSRV(t *testing.T) {
if testing.Short() || !*testExternal {
t.Skip("skipping test to avoid external network")
}
- _, addrs, err := LookupSRV("xmpp-server", "tcp", "google.com")
- if err != nil {
- t.Errorf("failed: %s", err)
+
+ for _, tt := range lookupGoogleSRVTests {
+ cname, srvs, err := LookupSRV(tt.service, tt.proto, tt.name)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(srvs) == 0 {
+ t.Error("got no record")
+ }
+ if !strings.Contains(cname, tt.cname) {
+ t.Errorf("got %q; want %q", 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 len(addrs) == 0 {
- t.Errorf("no results")
+}
+
+func TestLookupGmailMX(t *testing.T) {
+ if testing.Short() || !*testExternal {
+ t.Skip("skipping test to avoid external network")
}
- // Non-standard back door.
- _, addrs, err = LookupSRV("", "", "_xmpp-server._tcp.google.com")
+ mxs, err := LookupMX("gmail.com")
if err != nil {
- t.Errorf("back door failed: %s", err)
+ t.Fatal(err)
}
- if len(addrs) == 0 {
- t.Errorf("back door no results")
+ if len(mxs) == 0 {
+ t.Error("got no record")
+ }
+ for _, mx := range mxs {
+ if !strings.Contains(mx.Host, ".google.com") {
+ t.Errorf("got %v; want a record containing .google.com.", mx)
+ }
}
}
-func TestGmailMX(t *testing.T) {
+func TestLookupGmailNS(t *testing.T) {
if testing.Short() || !*testExternal {
t.Skip("skipping test to avoid external network")
}
- mx, err := LookupMX("gmail.com")
+
+ nss, err := LookupNS("gmail.com")
if err != nil {
- t.Errorf("failed: %s", err)
+ t.Fatal(err)
+ }
+ if len(nss) == 0 {
+ t.Error("got no record")
}
- if len(mx) == 0 {
- t.Errorf("no results")
+ for _, ns := range nss {
+ if !strings.Contains(ns.Host, ".google.com") {
+ t.Errorf("got %v; want a record containing .google.com.", ns)
+ }
}
}
-func TestGmailNS(t *testing.T) {
+func TestLookupGmailTXT(t *testing.T) {
if testing.Short() || !*testExternal {
t.Skip("skipping test to avoid external network")
}
- ns, err := LookupNS("gmail.com")
+
+ txts, err := LookupTXT("gmail.com")
if err != nil {
- t.Errorf("failed: %s", err)
+ t.Fatal(err)
+ }
+ 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)
+ }
+ }
+}
+
+var lookupGooglePublicDNSAddrs = []struct {
+ addr string
+ 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."},
+}
+
+func TestLookupGooglePublicDNSAddr(t *testing.T) {
+ if testing.Short() || !*testExternal {
+ t.Skip("skipping test to avoid external network")
}
- if len(ns) == 0 {
- t.Errorf("no results")
+
+ for _, tt := range lookupGooglePublicDNSAddrs {
+ names, err := LookupAddr(tt.addr)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(names) == 0 {
+ 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)
+ }
+ }
}
}
-func TestGmailTXT(t *testing.T) {
+func TestLookupIANACNAME(t *testing.T) {
if testing.Short() || !*testExternal {
t.Skip("skipping test to avoid external network")
}
- txt, err := LookupTXT("gmail.com")
+
+ cname, err := LookupCNAME("www.iana.org")
if err != nil {
- t.Errorf("failed: %s", err)
+ t.Fatal(err)
}
- if len(txt) == 0 || len(txt[0]) == 0 {
- t.Errorf("no results")
+ if !strings.HasSuffix(cname, ".icann.org.") {
+ t.Errorf("got %q; want a record containing .icann.org.", cname)
}
}
-func TestGoogleDNSAddr(t *testing.T) {
+func TestLookupGoogleHost(t *testing.T) {
if testing.Short() || !*testExternal {
t.Skip("skipping test to avoid external network")
}
- names, err := LookupAddr("8.8.8.8")
+
+ addrs, err := LookupHost("google.com")
if err != nil {
- t.Errorf("failed: %s", err)
+ t.Fatal(err)
+ }
+ if len(addrs) == 0 {
+ t.Error("got no record")
}
- if len(names) == 0 {
- t.Errorf("no results")
+ for _, addr := range addrs {
+ if ParseIP(addr) == nil {
+ t.Errorf("got %q; want a literal ip address", addr)
+ }
}
}
-func TestLookupIANACNAME(t *testing.T) {
+func TestLookupGoogleIP(t *testing.T) {
if testing.Short() || !*testExternal {
t.Skip("skipping test to avoid external network")
}
- cname, err := LookupCNAME("www.iana.org")
- if !strings.HasSuffix(cname, ".icann.org.") || err != nil {
- t.Errorf(`LookupCNAME("www.iana.org.") = %q, %v, want "*.icann.org.", nil`, cname, err)
+
+ ips, err := LookupIP("google.com")
+ 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)
+ }
}
}
diff --git a/libgo/go/net/lookup_unix.go b/libgo/go/net/lookup_unix.go
index 59e9f63210..a54578456d 100644
--- a/libgo/go/net/lookup_unix.go
+++ b/libgo/go/net/lookup_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package net
diff --git a/libgo/go/net/lookup_windows.go b/libgo/go/net/lookup_windows.go
index 130364231d..6a925b0a7a 100644
--- a/libgo/go/net/lookup_windows.go
+++ b/libgo/go/net/lookup_windows.go
@@ -210,14 +210,21 @@ func lookupCNAME(name string) (cname string, err error) {
defer releaseThread()
var r *syscall.DNSRecord
e := syscall.DnsQuery(name, syscall.DNS_TYPE_CNAME, 0, nil, &r, nil)
+ // windows returns DNS_INFO_NO_RECORDS if there are no CNAME-s
+ if errno, ok := e.(syscall.Errno); ok && errno == syscall.DNS_INFO_NO_RECORDS {
+ // if there are no aliases, the canonical name is the input name
+ if name == "" || name[len(name)-1] != '.' {
+ return name + ".", nil
+ }
+ return name, nil
+ }
if e != nil {
return "", os.NewSyscallError("LookupCNAME", e)
}
defer syscall.DnsRecordListFree(r, 1)
- if r != nil && r.Type == syscall.DNS_TYPE_CNAME {
- v := (*syscall.DNSPTRData)(unsafe.Pointer(&r.Data[0]))
- cname = syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]) + "."
- }
+
+ resolved := resolveCNAME(syscall.StringToUTF16Ptr(name), r)
+ cname = syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(resolved))[:]) + "."
return
}
@@ -236,8 +243,9 @@ func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err err
return "", nil, os.NewSyscallError("LookupSRV", e)
}
defer syscall.DnsRecordListFree(r, 1)
+
addrs = make([]*SRV, 0, 10)
- for p := r; p != nil && p.Type == syscall.DNS_TYPE_SRV; p = p.Next {
+ 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})
}
@@ -254,8 +262,9 @@ func lookupMX(name string) (mx []*MX, err error) {
return nil, os.NewSyscallError("LookupMX", e)
}
defer syscall.DnsRecordListFree(r, 1)
+
mx = make([]*MX, 0, 10)
- for p := r; p != nil && p.Type == syscall.DNS_TYPE_MX; p = p.Next {
+ 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})
}
@@ -272,8 +281,9 @@ func lookupNS(name string) (ns []*NS, err error) {
return nil, os.NewSyscallError("LookupNS", e)
}
defer syscall.DnsRecordListFree(r, 1)
+
ns = make([]*NS, 0, 10)
- for p := r; p != nil && p.Type == syscall.DNS_TYPE_NS; p = p.Next {
+ 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))[:]) + "."})
}
@@ -289,9 +299,10 @@ func lookupTXT(name string) (txt []string, err error) {
return nil, os.NewSyscallError("LookupTXT", e)
}
defer syscall.DnsRecordListFree(r, 1)
+
txt = make([]string, 0, 10)
- if r != nil && r.Type == syscall.DNS_TYPE_TEXT {
- d := (*syscall.DNSTXTData)(unsafe.Pointer(&r.Data[0]))
+ 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)
@@ -313,10 +324,58 @@ func lookupAddr(addr string) (name []string, err error) {
return nil, os.NewSyscallError("LookupAddr", e)
}
defer syscall.DnsRecordListFree(r, 1)
+
name = make([]string, 0, 10)
- for p := r; p != nil && p.Type == syscall.DNS_TYPE_PTR; p = p.Next {
+ 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))[:]))
}
return name, nil
}
+
+const dnsSectionMask = 0x0003
+
+// returns only results applicable to name and resolves CNAME entries
+func validRecs(r *syscall.DNSRecord, dnstype uint16, name string) []*syscall.DNSRecord {
+ cname := syscall.StringToUTF16Ptr(name)
+ if dnstype != syscall.DNS_TYPE_CNAME {
+ cname = resolveCNAME(cname, r)
+ }
+ rec := make([]*syscall.DNSRecord, 0, 10)
+ for p := r; p != nil; p = p.Next {
+ if p.Dw&dnsSectionMask != syscall.DnsSectionAnswer {
+ continue
+ }
+ if p.Type != dnstype {
+ continue
+ }
+ if !syscall.DnsNameCompare(cname, p.Name) {
+ continue
+ }
+ rec = append(rec, p)
+ }
+ return rec
+}
+
+// returns the last CNAME in chain
+func resolveCNAME(name *uint16, r *syscall.DNSRecord) *uint16 {
+ // limit cname resolving to 10 in case of a infinite CNAME loop
+Cname:
+ for cnameloop := 0; cnameloop < 10; cnameloop++ {
+ for p := r; p != nil; p = p.Next {
+ if p.Dw&dnsSectionMask != syscall.DnsSectionAnswer {
+ continue
+ }
+ if p.Type != syscall.DNS_TYPE_CNAME {
+ continue
+ }
+ if !syscall.DnsNameCompare(name, p.Name) {
+ continue
+ }
+ name = (*syscall.DNSPTRData)(unsafe.Pointer(&r.Data[0])).Host
+ continue Cname
+ }
+ break
+ }
+ return name
+}
diff --git a/libgo/go/net/mail/message.go b/libgo/go/net/mail/message.go
index dc2ab44dab..19aa888d87 100644
--- a/libgo/go/net/mail/message.go
+++ b/libgo/go/net/mail/message.go
@@ -28,6 +28,7 @@ import (
"strconv"
"strings"
"time"
+ "unicode"
)
var debug = debugT(false)
@@ -159,7 +160,9 @@ func (a *Address) String() string {
// If every character is printable ASCII, quoting is simple.
allPrintable := true
for i := 0; i < len(a.Name); i++ {
- if !isVchar(a.Name[i]) {
+ // isWSP here should actually be isFWS,
+ // but we don't support folding yet.
+ if !isVchar(a.Name[i]) && !isWSP(a.Name[i]) {
allPrintable = false
break
}
@@ -167,7 +170,7 @@ func (a *Address) String() string {
if allPrintable {
b := bytes.NewBufferString(`"`)
for i := 0; i < len(a.Name); i++ {
- if !isQtext(a.Name[i]) {
+ if !isQtext(a.Name[i]) && !isWSP(a.Name[i]) {
b.WriteByte('\\')
}
b.WriteByte(a.Name[i])
@@ -361,7 +364,7 @@ func (p *addrParser) consumePhrase() (phrase string, err error) {
// Ignore any error if we got at least one word.
if err != nil && len(words) == 0 {
debug.Printf("consumePhrase: hit err: %v", err)
- return "", errors.New("mail: missing word in phrase")
+ return "", fmt.Errorf("mail: missing word in phrase: %v", err)
}
phrase = strings.Join(words, " ")
return phrase, nil
@@ -440,11 +443,11 @@ func (p *addrParser) len() int {
func decodeRFC2047Word(s string) (string, error) {
fields := strings.Split(s, "?")
if len(fields) != 5 || fields[0] != "=" || fields[4] != "=" {
- return "", errors.New("mail: address not RFC 2047 encoded")
+ return "", errors.New("address not RFC 2047 encoded")
}
charset, enc := strings.ToLower(fields[1]), strings.ToLower(fields[2])
- if charset != "iso-8859-1" && charset != "utf-8" {
- return "", fmt.Errorf("mail: charset not supported: %q", charset)
+ if charset != "us-ascii" && charset != "iso-8859-1" && charset != "utf-8" {
+ return "", fmt.Errorf("charset not supported: %q", charset)
}
in := bytes.NewBufferString(fields[3])
@@ -455,7 +458,7 @@ func decodeRFC2047Word(s string) (string, error) {
case "q":
r = qDecoder{r: in}
default:
- return "", fmt.Errorf("mail: RFC 2047 encoding not supported: %q", enc)
+ return "", fmt.Errorf("RFC 2047 encoding not supported: %q", enc)
}
dec, err := ioutil.ReadAll(r)
@@ -464,6 +467,16 @@ func decodeRFC2047Word(s string) (string, error) {
}
switch charset {
+ case "us-ascii":
+ b := new(bytes.Buffer)
+ for _, c := range dec {
+ if c >= 0x80 {
+ b.WriteRune(unicode.ReplacementChar)
+ } else {
+ b.WriteRune(rune(c))
+ }
+ }
+ return b.String(), nil
case "iso-8859-1":
b := new(bytes.Buffer)
for _, c := range dec {
@@ -535,3 +548,9 @@ func isVchar(c byte) bool {
// Visible (printing) characters.
return '!' <= c && c <= '~'
}
+
+// isWSP returns true if 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 3c037f3838..6ba48be04f 100644
--- a/libgo/go/net/mail/message_test.go
+++ b/libgo/go/net/mail/message_test.go
@@ -8,6 +8,7 @@ import (
"bytes"
"io/ioutil"
"reflect"
+ "strings"
"testing"
"time"
)
@@ -116,6 +117,14 @@ func TestDateParsing(t *testing.T) {
}
}
+func TestAddressParsingError(t *testing.T) {
+ const txt = "=?iso-8859-2?Q?Bogl=E1rka_Tak=E1cs?= <unknown@gmail.com>"
+ _, err := ParseAddress(txt)
+ if err == nil || !strings.Contains(err.Error(), "charset not supported") {
+ t.Errorf(`mail.ParseAddress(%q) err: %q, want ".*charset not supported.*"`, txt, err)
+ }
+}
+
func TestAddressParsing(t *testing.T) {
tests := []struct {
addrsStr string
@@ -185,6 +194,16 @@ func TestAddressParsing(t *testing.T) {
},
},
},
+ // RFC 2047 "Q"-encoded US-ASCII address. Dumb but legal.
+ {
+ `=?us-ascii?q?J=6Frg_Doe?= <joerg@example.com>`,
+ []*Address{
+ {
+ Name: `Jorg Doe`,
+ Address: "joerg@example.com",
+ },
+ },
+ },
// RFC 2047 "Q"-encoded UTF-8 address.
{
`=?utf-8?q?J=C3=B6rg_Doe?= <joerg@example.com>`,
@@ -277,6 +296,14 @@ func TestAddressFormatting(t *testing.T) {
&Address{Name: "Böb", Address: "bob@example.com"},
`=?utf-8?q?B=C3=B6b?= <bob@example.com>`,
},
+ {
+ &Address{Name: "Bob Jane", Address: "bob@example.com"},
+ `"Bob Jane" <bob@example.com>`,
+ },
+ {
+ &Address{Name: "Böb Jacöb", Address: "bob@example.com"},
+ `=?utf-8?q?B=C3=B6b_Jac=C3=B6b?= <bob@example.com>`,
+ },
}
for _, test := range tests {
s := test.addr.String()
diff --git a/libgo/go/net/multicast_test.go b/libgo/go/net/multicast_test.go
index 5660fd42f8..5f253f44a4 100644
--- a/libgo/go/net/multicast_test.go
+++ b/libgo/go/net/multicast_test.go
@@ -25,8 +25,10 @@ var ipv4MulticastListenerTests = []struct {
// port.
func TestIPv4MulticastListener(t *testing.T) {
switch runtime.GOOS {
- case "plan9":
+ 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) {
@@ -93,8 +95,10 @@ var ipv6MulticastListenerTests = []struct {
// port.
func TestIPv6MulticastListener(t *testing.T) {
switch runtime.GOOS {
- case "plan9", "solaris":
+ 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")
diff --git a/libgo/go/net/net.go b/libgo/go/net/net.go
index 2e6db55514..cb31af5e34 100644
--- a/libgo/go/net/net.go
+++ b/libgo/go/net/net.go
@@ -32,7 +32,6 @@ The Listen function creates servers:
conn, err := ln.Accept()
if err != nil {
// handle error
- continue
}
go handleConnection(conn)
}
@@ -275,7 +274,16 @@ type Listener interface {
Addr() Addr
}
-var errMissingAddress = errors.New("missing address")
+// Various errors contained in OpError.
+var (
+ // For connection setup and write operations.
+ errMissingAddress = errors.New("missing address")
+
+ // For both read and write operations.
+ errTimeout error = &timeoutError{}
+ errClosing = errors.New("use of closed network connection")
+ ErrWriteToConnected = errors.New("use of WriteTo with pre-connected connection")
+)
// OpError is the error type usually returned by functions in the net
// package. It describes the operation, network type, and address of
@@ -337,10 +345,6 @@ func (e *timeoutError) Error() string { return "i/o timeout" }
func (e *timeoutError) Timeout() bool { return true }
func (e *timeoutError) Temporary() bool { return true }
-var errTimeout error = &timeoutError{}
-
-var errClosing = errors.New("use of closed network connection")
-
type AddrError struct {
Err string
Addr string
diff --git a/libgo/go/net/net_test.go b/libgo/go/net/net_test.go
index 1320096df8..bfed4d657f 100644
--- a/libgo/go/net/net_test.go
+++ b/libgo/go/net/net_test.go
@@ -28,12 +28,14 @@ func TestShutdown(t *testing.T) {
defer ln.Close()
c, err := ln.Accept()
if err != nil {
- t.Fatalf("Accept: %v", err)
+ t.Errorf("Accept: %v", err)
+ return
}
var buf [10]byte
n, err := c.Read(buf[:])
if n != 0 || err != io.EOF {
- t.Fatalf("server Read = %d, %v; want 0, io.EOF", n, err)
+ t.Errorf("server Read = %d, %v; want 0, io.EOF", n, err)
+ return
}
c.Write([]byte("response"))
c.Close()
@@ -62,7 +64,7 @@ func TestShutdown(t *testing.T) {
func TestShutdownUnix(t *testing.T) {
switch runtime.GOOS {
- case "windows", "plan9":
+ case "nacl", "plan9", "windows":
t.Skipf("skipping test on %q", runtime.GOOS)
}
f, err := ioutil.TempFile("", "go_net_unixtest")
@@ -84,12 +86,14 @@ func TestShutdownUnix(t *testing.T) {
go func() {
c, err := ln.Accept()
if err != nil {
- t.Fatalf("Accept: %v", err)
+ t.Errorf("Accept: %v", err)
+ return
}
var buf [10]byte
n, err := c.Read(buf[:])
if n != 0 || err != io.EOF {
- t.Fatalf("server Read = %d, %v; want 0, io.EOF", n, err)
+ t.Errorf("server Read = %d, %v; want 0, io.EOF", n, err)
+ return
}
c.Write([]byte("response"))
c.Close()
@@ -196,7 +200,8 @@ func TestTCPClose(t *testing.T) {
go func() {
c, err := Dial("tcp", l.Addr().String())
if err != nil {
- t.Fatal(err)
+ t.Errorf("Dial: %v", err)
+ return
}
go read(c)
@@ -231,12 +236,12 @@ func TestErrorNil(t *testing.T) {
// Make Listen fail by relistening on the same address.
l, err := Listen("tcp", "127.0.0.1:0")
if err != nil {
- t.Fatal("Listen 127.0.0.1:0: %v", err)
+ t.Fatalf("Listen 127.0.0.1:0: %v", err)
}
defer l.Close()
l1, err := Listen("tcp", l.Addr().String())
if err == nil {
- t.Fatal("second Listen %v: %v", l.Addr(), err)
+ 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)
@@ -245,12 +250,12 @@ func TestErrorNil(t *testing.T) {
// Make ListenPacket fail by relistening on the same address.
lp, err := ListenPacket("udp", "127.0.0.1:0")
if err != nil {
- t.Fatal("Listen 127.0.0.1:0: %v", err)
+ t.Fatalf("Listen 127.0.0.1:0: %v", err)
}
defer lp.Close()
lp1, err := ListenPacket("udp", lp.LocalAddr().String())
if err == nil {
- t.Fatal("second Listen %v: %v", lp.LocalAddr(), err)
+ 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)
diff --git a/libgo/go/net/packetconn_test.go b/libgo/go/net/packetconn_test.go
index 945003f67a..b6e4e76f93 100644
--- a/libgo/go/net/packetconn_test.go
+++ b/libgo/go/net/packetconn_test.go
@@ -15,12 +15,6 @@ import (
"time"
)
-func strfunc(s string) func() string {
- return func() string {
- return s
- }
-}
-
func packetConnTestData(t *testing.T, net string, i int) ([]byte, func()) {
switch net {
case "udp":
@@ -46,7 +40,7 @@ func packetConnTestData(t *testing.T, net string, i int) ([]byte, func()) {
return b, nil
case "unixgram":
switch runtime.GOOS {
- case "plan9", "windows":
+ case "nacl", "plan9", "windows":
return nil, func() {
t.Logf("skipping %q test on %q", net, runtime.GOOS)
}
@@ -62,12 +56,12 @@ func packetConnTestData(t *testing.T, net string, i int) ([]byte, func()) {
var packetConnTests = []struct {
net string
- addr1 func() string
- addr2 func() string
+ addr1 string
+ addr2 string
}{
- {"udp", strfunc("127.0.0.1:0"), strfunc("127.0.0.1:0")},
- {"ip:icmp", strfunc("127.0.0.1"), strfunc("127.0.0.1")},
- {"unixgram", testUnixAddr, testUnixAddr},
+ {"udp", "127.0.0.1:0", "127.0.0.1:0"},
+ {"ip:icmp", "127.0.0.1", "127.0.0.1"},
+ {"unixgram", testUnixAddr(), testUnixAddr()},
}
func TestPacketConn(t *testing.T) {
@@ -88,22 +82,21 @@ func TestPacketConn(t *testing.T) {
continue
}
- addr1, addr2 := tt.addr1(), tt.addr2()
- c1, err := ListenPacket(tt.net, addr1)
+ c1, err := ListenPacket(tt.net, tt.addr1)
if err != nil {
t.Fatalf("ListenPacket failed: %v", err)
}
- defer closer(c1, netstr[0], addr1, addr2)
+ defer closer(c1, netstr[0], 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))
- c2, err := ListenPacket(tt.net, addr2)
+ c2, err := ListenPacket(tt.net, tt.addr2)
if err != nil {
t.Fatalf("ListenPacket failed: %v", err)
}
- defer closer(c2, netstr[0], addr1, addr2)
+ defer closer(c2, netstr[0], tt.addr1, tt.addr2)
c2.LocalAddr()
c2.SetDeadline(time.Now().Add(100 * time.Millisecond))
c2.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
@@ -145,12 +138,11 @@ func TestConnAndPacketConn(t *testing.T) {
continue
}
- addr1, addr2 := tt.addr1(), tt.addr2()
- c1, err := ListenPacket(tt.net, addr1)
+ c1, err := ListenPacket(tt.net, tt.addr1)
if err != nil {
t.Fatalf("ListenPacket failed: %v", err)
}
- defer closer(c1, netstr[0], addr1, addr2)
+ defer closer(c1, netstr[0], tt.addr1, tt.addr2)
c1.LocalAddr()
c1.SetDeadline(time.Now().Add(100 * time.Millisecond))
c1.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
diff --git a/libgo/go/net/parse.go b/libgo/go/net/parse.go
index 6056de248e..e1d0130c9a 100644
--- a/libgo/go/net/parse.go
+++ b/libgo/go/net/parse.go
@@ -67,7 +67,7 @@ func open(name string) (*file, error) {
if err != nil {
return nil, err
}
- return &file{fd, make([]byte, os.Getpagesize())[0:0], false}, nil
+ return &file{fd, make([]byte, 0, os.Getpagesize()), false}, nil
}
func byteIndex(s string, c byte) int {
@@ -210,18 +210,18 @@ func itod(i uint) string {
return string(b[bp:])
}
-// Convert i to hexadecimal string.
-func itox(i uint, min int) string {
- // Assemble hexadecimal in reverse order.
- var b [32]byte
- bp := len(b)
- for ; i > 0 || min > 0; i /= 16 {
- bp--
- b[bp] = "0123456789abcdef"[byte(i%16)]
- min--
+// Convert i to a hexadecimal string. Leading zeros are not printed.
+func appendHex(dst []byte, i uint32) []byte {
+ if i == 0 {
+ return append(dst, '0')
}
-
- return string(b[bp:])
+ for j := 7; j >= 0; j-- {
+ v := i >> uint(j*4)
+ if v > 0 {
+ dst = append(dst, hexDigit[v&0xf])
+ }
+ }
+ return dst
}
// Number of occurrences of b in s.
diff --git a/libgo/go/net/parse_test.go b/libgo/go/net/parse_test.go
index b86bc32884..7b213b75bd 100644
--- a/libgo/go/net/parse_test.go
+++ b/libgo/go/net/parse_test.go
@@ -12,9 +12,9 @@ import (
)
func TestReadLine(t *testing.T) {
- // /etc/services file does not exist on windows and Plan 9.
+ // /etc/services file does not exist on android, plan9, windows.
switch runtime.GOOS {
- case "plan9", "windows":
+ case "android", "plan9", "windows":
t.Skipf("skipping test on %q", runtime.GOOS)
}
filename := "/etc/services" // a nice big file
diff --git a/libgo/go/net/port_test.go b/libgo/go/net/port_test.go
index 9e8968f359..4811ade69e 100644
--- a/libgo/go/net/port_test.go
+++ b/libgo/go/net/port_test.go
@@ -5,6 +5,7 @@
package net
import (
+ "runtime"
"testing"
)
@@ -43,6 +44,11 @@ var porttests = []portTest{
}
func TestLookupPort(t *testing.T) {
+ switch runtime.GOOS {
+ case "nacl":
+ t.Skipf("skipping test on %q", runtime.GOOS)
+ }
+
for i := 0; i < len(porttests); i++ {
tt := porttests[i]
if port, err := LookupPort(tt.netw, tt.name); port != tt.port || (err == nil) != tt.ok {
diff --git a/libgo/go/net/port_unix.go b/libgo/go/net/port_unix.go
index 3cd9ca2aa7..348c771c35 100644
--- a/libgo/go/net/port_unix.go
+++ b/libgo/go/net/port_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
// Read system port mappings from /etc/services
@@ -10,12 +10,16 @@ package net
import "sync"
-var services map[string]map[string]int
+// services contains minimal mappings between services names and port
+// numbers for platforms that don't have a complete list of port numbers
+// (some Solaris distros).
+var services = map[string]map[string]int{
+ "tcp": {"http": 80},
+}
var servicesError error
var onceReadServices sync.Once
func readServices() {
- services = make(map[string]map[string]int)
var file *file
if file, servicesError = open("/etc/services"); servicesError != nil {
return
@@ -29,7 +33,7 @@ func readServices() {
if len(f) < 2 {
continue
}
- portnet := f[1] // "tcp/80"
+ portnet := f[1] // "80/tcp"
port, j, ok := dtoi(portnet, 0)
if !ok || port <= 0 || j >= len(portnet) || portnet[j] != '/' {
continue
diff --git a/libgo/go/net/protoconn_test.go b/libgo/go/net/protoconn_test.go
index 5a8958b086..12856b6c31 100644
--- a/libgo/go/net/protoconn_test.go
+++ b/libgo/go/net/protoconn_test.go
@@ -19,7 +19,7 @@ import (
// also uses /tmp directory in case it is prohibited to create UNIX
// sockets in TMPDIR.
func testUnixAddr() string {
- f, err := ioutil.TempFile("/tmp", "nettest")
+ f, err := ioutil.TempFile("", "nettest")
if err != nil {
panic(err)
}
@@ -236,7 +236,7 @@ func TestIPConnSpecificMethods(t *testing.T) {
func TestUnixListenerSpecificMethods(t *testing.T) {
switch runtime.GOOS {
- case "plan9", "windows":
+ case "nacl", "plan9", "windows":
t.Skipf("skipping test on %q", runtime.GOOS)
}
@@ -278,7 +278,7 @@ func TestUnixListenerSpecificMethods(t *testing.T) {
func TestUnixConnSpecificMethods(t *testing.T) {
switch runtime.GOOS {
- case "plan9", "windows":
+ case "nacl", "plan9", "windows":
t.Skipf("skipping test on %q", runtime.GOOS)
}
diff --git a/libgo/go/net/rpc/client.go b/libgo/go/net/rpc/client.go
index c524d0a0a2..d0c4a69214 100644
--- a/libgo/go/net/rpc/client.go
+++ b/libgo/go/net/rpc/client.go
@@ -39,14 +39,16 @@ type Call struct {
// with a single Client, and a Client may be used by
// multiple goroutines simultaneously.
type Client struct {
- mutex sync.Mutex // protects pending, seq, request
- sending sync.Mutex
+ codec ClientCodec
+
+ reqMutex sync.Mutex // protects following
request Request
+
+ mutex sync.Mutex // protects following
seq uint64
- codec ClientCodec
pending map[uint64]*Call
- closing bool
- shutdown bool
+ closing bool // user has called Close
+ shutdown bool // server has told us to stop
}
// A ClientCodec implements writing of RPC requests and
@@ -67,8 +69,8 @@ type ClientCodec interface {
}
func (client *Client) send(call *Call) {
- client.sending.Lock()
- defer client.sending.Unlock()
+ client.reqMutex.Lock()
+ defer client.reqMutex.Unlock()
// Register this call.
client.mutex.Lock()
@@ -144,7 +146,7 @@ func (client *Client) input() {
}
}
// Terminate pending calls.
- client.sending.Lock()
+ client.reqMutex.Lock()
client.mutex.Lock()
client.shutdown = true
closing := client.closing
@@ -160,7 +162,7 @@ func (client *Client) input() {
call.done()
}
client.mutex.Unlock()
- client.sending.Unlock()
+ client.reqMutex.Unlock()
if debugLog && err != io.EOF && !closing {
log.Println("rpc: client protocol error:", err)
}
@@ -274,7 +276,7 @@ func Dial(network, address string) (*Client, error) {
func (client *Client) Close() error {
client.mutex.Lock()
- if client.shutdown || client.closing {
+ if client.closing {
client.mutex.Unlock()
return ErrShutdown
}
diff --git a/libgo/go/net/rpc/client_test.go b/libgo/go/net/rpc/client_test.go
new file mode 100644
index 0000000000..5dd111b299
--- /dev/null
+++ b/libgo/go/net/rpc/client_test.go
@@ -0,0 +1,91 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rpc
+
+import (
+ "errors"
+ "fmt"
+ "net"
+ "runtime"
+ "strings"
+ "testing"
+)
+
+type shutdownCodec struct {
+ responded chan int
+ closed bool
+}
+
+func (c *shutdownCodec) WriteRequest(*Request, interface{}) error { return nil }
+func (c *shutdownCodec) ReadResponseBody(interface{}) error { return nil }
+func (c *shutdownCodec) ReadResponseHeader(*Response) error {
+ c.responded <- 1
+ return errors.New("shutdownCodec ReadResponseHeader")
+}
+func (c *shutdownCodec) Close() error {
+ c.closed = true
+ return nil
+}
+
+func TestCloseCodec(t *testing.T) {
+ codec := &shutdownCodec{responded: make(chan int)}
+ client := NewClientWithCodec(codec)
+ <-codec.responded
+ client.Close()
+ if !codec.closed {
+ t.Error("client.Close did not close codec")
+ }
+}
+
+// Test that errors in gob shut down the connection. Issue 7689.
+
+type R struct {
+ msg []byte // Not exported, so R does not work with gob.
+}
+
+type S struct{}
+
+func (s *S) Recv(nul *struct{}, reply *R) error {
+ *reply = R{[]byte("foo")}
+ return nil
+}
+
+func TestGobError(t *testing.T) {
+ if runtime.GOOS == "plan9" {
+ t.Skip("skipping test; see http://golang.org/issue/8908")
+ }
+ defer func() {
+ err := recover()
+ if err == nil {
+ t.Fatal("no error")
+ }
+ if !strings.Contains("reading body EOF", err.(error).Error()) {
+ t.Fatal("expected `reading body EOF', got", err)
+ }
+ }()
+ Register(new(S))
+
+ listen, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ panic(err)
+ }
+ go Accept(listen)
+
+ client, err := Dial("tcp", listen.Addr().String())
+ if err != nil {
+ panic(err)
+ }
+
+ var reply Reply
+ err = client.Call("S.Recv", &struct{}{}, &reply)
+ if err != nil {
+ panic(err)
+ }
+
+ fmt.Printf("%#v\n", reply)
+ client.Close()
+
+ listen.Close()
+}
diff --git a/libgo/go/net/rpc/debug.go b/libgo/go/net/rpc/debug.go
index 926466d625..98b2c1c6c4 100644
--- a/libgo/go/net/rpc/debug.go
+++ b/libgo/go/net/rpc/debug.go
@@ -11,9 +11,9 @@ package rpc
import (
"fmt"
+ "html/template"
"net/http"
"sort"
- "text/template"
)
const debugText = `<html>
diff --git a/libgo/go/net/rpc/jsonrpc/all_test.go b/libgo/go/net/rpc/jsonrpc/all_test.go
index 40d4b82d7f..a433a365e8 100644
--- a/libgo/go/net/rpc/jsonrpc/all_test.go
+++ b/libgo/go/net/rpc/jsonrpc/all_test.go
@@ -5,6 +5,7 @@
package jsonrpc
import (
+ "bytes"
"encoding/json"
"errors"
"fmt"
@@ -12,6 +13,7 @@ import (
"io/ioutil"
"net"
"net/rpc"
+ "strings"
"testing"
)
@@ -202,6 +204,39 @@ func TestMalformedOutput(t *testing.T) {
}
}
+func TestServerErrorHasNullResult(t *testing.T) {
+ var out bytes.Buffer
+ sc := NewServerCodec(struct {
+ io.Reader
+ io.Writer
+ io.Closer
+ }{
+ Reader: strings.NewReader(`{"method": "Arith.Add", "id": "123", "params": []}`),
+ Writer: &out,
+ Closer: ioutil.NopCloser(nil),
+ })
+ r := new(rpc.Request)
+ if err := sc.ReadRequestHeader(r); err != nil {
+ t.Fatal(err)
+ }
+ const valueText = "the value we don't want to see"
+ const errorText = "some error"
+ err := sc.WriteResponse(&rpc.Response{
+ ServiceMethod: "Method",
+ Seq: 1,
+ Error: errorText,
+ }, valueText)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !strings.Contains(out.String(), errorText) {
+ t.Fatalf("Response didn't contain expected error %q: %s", errorText, &out)
+ }
+ if strings.Contains(out.String(), valueText) {
+ t.Errorf("Response contains both an error and value: %s", &out)
+ }
+}
+
func TestUnexpectedError(t *testing.T) {
cli, srv := myPipe()
go cli.PipeWriter.CloseWithError(errors.New("unexpected error!")) // reader will get this error
diff --git a/libgo/go/net/rpc/jsonrpc/server.go b/libgo/go/net/rpc/jsonrpc/server.go
index 16ec0fe9ad..e6d37cfa64 100644
--- a/libgo/go/net/rpc/jsonrpc/server.go
+++ b/libgo/go/net/rpc/jsonrpc/server.go
@@ -100,7 +100,6 @@ func (c *serverCodec) ReadRequestBody(x interface{}) error {
var null = json.RawMessage([]byte("null"))
func (c *serverCodec) WriteResponse(r *rpc.Response, x interface{}) error {
- var resp serverResponse
c.mutex.Lock()
b, ok := c.pending[r.Seq]
if !ok {
@@ -114,10 +113,9 @@ func (c *serverCodec) WriteResponse(r *rpc.Response, x interface{}) error {
// Invalid request so no id. Use JSON null.
b = &null
}
- resp.Id = b
- resp.Result = x
+ resp := serverResponse{Id: b}
if r.Error == "" {
- resp.Error = nil
+ resp.Result = x
} else {
resp.Error = r.Error
}
diff --git a/libgo/go/net/rpc/server.go b/libgo/go/net/rpc/server.go
index 7eb2dcf5a9..83728d55a1 100644
--- a/libgo/go/net/rpc/server.go
+++ b/libgo/go/net/rpc/server.go
@@ -217,10 +217,11 @@ 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
-// - two arguments, both pointers to exported structs
+// - two arguments, both of exported type
+// - the second argument is a pointer
// - one return value, of type error
// It returns an error if the receiver is not an exported type or has
-// no methods or unsuitable methods. It also logs the error using package log.
+// no suitable methods. It also logs the error using package log.
// The client accesses each method using a string of the form "Type.Method",
// where Type is the receiver's concrete type.
func (server *Server) Register(rcvr interface{}) error {
@@ -394,6 +395,7 @@ type gobServerCodec struct {
dec *gob.Decoder
enc *gob.Encoder
encBuf *bufio.Writer
+ closed bool
}
func (c *gobServerCodec) ReadRequestHeader(r *Request) error {
@@ -406,15 +408,32 @@ func (c *gobServerCodec) ReadRequestBody(body interface{}) error {
func (c *gobServerCodec) WriteResponse(r *Response, body interface{}) (err error) {
if err = c.enc.Encode(r); err != nil {
+ if c.encBuf.Flush() == nil {
+ // Gob couldn't encode the header. Should not happen, so if it does,
+ // shut down the connection to signal that the connection is broken.
+ log.Println("rpc: gob error encoding response:", err)
+ c.Close()
+ }
return
}
if err = c.enc.Encode(body); err != nil {
+ if c.encBuf.Flush() == nil {
+ // Was a gob problem encoding the body but the header has been written.
+ // Shut down the connection to signal that the connection is broken.
+ log.Println("rpc: gob error encoding body:", err)
+ c.Close()
+ }
return
}
return c.encBuf.Flush()
}
func (c *gobServerCodec) Close() error {
+ if c.closed {
+ // Only call c.rwc.Close once; otherwise the semantics are undefined.
+ return nil
+ }
+ c.closed = true
return c.rwc.Close()
}
@@ -425,7 +444,12 @@ func (c *gobServerCodec) Close() error {
// connection. To use an alternate codec, use ServeCodec.
func (server *Server) ServeConn(conn io.ReadWriteCloser) {
buf := bufio.NewWriter(conn)
- srv := &gobServerCodec{conn, gob.NewDecoder(conn), gob.NewEncoder(buf), buf}
+ srv := &gobServerCodec{
+ rwc: conn,
+ dec: gob.NewDecoder(conn),
+ enc: gob.NewEncoder(buf),
+ encBuf: buf,
+ }
server.ServeCodec(srv)
}
diff --git a/libgo/go/net/rpc/server_test.go b/libgo/go/net/rpc/server_test.go
index 3b9a88380c..0dc4ddc2de 100644
--- a/libgo/go/net/rpc/server_test.go
+++ b/libgo/go/net/rpc/server_test.go
@@ -594,7 +594,6 @@ func TestErrorAfterClientClose(t *testing.T) {
}
func benchmarkEndToEnd(dial func() (*Client, error), b *testing.B) {
- b.StopTimer()
once.Do(startServer)
client, err := dial()
if err != nil {
@@ -604,33 +603,24 @@ func benchmarkEndToEnd(dial func() (*Client, error), b *testing.B) {
// Synchronous calls
args := &Args{7, 8}
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N)
- var wg sync.WaitGroup
- wg.Add(procs)
- b.StartTimer()
-
- for p := 0; p < procs; p++ {
- go func() {
- reply := new(Reply)
- for atomic.AddInt32(&N, -1) >= 0 {
- err := client.Call("Arith.Add", args, reply)
- if err != nil {
- b.Fatalf("rpc error: Add: expected no error but got string %q", err.Error())
- }
- if reply.C != args.A+args.B {
- b.Fatalf("rpc error: Add: expected %d got %d", reply.C, args.A+args.B)
- }
+ b.ResetTimer()
+
+ b.RunParallel(func(pb *testing.PB) {
+ reply := new(Reply)
+ for pb.Next() {
+ err := client.Call("Arith.Add", args, reply)
+ if err != nil {
+ b.Fatalf("rpc error: Add: expected no error but got string %q", err.Error())
}
- wg.Done()
- }()
- }
- wg.Wait()
+ if reply.C != args.A+args.B {
+ b.Fatalf("rpc error: Add: expected %d got %d", reply.C, args.A+args.B)
+ }
+ }
+ })
}
func benchmarkEndToEndAsync(dial func() (*Client, error), b *testing.B) {
const MaxConcurrentCalls = 100
- b.StopTimer()
once.Do(startServer)
client, err := dial()
if err != nil {
@@ -647,7 +637,7 @@ func benchmarkEndToEndAsync(dial func() (*Client, error), b *testing.B) {
wg.Add(procs)
gate := make(chan bool, MaxConcurrentCalls)
res := make(chan *Call, MaxConcurrentCalls)
- b.StartTimer()
+ b.ResetTimer()
for p := 0; p < procs; p++ {
go func() {
diff --git a/libgo/go/net/sendfile_dragonfly.go b/libgo/go/net/sendfile_dragonfly.go
index a2219c1633..bc88fd3b90 100644
--- a/libgo/go/net/sendfile_dragonfly.go
+++ b/libgo/go/net/sendfile_dragonfly.go
@@ -23,7 +23,7 @@ const maxSendfileSize int = 4 << 20
// if handled == false, sendFile performed no work.
func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
// DragonFly 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 nauseum until it's sent
+ // 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
diff --git a/libgo/go/net/sendfile_freebsd.go b/libgo/go/net/sendfile_freebsd.go
index 42fe799efb..ffc147262a 100644
--- a/libgo/go/net/sendfile_freebsd.go
+++ b/libgo/go/net/sendfile_freebsd.go
@@ -23,7 +23,7 @@ const maxSendfileSize int = 4 << 20
// if handled == false, sendFile performed no work.
func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
// FreeBSD 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 nauseum until it's sent
+ // 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
diff --git a/libgo/go/net/sendfile_stub.go b/libgo/go/net/sendfile_stub.go
index 3660849c18..03426ef0df 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 netbsd openbsd
+// +build darwin nacl netbsd openbsd solaris
package net
diff --git a/libgo/go/net/server_test.go b/libgo/go/net/server_test.go
index 9194a8ec24..6a2bb92432 100644
--- a/libgo/go/net/server_test.go
+++ b/libgo/go/net/server_test.go
@@ -9,21 +9,20 @@ import (
"io"
"os"
"runtime"
- "strconv"
"testing"
"time"
)
-func skipServerTest(net, unixsotype, addr string, ipv6, ipv4map, linuxonly bool) bool {
+func skipServerTest(net, unixsotype, addr string, ipv6, ipv4map, linuxOnly bool) bool {
switch runtime.GOOS {
case "linux":
- case "plan9", "windows":
+ case "nacl", "plan9", "windows":
// "unix" sockets are not supported on Windows and Plan 9.
if net == unixsotype {
return true
}
default:
- if net == unixsotype && linuxonly {
+ if net == unixsotype && linuxOnly {
return true
}
}
@@ -42,21 +41,15 @@ func skipServerTest(net, unixsotype, addr string, ipv6, ipv4map, linuxonly bool)
return false
}
-func tempfile(filename string) string {
- // use /tmp in case it is prohibited to create
- // UNIX sockets in TMPDIR
- return "/tmp/" + filename + "." + strconv.Itoa(os.Getpid())
-}
-
var streamConnServerTests = []struct {
- snet string // server side
- saddr string
- cnet string // client side
- caddr string
- ipv6 bool // test with underlying AF_INET6 socket
- ipv4map bool // test with IPv6 IPv4-mapping functionality
- empty bool // test with empty data
- linux bool // test with abstract unix domain socket, a Linux-ism
+ snet 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
}{
{snet: "tcp", saddr: "", cnet: "tcp", caddr: "127.0.0.1"},
{snet: "tcp", saddr: "0.0.0.0", cnet: "tcp", caddr: "127.0.0.1"},
@@ -93,13 +86,13 @@ var streamConnServerTests = []struct {
{snet: "tcp6", saddr: "[::1]", cnet: "tcp6", caddr: "[::1]", ipv6: true},
- {snet: "unix", saddr: tempfile("gotest1.net"), cnet: "unix", caddr: tempfile("gotest1.net.local")},
- {snet: "unix", saddr: "@gotest2/net", cnet: "unix", caddr: "@gotest2/net.local", linux: true},
+ {snet: "unix", saddr: testUnixAddr(), cnet: "unix", caddr: testUnixAddr()},
+ {snet: "unix", saddr: "@gotest2/net", cnet: "unix", caddr: "@gotest2/net.local", linuxOnly: true},
}
func TestStreamConnServer(t *testing.T) {
for _, tt := range streamConnServerTests {
- if skipServerTest(tt.snet, "unix", tt.saddr, tt.ipv6, tt.ipv4map, tt.linux) {
+ if skipServerTest(tt.snet, "unix", tt.saddr, tt.ipv6, tt.ipv4map, tt.linuxOnly) {
continue
}
@@ -137,21 +130,28 @@ func TestStreamConnServer(t *testing.T) {
}
var seqpacketConnServerTests = []struct {
- net string
- saddr string // server address
- caddr string // client address
- empty bool // test with empty data
+ 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
}{
- {net: "unixpacket", saddr: tempfile("/gotest3.net"), caddr: tempfile("gotest3.net.local")},
- {net: "unixpacket", saddr: "@gotest4/net", caddr: "@gotest4/net.local"},
+ {net: "unixpacket", saddr: testUnixAddr(), caddr: testUnixAddr()},
+ {net: "unixpacket", saddr: "@gotest4/net", caddr: "@gotest4/net.local", linuxOnly: true},
}
func TestSeqpacketConnServer(t *testing.T) {
- if runtime.GOOS != "linux" {
+ 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)
}
for _, tt := range seqpacketConnServerTests {
+ if runtime.GOOS != "linux" && tt.linuxOnly {
+ continue
+ }
listening := make(chan string)
done := make(chan int)
switch tt.net {
@@ -248,15 +248,15 @@ func runStreamConnClient(t *testing.T, net, taddr string, isEmpty bool) {
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
- linux bool // test with abstract unix domain socket, a Linux-ism
+ 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
}{
{snet: "udp", saddr: "", cnet: "udp", caddr: "127.0.0.1"},
{snet: "udp", saddr: "0.0.0.0", cnet: "udp", caddr: "127.0.0.1"},
@@ -301,12 +301,12 @@ var datagramPacketConnServerTests = []struct {
{snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true, empty: true},
{snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true, dial: true, empty: true},
- {snet: "unixgram", saddr: tempfile("gotest5.net"), cnet: "unixgram", caddr: tempfile("gotest5.net.local")},
- {snet: "unixgram", saddr: tempfile("gotest5.net"), cnet: "unixgram", caddr: tempfile("gotest5.net.local"), dial: true},
- {snet: "unixgram", saddr: tempfile("gotest5.net"), cnet: "unixgram", caddr: tempfile("gotest5.net.local"), empty: true},
- {snet: "unixgram", saddr: tempfile("gotest5.net"), cnet: "unixgram", caddr: tempfile("gotest5.net.local"), dial: true, empty: 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", linux: true},
+ {snet: "unixgram", saddr: "@gotest6/net", cnet: "unixgram", caddr: "@gotest6/net.local", linuxOnly: true},
}
func TestDatagramPacketConnServer(t *testing.T) {
@@ -315,7 +315,7 @@ func TestDatagramPacketConnServer(t *testing.T) {
}
for _, tt := range datagramPacketConnServerTests {
- if skipServerTest(tt.snet, "unixgram", tt.saddr, tt.ipv6, tt.ipv4map, tt.linux) {
+ if skipServerTest(tt.snet, "unixgram", tt.saddr, tt.ipv6, tt.ipv4map, tt.linuxOnly) {
continue
}
diff --git a/libgo/go/net/singleflight.go b/libgo/go/net/singleflight.go
index dc58affdaa..bf599f0cc9 100644
--- a/libgo/go/net/singleflight.go
+++ b/libgo/go/net/singleflight.go
@@ -8,10 +8,18 @@ import "sync"
// call is an in-flight or completed singleflight.Do call
type call struct {
- wg sync.WaitGroup
- val interface{}
- err error
- dups int
+ 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
@@ -21,6 +29,14 @@ type singleflight struct {
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
@@ -42,12 +58,52 @@ func (g *singleflight) Do(key string, fn func() (interface{}, error)) (v interfa
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()
+}
- return c.val, c.err, c.dups > 0
+// 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 a0a478a852..87dea442c4 100644
--- a/libgo/go/net/smtp/smtp.go
+++ b/libgo/go/net/smtp/smtp.go
@@ -264,6 +264,8 @@ func (c *Client) Data() (io.WriteCloser, error) {
return &dataCloser{c, c.Text.DotWriter()}, nil
}
+var testHookStartTLS func(*tls.Config) // nil, except for tests
+
// SendMail connects to the server at addr, switches to TLS if
// possible, authenticates with the optional mechanism a if possible,
// and then sends an email from address from, to addresses to, with
@@ -278,7 +280,11 @@ func SendMail(addr string, a Auth, from string, to []string, msg []byte) error {
return err
}
if ok, _ := c.Extension("STARTTLS"); ok {
- if err = c.StartTLS(nil); err != nil {
+ config := &tls.Config{ServerName: c.serverName}
+ if testHookStartTLS != nil {
+ testHookStartTLS(config)
+ }
+ if err = c.StartTLS(config); err != nil {
return err
}
}
diff --git a/libgo/go/net/smtp/smtp_test.go b/libgo/go/net/smtp/smtp_test.go
index 2133dc7c7b..5c659e8a09 100644
--- a/libgo/go/net/smtp/smtp_test.go
+++ b/libgo/go/net/smtp/smtp_test.go
@@ -7,6 +7,8 @@ package smtp
import (
"bufio"
"bytes"
+ "crypto/tls"
+ "crypto/x509"
"io"
"net"
"net/textproto"
@@ -548,3 +550,145 @@ AUTH PLAIN AHVzZXIAcGFzcw==
*
QUIT
`
+
+func TestTLSClient(t *testing.T) {
+ ln := newLocalListener(t)
+ defer ln.Close()
+ errc := make(chan error)
+ go func() {
+ errc <- sendMail(ln.Addr().String())
+ }()
+ conn, err := ln.Accept()
+ if err != nil {
+ t.Fatalf("failed to accept connection: %v", err)
+ }
+ defer conn.Close()
+ if err := serverHandle(conn, t); err != nil {
+ t.Fatalf("failed to handle connection: %v", err)
+ }
+ if err := <-errc; err != nil {
+ t.Fatalf("client error: %v", err)
+ }
+}
+
+func newLocalListener(t *testing.T) net.Listener {
+ ln, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ ln, err = net.Listen("tcp6", "[::1]:0")
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+ return ln
+}
+
+type smtpSender struct {
+ w io.Writer
+}
+
+func (s smtpSender) send(f string) {
+ s.w.Write([]byte(f + "\r\n"))
+}
+
+// smtp server, finely tailored to deal with our own client only!
+func serverHandle(c net.Conn, t *testing.T) error {
+ send := smtpSender{c}.send
+ send("220 127.0.0.1 ESMTP service ready")
+ s := bufio.NewScanner(c)
+ for s.Scan() {
+ switch s.Text() {
+ case "EHLO localhost":
+ send("250-127.0.0.1 ESMTP offers a warm hug of welcome")
+ send("250-STARTTLS")
+ send("250 Ok")
+ case "STARTTLS":
+ send("220 Go ahead")
+ keypair, err := tls.X509KeyPair(localhostCert, localhostKey)
+ if err != nil {
+ return err
+ }
+ config := &tls.Config{Certificates: []tls.Certificate{keypair}}
+ c = tls.Server(c, config)
+ defer c.Close()
+ return serverHandleTLS(c, t)
+ default:
+ t.Fatalf("unrecognized command: %q", s.Text())
+ }
+ }
+ return s.Err()
+}
+
+func serverHandleTLS(c net.Conn, t *testing.T) error {
+ send := smtpSender{c}.send
+ s := bufio.NewScanner(c)
+ for s.Scan() {
+ switch s.Text() {
+ case "EHLO localhost":
+ send("250 Ok")
+ case "MAIL FROM:<joe1@example.com>":
+ send("250 Ok")
+ case "RCPT TO:<joe2@example.com>":
+ send("250 Ok")
+ case "DATA":
+ send("354 send the mail data, end with .")
+ send("250 Ok")
+ case "Subject: test":
+ case "":
+ case "howdy!":
+ case ".":
+ case "QUIT":
+ send("221 127.0.0.1 Service closing transmission channel")
+ return nil
+ default:
+ t.Fatalf("unrecognized command during TLS: %q", s.Text())
+ }
+ }
+ return s.Err()
+}
+
+func init() {
+ testRootCAs := x509.NewCertPool()
+ testRootCAs.AppendCertsFromPEM(localhostCert)
+ testHookStartTLS = func(config *tls.Config) {
+ config.RootCAs = testRootCAs
+ }
+}
+
+func sendMail(hostPort string) error {
+ host, _, err := net.SplitHostPort(hostPort)
+ if err != nil {
+ return err
+ }
+ auth := PlainAuth("", "", "", host)
+ from := "joe1@example.com"
+ to := []string{"joe2@example.com"}
+ return SendMail(hostPort, auth, from, to, []byte("Subject: test\n\nhowdy!"))
+}
+
+// (copied from net/http/httptest)
+// localhostCert is a PEM-encoded TLS cert with SAN IPs
+// "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
+var localhostCert = []byte(`-----BEGIN CERTIFICATE-----
+MIIBdzCCASOgAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD
+bzAeFw03MDAxMDEwMDAwMDBaFw00OTEyMzEyMzU5NTlaMBIxEDAOBgNVBAoTB0Fj
+bWUgQ28wWjALBgkqhkiG9w0BAQEDSwAwSAJBAN55NcYKZeInyTuhcCwFMhDHCmwa
+IUSdtXdcbItRB/yfXGBhiex00IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEA
+AaNoMGYwDgYDVR0PAQH/BAQDAgCkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1Ud
+EwEB/wQFMAMBAf8wLgYDVR0RBCcwJYILZXhhbXBsZS5jb22HBH8AAAGHEAAAAAAA
+AAAAAAAAAAAAAAEwCwYJKoZIhvcNAQEFA0EAAoQn/ytgqpiLcZu9XKbCJsJcvkgk
+Se6AbGXgSlq+ZCEVo0qIwSgeBqmsJxUu7NCSOwVJLYNEBO2DtIxoYVk+MA==
+-----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=
+-----END RSA PRIVATE KEY-----`)
diff --git a/libgo/go/net/sock_cloexec.go b/libgo/go/net/sock_cloexec.go
index 3f22cd8f57..dec81855b6 100644
--- a/libgo/go/net/sock_cloexec.go
+++ b/libgo/go/net/sock_cloexec.go
@@ -5,7 +5,7 @@
// This file implements sysSocket and accept for platforms that
// provide a fast path for setting SetNonblock and CloseOnExec.
-// +build linux
+// +build freebsd linux
package net
@@ -13,18 +13,20 @@ import "syscall"
// Wrapper around the socket system call that marks the returned file
// descriptor as nonblocking and close-on-exec.
-func sysSocket(f, t, p int) (int, error) {
- s, err := syscall.Socket(f, t|syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC, p)
- // The SOCK_NONBLOCK and SOCK_CLOEXEC flags were introduced in
- // Linux 2.6.27. If we get an EINVAL error, fall back to
- // using socket without them.
- if err == nil || err != syscall.EINVAL {
+func sysSocket(family, sotype, proto int) (int, error) {
+ s, err := syscall.Socket(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
}
// See ../syscall/exec_unix.go for description of ForkLock.
syscall.ForkLock.RLock()
- s, err = syscall.Socket(f, t, p)
+ s, err = syscall.Socket(family, sotype, proto)
if err == nil {
syscall.CloseOnExec(s)
}
@@ -41,12 +43,19 @@ func sysSocket(f, t, p int) (int, error) {
// Wrapper around the accept system call that marks the returned file
// descriptor as nonblocking and close-on-exec.
-func accept(fd int) (int, syscall.Sockaddr, error) {
- nfd, sa, err := syscall.Accept4(fd, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC)
- // The accept4 system call was introduced in Linux 2.6.28. If
- // we get an ENOSYS or EINVAL error, fall back to using accept.
- if err == nil || (err != syscall.ENOSYS && err != syscall.EINVAL) {
- return nfd, sa, err
+func accept(s int) (int, syscall.Sockaddr, error) {
+ ns, sa, err := syscall.Accept4(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 syscall.ENOSYS: // syscall missing
+ case syscall.EINVAL: // some Linux use this instead of ENOSYS
+ case syscall.EACCES: // some Linux use this instead of ENOSYS
+ case syscall.EFAULT: // some Linux use this instead of ENOSYS
}
// See ../syscall/exec_unix.go for description of ForkLock.
@@ -54,16 +63,16 @@ func accept(fd 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.
- nfd, sa, err = syscall.Accept(fd)
+ ns, sa, err = syscall.Accept(s)
if err == nil {
- syscall.CloseOnExec(nfd)
+ syscall.CloseOnExec(ns)
}
if err != nil {
return -1, nil, err
}
- if err = syscall.SetNonblock(nfd, true); err != nil {
- syscall.Close(nfd)
+ if err = syscall.SetNonblock(ns, true); err != nil {
+ syscall.Close(ns)
return -1, nil, err
}
- return nfd, sa, nil
+ return ns, sa, nil
}
diff --git a/libgo/go/net/sock_posix.go b/libgo/go/net/sock_posix.go
index c2d343c585..3f956df65a 100644
--- a/libgo/go/net/sock_posix.go
+++ b/libgo/go/net/sock_posix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
package net
@@ -36,7 +36,7 @@ type sockaddr interface {
// socket returns a network file descriptor that is ready for
// asynchronous I/O using the network poller.
-func socket(net string, family, sotype, proto int, ipv6only bool, laddr, raddr sockaddr, deadline time.Time, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) {
+func socket(net string, family, sotype, proto int, ipv6only bool, laddr, raddr sockaddr, deadline time.Time) (fd *netFD, err error) {
s, err := sysSocket(family, sotype, proto)
if err != nil {
return nil, err
@@ -75,27 +75,51 @@ func socket(net string, family, sotype, proto int, ipv6only bool, laddr, raddr s
if laddr != nil && raddr == nil {
switch sotype {
case syscall.SOCK_STREAM, syscall.SOCK_SEQPACKET:
- if err := fd.listenStream(laddr, listenerBacklog, toAddr); err != nil {
+ if err := fd.listenStream(laddr, listenerBacklog); err != nil {
fd.Close()
return nil, err
}
return fd, nil
case syscall.SOCK_DGRAM:
- if err := fd.listenDatagram(laddr, toAddr); err != nil {
+ if err := fd.listenDatagram(laddr); err != nil {
fd.Close()
return nil, err
}
return fd, nil
}
}
- if err := fd.dial(laddr, raddr, deadline, toAddr); err != nil {
+ if err := fd.dial(laddr, raddr, deadline); err != nil {
fd.Close()
return nil, err
}
return fd, nil
}
-func (fd *netFD) dial(laddr, raddr sockaddr, deadline time.Time, toAddr func(syscall.Sockaddr) Addr) error {
+func (fd *netFD) addrFunc() func(syscall.Sockaddr) Addr {
+ switch fd.family {
+ case syscall.AF_INET, syscall.AF_INET6:
+ switch fd.sotype {
+ case syscall.SOCK_STREAM:
+ return sockaddrToTCP
+ case syscall.SOCK_DGRAM:
+ return sockaddrToUDP
+ case syscall.SOCK_RAW:
+ return sockaddrToIP
+ }
+ case syscall.AF_UNIX:
+ switch fd.sotype {
+ case syscall.SOCK_STREAM:
+ return sockaddrToUnix
+ case syscall.SOCK_DGRAM:
+ return sockaddrToUnixgram
+ case syscall.SOCK_SEQPACKET:
+ return sockaddrToUnixpacket
+ }
+ }
+ return func(syscall.Sockaddr) Addr { return nil }
+}
+
+func (fd *netFD) dial(laddr, raddr sockaddr, deadline time.Time) error {
var err error
var lsa syscall.Sockaddr
if laddr != nil {
@@ -107,36 +131,30 @@ func (fd *netFD) dial(laddr, raddr sockaddr, deadline time.Time, toAddr func(sys
}
}
}
- if err := fd.init(); err != nil {
- return err
- }
var rsa syscall.Sockaddr
if raddr != nil {
if rsa, err = raddr.sockaddr(fd.family); err != nil {
return err
- } else if rsa != nil {
- if !deadline.IsZero() {
- fd.setWriteDeadline(deadline)
- }
- if err := fd.connect(lsa, rsa); err != nil {
- return err
- }
- fd.isConnected = true
- if !deadline.IsZero() {
- fd.setWriteDeadline(noDeadline)
- }
+ }
+ if err := fd.connect(lsa, rsa, deadline); err != nil {
+ return err
+ }
+ fd.isConnected = true
+ } else {
+ if err := fd.init(); err != nil {
+ return err
}
}
lsa, _ = syscall.Getsockname(fd.sysfd)
if rsa, _ = syscall.Getpeername(fd.sysfd); rsa != nil {
- fd.setAddr(toAddr(lsa), toAddr(rsa))
+ fd.setAddr(fd.addrFunc()(lsa), fd.addrFunc()(rsa))
} else {
- fd.setAddr(toAddr(lsa), raddr)
+ fd.setAddr(fd.addrFunc()(lsa), raddr)
}
return nil
}
-func (fd *netFD) listenStream(laddr sockaddr, backlog int, toAddr func(syscall.Sockaddr) Addr) error {
+func (fd *netFD) listenStream(laddr sockaddr, backlog int) error {
if err := setDefaultListenerSockopts(fd.sysfd); err != nil {
return err
}
@@ -154,11 +172,11 @@ func (fd *netFD) listenStream(laddr sockaddr, backlog int, toAddr func(syscall.S
return err
}
lsa, _ := syscall.Getsockname(fd.sysfd)
- fd.setAddr(toAddr(lsa), nil)
+ fd.setAddr(fd.addrFunc()(lsa), nil)
return nil
}
-func (fd *netFD) listenDatagram(laddr sockaddr, toAddr func(syscall.Sockaddr) Addr) error {
+func (fd *netFD) listenDatagram(laddr sockaddr) error {
switch addr := laddr.(type) {
case *UDPAddr:
// We provide a socket that listens to a wildcard
@@ -193,6 +211,6 @@ func (fd *netFD) listenDatagram(laddr sockaddr, toAddr func(syscall.Sockaddr) Ad
return err
}
lsa, _ := syscall.Getsockname(fd.sysfd)
- fd.setAddr(toAddr(lsa), nil)
+ fd.setAddr(fd.addrFunc()(lsa), nil)
return nil
}
diff --git a/libgo/go/net/sock_solaris.go b/libgo/go/net/sock_solaris.go
deleted file mode 100644
index 484e1fe461..0000000000
--- a/libgo/go/net/sock_solaris.go
+++ /dev/null
@@ -1,18 +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 solaris
-
-// Sockets for Solaris
-
-package net
-
-import (
- "syscall"
-)
-
-func maxListenerBacklog() int {
- // The kernel does not track the limit.
- return syscall.SOMAXCONN
-}
diff --git a/libgo/go/net/sock_stub.go b/libgo/go/net/sock_stub.go
new file mode 100644
index 0000000000..ed6b089489
--- /dev/null
+++ b/libgo/go/net/sock_stub.go
@@ -0,0 +1,15 @@
+// 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 nacl solaris
+
+package net
+
+import "syscall"
+
+func maxListenerBacklog() int {
+ // TODO: Implement this
+ // NOTE: Never return a number bigger than 1<<16 - 1. See issue 5030.
+ return syscall.SOMAXCONN
+}
diff --git a/libgo/go/net/sockopt_bsd.go b/libgo/go/net/sockopt_bsd.go
index 4b9c2f9afb..d5b3621c52 100644
--- a/libgo/go/net/sockopt_bsd.go
+++ b/libgo/go/net/sockopt_bsd.go
@@ -8,10 +8,23 @@ package net
import (
"os"
+ "runtime"
"syscall"
)
func setDefaultSockopts(s, family, sotype int, ipv6only bool) error {
+ if runtime.GOOS == "dragonfly" && sotype != syscall.SOCK_RAW {
+ // On DragonFly BSD, we adjust the ephemeral port
+ // range because unlike other BSD systems its default
+ // port range doesn't conform to IANA recommendation
+ // as described in RFC 6056 and is pretty narrow.
+ switch family {
+ case syscall.AF_INET:
+ syscall.SetsockoptInt(s, syscall.IPPROTO_IP, syscall.IP_PORTRANGE, syscall.IP_PORTRANGE_HIGH)
+ case syscall.AF_INET6:
+ syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_PORTRANGE, syscall.IPV6_PORTRANGE_HIGH)
+ }
+ }
if family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW {
// Allow both IP versions even if the OS default
// is otherwise. Note that some operating systems
diff --git a/libgo/go/net/sockopt_plan9.go b/libgo/go/net/sockopt_plan9.go
new file mode 100644
index 0000000000..8bc689b6c2
--- /dev/null
+++ b/libgo/go/net/sockopt_plan9.go
@@ -0,0 +1,13 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+func setKeepAlive(fd *netFD, keepalive bool) error {
+ if keepalive {
+ _, e := fd.ctl.WriteAt([]byte("keepalive"), 0)
+ return e
+ }
+ return nil
+}
diff --git a/libgo/go/net/sockopt_posix.go b/libgo/go/net/sockopt_posix.go
index ff3bc68994..1654d1b85e 100644
--- a/libgo/go/net/sockopt_posix.go
+++ b/libgo/go/net/sockopt_posix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd windows
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
package net
diff --git a/libgo/go/net/sockopt_solaris.go b/libgo/go/net/sockopt_solaris.go
new file mode 100644
index 0000000000..54c20b1409
--- /dev/null
+++ b/libgo/go/net/sockopt_solaris.go
@@ -0,0 +1,32 @@
+// 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 (
+ "os"
+ "syscall"
+)
+
+func setDefaultSockopts(s, family, sotype int, ipv6only bool) error {
+ if 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.
+ syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only))
+ }
+ // Allow broadcast.
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1))
+}
+
+func setDefaultListenerSockopts(s int) error {
+ // Allow reuse of recently-used addresses.
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1))
+}
+
+func setDefaultMulticastSockopts(s int) error {
+ // Allow multicast UDP and raw IP datagram sockets to listen
+ // concurrently across multiple listeners.
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1))
+}
diff --git a/libgo/go/net/sockopt_stub.go b/libgo/go/net/sockopt_stub.go
new file mode 100644
index 0000000000..de5ee0bb63
--- /dev/null
+++ b/libgo/go/net/sockopt_stub.go
@@ -0,0 +1,37 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build nacl
+
+package net
+
+import "syscall"
+
+func setDefaultSockopts(s, family, sotype int, ipv6only bool) error {
+ return nil
+}
+
+func setDefaultListenerSockopts(s int) error {
+ return nil
+}
+
+func setDefaultMulticastSockopts(s int) error {
+ return nil
+}
+
+func setReadBuffer(fd *netFD, bytes int) error {
+ return syscall.ENOPROTOOPT
+}
+
+func setWriteBuffer(fd *netFD, bytes int) error {
+ return syscall.ENOPROTOOPT
+}
+
+func setKeepAlive(fd *netFD, keepalive bool) error {
+ return syscall.ENOPROTOOPT
+}
+
+func setLinger(fd *netFD, sec int) error {
+ return syscall.ENOPROTOOPT
+}
diff --git a/libgo/go/net/sockoptip_stub.go b/libgo/go/net/sockoptip_stub.go
new file mode 100644
index 0000000000..32ec5ddb85
--- /dev/null
+++ b/libgo/go/net/sockoptip_stub.go
@@ -0,0 +1,39 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build nacl solaris
+
+package net
+
+import "syscall"
+
+func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
+ // See golang.org/issue/7399.
+ return syscall.ENOPROTOOPT
+}
+
+func setIPv4MulticastLoopback(fd *netFD, v bool) error {
+ // See golang.org/issue/7399.
+ return syscall.ENOPROTOOPT
+}
+
+func joinIPv4Group(fd *netFD, ifi *Interface, ip IP) error {
+ // See golang.org/issue/7399.
+ return syscall.ENOPROTOOPT
+}
+
+func setIPv6MulticastInterface(fd *netFD, ifi *Interface) error {
+ // See golang.org/issue/7399.
+ return syscall.ENOPROTOOPT
+}
+
+func setIPv6MulticastLoopback(fd *netFD, v bool) error {
+ // See golang.org/issue/7399.
+ return syscall.ENOPROTOOPT
+}
+
+func joinIPv6Group(fd *netFD, ifi *Interface, ip IP) error {
+ // See golang.org/issue/7399.
+ return syscall.ENOPROTOOPT
+}
diff --git a/libgo/go/net/sys_cloexec.go b/libgo/go/net/sys_cloexec.go
index bbfcc1a4fc..898fb7c0c2 100644
--- a/libgo/go/net/sys_cloexec.go
+++ b/libgo/go/net/sys_cloexec.go
@@ -5,7 +5,7 @@
// This file implements sysSocket and accept for platforms that do not
// provide a fast path for setting SetNonblock and CloseOnExec.
-// +build darwin dragonfly freebsd netbsd openbsd
+// +build darwin dragonfly nacl netbsd openbsd solaris
package net
@@ -13,10 +13,10 @@ import "syscall"
// Wrapper around the socket system call that marks the returned file
// descriptor as nonblocking and close-on-exec.
-func sysSocket(f, t, p int) (int, error) {
+func sysSocket(family, sotype, proto int) (int, error) {
// See ../syscall/exec_unix.go for description of ForkLock.
syscall.ForkLock.RLock()
- s, err := syscall.Socket(f, t, p)
+ s, err := syscall.Socket(family, sotype, proto)
if err == nil {
syscall.CloseOnExec(s)
}
@@ -33,22 +33,22 @@ func sysSocket(f, t, p int) (int, error) {
// Wrapper around the accept system call that marks the returned file
// descriptor as nonblocking and close-on-exec.
-func accept(fd int) (int, syscall.Sockaddr, error) {
+func accept(s int) (int, syscall.Sockaddr, error) {
// See ../syscall/exec_unix.go for description of ForkLock.
// It is probably okay to hold the lock across syscall.Accept
// 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.
- nfd, sa, err := syscall.Accept(fd)
+ ns, sa, err := syscall.Accept(s)
if err == nil {
- syscall.CloseOnExec(nfd)
+ syscall.CloseOnExec(ns)
}
if err != nil {
return -1, nil, err
}
- if err = syscall.SetNonblock(nfd, true); err != nil {
- syscall.Close(nfd)
+ if err = syscall.SetNonblock(ns, true); err != nil {
+ syscall.Close(ns)
return -1, nil, err
}
- return nfd, sa, nil
+ return ns, sa, nil
}
diff --git a/libgo/go/net/tcp_test.go b/libgo/go/net/tcp_test.go
index 62fd99f5c0..c04198ea00 100644
--- a/libgo/go/net/tcp_test.go
+++ b/libgo/go/net/tcp_test.go
@@ -97,6 +97,7 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
b.Fatalf("Listen failed: %v", err)
}
defer ln.Close()
+ serverSem := make(chan bool, numConcurrent)
// Acceptor.
go func() {
for {
@@ -104,9 +105,13 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
if err != nil {
break
}
+ serverSem <- true
// Server connection.
go func(c Conn) {
- defer c.Close()
+ defer func() {
+ c.Close()
+ <-serverSem
+ }()
if timeout {
c.SetDeadline(time.Now().Add(time.Hour)) // Not intended to fire.
}
@@ -119,13 +124,13 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
}(c)
}
}()
- sem := make(chan bool, numConcurrent)
+ clientSem := make(chan bool, numConcurrent)
for i := 0; i < conns; i++ {
- sem <- true
+ clientSem <- true
// Client connection.
go func() {
defer func() {
- <-sem
+ <-clientSem
}()
c, err := Dial("tcp", ln.Addr().String())
if err != nil {
@@ -144,8 +149,9 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
}
}()
}
- for i := 0; i < cap(sem); i++ {
- sem <- true
+ for i := 0; i < numConcurrent; i++ {
+ clientSem <- true
+ serverSem <- true
}
}
@@ -185,7 +191,8 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
for p := 0; p < P; p++ {
s, err := ln.Accept()
if err != nil {
- b.Fatalf("Accept failed: %v", err)
+ b.Errorf("Accept failed: %v", err)
+ return
}
servers[p] = s
}
@@ -217,7 +224,8 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
buf[0] = v
_, err := c.Write(buf[:])
if err != nil {
- b.Fatalf("Write failed: %v", err)
+ b.Errorf("Write failed: %v", err)
+ return
}
}
}(clients[p])
@@ -232,7 +240,8 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
for i := 0; i < N; i++ {
_, err := s.Read(buf[:])
if err != nil {
- b.Fatalf("Read failed: %v", err)
+ b.Errorf("Read failed: %v", err)
+ return
}
pipe <- buf[0]
}
@@ -250,7 +259,8 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
buf[0] = v
_, err := s.Write(buf[:])
if err != nil {
- b.Fatalf("Write failed: %v", err)
+ b.Errorf("Write failed: %v", err)
+ return
}
}
s.Close()
@@ -263,7 +273,8 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
for i := 0; i < N; i++ {
_, err := c.Read(buf[:])
if err != nil {
- b.Fatalf("Read failed: %v", err)
+ b.Errorf("Read failed: %v", err)
+ return
}
}
c.Close()
@@ -388,7 +399,7 @@ func TestIPv6LinkLocalUnicastTCP(t *testing.T) {
{"tcp6", "[" + laddr + "%" + ifi.Name + "]:0", false},
}
switch runtime.GOOS {
- case "darwin", "freebsd", "opensbd", "netbsd":
+ case "darwin", "freebsd", "openbsd", "netbsd":
tests = append(tests, []test{
{"tcp", "[localhost%" + ifi.Name + "]:0", true},
{"tcp6", "[localhost%" + ifi.Name + "]:0", true},
@@ -460,15 +471,25 @@ func TestTCPConcurrentAccept(t *testing.T) {
wg.Done()
}()
}
- for i := 0; i < 10*N; i++ {
- c, err := Dial("tcp", ln.Addr().String())
+ attempts := 10 * N
+ fails := 0
+ d := &Dialer{Timeout: 200 * time.Millisecond}
+ for i := 0; i < attempts; i++ {
+ c, err := d.Dial("tcp", ln.Addr().String())
if err != nil {
- t.Fatalf("Dial failed: %v", err)
+ fails++
+ } else {
+ c.Close()
}
- c.Close()
}
ln.Close()
wg.Wait()
+ if fails > attempts/9 { // see issues 7400 and 7541
+ t.Fatalf("too many Dial failed: %v", fails)
+ }
+ if fails > 0 {
+ t.Logf("# of failed Dials: %v", fails)
+ }
}
func TestTCPReadWriteMallocs(t *testing.T) {
diff --git a/libgo/go/net/tcpsock_plan9.go b/libgo/go/net/tcpsock_plan9.go
index cf9c0f8904..52019d7b4e 100644
--- a/libgo/go/net/tcpsock_plan9.go
+++ b/libgo/go/net/tcpsock_plan9.go
@@ -32,7 +32,7 @@ func (c *TCPConn) CloseRead() error {
if !c.ok() {
return syscall.EINVAL
}
- return c.fd.CloseRead()
+ return c.fd.closeRead()
}
// CloseWrite shuts down the writing side of the TCP connection.
@@ -41,20 +41,21 @@ func (c *TCPConn) CloseWrite() error {
if !c.ok() {
return syscall.EINVAL
}
- return c.fd.CloseWrite()
+ return c.fd.closeWrite()
}
-// SetLinger sets the behavior of Close() on a connection which still
+// SetLinger sets the behavior of Close on a connection which still
// has data waiting to be sent or to be acknowledged.
//
-// If sec < 0 (the default), Close returns immediately and the
-// operating system finishes sending the data in the background.
+// If sec < 0 (the default), the operating system finishes sending the
+// data in the background.
//
-// If sec == 0, Close returns immediately and the operating system
-// discards any unsent or unacknowledged data.
+// If sec == 0, the operating system discards any unsent or
+// unacknowledged data.
//
-// If sec > 0, Close blocks for at most sec seconds waiting for data
-// to be sent and acknowledged.
+// If sec > 0, the data is sent in the background as with sec < 0. On
+// 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
}
@@ -62,12 +63,18 @@ func (c *TCPConn) SetLinger(sec int) error {
// SetKeepAlive sets whether the operating system should send
// keepalive messages on the connection.
func (c *TCPConn) SetKeepAlive(keepalive bool) error {
- return syscall.EPLAN9
+ if !c.ok() {
+ return syscall.EPLAN9
+ }
+ return setKeepAlive(c.fd, keepalive)
}
// SetKeepAlivePeriod sets period between keep alives.
func (c *TCPConn) SetKeepAlivePeriod(d time.Duration) error {
- return syscall.EPLAN9
+ if !c.ok() {
+ return syscall.EPLAN9
+ }
+ return setKeepAlivePeriod(c.fd, d)
}
// SetNoDelay controls whether the operating system should delay
diff --git a/libgo/go/net/tcpsock_posix.go b/libgo/go/net/tcpsock_posix.go
index 00c692e423..dd78aefa77 100644
--- a/libgo/go/net/tcpsock_posix.go
+++ b/libgo/go/net/tcpsock_posix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
package net
@@ -78,7 +78,7 @@ func (c *TCPConn) CloseRead() error {
if !c.ok() {
return syscall.EINVAL
}
- return c.fd.CloseRead()
+ return c.fd.closeRead()
}
// CloseWrite shuts down the writing side of the TCP connection.
@@ -87,20 +87,21 @@ func (c *TCPConn) CloseWrite() error {
if !c.ok() {
return syscall.EINVAL
}
- return c.fd.CloseWrite()
+ return c.fd.closeWrite()
}
-// SetLinger sets the behavior of Close() on a connection which still
+// SetLinger sets the behavior of Close on a connection which still
// has data waiting to be sent or to be acknowledged.
//
-// If sec < 0 (the default), Close returns immediately and the
-// operating system finishes sending the data in the background.
+// If sec < 0 (the default), the operating system finishes sending the
+// data in the background.
//
-// If sec == 0, Close returns immediately and the operating system
-// discards any unsent or unacknowledged data.
+// If sec == 0, the operating system discards any unsent or
+// unacknowledged data.
//
-// If sec > 0, Close blocks for at most sec seconds waiting for data
-// to be sent and acknowledged.
+// If sec > 0, the data is sent in the background as with sec < 0. On
+// some operating systems after sec seconds have elapsed any remaining
+// unsent data may be discarded.
func (c *TCPConn) SetLinger(sec int) error {
if !c.ok() {
return syscall.EINVAL
@@ -152,7 +153,7 @@ func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
}
func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, error) {
- fd, err := internetSocket(net, laddr, raddr, deadline, syscall.SOCK_STREAM, 0, "dial", sockaddrToTCP)
+ fd, err := internetSocket(net, laddr, raddr, deadline, syscall.SOCK_STREAM, 0, "dial")
// TCP has a rarely used mechanism called a 'simultaneous connection' in
// which Dial("tcp", addr1, addr2) run on the machine at addr1 can
@@ -182,7 +183,7 @@ func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, e
if err == nil {
fd.Close()
}
- fd, err = internetSocket(net, laddr, raddr, deadline, syscall.SOCK_STREAM, 0, "dial", sockaddrToTCP)
+ fd, err = internetSocket(net, laddr, raddr, deadline, syscall.SOCK_STREAM, 0, "dial")
}
if err != nil {
@@ -230,7 +231,7 @@ func (l *TCPListener) AcceptTCP() (*TCPConn, error) {
if l == nil || l.fd == nil {
return nil, syscall.EINVAL
}
- fd, err := l.fd.accept(sockaddrToTCP)
+ fd, err := l.fd.accept()
if err != nil {
return nil, err
}
@@ -290,7 +291,7 @@ func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) {
if laddr == nil {
laddr = &TCPAddr{}
}
- fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_STREAM, 0, "listen", sockaddrToTCP)
+ 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}
}
diff --git a/libgo/go/net/tcpsockopt_darwin.go b/libgo/go/net/tcpsockopt_darwin.go
index 33140849c9..1f1609088b 100644
--- a/libgo/go/net/tcpsockopt_darwin.go
+++ b/libgo/go/net/tcpsockopt_darwin.go
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// TCP socket options for darwin
-
package net
import (
@@ -12,16 +10,20 @@ import (
"time"
)
-// Set keep alive period.
+const sysTCP_KEEPINTVL = 0x101
+
func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
if err := fd.incref(); err != nil {
return err
}
defer fd.decref()
-
// The kernel expects seconds so round to next highest second.
d += (time.Second - time.Nanosecond)
secs := int(d.Seconds())
-
+ switch err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, sysTCP_KEEPINTVL, secs); err {
+ case nil, syscall.ENOPROTOOPT: // OS X 10.7 and earlier don't support this option
+ default:
+ return os.NewSyscallError("setsockopt", err)
+ }
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE, secs))
}
diff --git a/libgo/go/net/tcpsockopt_dragonfly.go b/libgo/go/net/tcpsockopt_dragonfly.go
new file mode 100644
index 0000000000..0aa213239d
--- /dev/null
+++ b/libgo/go/net/tcpsockopt_dragonfly.go
@@ -0,0 +1,26 @@
+// 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 (
+ "os"
+ "syscall"
+ "time"
+)
+
+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)
+ if err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, msecs); err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, msecs))
+}
diff --git a/libgo/go/net/tcpsockopt_openbsd.go b/libgo/go/net/tcpsockopt_openbsd.go
index 3480f932c8..041e1786a9 100644
--- a/libgo/go/net/tcpsockopt_openbsd.go
+++ b/libgo/go/net/tcpsockopt_openbsd.go
@@ -2,26 +2,15 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// TCP socket options for openbsd
-
package net
import (
- "os"
"syscall"
"time"
)
-// Set keep alive period.
func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
- if err := fd.incref(); err != nil {
- return err
- }
- defer fd.decref()
-
- // The kernel expects seconds so round to next highest second.
- d += (time.Second - time.Nanosecond)
- secs := int(d.Seconds())
-
- return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.SO_KEEPALIVE, secs))
+ // OpenBSD has no user-settable per-socket TCP keepalive
+ // options.
+ return syscall.ENOPROTOOPT
}
diff --git a/libgo/go/net/tcpsockopt_plan9.go b/libgo/go/net/tcpsockopt_plan9.go
new file mode 100644
index 0000000000..0e7a6647ca
--- /dev/null
+++ b/libgo/go/net/tcpsockopt_plan9.go
@@ -0,0 +1,18 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TCP socket options for plan9
+
+package net
+
+import (
+ "time"
+)
+
+// Set keep alive period.
+func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
+ cmd := "keepalive " + string(int64(d/time.Millisecond))
+ _, e := fd.ctl.WriteAt([]byte(cmd), 0)
+ return e
+}
diff --git a/libgo/go/net/tcpsockopt_posix.go b/libgo/go/net/tcpsockopt_posix.go
index e03476ac63..0abf3f97f6 100644
--- a/libgo/go/net/tcpsockopt_posix.go
+++ b/libgo/go/net/tcpsockopt_posix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd windows
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
package net
diff --git a/libgo/go/net/tcpsockopt_solaris.go b/libgo/go/net/tcpsockopt_solaris.go
new file mode 100644
index 0000000000..eaab6b6787
--- /dev/null
+++ b/libgo/go/net/tcpsockopt_solaris.go
@@ -0,0 +1,27 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TCP socket options for solaris
+
+package net
+
+import (
+ "os"
+ "syscall"
+ "time"
+)
+
+// Set keep alive period.
+func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
+ if err := fd.incref(); err != nil {
+ return err
+ }
+ defer fd.decref()
+
+ // The kernel expects seconds so round to next highest second.
+ d += (time.Second - time.Nanosecond)
+ secs := int(d.Seconds())
+
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.SO_KEEPALIVE, secs))
+}
diff --git a/libgo/go/net/tcpsockopt_stub.go b/libgo/go/net/tcpsockopt_stub.go
new file mode 100644
index 0000000000..b413a764d8
--- /dev/null
+++ b/libgo/go/net/tcpsockopt_stub.go
@@ -0,0 +1,20 @@
+// 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 nacl
+
+package net
+
+import (
+ "syscall"
+ "time"
+)
+
+func setNoDelay(fd *netFD, noDelay bool) error {
+ return syscall.ENOPROTOOPT
+}
+
+func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
+ return syscall.ENOPROTOOPT
+}
diff --git a/libgo/go/net/tcpsockopt_unix.go b/libgo/go/net/tcpsockopt_unix.go
index 89d9143b52..c9f604cad7 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 dragonfly freebsd linux netbsd
+// +build freebsd linux netbsd solaris
package net
@@ -12,20 +12,16 @@ import (
"time"
)
-// Set keep alive period.
func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
if err := fd.incref(); err != nil {
return err
}
defer fd.decref()
-
// The kernel expects seconds so round to next highest second.
d += (time.Second - time.Nanosecond)
secs := int(d.Seconds())
-
- err := os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, secs))
- if err != nil {
- return err
+ if err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, secs); err != nil {
+ return os.NewSyscallError("setsockopt", err)
}
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, secs))
}
diff --git a/libgo/go/net/tcpsockopt_windows.go b/libgo/go/net/tcpsockopt_windows.go
index 0bf4312f24..091f5233f2 100644
--- a/libgo/go/net/tcpsockopt_windows.go
+++ b/libgo/go/net/tcpsockopt_windows.go
@@ -2,12 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// TCP socket options for windows
-
package net
import (
+ "os"
+ "syscall"
"time"
+ "unsafe"
)
func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
@@ -15,7 +16,17 @@ func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
return err
}
defer fd.decref()
-
- // We can't actually set this per connection. Act as a noop rather than an error.
- return nil
+ // The kernel expects milliseconds so round to next highest
+ // millisecond.
+ d += (time.Millisecond - time.Nanosecond)
+ msecs := uint32(d / time.Millisecond)
+ ka := syscall.TCPKeepalive{
+ OnOff: 1,
+ Time: msecs,
+ Interval: msecs,
+ }
+ 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)
}
diff --git a/libgo/go/net/testdata/domain-resolv.conf b/libgo/go/net/testdata/domain-resolv.conf
new file mode 100644
index 0000000000..ff269180f4
--- /dev/null
+++ b/libgo/go/net/testdata/domain-resolv.conf
@@ -0,0 +1,5 @@
+# /etc/resolv.conf
+
+search test invalid
+domain localdomain
+nameserver 8.8.8.8
diff --git a/libgo/go/net/testdata/empty-resolv.conf b/libgo/go/net/testdata/empty-resolv.conf
new file mode 100644
index 0000000000..c4b2b57654
--- /dev/null
+++ b/libgo/go/net/testdata/empty-resolv.conf
@@ -0,0 +1 @@
+# /etc/resolv.conf
diff --git a/libgo/go/net/testdata/resolv.conf b/libgo/go/net/testdata/resolv.conf
new file mode 100644
index 0000000000..04e87eed03
--- /dev/null
+++ b/libgo/go/net/testdata/resolv.conf
@@ -0,0 +1,8 @@
+# /etc/resolv.conf
+
+domain localdomain
+nameserver 8.8.8.8
+nameserver 2001:4860:4860::8888
+nameserver fe80::1%lo0
+options ndots:5 timeout:10 attempts:3 rotate
+options attempts 3
diff --git a/libgo/go/net/testdata/search-resolv.conf b/libgo/go/net/testdata/search-resolv.conf
new file mode 100644
index 0000000000..1c846bfaff
--- /dev/null
+++ b/libgo/go/net/testdata/search-resolv.conf
@@ -0,0 +1,5 @@
+# /etc/resolv.conf
+
+domain localdomain
+search test invalid
+nameserver 8.8.8.8
diff --git a/libgo/go/net/textproto/reader.go b/libgo/go/net/textproto/reader.go
index b0c07413c1..eea9207f25 100644
--- a/libgo/go/net/textproto/reader.go
+++ b/libgo/go/net/textproto/reader.go
@@ -562,19 +562,12 @@ const toLower = 'a' - 'A'
// allowed to mutate the provided byte slice before returning the
// string.
func canonicalMIMEHeaderKey(a []byte) string {
- // Look for it in commonHeaders , so that we can avoid an
- // allocation by sharing the strings among all users
- // of textproto. If we don't find it, a has been canonicalized
- // so just return string(a).
upper := true
- lo := 0
- hi := len(commonHeaders)
- for i := 0; i < len(a); i++ {
+ 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.
- c := a[i]
if c == ' ' {
c = '-'
} else if upper && 'a' <= c && c <= 'z' {
@@ -584,60 +577,61 @@ func canonicalMIMEHeaderKey(a []byte) string {
}
a[i] = c
upper = c == '-' // for next time
-
- if lo < hi {
- for lo < hi && (len(commonHeaders[lo]) <= i || commonHeaders[lo][i] < c) {
- lo++
- }
- for hi > lo && commonHeaders[hi-1][i] > c {
- hi--
- }
- }
}
- if lo < hi && len(commonHeaders[lo]) == len(a) {
- return commonHeaders[lo]
+ // The compiler recognizes m[string(byteSlice)] as a special
+ // case, so a copy of a's bytes into a new string does not
+ // happen in this map lookup:
+ if v := commonHeader[string(a)]; v != "" {
+ return v
}
return string(a)
}
-var commonHeaders = []string{
- "Accept",
- "Accept-Charset",
- "Accept-Encoding",
- "Accept-Language",
- "Accept-Ranges",
- "Cache-Control",
- "Cc",
- "Connection",
- "Content-Id",
- "Content-Language",
- "Content-Length",
- "Content-Transfer-Encoding",
- "Content-Type",
- "Cookie",
- "Date",
- "Dkim-Signature",
- "Etag",
- "Expires",
- "From",
- "Host",
- "If-Modified-Since",
- "If-None-Match",
- "In-Reply-To",
- "Last-Modified",
- "Location",
- "Message-Id",
- "Mime-Version",
- "Pragma",
- "Received",
- "Return-Path",
- "Server",
- "Set-Cookie",
- "Subject",
- "To",
- "User-Agent",
- "Via",
- "X-Forwarded-For",
- "X-Imforwards",
- "X-Powered-By",
+// commonHeader interns common header strings.
+var commonHeader = make(map[string]string)
+
+func init() {
+ for _, v := range []string{
+ "Accept",
+ "Accept-Charset",
+ "Accept-Encoding",
+ "Accept-Language",
+ "Accept-Ranges",
+ "Cache-Control",
+ "Cc",
+ "Connection",
+ "Content-Id",
+ "Content-Language",
+ "Content-Length",
+ "Content-Transfer-Encoding",
+ "Content-Type",
+ "Cookie",
+ "Date",
+ "Dkim-Signature",
+ "Etag",
+ "Expires",
+ "From",
+ "Host",
+ "If-Modified-Since",
+ "If-None-Match",
+ "In-Reply-To",
+ "Last-Modified",
+ "Location",
+ "Message-Id",
+ "Mime-Version",
+ "Pragma",
+ "Received",
+ "Return-Path",
+ "Server",
+ "Set-Cookie",
+ "Subject",
+ "To",
+ "User-Agent",
+ "Via",
+ "X-Forwarded-For",
+ "X-Imforwards",
+ "X-Powered-By",
+ } {
+ commonHeader[v] = v
+ }
}
diff --git a/libgo/go/net/textproto/reader_test.go b/libgo/go/net/textproto/reader_test.go
index cc12912b63..c89566635e 100644
--- a/libgo/go/net/textproto/reader_test.go
+++ b/libgo/go/net/textproto/reader_test.go
@@ -247,24 +247,21 @@ func TestRFC959Lines(t *testing.T) {
}
func TestCommonHeaders(t *testing.T) {
- // need to disable the commonHeaders-based optimization
- // during this check, or we'd not be testing anything
- oldch := commonHeaders
- commonHeaders = []string{}
- defer func() { commonHeaders = oldch }()
-
- last := ""
- for _, h := range oldch {
- if last > h {
- t.Errorf("%v is out of order", h)
- }
- if last == h {
- t.Errorf("%v is duplicated", h)
+ for h := range commonHeader {
+ if h != CanonicalMIMEHeaderKey(h) {
+ t.Errorf("Non-canonical header %q in commonHeader", h)
}
- if canon := CanonicalMIMEHeaderKey(h); h != canon {
- t.Errorf("%v is not canonical", h)
+ }
+ t.Skip("gccgo escape analysis")
+ b := []byte("content-Length")
+ want := "Content-Length"
+ n := testing.AllocsPerRun(200, func() {
+ if x := canonicalMIMEHeaderKey(b); x != want {
+ t.Fatalf("canonicalMIMEHeaderKey(%q) = %q; want %q", b, x, want)
}
- last = h
+ })
+ if n > 0 {
+ t.Errorf("canonicalMIMEHeaderKey allocs = %v; want 0", n)
}
}
diff --git a/libgo/go/net/timeout_test.go b/libgo/go/net/timeout_test.go
index 35d427a69c..9ef0c4d15c 100644
--- a/libgo/go/net/timeout_test.go
+++ b/libgo/go/net/timeout_test.go
@@ -120,6 +120,9 @@ func TestReadTimeout(t *testing.T) {
t.Fatalf("Read: expected err %v, got %v", errClosing, err)
}
default:
+ if err == io.EOF && runtime.GOOS == "nacl" { // close enough; golang.org/issue/8044
+ break
+ }
if err != errClosing {
t.Fatalf("Read: expected err %v, got %v", errClosing, err)
}
@@ -348,7 +351,8 @@ func TestReadWriteDeadline(t *testing.T) {
go func() {
c, err := ln.Accept()
if err != nil {
- t.Fatalf("Accept: %v", err)
+ t.Errorf("Accept: %v", err)
+ return
}
defer c.Close()
lnquit <- true
@@ -493,10 +497,7 @@ func testVariousDeadlines(t *testing.T, maxProcs int) {
clientc <- copyRes{n, err, d}
}()
- tooLong := 2 * time.Second
- if runtime.GOOS == "windows" {
- tooLong = 5 * time.Second
- }
+ tooLong := 5 * time.Second
select {
case res := <-clientc:
if isTimeout(res.err) {
@@ -536,7 +537,8 @@ func TestReadDeadlineDataAvailable(t *testing.T) {
go func() {
c, err := ln.Accept()
if err != nil {
- t.Fatalf("Accept: %v", err)
+ t.Errorf("Accept: %v", err)
+ return
}
defer c.Close()
n, err := c.Write([]byte(msg))
@@ -574,7 +576,8 @@ func TestWriteDeadlineBufferAvailable(t *testing.T) {
go func() {
c, err := ln.Accept()
if err != nil {
- t.Fatalf("Accept: %v", err)
+ t.Errorf("Accept: %v", err)
+ return
}
defer c.Close()
c.SetWriteDeadline(time.Now().Add(-5 * time.Second)) // in the past
@@ -610,7 +613,8 @@ func TestAcceptDeadlineConnectionAvailable(t *testing.T) {
go func() {
c, err := Dial("tcp", ln.Addr().String())
if err != nil {
- t.Fatalf("Dial: %v", err)
+ t.Errorf("Dial: %v", err)
+ return
}
defer c.Close()
var buf [1]byte
@@ -669,7 +673,8 @@ func TestProlongTimeout(t *testing.T) {
s, err := ln.Accept()
connected <- true
if err != nil {
- t.Fatalf("ln.Accept: %v", err)
+ t.Errorf("ln.Accept: %v", err)
+ return
}
defer s.Close()
s.SetDeadline(time.Now().Add(time.Hour))
@@ -706,7 +711,7 @@ func TestProlongTimeout(t *testing.T) {
func TestDeadlineRace(t *testing.T) {
switch runtime.GOOS {
- case "plan9":
+ case "nacl", "plan9":
t.Skipf("skipping test on %q", runtime.GOOS)
}
diff --git a/libgo/go/net/udp_test.go b/libgo/go/net/udp_test.go
index 6f4d2152c3..125bbca6c4 100644
--- a/libgo/go/net/udp_test.go
+++ b/libgo/go/net/udp_test.go
@@ -9,6 +9,7 @@ import (
"runtime"
"strings"
"testing"
+ "time"
)
func TestResolveUDPAddr(t *testing.T) {
@@ -34,6 +35,46 @@ func TestResolveUDPAddr(t *testing.T) {
}
}
+func TestReadFromUDP(t *testing.T) {
+ switch runtime.GOOS {
+ case "nacl", "plan9":
+ t.Skipf("skipping test on %q, see issue 8916", runtime.GOOS)
+ }
+
+ ra, err := ResolveUDPAddr("udp", "127.0.0.1:7")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ la, err := ResolveUDPAddr("udp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ c, err := ListenUDP("udp", la)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer c.Close()
+
+ _, err = c.WriteToUDP([]byte("a"), ra)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = c.SetDeadline(time.Now().Add(100 * time.Millisecond))
+ if err != nil {
+ t.Fatal(err)
+ }
+ b := make([]byte, 1)
+ _, _, err = c.ReadFromUDP(b)
+ if err == nil {
+ t.Fatal("ReadFromUDP should fail")
+ } else if !isTimeout(err) {
+ t.Fatal(err)
+ }
+}
+
func TestWriteToUDP(t *testing.T) {
switch runtime.GOOS {
case "plan9":
@@ -201,6 +242,10 @@ func TestIPv6LinkLocalUnicastUDP(t *testing.T) {
{"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{
diff --git a/libgo/go/net/udpsock.go b/libgo/go/net/udpsock.go
index 0dd0dbd711..4c99ae4af6 100644
--- a/libgo/go/net/udpsock.go
+++ b/libgo/go/net/udpsock.go
@@ -4,10 +4,6 @@
package net
-import "errors"
-
-var ErrWriteToConnected = errors.New("use of WriteTo with pre-connected UDP")
-
// UDPAddr represents the address of a UDP end point.
type UDPAddr struct {
IP IP
diff --git a/libgo/go/net/udpsock_plan9.go b/libgo/go/net/udpsock_plan9.go
index 73621706d5..510ac5e4aa 100644
--- a/libgo/go/net/udpsock_plan9.go
+++ b/libgo/go/net/udpsock_plan9.go
@@ -190,7 +190,8 @@ func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
if err != nil {
return nil, err
}
- return newUDPConn(l.netFD()), nil
+ fd, err := l.netFD()
+ return newUDPConn(fd), err
}
// ListenMulticastUDP listens for incoming multicast UDP packets
diff --git a/libgo/go/net/udpsock_posix.go b/libgo/go/net/udpsock_posix.go
index 142da8186f..a0533366a4 100644
--- a/libgo/go/net/udpsock_posix.go
+++ b/libgo/go/net/udpsock_posix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
package net
@@ -64,7 +64,7 @@ func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
if !c.ok() {
return 0, nil, syscall.EINVAL
}
- n, sa, err := c.fd.ReadFrom(b)
+ n, sa, err := c.fd.readFrom(b)
switch sa := sa.(type) {
case *syscall.SockaddrInet4:
addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
@@ -93,7 +93,7 @@ func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr,
return 0, 0, 0, nil, syscall.EINVAL
}
var sa syscall.Sockaddr
- n, oobn, flags, sa, err = c.fd.ReadMsg(b, oob)
+ n, oobn, flags, sa, err = c.fd.readMsg(b, oob)
switch sa := sa.(type) {
case *syscall.SockaddrInet4:
addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
@@ -124,7 +124,7 @@ func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {
if err != nil {
return 0, &OpError{"write", c.fd.net, addr, err}
}
- return c.fd.WriteTo(b, sa)
+ return c.fd.writeTo(b, sa)
}
// WriteTo implements the PacketConn WriteTo method.
@@ -156,7 +156,7 @@ func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err er
if err != nil {
return 0, 0, &OpError{"write", c.fd.net, addr, err}
}
- return c.fd.WriteMsg(b, oob, sa)
+ return c.fd.writeMsg(b, oob, sa)
}
// DialUDP connects to the remote address raddr on the network net,
@@ -175,7 +175,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", sockaddrToUDP)
+ 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}
}
@@ -198,7 +198,7 @@ func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
if laddr == nil {
laddr = &UDPAddr{}
}
- fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen", sockaddrToUDP)
+ 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}
}
@@ -218,7 +218,7 @@ func ListenMulticastUDP(net string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, e
if gaddr == nil || gaddr.IP == nil {
return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: errMissingAddress}
}
- fd, err := internetSocket(net, gaddr, nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen", sockaddrToUDP)
+ fd, err := internetSocket(net, gaddr, nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen")
if err != nil {
return nil, &OpError{Op: "listen", Net: net, Addr: gaddr, Err: err}
}
diff --git a/libgo/go/net/unicast_posix_test.go b/libgo/go/net/unicast_posix_test.go
index 5deb8f47c6..ab7ef40a75 100644
--- a/libgo/go/net/unicast_posix_test.go
+++ b/libgo/go/net/unicast_posix_test.go
@@ -166,9 +166,12 @@ var dualStackListenerTests = []struct {
}
// TestDualStackTCPListener tests both single and double listen
-// to a test listener with various address families, differnet
+// 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)
@@ -178,7 +181,7 @@ func TestDualStackTCPListener(t *testing.T) {
}
for _, tt := range dualStackListenerTests {
- if tt.wildcard && (testing.Short() || !*testExternal) {
+ if tt.wildcard && !*testExternal {
continue
}
switch runtime.GOOS {
@@ -201,6 +204,9 @@ func TestDualStackTCPListener(t *testing.T) {
// to a test listener with various address families, differnet
// listening address and same port.
func TestDualStackUDPListener(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping in -short mode, see issue 5001")
+ }
switch runtime.GOOS {
case "plan9":
t.Skipf("skipping test on %q", runtime.GOOS)
diff --git a/libgo/go/net/unix_test.go b/libgo/go/net/unix_test.go
index 91df3ff887..1cdff3908c 100644
--- a/libgo/go/net/unix_test.go
+++ b/libgo/go/net/unix_test.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 !plan9,!windows
+// +build !nacl,!plan9,!windows
package net
@@ -151,6 +151,73 @@ func TestUnixAutobindClose(t *testing.T) {
ln.Close()
}
+func TestUnixgramWrite(t *testing.T) {
+ addr := testUnixAddr()
+ laddr, err := ResolveUnixAddr("unixgram", addr)
+ if err != nil {
+ t.Fatalf("ResolveUnixAddr failed: %v", err)
+ }
+ c, err := ListenPacket("unixgram", addr)
+ if err != nil {
+ t.Fatalf("ListenPacket failed: %v", err)
+ }
+ defer os.Remove(addr)
+ defer c.Close()
+
+ testUnixgramWriteConn(t, laddr)
+ testUnixgramWritePacketConn(t, laddr)
+}
+
+func testUnixgramWriteConn(t *testing.T, raddr *UnixAddr) {
+ c, err := Dial("unixgram", raddr.String())
+ if err != nil {
+ t.Fatalf("Dial failed: %v", err)
+ }
+ defer c.Close()
+
+ if _, err := c.(*UnixConn).WriteToUnix([]byte("Connection-oriented mode socket"), raddr); err == nil {
+ t.Fatal("WriteToUnix should fail")
+ } else if err.(*OpError).Err != ErrWriteToConnected {
+ t.Fatalf("WriteToUnix should fail as ErrWriteToConnected: %v", err)
+ }
+ if _, err = c.(*UnixConn).WriteTo([]byte("Connection-oriented mode socket"), raddr); err == nil {
+ t.Fatal("WriteTo should fail")
+ } else if err.(*OpError).Err != ErrWriteToConnected {
+ t.Fatalf("WriteTo 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")
+ } else if err.(*OpError).Err != ErrWriteToConnected {
+ t.Fatalf("WriteMsgUnix should fail as ErrWriteToConnected: %v", err)
+ }
+ if _, err := c.Write([]byte("Connection-oriented mode socket")); err != nil {
+ t.Fatalf("Write failed: %v", err)
+ }
+}
+
+func testUnixgramWritePacketConn(t *testing.T, raddr *UnixAddr) {
+ addr := testUnixAddr()
+ c, err := ListenPacket("unixgram", addr)
+ if err != nil {
+ t.Fatalf("ListenPacket failed: %v", 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)
+ }
+ if _, err := c.WriteTo([]byte("Connectionless mode socket"), raddr); err != nil {
+ t.Fatalf("WriteTo failed: %v", err)
+ }
+ if _, _, err := c.(*UnixConn).WriteMsgUnix([]byte("Connectionless mode socket"), nil, raddr); err != nil {
+ t.Fatalf("WriteMsgUnix failed: %v", err)
+ }
+ if _, err := c.(*UnixConn).Write([]byte("Connectionless mode socket")); err == nil {
+ t.Fatal("Write should fail")
+ }
+}
+
func TestUnixConnLocalAndRemoteNames(t *testing.T) {
for _, laddr := range []string{"", testUnixAddr()} {
laddr := laddr
@@ -189,8 +256,11 @@ func TestUnixConnLocalAndRemoteNames(t *testing.T) {
t.Fatalf("UnixConn.Write failed: %v", err)
}
- if runtime.GOOS == "linux" && laddr == "" {
- laddr = "@" // autobind feature
+ switch runtime.GOOS {
+ case "android", "linux":
+ if laddr == "" {
+ laddr = "@" // autobind feature
+ }
}
var connAddrs = [3]struct{ got, want Addr }{
{ln.Addr(), ta},
@@ -241,9 +311,13 @@ func TestUnixgramConnLocalAndRemoteNames(t *testing.T) {
}
}()
- if runtime.GOOS == "linux" && laddr == "" {
- laddr = "@" // autobind feature
+ switch runtime.GOOS {
+ case "android", "linux":
+ if laddr == "" {
+ laddr = "@" // autobind feature
+ }
}
+
var connAddrs = [4]struct{ got, want Addr }{
{c1.LocalAddr(), ta},
{c1.RemoteAddr(), nil},
diff --git a/libgo/go/net/unixsock_posix.go b/libgo/go/net/unixsock_posix.go
index b82f3cee0b..3c2e78bdca 100644
--- a/libgo/go/net/unixsock_posix.go
+++ b/libgo/go/net/unixsock_posix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
package net
@@ -42,14 +42,7 @@ func unixSocket(net string, laddr, raddr sockaddr, mode string, deadline time.Ti
return nil, errors.New("unknown mode: " + mode)
}
- f := sockaddrToUnix
- if sotype == syscall.SOCK_DGRAM {
- f = sockaddrToUnixgram
- } else if sotype == syscall.SOCK_SEQPACKET {
- f = sockaddrToUnixpacket
- }
-
- fd, err := socket(net, syscall.AF_UNIX, sotype, 0, false, laddr, raddr, deadline, f)
+ fd, err := socket(net, syscall.AF_UNIX, sotype, 0, false, laddr, raddr, deadline)
if err != nil {
return nil, err
}
@@ -124,7 +117,7 @@ func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err error) {
if !c.ok() {
return 0, nil, syscall.EINVAL
}
- n, sa, err := c.fd.ReadFrom(b)
+ n, sa, err := c.fd.readFrom(b)
switch sa := sa.(type) {
case *syscall.SockaddrUnix:
if sa.Name != "" {
@@ -151,7 +144,7 @@ func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAdd
if !c.ok() {
return 0, 0, 0, nil, syscall.EINVAL
}
- n, oobn, flags, sa, err := c.fd.ReadMsg(b, oob)
+ n, oobn, flags, sa, err := c.fd.readMsg(b, oob)
switch sa := sa.(type) {
case *syscall.SockaddrUnix:
if sa.Name != "" {
@@ -171,6 +164,9 @@ func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err 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}
+ }
if addr == nil {
return 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress}
}
@@ -178,7 +174,7 @@ func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err error) {
return 0, syscall.EAFNOSUPPORT
}
sa := &syscall.SockaddrUnix{Name: addr.Name}
- return c.fd.WriteTo(b, sa)
+ return c.fd.writeTo(b, sa)
}
// WriteTo implements the PacketConn WriteTo method.
@@ -200,14 +196,17 @@ func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err
if !c.ok() {
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}
+ }
if addr != nil {
if addr.Net != sotypeToNet(c.fd.sotype) {
return 0, 0, syscall.EAFNOSUPPORT
}
sa := &syscall.SockaddrUnix{Name: addr.Name}
- return c.fd.WriteMsg(b, oob, sa)
+ return c.fd.writeMsg(b, oob, sa)
}
- return c.fd.WriteMsg(b, oob, nil)
+ return c.fd.writeMsg(b, oob, nil)
}
// CloseRead shuts down the reading side of the Unix domain connection.
@@ -216,7 +215,7 @@ func (c *UnixConn) CloseRead() error {
if !c.ok() {
return syscall.EINVAL
}
- return c.fd.CloseRead()
+ return c.fd.closeRead()
}
// CloseWrite shuts down the writing side of the Unix domain connection.
@@ -225,7 +224,7 @@ func (c *UnixConn) CloseWrite() error {
if !c.ok() {
return syscall.EINVAL
}
- return c.fd.CloseWrite()
+ return c.fd.closeWrite()
}
// DialUnix connects to the remote address raddr on the network net,
@@ -280,7 +279,7 @@ func (l *UnixListener) AcceptUnix() (*UnixConn, error) {
if l == nil || l.fd == nil {
return nil, syscall.EINVAL
}
- fd, err := l.fd.accept(sockaddrToUnix)
+ fd, err := l.fd.accept()
if err != nil {
return nil, err
}
diff --git a/libgo/go/net/url/url.go b/libgo/go/net/url/url.go
index 3b3787202b..f167408fab 100644
--- a/libgo/go/net/url/url.go
+++ b/libgo/go/net/url/url.go
@@ -64,7 +64,6 @@ func (e EscapeError) Error() string {
// Return true if the specified character should be escaped when
// appearing in a URL string, according to RFC 3986.
-// When 'all' is true the full range of reserved characters are matched.
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' {
@@ -86,10 +85,12 @@ func shouldEscape(c byte, mode encoding) bool {
// last two as well. That leaves only ? to escape.
return c == '?'
- case encodeUserPassword: // §3.2.2
- // The RFC allows ; : & = + $ , in userinfo, so we must escape only @ and /.
- // The parsing of userinfo treats : as special so we must escape that too.
- return c == '@' || c == '/' || c == ':'
+ case encodeUserPassword: // §3.2.1
+ // The RFC allows ';', ':', '&', '=', '+', '$', and ',' in
+ // userinfo, so we must escape only '@', '/', and '?'.
+ // The parsing of userinfo treats ':' as special so we must escape
+ // that too.
+ return c == '@' || c == '/' || c == '?' || c == ':'
case encodeQueryComponent: // §3.4
// The RFC reserves (so we must escape) everything.
@@ -440,6 +441,24 @@ func parseAuthority(authority string) (user *Userinfo, host string, err error) {
}
// String reassembles the URL into a valid URL string.
+// The general form of the result is one of:
+//
+// scheme:opaque
+// scheme://userinfo@host/path?query#fragment
+//
+// If u.Opaque is non-empty, String uses the first form;
+// otherwise it uses the second form.
+//
+// In the second form, the following rules apply:
+// - if u.Scheme is empty, scheme: is omitted.
+// - if u.User is nil, userinfo@ is omitted.
+// - if u.Host is empty, host/ is omitted.
+// - if u.Scheme and u.Host are empty and u.User is nil,
+// the entire scheme://userinfo@host/ is omitted.
+// - if u.Host is non-empty and u.Path begins with a /,
+// the form host/path does not add its own /.
+// - if u.RawQuery is empty, ?query is omitted.
+// - if u.Fragment is empty, #fragment is omitted.
func (u *URL) String() string {
var buf bytes.Buffer
if u.Scheme != "" {
@@ -502,7 +521,7 @@ func (v Values) Set(key, value string) {
v[key] = []string{value}
}
-// Add adds the key to value. It appends to any existing
+// Add adds the value to key. It appends to any existing
// values associated with key.
func (v Values) Add(key, value string) {
v[key] = append(v[key], value)
diff --git a/libgo/go/net/url/url_test.go b/libgo/go/net/url/url_test.go
index 7578eb15b9..d8b19d805d 100644
--- a/libgo/go/net/url/url_test.go
+++ b/libgo/go/net/url/url_test.go
@@ -251,6 +251,17 @@ var urltests = []URLTest{
},
"file:///home/adg/rabbits",
},
+ // "Windows" paths are no exception to the rule.
+ // See golang.org/issue/6027, especially comment #9.
+ {
+ "file:///C:/FooBar/Baz.txt",
+ &URL{
+ Scheme: "file",
+ Host: "",
+ Path: "/C:/FooBar/Baz.txt",
+ },
+ "file:///C:/FooBar/Baz.txt",
+ },
// case-insensitive scheme
{
"MaIlTo:webmaster@golang.org",
@@ -268,6 +279,16 @@ var urltests = []URLTest{
},
"a/b/c",
},
+ // escaped '?' in username and password
+ {
+ "http://%3Fam:pa%3Fsword@google.com",
+ &URL{
+ Scheme: "http",
+ User: UserPassword("?am", "pa?sword"),
+ Host: "google.com",
+ },
+ "",
+ },
}
// more useful string for debugging than fmt's struct printer
@@ -892,3 +913,49 @@ func TestParseFailure(t *testing.T) {
t.Errorf(`ParseQuery(%q) returned error %q, want something containing %q"`, url, errStr, "%gh")
}
}
+
+type shouldEscapeTest struct {
+ in byte
+ mode encoding
+ escape bool
+}
+
+var shouldEscapeTests = []shouldEscapeTest{
+ // Unreserved characters (§2.3)
+ {'a', encodePath, false},
+ {'a', encodeUserPassword, false},
+ {'a', encodeQueryComponent, false},
+ {'a', encodeFragment, false},
+ {'z', encodePath, false},
+ {'A', encodePath, false},
+ {'Z', encodePath, false},
+ {'0', encodePath, false},
+ {'9', encodePath, false},
+ {'-', encodePath, false},
+ {'-', encodeUserPassword, false},
+ {'-', encodeQueryComponent, false},
+ {'-', encodeFragment, false},
+ {'.', encodePath, false},
+ {'_', encodePath, false},
+ {'~', encodePath, false},
+
+ // User information (§3.2.1)
+ {':', encodeUserPassword, true},
+ {'/', encodeUserPassword, true},
+ {'?', encodeUserPassword, true},
+ {'@', encodeUserPassword, true},
+ {'$', encodeUserPassword, false},
+ {'&', encodeUserPassword, false},
+ {'+', encodeUserPassword, false},
+ {',', encodeUserPassword, false},
+ {';', encodeUserPassword, false},
+ {'=', encodeUserPassword, false},
+}
+
+func TestShouldEscape(t *testing.T) {
+ for _, tt := range shouldEscapeTests {
+ if shouldEscape(tt.in, tt.mode) != tt.escape {
+ t.Errorf("shouldEscape(%q, %v) returned %v; expected %v", tt.in, tt.mode, !tt.escape, tt.escape)
+ }
+ }
+}
diff --git a/libgo/go/net/z_last_test.go b/libgo/go/net/z_last_test.go
new file mode 100644
index 0000000000..716c103db2
--- /dev/null
+++ b/libgo/go/net/z_last_test.go
@@ -0,0 +1,99 @@
+// 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/dir_unix.go b/libgo/go/os/dir_unix.go
index 9fa7ad664f..589db85274 100644
--- a/libgo/go/os/dir_unix.go
+++ b/libgo/go/os/dir_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 netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package os
@@ -36,7 +36,7 @@ func (f *File) readdirnames(n int) (names []string, err error) {
if d.bufp >= d.nbuf {
d.bufp = 0
var errno error
- d.nbuf, errno = syscall.ReadDirent(f.fd, d.buf)
+ d.nbuf, errno = fixCount(syscall.ReadDirent(f.fd, d.buf))
if errno != nil {
return names, NewSyscallError("readdirent", errno)
}
diff --git a/libgo/go/os/doc.go b/libgo/go/os/doc.go
index a954e313d1..389a8eb14c 100644
--- a/libgo/go/os/doc.go
+++ b/libgo/go/os/doc.go
@@ -39,11 +39,14 @@ func (p *Process) Kill() error {
// Wait waits for the Process to exit, and then returns a
// ProcessState describing its status and an error, if any.
// Wait releases any resources associated with the Process.
+// On most operating systems, the Process must be a child
+// of the current process or an error will be returned.
func (p *Process) Wait() (*ProcessState, error) {
return p.wait()
}
// Signal sends a signal to the Process.
+// Sending Interrupt on Windows is not implemented.
func (p *Process) Signal(sig Signal) error {
return p.signal(sig)
}
diff --git a/libgo/go/os/env.go b/libgo/go/os/env.go
index db7fc72b8a..d0494a4763 100644
--- a/libgo/go/os/env.go
+++ b/libgo/go/os/env.go
@@ -91,6 +91,11 @@ func Setenv(key, value string) error {
return nil
}
+// Unsetenv unsets a single environment variable.
+func Unsetenv(key string) error {
+ return syscall.Unsetenv(key)
+}
+
// Clearenv deletes all environment variables.
func Clearenv() {
syscall.Clearenv()
diff --git a/libgo/go/os/env_test.go b/libgo/go/os/env_test.go
index 991fa4d057..e618067513 100644
--- a/libgo/go/os/env_test.go
+++ b/libgo/go/os/env_test.go
@@ -7,6 +7,7 @@ package os_test
import (
. "os"
"reflect"
+ "strings"
"testing"
)
@@ -68,3 +69,28 @@ func TestConsistentEnviron(t *testing.T) {
}
}
}
+
+func TestUnsetenv(t *testing.T) {
+ const testKey = "GO_TEST_UNSETENV"
+ set := func() bool {
+ prefix := testKey + "="
+ for _, key := range Environ() {
+ if strings.HasPrefix(key, prefix) {
+ return true
+ }
+ }
+ return false
+ }
+ if err := Setenv(testKey, "1"); err != nil {
+ t.Fatalf("Setenv: %v", err)
+ }
+ if !set() {
+ t.Error("Setenv didn't set TestUnsetenv")
+ }
+ if err := Unsetenv(testKey); err != nil {
+ t.Fatalf("Unsetenv: %v", err)
+ }
+ if set() {
+ t.Fatal("Unsetenv didn't clear TestUnsetenv")
+ }
+}
diff --git a/libgo/go/os/env_unix_test.go b/libgo/go/os/env_unix_test.go
index e16d71a649..5ec07ee1b1 100644
--- a/libgo/go/os/env_unix_test.go
+++ b/libgo/go/os/env_unix_test.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 netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package os_test
diff --git a/libgo/go/os/error_plan9.go b/libgo/go/os/error_plan9.go
index 85260c82ae..001cdfcf2e 100644
--- a/libgo/go/os/error_plan9.go
+++ b/libgo/go/os/error_plan9.go
@@ -25,7 +25,8 @@ func isNotExist(err error) bool {
case *LinkError:
err = pe.Err
}
- return contains(err.Error(), "does not exist")
+ return contains(err.Error(), "does not exist") || contains(err.Error(), "not found") ||
+ contains(err.Error(), "has been removed") || contains(err.Error(), "no parent")
}
func isPermission(err error) bool {
diff --git a/libgo/go/os/error_unix.go b/libgo/go/os/error_unix.go
index 6250349e5b..f2aabbb45c 100644
--- a/libgo/go/os/error_unix.go
+++ b/libgo/go/os/error_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 netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package os
diff --git a/libgo/go/os/exec/exec.go b/libgo/go/os/exec/exec.go
index 491cc242bb..72b4905d56 100644
--- a/libgo/go/os/exec/exec.go
+++ b/libgo/go/os/exec/exec.go
@@ -12,7 +12,10 @@ import (
"errors"
"io"
"os"
+ "path/filepath"
+ "runtime"
"strconv"
+ "strings"
"sync"
"syscall"
)
@@ -33,7 +36,8 @@ type Cmd struct {
// Path is the path of the command to run.
//
// This is the only field that must be set to a non-zero
- // value.
+ // value. If Path is relative, it is evaluated relative
+ // to Dir.
Path string
// Args holds command line arguments, including the command as Args[0].
@@ -51,8 +55,15 @@ type Cmd struct {
// calling process's current directory.
Dir string
- // Stdin specifies the process's standard input. If Stdin is
- // nil, the process reads from the null device (os.DevNull).
+ // Stdin specifies the process's standard input.
+ // If Stdin is nil, the process reads from the null device (os.DevNull).
+ // If Stdin is an *os.File, the process's standard input is connected
+ // directly to that file.
+ // Otherwise, during the execution of the command a separate
+ // goroutine reads from Stdin and delivers that data to the command
+ // over a pipe. In this case, Wait does not complete until the goroutine
+ // stops copying, either because it has reached the end of Stdin
+ // (EOF or a read error) or because writing to the pipe returned an error.
Stdin io.Reader
// Stdout and Stderr specify the process's standard output and error.
@@ -84,7 +95,7 @@ type Cmd struct {
// available after a call to Wait or Run.
ProcessState *os.ProcessState
- err error // last error (from LookPath, stdin, stdout, stderr)
+ lookPathErr error // LookPath error, if any.
finished bool // when Wait was called
childFiles []*os.File
closeAfterStart []io.Closer
@@ -96,8 +107,7 @@ type Cmd struct {
// Command returns the Cmd struct to execute the named program with
// the given arguments.
//
-// It sets Path and Args in the returned structure and zeroes the
-// other fields.
+// It sets only the Path and Args in the returned structure.
//
// If name contains no path separators, Command uses LookPath to
// resolve the path to a complete name if possible. Otherwise it uses
@@ -107,19 +117,22 @@ type Cmd struct {
// followed by the elements of arg, so arg should not include the
// command name itself. For example, Command("echo", "hello")
func Command(name string, arg ...string) *Cmd {
- aname, err := LookPath(name)
- if err != nil {
- aname = name
- }
- return &Cmd{
- Path: aname,
+ cmd := &Cmd{
+ Path: name,
Args: append([]string{name}, arg...),
- err: err,
}
+ if filepath.Base(name) == name {
+ if lp, err := LookPath(name); err != nil {
+ cmd.lookPathErr = err
+ } else {
+ cmd.Path = lp
+ }
+ }
+ return cmd
}
// interfaceEqual protects against panics from doing equality tests on
-// two interfaces with non-comparable underlying types
+// two interfaces with non-comparable underlying types.
func interfaceEqual(a, b interface{}) bool {
defer func() {
recover()
@@ -233,12 +246,50 @@ func (c *Cmd) Run() error {
return c.Wait()
}
+// lookExtensions finds windows executable by its dir and path.
+// It uses LookPath to try appropriate extensions.
+// lookExtensions does not search PATH, instead it converts `prog` into `.\prog`.
+func lookExtensions(path, dir string) (string, error) {
+ if filepath.Base(path) == path {
+ path = filepath.Join(".", path)
+ }
+ if dir == "" {
+ return LookPath(path)
+ }
+ if filepath.VolumeName(path) != "" {
+ return LookPath(path)
+ }
+ if len(path) > 1 && os.IsPathSeparator(path[0]) {
+ return LookPath(path)
+ }
+ dirandpath := filepath.Join(dir, path)
+ // We assume that LookPath will only add file extension.
+ lp, err := LookPath(dirandpath)
+ if err != nil {
+ return "", err
+ }
+ ext := strings.TrimPrefix(lp, dirandpath)
+ return path + ext, nil
+}
+
// Start starts the specified command but does not wait for it to complete.
+//
+// The Wait method will return the exit code and release associated resources
+// once the command exits.
func (c *Cmd) Start() error {
- if c.err != nil {
+ if c.lookPathErr != nil {
c.closeDescriptors(c.closeAfterStart)
c.closeDescriptors(c.closeAfterWait)
- return c.err
+ return c.lookPathErr
+ }
+ if runtime.GOOS == "windows" {
+ lp, err := lookExtensions(c.Path, c.Dir)
+ if err != nil {
+ c.closeDescriptors(c.closeAfterStart)
+ c.closeDescriptors(c.closeAfterWait)
+ return err
+ }
+ c.Path = lp
}
if c.Process != nil {
return errors.New("exec: already started")
@@ -300,6 +351,8 @@ func (e *ExitError) Error() string {
// If the command fails to run or doesn't complete successfully, the
// error is of type *ExitError. Other error types may be
// returned for I/O problems.
+//
+// Wait releases any resources associated with the Cmd.
func (c *Cmd) Wait() error {
if c.Process == nil {
return errors.New("exec: not started")
@@ -312,7 +365,7 @@ func (c *Cmd) Wait() error {
c.ProcessState = state
var copyError error
- for _ = range c.goroutine {
+ for range c.goroutine {
if err := <-c.errch; err != nil && copyError == nil {
copyError = err
}
@@ -383,15 +436,17 @@ func (c *Cmd) StdinPipe() (io.WriteCloser, error) {
type closeOnce struct {
*os.File
- close sync.Once
- closeErr error
+ once sync.Once
+ err error
}
func (c *closeOnce) Close() error {
- c.close.Do(func() {
- c.closeErr = c.File.Close()
- })
- return c.closeErr
+ c.once.Do(c.close)
+ return c.err
+}
+
+func (c *closeOnce) close() {
+ c.err = c.File.Close()
}
// StdoutPipe returns a pipe that will be connected to the command's
diff --git a/libgo/go/os/exec/exec_test.go b/libgo/go/os/exec/exec_test.go
index b6addcd45a..f9ffde602c 100644
--- a/libgo/go/os/exec/exec_test.go
+++ b/libgo/go/os/exec/exec_test.go
@@ -2,7 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package exec
+// Use an external test to avoid os/exec -> net/http -> crypto/x509 -> os/exec
+// circular dependency on non-cgo darwin.
+
+package exec_test
import (
"bufio"
@@ -10,10 +13,12 @@ import (
"fmt"
"io"
"io/ioutil"
+ "log"
"net"
"net/http"
"net/http/httptest"
"os"
+ "os/exec"
"path/filepath"
"runtime"
"strconv"
@@ -22,10 +27,13 @@ import (
"time"
)
-func helperCommand(s ...string) *Cmd {
+func helperCommand(t *testing.T, s ...string) *exec.Cmd {
+ if runtime.GOOS == "nacl" {
+ t.Skip("skipping on nacl")
+ }
cs := []string{"-test.run=TestHelperProcess", "--"}
cs = append(cs, s...)
- cmd := Command(os.Args[0], cs...)
+ cmd := exec.Command(os.Args[0], cs...)
cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
path := os.Getenv("LD_LIBRARY_PATH")
if path != "" {
@@ -35,7 +43,7 @@ func helperCommand(s ...string) *Cmd {
}
func TestEcho(t *testing.T) {
- bs, err := helperCommand("echo", "foo bar", "baz").Output()
+ bs, err := helperCommand(t, "echo", "foo bar", "baz").Output()
if err != nil {
t.Errorf("echo: %v", err)
}
@@ -44,10 +52,37 @@ func TestEcho(t *testing.T) {
}
}
+func TestCommandRelativeName(t *testing.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"
+ dir := filepath.Dir(os.Args[0]) // "/tmp/go-buildNNNN/os/exec/_test"
+ if dir == "." {
+ t.Skip("skipping; running test at root somehow")
+ }
+ parentDir := filepath.Dir(dir) // "/tmp/go-buildNNNN/os/exec"
+ dirBase := filepath.Base(dir) // "_test"
+ if dirBase == "." {
+ t.Skipf("skipping; unexpected shallow dir of %q", dir)
+ }
+
+ cmd := exec.Command(filepath.Join(dirBase, base), "-test.run=TestHelperProcess", "--", "echo", "foo")
+ cmd.Dir = parentDir
+ cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
+
+ out, err := cmd.Output()
+ if err != nil {
+ t.Errorf("echo: %v", err)
+ }
+ if g, e := string(out), "foo\n"; g != e {
+ t.Errorf("echo: want %q, got %q", e, g)
+ }
+}
+
func TestCatStdin(t *testing.T) {
// Cat, testing stdin and stdout.
input := "Input string\nLine 2"
- p := helperCommand("cat")
+ p := helperCommand(t, "cat")
p.Stdin = strings.NewReader(input)
bs, err := p.Output()
if err != nil {
@@ -61,9 +96,9 @@ func TestCatStdin(t *testing.T) {
func TestCatGoodAndBadFile(t *testing.T) {
// Testing combined output and error values.
- bs, err := helperCommand("cat", "/bogus/file.foo", "exec_test.go").CombinedOutput()
- if _, ok := err.(*ExitError); !ok {
- t.Errorf("expected *ExitError from cat combined; got %T: %v", err, err)
+ bs, err := helperCommand(t, "cat", "/bogus/file.foo", "exec_test.go").CombinedOutput()
+ if _, ok := err.(*exec.ExitError); !ok {
+ t.Errorf("expected *exec.ExitError from cat combined; got %T: %v", err, err)
}
s := string(bs)
sp := strings.SplitN(s, "\n", 2)
@@ -81,7 +116,7 @@ func TestCatGoodAndBadFile(t *testing.T) {
func TestNoExistBinary(t *testing.T) {
// Can't run a non-existent binary
- err := Command("/no-exist-binary").Run()
+ err := exec.Command("/no-exist-binary").Run()
if err == nil {
t.Error("expected error from /no-exist-binary")
}
@@ -89,19 +124,19 @@ func TestNoExistBinary(t *testing.T) {
func TestExitStatus(t *testing.T) {
// Test that exit values are returned correctly
- cmd := helperCommand("exit", "42")
+ cmd := helperCommand(t, "exit", "42")
err := cmd.Run()
want := "exit status 42"
switch runtime.GOOS {
case "plan9":
want = fmt.Sprintf("exit status: '%s %d: 42'", filepath.Base(cmd.Path), cmd.ProcessState.Pid())
}
- if werr, ok := err.(*ExitError); ok {
+ if werr, ok := err.(*exec.ExitError); ok {
if s := werr.Error(); s != want {
t.Errorf("from exit 42 got exit %q, want %q", s, want)
}
} else {
- t.Fatalf("expected *ExitError from exit 42; got %T: %v", err, err)
+ t.Fatalf("expected *exec.ExitError from exit 42; got %T: %v", err, err)
}
}
@@ -112,7 +147,7 @@ func TestPipes(t *testing.T) {
}
}
// Cat, testing stdin and stdout.
- c := helperCommand("pipetest")
+ c := helperCommand(t, "pipetest")
stdin, err := c.StdinPipe()
check("StdinPipe", err)
stdout, err := c.StdoutPipe()
@@ -165,7 +200,7 @@ func TestStdinClose(t *testing.T) {
t.Fatalf("%s: %v", what, err)
}
}
- cmd := helperCommand("stdinClose")
+ cmd := helperCommand(t, "stdinClose")
stdin, err := cmd.StdinPipe()
check("StdinPipe", err)
// Check that we can access methods of the underlying os.File.`
@@ -186,9 +221,9 @@ func TestStdinClose(t *testing.T) {
// Issue 5071
func TestPipeLookPathLeak(t *testing.T) {
- fd0 := numOpenFDS(t)
+ fd0, lsof0 := numOpenFDS(t)
for i := 0; i < 4; i++ {
- cmd := Command("something-that-does-not-exist-binary")
+ cmd := exec.Command("something-that-does-not-exist-binary")
cmd.StdoutPipe()
cmd.StderrPipe()
cmd.StdinPipe()
@@ -196,19 +231,30 @@ func TestPipeLookPathLeak(t *testing.T) {
t.Fatal("unexpected success")
}
}
- fdGrowth := numOpenFDS(t) - fd0
- if fdGrowth > 2 {
- t.Errorf("leaked %d fds; want ~0", fdGrowth)
+ for triesLeft := 3; triesLeft >= 0; triesLeft-- {
+ open, lsof := numOpenFDS(t)
+ fdGrowth := open - fd0
+ if fdGrowth > 2 {
+ if triesLeft > 0 {
+ // Work around what appears to be a race with Linux's
+ // proc filesystem (as used by lsof). It seems to only
+ // be eventually consistent. Give it awhile to settle.
+ // See golang.org/issue/7808
+ time.Sleep(100 * time.Millisecond)
+ continue
+ }
+ t.Errorf("leaked %d fds; want ~0; have:\n%s\noriginally:\n%s", fdGrowth, lsof, lsof0)
+ }
+ break
}
}
-func numOpenFDS(t *testing.T) int {
- lsof, err := Command("lsof", "-n", "-p", strconv.Itoa(os.Getpid())).Output()
+func numOpenFDS(t *testing.T) (n int, lsof []byte) {
+ 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")
- return 0
}
- return bytes.Count(lsof, []byte("\n"))
+ return bytes.Count(lsof, []byte("\n")), lsof
}
var testedAlreadyLeaked = false
@@ -216,15 +262,7 @@ var testedAlreadyLeaked = false
// basefds returns the number of expected file descriptors
// to be present in a process at start.
func basefds() uintptr {
- n := os.Stderr.Fd() + 1
-
- // Go runtime for 32-bit Plan 9 requires that /dev/bintime
- // be kept open.
- // See ../../runtime/time_plan9_386.c:/^runtime·nanotime
- if runtime.GOOS == "plan9" && runtime.GOARCH == "386" {
- n++
- }
- return n
+ return os.Stderr.Fd() + 1
}
func closeUnexpectedFds(t *testing.T, m string) {
@@ -274,7 +312,7 @@ func TestExtraFilesFDShuffle(t *testing.T) {
// Moving this test case around within the overall tests may
// affect the FDs obtained and hence the checks to catch these cases.
npipes := 2
- c := helperCommand("extraFilesAndPipes", strconv.Itoa(npipes+1))
+ c := helperCommand(t, "extraFilesAndPipes", strconv.Itoa(npipes+1))
rd, wr, _ := os.Pipe()
defer rd.Close()
if rd.Fd() != 3 {
@@ -341,8 +379,9 @@ func TestExtraFilesFDShuffle(t *testing.T) {
}
func TestExtraFiles(t *testing.T) {
- if runtime.GOOS == "windows" {
- t.Skip("no operating system support; skipping")
+ switch runtime.GOOS {
+ case "nacl", "windows":
+ t.Skipf("skipping test on %q", runtime.GOOS)
}
// Ensure that file descriptors have not already been leaked into
@@ -374,11 +413,15 @@ func TestExtraFiles(t *testing.T) {
// Force TLS root certs to be loaded (which might involve
// cgo), to make sure none of that potential C code leaks fds.
- ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- w.Write([]byte("Hello"))
- }))
+ ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
+ // quiet expected TLS handshake error "remote error: bad certificate"
+ ts.Config.ErrorLog = log.New(ioutil.Discard, "", 0)
+ ts.StartTLS()
defer ts.Close()
- http.Get(ts.URL) // ignore result; just calling to force root cert loading
+ _, err = http.Get(ts.URL)
+ if err == nil {
+ t.Errorf("success trying to fetch %s; want an error", ts.URL)
+ }
tf, err := ioutil.TempFile("", "")
if err != nil {
@@ -397,7 +440,7 @@ func TestExtraFiles(t *testing.T) {
t.Fatalf("Seek: %v", err)
}
- c := helperCommand("read3")
+ c := helperCommand(t, "read3")
var stdout, stderr bytes.Buffer
c.Stdout = &stdout
c.Stderr = &stderr
@@ -429,7 +472,7 @@ func TestExtraFilesRace(t *testing.T) {
}
return f
}
- runCommand := func(c *Cmd, out chan<- string) {
+ runCommand := func(c *exec.Cmd, out chan<- string) {
bout, err := c.CombinedOutput()
if err != nil {
out <- "ERROR:" + err.Error()
@@ -440,10 +483,10 @@ func TestExtraFilesRace(t *testing.T) {
for i := 0; i < 10; i++ {
la := listen()
- ca := helperCommand("describefiles")
+ ca := helperCommand(t, "describefiles")
ca.ExtraFiles = []*os.File{listenerFile(la)}
lb := listen()
- cb := helperCommand("describefiles")
+ cb := helperCommand(t, "describefiles")
cb.ExtraFiles = []*os.File{listenerFile(lb)}
ares := make(chan string)
bres := make(chan string)
@@ -480,6 +523,8 @@ func TestHelperProcess(*testing.T) {
switch runtime.GOOS {
case "dragonfly", "freebsd", "netbsd", "openbsd":
ofcmd = "fstat"
+ case "plan9":
+ ofcmd = "/bin/cat"
}
args := os.Args
@@ -570,6 +615,14 @@ func TestHelperProcess(*testing.T) {
// the cloned file descriptors that result from opening
// /dev/urandom.
// http://golang.org/issue/3955
+ case "plan9":
+ // TODO(0intro): Determine why Plan 9 is leaking
+ // file descriptors.
+ // http://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
default:
// Now verify that there are no other open fds.
var files []*os.File
@@ -581,7 +634,14 @@ func TestHelperProcess(*testing.T) {
}
if got := f.Fd(); got != wantfd {
fmt.Printf("leaked parent file. fd = %d; want %d\n", got, wantfd)
- out, _ := Command(ofcmd, "-p", fmt.Sprint(os.Getpid())).CombinedOutput()
+ var args []string
+ switch runtime.GOOS {
+ case "plan9":
+ args = []string{fmt.Sprintf("/proc/%d/fd", os.Getpid())}
+ default:
+ args = []string{"-p", fmt.Sprint(os.Getpid())}
+ }
+ out, _ := exec.Command(ofcmd, args...).CombinedOutput()
fmt.Print(string(out))
os.Exit(1)
}
@@ -638,6 +698,24 @@ func TestHelperProcess(*testing.T) {
}
fmt.Fprintf(os.Stderr, "child: %s", response)
os.Exit(0)
+ case "exec":
+ cmd := exec.Command(args[1])
+ cmd.Dir = args[0]
+ output, err := cmd.CombinedOutput()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Child: %s %s", err, string(output))
+ os.Exit(1)
+ }
+ fmt.Printf("%s", string(output))
+ os.Exit(0)
+ case "lookpath":
+ p, err := exec.LookPath(args[0])
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "LookPath failed: %v\n", err)
+ os.Exit(1)
+ }
+ fmt.Print(p)
+ os.Exit(0)
default:
fmt.Fprintf(os.Stderr, "Unknown command %q\n", cmd)
os.Exit(2)
diff --git a/libgo/go/os/exec/lp_unix.go b/libgo/go/os/exec/lp_unix.go
index 7ff2d201bc..3f895d5b3b 100644
--- a/libgo/go/os/exec/lp_unix.go
+++ b/libgo/go/os/exec/lp_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 netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package exec
diff --git a/libgo/go/os/exec/lp_unix_test.go b/libgo/go/os/exec/lp_unix_test.go
index f1ab6deffd..051db664a8 100644
--- a/libgo/go/os/exec/lp_unix_test.go
+++ b/libgo/go/os/exec/lp_unix_test.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 netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package exec
diff --git a/libgo/go/os/exec_plan9.go b/libgo/go/os/exec_plan9.go
index 2bd5b6888d..676be36ac7 100644
--- a/libgo/go/os/exec_plan9.go
+++ b/libgo/go/os/exec_plan9.go
@@ -52,10 +52,6 @@ func (p *Process) signal(sig Signal) error {
if p.done() {
return errors.New("os: process already finished")
}
- if sig == Kill {
- // Special-case the kill signal since it doesn't use /proc/$pid/note.
- return p.Kill()
- }
if e := p.writeProcFile("note", sig.String()); e != nil {
return NewSyscallError("signal", e)
}
@@ -63,10 +59,7 @@ func (p *Process) signal(sig Signal) error {
}
func (p *Process) kill() error {
- if e := p.writeProcFile("ctl", "kill"); e != nil {
- return NewSyscallError("kill", e)
- }
- return nil
+ return p.signal(Kill)
}
func (p *Process) wait() (ps *ProcessState, err error) {
diff --git a/libgo/go/os/exec_posix.go b/libgo/go/os/exec_posix.go
index fb123aefbc..fb9d291e66 100644
--- a/libgo/go/os/exec_posix.go
+++ b/libgo/go/os/exec_posix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
package os
diff --git a/libgo/go/os/exec_unix.go b/libgo/go/os/exec_unix.go
index 5572e628e6..ed97f85e22 100644
--- a/libgo/go/os/exec_unix.go
+++ b/libgo/go/os/exec_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 netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package os
@@ -34,15 +34,26 @@ func (p *Process) wait() (ps *ProcessState, err error) {
return ps, nil
}
+var errFinished = errors.New("os: process already finished")
+
func (p *Process) signal(sig Signal) error {
+ if p.Pid == -1 {
+ return errors.New("os: process already released")
+ }
+ if p.Pid == 0 {
+ return errors.New("os: process not initialized")
+ }
if p.done() {
- return errors.New("os: process already finished")
+ return errFinished
}
s, ok := sig.(syscall.Signal)
if !ok {
return errors.New("os: unsupported signal type")
}
if e := syscall.Kill(p.Pid, s); e != nil {
+ if e == syscall.ESRCH {
+ return errFinished
+ }
return e
}
return nil
diff --git a/libgo/go/os/exec_windows.go b/libgo/go/os/exec_windows.go
index c4f3d4f853..393393b237 100644
--- a/libgo/go/os/exec_windows.go
+++ b/libgo/go/os/exec_windows.go
@@ -53,6 +53,9 @@ func terminateProcess(pid, exitcode int) error {
}
func (p *Process) signal(sig Signal) error {
+ if p.handle == uintptr(syscall.InvalidHandle) {
+ return syscall.EINVAL
+ }
if p.done() {
return errors.New("os: process already finished")
}
diff --git a/libgo/go/os/file.go b/libgo/go/os/file.go
index 2dd1fcf282..e12428cbe1 100644
--- a/libgo/go/os/file.go
+++ b/libgo/go/os/file.go
@@ -140,6 +140,9 @@ func (f *File) Write(b []byte) (n int, err error) {
if n < 0 {
n = 0
}
+ if n != len(b) {
+ err = io.ErrShortWrite
+ }
epipecheck(f, e)
@@ -247,3 +250,17 @@ func Create(name string) (file *File, err error) {
// lstat is overridden in tests.
var lstat = Lstat
+
+// Rename renames (moves) a file. OS-specific restrictions might apply.
+func Rename(oldpath, newpath string) error {
+ return rename(oldpath, newpath)
+}
+
+// Many functions in package syscall return a count of -1 instead of 0.
+// Using fixCount(call()) instead of call() corrects the count.
+func fixCount(n int, err error) (int, error) {
+ if n < 0 {
+ n = 0
+ }
+ return n, err
+}
diff --git a/libgo/go/os/file_plan9.go b/libgo/go/os/file_plan9.go
index 708163ee1c..132594eede 100644
--- a/libgo/go/os/file_plan9.go
+++ b/libgo/go/os/file_plan9.go
@@ -25,7 +25,8 @@ type file struct {
dirinfo *dirInfo // nil unless directory being read
}
-// Fd returns the integer Unix file descriptor referencing the open file.
+// Fd returns the integer Plan 9 file descriptor referencing the open file.
+// The file descriptor is valid only until f.Close is called or f is garbage collected.
func (f *File) Fd() uintptr {
if f == nil {
return ^(uintptr(0))
@@ -244,14 +245,14 @@ func (f *File) Sync() (err error) {
// read reads up to len(b) bytes from the File.
// It returns the number of bytes read and an error, if any.
func (f *File) read(b []byte) (n int, err error) {
- return syscall.Read(f.fd, b)
+ return fixCount(syscall.Read(f.fd, b))
}
// pread reads len(b) bytes from the File starting at byte offset off.
// It returns the number of bytes read and the error, if any.
// EOF is signaled by a zero count with err set to nil.
func (f *File) pread(b []byte, off int64) (n int, err error) {
- return syscall.Pread(f.fd, b, off)
+ return fixCount(syscall.Pread(f.fd, b, off))
}
// write writes len(b) bytes to the File.
@@ -262,7 +263,7 @@ func (f *File) write(b []byte) (n int, err error) {
if len(b) == 0 {
return 0, nil
}
- return syscall.Write(f.fd, b)
+ return fixCount(syscall.Write(f.fd, b))
}
// pwrite writes len(b) bytes to the File starting at byte offset off.
@@ -273,7 +274,7 @@ func (f *File) pwrite(b []byte, off int64) (n int, err error) {
if len(b) == 0 {
return 0, nil
}
- return syscall.Pwrite(f.fd, b, off)
+ return fixCount(syscall.Pwrite(f.fd, b, off))
}
// seek sets the offset for the next Read or Write on file to offset, interpreted
@@ -313,8 +314,33 @@ func Remove(name string) error {
return nil
}
-// Rename renames a file.
-func Rename(oldname, newname string) error {
+// HasPrefix from the strings package.
+func hasPrefix(s, prefix string) bool {
+ return len(s) >= len(prefix) && s[0:len(prefix)] == prefix
+}
+
+// Variant of LastIndex from the strings package.
+func lastIndex(s string, sep byte) int {
+ for i := len(s) - 1; i >= 0; i-- {
+ if s[i] == sep {
+ return i
+ }
+ }
+ return -1
+}
+
+func rename(oldname, newname string) error {
+ dirname := oldname[:lastIndex(oldname, '/')+1]
+ if hasPrefix(newname, dirname) {
+ newname = newname[len(dirname):]
+ } else {
+ return &LinkError{"rename", oldname, newname, ErrInvalid}
+ }
+
+ // If newname still contains slashes after removing the oldname
+ // prefix, the rename is cross-directory and must be rejected.
+ // This case is caught by d.Marshal below.
+
var d syscall.Dir
d.Null()
@@ -323,10 +349,10 @@ func Rename(oldname, newname string) error {
buf := make([]byte, syscall.STATFIXLEN+len(d.Name))
n, err := d.Marshal(buf[:])
if err != nil {
- return &PathError{"rename", oldname, err}
+ return &LinkError{"rename", oldname, newname, err}
}
if err = syscall.Wstat(oldname, buf[:n]); err != nil {
- return &PathError{"rename", oldname, err}
+ return &LinkError{"rename", oldname, newname, err}
}
return nil
}
diff --git a/libgo/go/os/file_posix.go b/libgo/go/os/file_posix.go
index a8bef359b9..fbb3b5e4d8 100644
--- a/libgo/go/os/file_posix.go
+++ b/libgo/go/os/file_posix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
package os
@@ -13,32 +13,12 @@ import (
func sigpipe() // implemented in package runtime
-// Link creates newname as a hard link to the oldname file.
-// If there is an error, it will be of type *LinkError.
-func Link(oldname, newname string) error {
- e := syscall.Link(oldname, newname)
- if e != nil {
- return &LinkError{"link", oldname, newname, e}
- }
- return nil
-}
-
-// Symlink creates newname as a symbolic link to oldname.
-// If there is an error, it will be of type *LinkError.
-func Symlink(oldname, newname string) error {
- e := syscall.Symlink(oldname, newname)
- if e != nil {
- return &LinkError{"symlink", oldname, newname, e}
- }
- return nil
-}
-
// Readlink returns the destination of the named symbolic link.
// If there is an error, it will be of type *PathError.
func Readlink(name string) (string, error) {
for len := 128; ; len *= 2 {
b := make([]byte, len)
- n, e := syscall.Readlink(name, b)
+ n, e := fixCount(syscall.Readlink(name, b))
if e != nil {
return "", &PathError{"readlink", name, e}
}
@@ -48,8 +28,7 @@ func Readlink(name string) (string, error) {
}
}
-// Rename renames a file.
-func Rename(oldname, newname string) error {
+func rename(oldname, newname string) error {
e := syscall.Rename(oldname, newname)
if e != nil {
return &LinkError{"rename", oldname, newname, e}
@@ -145,7 +124,7 @@ func (f *File) Truncate(size int64) error {
// of recently written data to disk.
func (f *File) Sync() (err error) {
if f == nil {
- return syscall.EINVAL
+ return ErrInvalid
}
if e := syscall.Fsync(f.fd); e != nil {
return NewSyscallError("fsync", e)
diff --git a/libgo/go/os/file_unix.go b/libgo/go/os/file_unix.go
index e8e42569bb..b25e62ff00 100644
--- a/libgo/go/os/file_unix.go
+++ b/libgo/go/os/file_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package os
@@ -29,6 +29,7 @@ type file struct {
}
// Fd returns the integer Unix file descriptor referencing the open file.
+// The file descriptor is valid only until f.Close is called or f is garbage collected.
func (f *File) Fd() uintptr {
if f == nil {
return ^(uintptr(0))
@@ -80,12 +81,7 @@ func OpenFile(name string, flag int, perm FileMode) (file *File, err error) {
// There's a race here with fork/exec, which we are
// content to live with. See ../syscall/exec_unix.go.
- // On OS X 10.6, the O_CLOEXEC flag is not respected.
- // On OS X 10.7, the O_CLOEXEC flag works.
- // Without a cheap & reliable way to detect 10.6 vs 10.7 at
- // runtime, we just always call syscall.CloseOnExec on Darwin.
- // Once >=10.7 is prevalent, this extra call can removed.
- if syscall.O_CLOEXEC == 0 || runtime.GOOS == "darwin" { // O_CLOEXEC not supported
+ if !supportsCloseOnExec {
syscall.CloseOnExec(r)
}
@@ -171,44 +167,71 @@ func (f *File) readdir(n int) (fi []FileInfo, err error) {
if dirname == "" {
dirname = "."
}
- dirname += "/"
names, err := f.Readdirnames(n)
- fi = make([]FileInfo, len(names))
- for i, filename := range names {
- fip, lerr := lstat(dirname + filename)
- if lerr != nil {
- fi[i] = &fileStat{name: filename}
+ fi = make([]FileInfo, 0, len(names))
+ for _, filename := range names {
+ fip, lerr := lstat(dirname + "/" + filename)
+ if IsNotExist(lerr) {
+ // File disappeared between readdir + stat.
+ // Just treat it as if it didn't exist.
continue
}
- fi[i] = fip
+ if lerr != nil {
+ return fi, lerr
+ }
+ fi = append(fi, fip)
}
return fi, err
}
+// Darwin and FreeBSD can't read or write 2GB+ at a time,
+// even on 64-bit systems. See golang.org/issue/7812.
+// Use 1GB instead of, say, 2GB-1, to keep subsequent
+// reads aligned.
+const (
+ needsMaxRW = runtime.GOOS == "darwin" || runtime.GOOS == "freebsd"
+ maxRW = 1 << 30
+)
+
// read reads up to len(b) bytes from the File.
// It returns the number of bytes read and an error, if any.
func (f *File) read(b []byte) (n int, err error) {
- return syscall.Read(f.fd, b)
+ if needsMaxRW && len(b) > maxRW {
+ b = b[:maxRW]
+ }
+ return fixCount(syscall.Read(f.fd, b))
}
// pread reads len(b) bytes from the File starting at byte offset off.
// It returns the number of bytes read and the error, if any.
-// EOF is signaled by a zero count with err set to 0.
+// EOF is signaled by a zero count with err set to nil.
func (f *File) pread(b []byte, off int64) (n int, err error) {
- return syscall.Pread(f.fd, b, off)
+ if needsMaxRW && len(b) > maxRW {
+ b = b[:maxRW]
+ }
+ return fixCount(syscall.Pread(f.fd, b, off))
}
// write writes len(b) bytes to the File.
// It returns the number of bytes written and an error, if any.
func (f *File) write(b []byte) (n int, err error) {
for {
- m, err := syscall.Write(f.fd, b)
+ bcap := b
+ if needsMaxRW && len(bcap) > maxRW {
+ bcap = bcap[:maxRW]
+ }
+ m, err := fixCount(syscall.Write(f.fd, bcap))
n += m
// If the syscall wrote some data but not all (short write)
// or it returned EINTR, then assume it stopped early for
// reasons that are uninteresting to the caller, and try again.
- if 0 < m && m < len(b) || err == syscall.EINTR {
+ if 0 < m && m < len(bcap) || err == syscall.EINTR {
+ b = b[m:]
+ continue
+ }
+
+ if needsMaxRW && len(bcap) != len(b) && err == nil {
b = b[m:]
continue
}
@@ -220,7 +243,10 @@ func (f *File) write(b []byte) (n int, err error) {
// pwrite writes len(b) bytes to the File starting at byte offset off.
// It returns the number of bytes written and an error, if any.
func (f *File) pwrite(b []byte, off int64) (n int, err error) {
- return syscall.Pwrite(f.fd, b, off)
+ if needsMaxRW && len(b) > maxRW {
+ b = b[:maxRW]
+ }
+ return fixCount(syscall.Pwrite(f.fd, b, off))
}
// seek sets the offset for the next Read or Write on file to offset, interpreted
@@ -294,7 +320,31 @@ func basename(name string) string {
func TempDir() string {
dir := Getenv("TMPDIR")
if dir == "" {
- dir = "/tmp"
+ if runtime.GOOS == "android" {
+ dir = "/data/local/tmp"
+ } else {
+ dir = "/tmp"
+ }
}
return dir
}
+
+// Link creates newname as a hard link to the oldname file.
+// If there is an error, it will be of type *LinkError.
+func Link(oldname, newname string) error {
+ e := syscall.Link(oldname, newname)
+ if e != nil {
+ return &LinkError{"link", oldname, newname, e}
+ }
+ return nil
+}
+
+// Symlink creates newname as a symbolic link to oldname.
+// If there is an error, it will be of type *LinkError.
+func Symlink(oldname, newname string) error {
+ e := syscall.Symlink(oldname, newname)
+ if e != nil {
+ return &LinkError{"symlink", oldname, newname, e}
+ }
+ return nil
+}
diff --git a/libgo/go/os/getwd.go b/libgo/go/os/getwd.go
index 8c5ff7fca5..d5da53b34b 100644
--- a/libgo/go/os/getwd.go
+++ b/libgo/go/os/getwd.go
@@ -5,6 +5,7 @@
package os
import (
+ "runtime"
"sync"
"syscall"
)
@@ -22,39 +23,42 @@ var useSyscallwd = func(error) bool { return true }
// current directory. If the current directory can be
// reached via multiple paths (due to symbolic links),
// Getwd may return any one of them.
-func Getwd() (pwd string, err error) {
- // If the operating system provides a Getwd call, use it.
- if syscall.ImplementsGetwd {
- s, e := syscall.Getwd()
- if useSyscallwd(e) {
- return s, NewSyscallError("getwd", e)
- }
+func Getwd() (dir string, err error) {
+ if runtime.GOOS == "windows" {
+ return syscall.Getwd()
}
- // Otherwise, we're trying to find our way back to ".".
+ // Clumsy but widespread kludge:
+ // if $PWD is set and matches ".", use it.
dot, err := Stat(".")
if err != nil {
return "", err
}
-
- // Clumsy but widespread kludge:
- // if $PWD is set and matches ".", use it.
- pwd = Getenv("PWD")
- if len(pwd) > 0 && pwd[0] == '/' {
- d, err := Stat(pwd)
+ dir = Getenv("PWD")
+ if len(dir) > 0 && dir[0] == '/' {
+ d, err := Stat(dir)
if err == nil && SameFile(dot, d) {
- return pwd, nil
+ return dir, nil
+ }
+ }
+
+ // If the operating system provides a Getwd call, use it.
+ // Otherwise, we're trying to find our way back to ".".
+ if syscall.ImplementsGetwd {
+ s, e := syscall.Getwd()
+ if useSyscallwd(e) {
+ return s, NewSyscallError("getwd", e)
}
}
// Apply same kludge but to cached dir instead of $PWD.
getwdCache.Lock()
- pwd = getwdCache.dir
+ dir = getwdCache.dir
getwdCache.Unlock()
- if len(pwd) > 0 {
- d, err := Stat(pwd)
+ if len(dir) > 0 {
+ d, err := Stat(dir)
if err == nil && SameFile(dot, d) {
- return pwd, nil
+ return dir, nil
}
}
@@ -71,8 +75,8 @@ func Getwd() (pwd string, err error) {
// General algorithm: find name in parent
// and then find name of parent. Each iteration
- // adds /name to the beginning of pwd.
- pwd = ""
+ // adds /name to the beginning of dir.
+ dir = ""
for parent := ".."; ; parent = "../" + parent {
if len(parent) >= 1024 { // Sanity check
return "", syscall.ENAMETOOLONG
@@ -91,7 +95,7 @@ func Getwd() (pwd string, err error) {
for _, name := range names {
d, _ := Lstat(parent + "/" + name)
if SameFile(d, dot) {
- pwd = "/" + name + pwd
+ dir = "/" + name + dir
goto Found
}
}
@@ -112,8 +116,8 @@ func Getwd() (pwd string, err error) {
// Save answer as hint to avoid the expensive path next time.
getwdCache.Lock()
- getwdCache.dir = pwd
+ getwdCache.dir = dir
getwdCache.Unlock()
- return pwd, nil
+ return dir, nil
}
diff --git a/libgo/go/os/os_test.go b/libgo/go/os/os_test.go
index 882e3da151..7a86efac21 100644
--- a/libgo/go/os/os_test.go
+++ b/libgo/go/os/os_test.go
@@ -6,6 +6,7 @@ package os_test
import (
"bytes"
+ "errors"
"flag"
"fmt"
"io"
@@ -13,14 +14,19 @@ import (
. "os"
osexec "os/exec"
"path/filepath"
+ "reflect"
"runtime"
+ "sort"
"strings"
+ "sync"
"syscall"
"testing"
"text/template"
"time"
)
+var supportsSymlinks = true
+
var dot = []string{
"dir_unix.go",
"env.go",
@@ -37,6 +43,14 @@ type sysDir struct {
var sysdir = func() (sd *sysDir) {
switch runtime.GOOS {
+ case "android":
+ sd = &sysDir{
+ "/system/etc",
+ []string{
+ "audio_policy.conf",
+ "system_fonts.xml",
+ },
+ }
case "windows":
sd = &sysDir{
Getenv("SystemRoot") + "\\system32\\drivers\\etc",
@@ -103,12 +117,27 @@ func newFile(testName string, t *testing.T) (f *File) {
// On Unix, override $TMPDIR in case the user
// has it set to an NFS-mounted directory.
dir := ""
- if runtime.GOOS != "windows" {
+ if runtime.GOOS != "android" && runtime.GOOS != "windows" {
dir = "/tmp"
}
f, err := ioutil.TempFile(dir, "_Go_"+testName)
if err != nil {
- t.Fatalf("open %s: %s", testName, err)
+ t.Fatalf("TempFile %s: %s", testName, err)
+ }
+ return
+}
+
+func newDir(testName string, t *testing.T) (name string) {
+ // Use a local file system, not NFS.
+ // On Unix, override $TMPDIR in case the user
+ // has it set to an NFS-mounted directory.
+ dir := ""
+ if runtime.GOOS != "android" && runtime.GOOS != "windows" {
+ dir = "/tmp"
+ }
+ name, err := ioutil.TempDir(dir, "_Go_"+testName)
+ if err != nil {
+ t.Fatalf("TempDir %s: %s", testName, err)
}
return
}
@@ -279,10 +308,12 @@ func TestReaddirnamesOneAtATime(t *testing.T) {
// big directory that doesn't change often.
dir := "/usr/bin"
switch runtime.GOOS {
- case "windows":
- dir = Getenv("SystemRoot") + "\\system32"
+ case "android":
+ dir = "/system/bin"
case "plan9":
dir = "/bin"
+ case "windows":
+ dir = Getenv("SystemRoot") + "\\system32"
}
file, err := Open(dir)
if err != nil {
@@ -380,9 +411,87 @@ func TestReaddirNValues(t *testing.T) {
}
}
+func touch(t *testing.T, name string) {
+ f, err := Create(name)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := f.Close(); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestReaddirStatFailures(t *testing.T) {
+ switch runtime.GOOS {
+ case "windows", "plan9":
+ // Windows and Plan 9 already do this correctly,
+ // but are structured with different syscalls such
+ // that they don't use Lstat, so the hook below for
+ // testing it wouldn't work.
+ t.Skipf("skipping test on %v", runtime.GOOS)
+ }
+ dir, err := ioutil.TempDir("", "")
+ if err != nil {
+ t.Fatalf("TempDir: %v", err)
+ }
+ defer RemoveAll(dir)
+ touch(t, filepath.Join(dir, "good1"))
+ touch(t, filepath.Join(dir, "x")) // will disappear or have an error
+ touch(t, filepath.Join(dir, "good2"))
+ defer func() {
+ *LstatP = Lstat
+ }()
+ var xerr error // error to return for x
+ *LstatP = func(path string) (FileInfo, error) {
+ if xerr != nil && strings.HasSuffix(path, "x") {
+ return nil, xerr
+ }
+ return Lstat(path)
+ }
+ readDir := func() ([]FileInfo, error) {
+ d, err := Open(dir)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer d.Close()
+ return d.Readdir(-1)
+ }
+ mustReadDir := func(testName string) []FileInfo {
+ fis, err := readDir()
+ if err != nil {
+ t.Fatalf("%s: Readdir: %v", testName, err)
+ }
+ return fis
+ }
+ names := func(fis []FileInfo) []string {
+ s := make([]string, len(fis))
+ for i, fi := range fis {
+ s[i] = fi.Name()
+ }
+ sort.Strings(s)
+ return s
+ }
+
+ if got, want := names(mustReadDir("inital readdir")),
+ []string{"good1", "good2", "x"}; !reflect.DeepEqual(got, want) {
+ t.Errorf("initial readdir got %q; want %q", got, want)
+ }
+
+ xerr = ErrNotExist
+ if got, want := names(mustReadDir("with x disappearing")),
+ []string{"good1", "good2"}; !reflect.DeepEqual(got, want) {
+ t.Errorf("with x disappearing, got %q; want %q", got, want)
+ }
+
+ xerr = errors.New("some real error")
+ if _, err := readDir(); err != xerr {
+ t.Errorf("with a non-ErrNotExist error, got error %v; want %v", err, xerr)
+ }
+}
+
func TestHardLink(t *testing.T) {
// Hardlinks are not supported under windows or Plan 9.
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+ if runtime.GOOS == "plan9" {
return
}
from, to := "hardlinktestfrom", "hardlinktestto"
@@ -413,10 +522,14 @@ func TestHardLink(t *testing.T) {
}
}
-func TestSymLink(t *testing.T) {
- // Symlinks are not supported under windows or Plan 9.
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
- return
+func TestSymlink(t *testing.T) {
+ switch runtime.GOOS {
+ case "android", "nacl", "plan9":
+ t.Skipf("skipping on %s", runtime.GOOS)
+ case "windows":
+ if !supportsSymlinks {
+ t.Skipf("skipping on %s", runtime.GOOS)
+ }
}
from, to := "symlinktestfrom", "symlinktestto"
Remove(from) // Just in case.
@@ -476,9 +589,13 @@ func TestSymLink(t *testing.T) {
}
func TestLongSymlink(t *testing.T) {
- // Symlinks are not supported under windows or Plan 9.
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
- return
+ switch runtime.GOOS {
+ case "plan9", "nacl":
+ t.Skipf("skipping on %s", runtime.GOOS)
+ case "windows":
+ if !supportsSymlinks {
+ t.Skipf("skipping on %s", runtime.GOOS)
+ }
}
s := "0123456789abcdef"
// Long, but not too long: a common limit is 255.
@@ -547,6 +664,11 @@ 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)
+ }
+
var dir, cmd string
var args []string
if runtime.GOOS == "windows" {
@@ -620,8 +742,10 @@ func TestFTruncate(t *testing.T) {
checkSize(t, f, 1024)
f.Truncate(0)
checkSize(t, f, 0)
- f.Write([]byte("surprise!"))
- checkSize(t, f, 13+9) // wrote at offset past where hello, world was.
+ _, err := f.Write([]byte("surprise!"))
+ if err == nil {
+ checkSize(t, f, 13+9) // wrote at offset past where hello, world was.
+ }
}
func TestTruncate(t *testing.T) {
@@ -638,49 +762,65 @@ func TestTruncate(t *testing.T) {
checkSize(t, f, 1024)
Truncate(f.Name(), 0)
checkSize(t, f, 0)
- f.Write([]byte("surprise!"))
- checkSize(t, f, 13+9) // wrote at offset past where hello, world was.
+ _, err := f.Write([]byte("surprise!"))
+ if err == nil {
+ checkSize(t, f, 13+9) // wrote at offset past where hello, world was.
+ }
}
-// Use TempDir() to make sure we're on a local file system,
+// Use TempDir (via newFile) to make sure we're on a local file system,
// so that timings are not distorted by latency and caching.
// On NFS, timings can be off due to caching of meta-data on
// NFS servers (Issue 848).
func TestChtimes(t *testing.T) {
f := newFile("TestChtimes", t)
defer Remove(f.Name())
- defer f.Close()
f.Write([]byte("hello, world\n"))
f.Close()
- st, err := Stat(f.Name())
+ testChtimes(t, f.Name())
+}
+
+// Use TempDir (via newDir) to make sure we're on a local file system,
+// so that timings are not distorted by latency and caching.
+// On NFS, timings can be off due to caching of meta-data on
+// NFS servers (Issue 848).
+func TestChtimesDir(t *testing.T) {
+ name := newDir("TestChtimes", t)
+ defer RemoveAll(name)
+
+ testChtimes(t, name)
+}
+
+func testChtimes(t *testing.T, name string) {
+ st, err := Stat(name)
if err != nil {
- t.Fatalf("Stat %s: %s", f.Name(), err)
+ t.Fatalf("Stat %s: %s", name, err)
}
preStat := st
// Move access and modification time back a second
at := Atime(preStat)
mt := preStat.ModTime()
- err = Chtimes(f.Name(), at.Add(-time.Second), mt.Add(-time.Second))
+ err = Chtimes(name, at.Add(-time.Second), mt.Add(-time.Second))
if err != nil {
- t.Fatalf("Chtimes %s: %s", f.Name(), err)
+ t.Fatalf("Chtimes %s: %s", name, err)
}
- st, err = Stat(f.Name())
+ st, err = Stat(name)
if err != nil {
- t.Fatalf("second Stat %s: %s", f.Name(), err)
+ t.Fatalf("second Stat %s: %s", name, err)
}
postStat := st
- /* Plan 9:
+ /* Plan 9, NaCl:
Mtime is the time of the last change of content. Similarly, atime is set whenever the
contents are accessed; also, it is set whenever mtime is set.
*/
pat := Atime(postStat)
pmt := postStat.ModTime()
- if !pat.Before(at) && runtime.GOOS != "plan9" {
+ if !pat.Before(at) && runtime.GOOS != "plan9" && runtime.GOOS != "nacl" {
t.Errorf("AccessTime didn't go backwards; was=%d, after=%d", at, pat)
}
@@ -699,12 +839,16 @@ func TestChdirAndGetwd(t *testing.T) {
t.Fatalf("Open .: %s", err)
}
// These are chosen carefully not to be symlinks on a Mac
- // (unlike, say, /var, /etc, and /tmp).
- dirs := []string{"/", "/usr/bin"}
- // /usr/bin does not usually exist on Plan 9.
- if runtime.GOOS == "plan9" {
+ // (unlike, say, /var, /etc), except /tmp, which we handle below.
+ dirs := []string{"/", "/usr/bin", "/tmp"}
+ // /usr/bin does not usually exist on Plan 9 or Android.
+ switch runtime.GOOS {
+ case "android":
+ dirs = []string{"/", "/system/bin"}
+ case "plan9":
dirs = []string{"/", "/usr"}
}
+ oldwd := Getenv("PWD")
for mode := 0; mode < 2; mode++ {
for _, d := range dirs {
if mode == 0 {
@@ -718,7 +862,11 @@ func TestChdirAndGetwd(t *testing.T) {
err = fd1.Chdir()
fd1.Close()
}
+ if d == "/tmp" {
+ Setenv("PWD", "/tmp")
+ }
pwd, err1 := Getwd()
+ Setenv("PWD", oldwd)
err2 := fd.Chdir()
if err2 != nil {
// We changed the current directory and cannot go back.
@@ -821,6 +969,12 @@ func TestOpenError(t *testing.T) {
syscallErrStr := perr.Err.Error()
expectedErrStr := strings.Replace(tt.error.Error(), "file ", "", 1)
if !strings.HasSuffix(syscallErrStr, expectedErrStr) {
+ // Some Plan 9 file servers incorrectly return
+ // EACCES rather than EISDIR when a directory is
+ // opened for write.
+ if tt.error == syscall.EISDIR && strings.HasSuffix(syscallErrStr, syscall.EACCES.Error()) {
+ continue
+ }
t.Errorf("Open(%q, %d) = _, %q; want suffix %q", tt.path, tt.mode, syscallErrStr, expectedErrStr)
}
continue
@@ -881,9 +1035,10 @@ func run(t *testing.T, cmd []string) string {
func TestHostname(t *testing.T) {
// There is no other way to fetch hostname on windows, but via winapi.
- // On Plan 9 it is can be taken from #c/sysname as Hostname() does.
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
- return
+ // 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)
}
// Check internal Hostname() against the output of /bin/hostname.
@@ -1143,6 +1298,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)
@@ -1198,6 +1358,36 @@ func TestKillStartProcess(t *testing.T) {
})
}
+func TestGetppid(t *testing.T) {
+ switch runtime.GOOS {
+ case "nacl":
+ t.Skip("skipping on nacl")
+ case "plan9":
+ // TODO: golang.org/issue/8206
+ t.Skipf("skipping test on plan9; see issue 8206")
+ }
+
+ if Getenv("GO_WANT_HELPER_PROCESS") == "1" {
+ fmt.Print(Getppid())
+ Exit(0)
+ }
+
+ cmd := osexec.Command(Args[0], "-test.run=TestGetppid")
+ cmd.Env = append(Environ(), "GO_WANT_HELPER_PROCESS=1")
+
+ // verify that Getppid() from the forked process reports our process id
+ output, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("Failed to spawn child process: %v %q", err, string(output))
+ }
+
+ childPpid := string(output)
+ ourPid := fmt.Sprintf("%d", Getpid())
+ if childPpid != ourPid {
+ t.Fatalf("Child process reports parent process id '%v', expected '%v'", childPpid, ourPid)
+ }
+}
+
func TestKillFindProcess(t *testing.T) {
testKillProcess(t, func(p *Process) {
p2, err := FindProcess(p.Pid)
@@ -1210,3 +1400,84 @@ func TestKillFindProcess(t *testing.T) {
}
})
}
+
+var nilFileMethodTests = []struct {
+ name string
+ f func(*File) error
+}{
+ {"Chdir", func(f *File) error { return f.Chdir() }},
+ {"Close", func(f *File) error { return f.Close() }},
+ {"Chmod", func(f *File) error { return f.Chmod(0) }},
+ {"Chown", func(f *File) error { return f.Chown(0, 0) }},
+ {"Read", func(f *File) error { _, err := f.Read(make([]byte, 0)); return err }},
+ {"ReadAt", func(f *File) error { _, err := f.ReadAt(make([]byte, 0), 0); return err }},
+ {"Readdir", func(f *File) error { _, err := f.Readdir(1); return err }},
+ {"Readdirnames", func(f *File) error { _, err := f.Readdirnames(1); return err }},
+ {"Seek", func(f *File) error { _, err := f.Seek(0, 0); return err }},
+ {"Stat", func(f *File) error { _, err := f.Stat(); return err }},
+ {"Sync", func(f *File) error { return f.Sync() }},
+ {"Truncate", func(f *File) error { return f.Truncate(0) }},
+ {"Write", func(f *File) error { _, err := f.Write(make([]byte, 0)); return err }},
+ {"WriteAt", func(f *File) error { _, err := f.WriteAt(make([]byte, 0), 0); return err }},
+ {"WriteString", func(f *File) error { _, err := f.WriteString(""); return err }},
+}
+
+// Test that all File methods give ErrInvalid if the receiver is nil.
+func TestNilFileMethods(t *testing.T) {
+ for _, tt := range nilFileMethodTests {
+ var file *File
+ got := tt.f(file)
+ if got != ErrInvalid {
+ t.Errorf("%v should fail when f is nil; got %v", tt.name, got)
+ }
+ }
+}
+
+func mkdirTree(t *testing.T, root string, level, max int) {
+ if level >= max {
+ return
+ }
+ level++
+ for i := 'a'; i < 'c'; i++ {
+ dir := filepath.Join(root, string(i))
+ if err := Mkdir(dir, 0700); err != nil {
+ t.Fatal(err)
+ }
+ mkdirTree(t, dir, level, max)
+ }
+}
+
+// Test that simultaneous RemoveAll do not report an error.
+// As long as it gets removed, we should be happy.
+func TestRemoveAllRace(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ // Windows has very strict rules about things like
+ // removing directories while someone else has
+ // them open. The racing doesn't work out nicely
+ // like it does on Unix.
+ t.Skip("skipping on windows")
+ }
+
+ n := runtime.GOMAXPROCS(16)
+ defer runtime.GOMAXPROCS(n)
+ root, err := ioutil.TempDir("", "issue")
+ if err != nil {
+ t.Fatal(err)
+ }
+ mkdirTree(t, root, 1, 6)
+ hold := make(chan struct{})
+ var wg sync.WaitGroup
+ for i := 0; i < 4; i++ {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ <-hold
+ err := RemoveAll(root)
+ if err != nil {
+ t.Errorf("unexpected error: %T, %q", err, err)
+ }
+ }()
+ }
+ close(hold) // let workers race to remove root
+ wg.Wait()
+}
diff --git a/libgo/go/os/os_unix_test.go b/libgo/go/os/os_unix_test.go
index b0fc0256de..21d40ccaf8 100644
--- a/libgo/go/os/os_unix_test.go
+++ b/libgo/go/os/os_unix_test.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 netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package os_test
@@ -74,41 +74,3 @@ func TestChown(t *testing.T) {
checkUidGid(t, f.Name(), int(sys.Uid), gid)
}
}
-
-func TestReaddirWithBadLstat(t *testing.T) {
- handle, err := Open(sfdir)
- failfile := sfdir + "/" + sfname
- if err != nil {
- t.Fatalf("Couldn't open %s: %s", sfdir, err)
- }
-
- *LstatP = func(file string) (FileInfo, error) {
- if file == failfile {
- var fi FileInfo
- return fi, ErrInvalid
- }
- return Lstat(file)
- }
- defer func() { *LstatP = Lstat }()
-
- dirs, err := handle.Readdir(-1)
- if err != nil {
- t.Fatalf("Expected Readdir to return no error, got %v", err)
- }
- foundfail := false
- for _, dir := range dirs {
- if dir.Name() == sfname {
- foundfail = true
- if dir.Sys() != nil {
- t.Errorf("Expected Readdir for %s should not contain Sys", failfile)
- }
- } else {
- if dir.Sys() == nil {
- t.Errorf("Readdir for every file other than %s should contain Sys, but %s/%s didn't either", failfile, sfdir, dir.Name())
- }
- }
- }
- if !foundfail {
- t.Fatalf("Expected %s from Readdir, but didn't find it", failfile)
- }
-}
diff --git a/libgo/go/os/path.go b/libgo/go/os/path.go
index 02a77ec805..84a3be3348 100644
--- a/libgo/go/os/path.go
+++ b/libgo/go/os/path.go
@@ -17,7 +17,7 @@ import (
// If path is already a directory, MkdirAll does nothing
// and returns nil.
func MkdirAll(path string, perm FileMode) error {
- // If path exists, stop with success or error.
+ // Fast path: if we can tell whether path is a directory or file, stop with success or error.
dir, err := Stat(path)
if err == nil {
if dir.IsDir() {
@@ -26,7 +26,7 @@ func MkdirAll(path string, perm FileMode) error {
return &PathError{"mkdir", path, syscall.ENOTDIR}
}
- // Doesn't already exist; make sure parent does.
+ // Slow path: make sure parent exists and then call Mkdir for path.
i := len(path)
for i > 0 && IsPathSeparator(path[i-1]) { // Skip trailing path separator.
i--
@@ -45,7 +45,7 @@ func MkdirAll(path string, perm FileMode) error {
}
}
- // Now parent exists, try to create.
+ // Parent now exists; invoke Mkdir and use its result.
err = Mkdir(path, perm)
if err != nil {
// Handle arguments like "foo/." by
@@ -66,7 +66,7 @@ func MkdirAll(path string, perm FileMode) error {
func RemoveAll(path string) error {
// Simple case: if Remove works, we're done.
err := Remove(path)
- if err == nil {
+ if err == nil || IsNotExist(err) {
return nil
}
@@ -86,6 +86,11 @@ func RemoveAll(path string) error {
// Directory.
fd, err := Open(path)
if err != nil {
+ if IsNotExist(err) {
+ // Race. It was deleted between the Lstat and Open.
+ // Return nil per RemoveAll's docs.
+ return nil
+ }
return err
}
@@ -116,6 +121,9 @@ func RemoveAll(path string) error {
// Remove directory.
err1 := Remove(path)
+ if err1 == nil || IsNotExist(err1) {
+ return nil
+ }
if err == nil {
err = err1
}
diff --git a/libgo/go/os/path_test.go b/libgo/go/os/path_test.go
index 27abf59826..6f24a43132 100644
--- a/libgo/go/os/path_test.go
+++ b/libgo/go/os/path_test.go
@@ -167,8 +167,13 @@ func TestRemoveAll(t *testing.T) {
}
func TestMkdirAllWithSymlink(t *testing.T) {
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
- t.Skip("Skipping test: symlinks don't exist under Windows/Plan 9")
+ switch runtime.GOOS {
+ case "nacl", "plan9":
+ t.Skipf("skipping on %s", runtime.GOOS)
+ case "windows":
+ if !supportsSymlinks {
+ t.Skipf("skipping on %s", runtime.GOOS)
+ }
}
tmpDir, err := ioutil.TempDir("", "TestMkdirAllWithSymlink-")
@@ -197,8 +202,9 @@ func TestMkdirAllWithSymlink(t *testing.T) {
}
func TestMkdirAllAtSlash(t *testing.T) {
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
- return
+ switch runtime.GOOS {
+ case "android", "plan9", "windows":
+ t.Skipf("skipping on %s", runtime.GOOS)
}
RemoveAll("/_go_os_test")
err := MkdirAll("/_go_os_test/dir", 0777)
diff --git a/libgo/go/os/path_unix.go b/libgo/go/os/path_unix.go
index 3bf63bf804..0211107ddf 100644
--- a/libgo/go/os/path_unix.go
+++ b/libgo/go/os/path_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 netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package os
diff --git a/libgo/go/os/pipe_bsd.go b/libgo/go/os/pipe_bsd.go
index 73d35b4d5e..3b81ed20f1 100644
--- a/libgo/go/os/pipe_bsd.go
+++ b/libgo/go/os/pipe_bsd.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd netbsd openbsd
+// +build darwin dragonfly freebsd nacl netbsd openbsd solaris
package os
diff --git a/libgo/go/os/proc.go b/libgo/go/os/proc.go
index 38c436ec54..774f09900e 100644
--- a/libgo/go/os/proc.go
+++ b/libgo/go/os/proc.go
@@ -6,11 +6,24 @@
package os
-import "syscall"
+import (
+ "runtime"
+ "syscall"
+)
// Args hold the command-line arguments, starting with the program name.
var Args []string
+func init() {
+ if runtime.GOOS == "windows" {
+ // Initialized in exec_windows.go.
+ return
+ }
+ Args = runtime_args()
+}
+
+func runtime_args() []string // in package runtime
+
// Getuid returns the numeric user id of the caller.
func Getuid() int { return syscall.Getuid() }
diff --git a/libgo/go/os/signal/signal_test.go b/libgo/go/os/signal/signal_test.go
index 741f2a0edf..22337a72d4 100644
--- a/libgo/go/os/signal/signal_test.go
+++ b/libgo/go/os/signal/signal_test.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 netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package signal
@@ -125,7 +125,7 @@ func TestStop(t *testing.T) {
if sig != syscall.SIGHUP || *sendUncaughtSighup == 1 {
syscall.Kill(syscall.Getpid(), sig)
}
- time.Sleep(10 * time.Millisecond)
+ time.Sleep(100 * time.Millisecond)
// Ask for signal
c := make(chan os.Signal, 1)
@@ -140,7 +140,7 @@ func TestStop(t *testing.T) {
select {
case s := <-c:
t.Fatalf("unexpected signal %v", s)
- case <-time.After(10 * time.Millisecond):
+ case <-time.After(100 * time.Millisecond):
// nothing to read - good
}
@@ -154,7 +154,7 @@ func TestStop(t *testing.T) {
select {
case s := <-c:
t.Fatalf("unexpected signal %v", s)
- case <-time.After(10 * time.Millisecond):
+ case <-time.After(100 * time.Millisecond):
// nothing to read - good
}
}
diff --git a/libgo/go/os/signal/signal_unix.go b/libgo/go/os/signal/signal_unix.go
index 318488dc04..94b8ab3ddb 100644
--- a/libgo/go/os/signal/signal_unix.go
+++ b/libgo/go/os/signal/signal_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 netbsd openbsd windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
package signal
diff --git a/libgo/go/os/stat_nacl.go b/libgo/go/os/stat_nacl.go
new file mode 100644
index 0000000000..a503b59fa3
--- /dev/null
+++ b/libgo/go/os/stat_nacl.go
@@ -0,0 +1,62 @@
+// 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 os
+
+import (
+ "syscall"
+ "time"
+)
+
+func sameFile(fs1, fs2 *fileStat) bool {
+ stat1 := fs1.sys.(*syscall.Stat_t)
+ stat2 := fs2.sys.(*syscall.Stat_t)
+ return stat1.Dev == stat2.Dev && stat1.Ino == stat2.Ino
+}
+
+func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
+ fs := &fileStat{
+ name: basename(name),
+ size: int64(st.Size),
+ modTime: timespecToTime(st.Mtime, st.MtimeNsec),
+ sys: st,
+ }
+ fs.mode = FileMode(st.Mode & 0777)
+ switch st.Mode & syscall.S_IFMT {
+ case syscall.S_IFBLK:
+ fs.mode |= ModeDevice
+ case syscall.S_IFCHR:
+ fs.mode |= ModeDevice | ModeCharDevice
+ case syscall.S_IFDIR:
+ fs.mode |= ModeDir
+ case syscall.S_IFIFO:
+ fs.mode |= ModeNamedPipe
+ case syscall.S_IFLNK:
+ fs.mode |= ModeSymlink
+ case syscall.S_IFREG:
+ // nothing to do
+ case syscall.S_IFSOCK:
+ fs.mode |= ModeSocket
+ }
+ if st.Mode&syscall.S_ISGID != 0 {
+ fs.mode |= ModeSetgid
+ }
+ if st.Mode&syscall.S_ISUID != 0 {
+ fs.mode |= ModeSetuid
+ }
+ if st.Mode&syscall.S_ISVTX != 0 {
+ fs.mode |= ModeSticky
+ }
+ return fs
+}
+
+func timespecToTime(sec, nsec int64) time.Time {
+ return time.Unix(sec, nsec)
+}
+
+// For testing.
+func atime(fi FileInfo) time.Time {
+ st := fi.Sys().(*syscall.Stat_t)
+ return timespecToTime(st.Atime, st.AtimeNsec)
+}
diff --git a/libgo/go/os/stat_solaris.go b/libgo/go/os/stat_solaris.go
index e4622b9371..3e88bd829e 100644
--- a/libgo/go/os/stat_solaris.go
+++ b/libgo/go/os/stat_solaris.go
@@ -24,8 +24,10 @@ func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
}
fs.mode = FileMode(st.Mode & 0777)
switch st.Mode & syscall.S_IFMT {
- case syscall.S_IFBLK, syscall.S_IFCHR:
+ case syscall.S_IFBLK:
fs.mode |= ModeDevice
+ case syscall.S_IFCHR:
+ fs.mode |= ModeDevice | ModeCharDevice
case syscall.S_IFDIR:
fs.mode |= ModeDir
case syscall.S_IFIFO:
@@ -43,6 +45,9 @@ func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
if st.Mode&syscall.S_ISUID != 0 {
fs.mode |= ModeSetuid
}
+ if st.Mode&syscall.S_ISVTX != 0 {
+ fs.mode |= ModeSticky
+ }
return fs
}
diff --git a/libgo/go/os/sys_bsd.go b/libgo/go/os/sys_bsd.go
index 9ad2f8546b..8ad5e21837 100644
--- a/libgo/go/os/sys_bsd.go
+++ b/libgo/go/os/sys_bsd.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd netbsd openbsd
+// +build darwin dragonfly freebsd nacl netbsd openbsd
// os code shared between *BSD systems including OS X (Darwin)
// and FreeBSD.
diff --git a/libgo/go/os/sys_darwin.go b/libgo/go/os/sys_darwin.go
new file mode 100644
index 0000000000..7a8330abb5
--- /dev/null
+++ b/libgo/go/os/sys_darwin.go
@@ -0,0 +1,31 @@
+// 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 os
+
+import "syscall"
+
+// supportsCloseOnExec reports whether the platform supports the
+// O_CLOEXEC flag.
+var supportsCloseOnExec bool
+
+func init() {
+ // Seems like kern.osreldate is veiled on latest OS X. We use
+ // kern.osrelease instead.
+ osver, err := syscall.Sysctl("kern.osrelease")
+ if err != nil {
+ return
+ }
+ var i int
+ for i = range osver {
+ if osver[i] != '.' {
+ continue
+ }
+ }
+ // The O_CLOEXEC flag was introduced in OS X 10.7 (Darwin
+ // 11.0.0). See http://support.apple.com/kb/HT1633.
+ if i > 2 || i == 2 && osver[0] >= '1' && osver[1] >= '1' {
+ supportsCloseOnExec = true
+ }
+}
diff --git a/libgo/go/os/sys_freebsd.go b/libgo/go/os/sys_freebsd.go
new file mode 100644
index 0000000000..273c2df1c1
--- /dev/null
+++ b/libgo/go/os/sys_freebsd.go
@@ -0,0 +1,23 @@
+// 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 os
+
+import "syscall"
+
+// supportsCloseOnExec reports whether the platform supports the
+// O_CLOEXEC flag.
+var supportsCloseOnExec bool
+
+func init() {
+ osrel, err := syscall.SysctlUint32("kern.osreldate")
+ if err != nil {
+ return
+ }
+ // The O_CLOEXEC flag was introduced in FreeBSD 8.3.
+ // See http://www.freebsd.org/doc/en/books/porters-handbook/freebsd-versions.html.
+ if osrel >= 803000 {
+ supportsCloseOnExec = true
+ }
+}
diff --git a/libgo/go/os/sys_nacl.go b/libgo/go/os/sys_nacl.go
new file mode 100644
index 0000000000..07907c8477
--- /dev/null
+++ b/libgo/go/os/sys_nacl.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.
+
+package os
+
+// supportsCloseOnExec reports whether the platform supports the
+// O_CLOEXEC flag.
+const supportsCloseOnExec = false
diff --git a/libgo/go/os/sys_unix.go b/libgo/go/os/sys_unix.go
new file mode 100644
index 0000000000..39c20dc739
--- /dev/null
+++ b/libgo/go/os/sys_unix.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 dragonfly linux netbsd openbsd solaris
+
+package os
+
+// supportsCloseOnExec reports whether the platform supports the
+// O_CLOEXEC flag.
+const supportsCloseOnExec = true
diff --git a/libgo/go/os/types_windows.go b/libgo/go/os/types_windows.go
index 38901681e6..7b2e54698c 100644
--- a/libgo/go/os/types_windows.go
+++ b/libgo/go/os/types_windows.go
@@ -39,6 +39,9 @@ func (fs *fileStat) Mode() (m FileMode) {
} else {
m |= 0666
}
+ if fs.sys.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 {
+ m |= ModeSymlink
+ }
return m
}
diff --git a/libgo/go/os/user/lookup_stubs.go b/libgo/go/os/user/lookup_stubs.go
index 86f0e6e645..4fb0e3c6ed 100644
--- a/libgo/go/os/user/lookup_stubs.go
+++ b/libgo/go/os/user/lookup_stubs.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,!windows,!plan9
+// +build !cgo,!windows,!plan9 android
package user
diff --git a/libgo/go/os/user/lookup_unix.go b/libgo/go/os/user/lookup_unix.go
index 2d309ed333..64f4576f69 100644
--- a/libgo/go/os/user/lookup_unix.go
+++ b/libgo/go/os/user/lookup_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd !android,linux netbsd openbsd solaris
// +build cgo
package user
diff --git a/libgo/go/path/filepath/export_test.go b/libgo/go/path/filepath/export_test.go
new file mode 100644
index 0000000000..0cf9e3bca1
--- /dev/null
+++ b/libgo/go/path/filepath/export_test.go
@@ -0,0 +1,7 @@
+// 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 filepath
+
+var LstatP = &lstat
diff --git a/libgo/go/path/filepath/match.go b/libgo/go/path/filepath/match.go
index 3d84145d7f..ecc07aa5da 100644
--- a/libgo/go/path/filepath/match.go
+++ b/libgo/go/path/filepath/match.go
@@ -228,9 +228,12 @@ func getEsc(chunk string) (r rune, nchunk string, err error) {
// as in Match. The pattern may describe hierarchical names such as
// /usr/*/bin/ed (assuming the Separator is '/').
//
+// Glob ignores file system errors such as I/O errors reading directories.
+// The only possible returned error is ErrBadPattern, when pattern
+// is malformed.
func Glob(pattern string) (matches []string, err error) {
if !hasMeta(pattern) {
- if _, err = os.Stat(pattern); err != nil {
+ if _, err = os.Lstat(pattern); err != nil {
return nil, nil
}
return []string{pattern}, nil
@@ -283,10 +286,7 @@ func glob(dir, pattern string, matches []string) (m []string, e error) {
}
defer d.Close()
- names, err := d.Readdirnames(-1)
- if err != nil {
- return
- }
+ names, _ := d.Readdirnames(-1)
sort.Strings(names)
for _, n := range names {
diff --git a/libgo/go/path/filepath/match_test.go b/libgo/go/path/filepath/match_test.go
index 6a2fd927e4..c29f93fb7b 100644
--- a/libgo/go/path/filepath/match_test.go
+++ b/libgo/go/path/filepath/match_test.go
@@ -2,9 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package filepath
+package filepath_test
import (
+ "io/ioutil"
+ "os"
+ . "path/filepath"
"runtime"
"strings"
"testing"
@@ -154,3 +157,56 @@ func TestGlobError(t *testing.T) {
t.Error("expected error for bad pattern; got none")
}
}
+
+var globSymlinkTests = []struct {
+ path, dest string
+ brokenLink bool
+}{
+ {"test1", "link1", false},
+ {"test2", "link2", true},
+}
+
+func TestGlobSymlink(t *testing.T) {
+ switch runtime.GOOS {
+ case "nacl", "plan9":
+ t.Skipf("skipping on %s", runtime.GOOS)
+ case "windows":
+ if !supportsSymlinks {
+ t.Skipf("skipping on %s", runtime.GOOS)
+ }
+
+ }
+
+ tmpDir, err := ioutil.TempDir("", "globsymlink")
+ if err != nil {
+ t.Fatal("creating temp dir:", err)
+ }
+ defer os.RemoveAll(tmpDir)
+
+ for _, tt := range globSymlinkTests {
+ path := Join(tmpDir, tt.path)
+ dest := Join(tmpDir, tt.dest)
+ f, err := os.Create(path)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := f.Close(); err != nil {
+ t.Fatal(err)
+ }
+ err = os.Symlink(path, dest)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if tt.brokenLink {
+ // Break the symlink.
+ os.Remove(path)
+ }
+ matches, err := Glob(dest)
+ if err != nil {
+ t.Errorf("GlobSymlink error for %q: %s", dest, err)
+ }
+ if !contains(matches, dest) {
+ t.Errorf("Glob(%#q) = %#v want %v", dest, matches, dest)
+ }
+ }
+}
diff --git a/libgo/go/path/filepath/path.go b/libgo/go/path/filepath/path.go
index f8c7e4b2f4..d37fc9dfc8 100644
--- a/libgo/go/path/filepath/path.go
+++ b/libgo/go/path/filepath/path.go
@@ -67,7 +67,7 @@ const (
// along with the non-.. element that precedes it.
// 4. Eliminate .. elements that begin a rooted path:
// that is, replace "/.." by "/" at the beginning of a path,
-// assuming Separator is '/'.
+// assuming Separator is '/'.
//
// The returned path ends in a slash only if it represents a root directory,
// such as "/" on Unix or `C:\` on Windows.
@@ -231,6 +231,10 @@ func EvalSymlinks(path string) (string, error) {
// working directory to turn it into an absolute path. The absolute
// path name for a given file is not guaranteed to be unique.
func Abs(path string) (string, error) {
+ return abs(path)
+}
+
+func unixAbs(path string) (string, error) {
if IsAbs(path) {
return Clean(path), nil
}
@@ -336,6 +340,8 @@ var SkipDir = errors.New("skip this directory")
// the next file.
type WalkFunc func(path string, info os.FileInfo, err error) error
+var lstat = os.Lstat // for testing
+
// walk recursively descends path, calling w.
func walk(path string, info os.FileInfo, walkFn WalkFunc) error {
err := walkFn(path, info, nil)
@@ -350,17 +356,25 @@ func walk(path string, info os.FileInfo, walkFn WalkFunc) error {
return nil
}
- list, err := readDir(path)
+ names, err := readDirNames(path)
if err != nil {
return walkFn(path, info, err)
}
- for _, fileInfo := range list {
- err = walk(Join(path, fileInfo.Name()), fileInfo, walkFn)
+ for _, name := range names {
+ filename := Join(path, name)
+ fileInfo, err := lstat(filename)
if err != nil {
- if !fileInfo.IsDir() || err != SkipDir {
+ if err := walkFn(filename, fileInfo, err); err != nil && err != SkipDir {
return err
}
+ } else {
+ err = walk(filename, fileInfo, walkFn)
+ if err != nil {
+ if !fileInfo.IsDir() || err != SkipDir {
+ return err
+ }
+ }
}
}
return nil
@@ -380,30 +394,22 @@ func Walk(root string, walkFn WalkFunc) error {
return walk(root, info, walkFn)
}
-// readDir reads the directory named by dirname and returns
+// readDirNames reads the directory named by dirname and returns
// a sorted list of directory entries.
-// Copied from io/ioutil to avoid the circular import.
-func readDir(dirname string) ([]os.FileInfo, error) {
+func readDirNames(dirname string) ([]string, error) {
f, err := os.Open(dirname)
if err != nil {
return nil, err
}
- list, err := f.Readdir(-1)
+ names, err := f.Readdirnames(-1)
f.Close()
if err != nil {
return nil, err
}
- sort.Sort(byName(list))
- return list, nil
+ sort.Strings(names)
+ return names, nil
}
-// byName implements sort.Interface.
-type byName []os.FileInfo
-
-func (f byName) Len() int { return len(f) }
-func (f byName) Less(i, j int) bool { return f[i].Name() < f[j].Name() }
-func (f byName) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
-
// Base returns the last element of path.
// Trailing path separators are removed before extracting the last element.
// If the path is empty, Base returns ".".
@@ -446,13 +452,6 @@ func Dir(path string) string {
i--
}
dir := Clean(path[len(vol) : i+1])
- last := len(dir) - 1
- if last > 0 && os.IsPathSeparator(dir[last]) {
- dir = dir[:last]
- }
- if dir == "" {
- dir = "."
- }
return vol + dir
}
diff --git a/libgo/go/path/filepath/path_plan9.go b/libgo/go/path/filepath/path_plan9.go
index 12e85aae00..ee8912d58e 100644
--- a/libgo/go/path/filepath/path_plan9.go
+++ b/libgo/go/path/filepath/path_plan9.go
@@ -28,3 +28,7 @@ func splitList(path string) []string {
}
return strings.Split(path, string(ListSeparator))
}
+
+func abs(path string) (string, error) {
+ return unixAbs(path)
+}
diff --git a/libgo/go/path/filepath/path_test.go b/libgo/go/path/filepath/path_test.go
index 3a6e83d8fa..c3ee0cb86b 100644
--- a/libgo/go/path/filepath/path_test.go
+++ b/libgo/go/path/filepath/path_test.go
@@ -5,6 +5,7 @@
package filepath_test
import (
+ "errors"
"io/ioutil"
"os"
"path/filepath"
@@ -14,6 +15,8 @@ import (
"testing"
)
+var supportsSymlinks = true
+
type PathTest struct {
path, result string
}
@@ -461,6 +464,63 @@ func TestWalk(t *testing.T) {
}
}
+func touch(t *testing.T, name string) {
+ f, err := os.Create(name)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := f.Close(); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestWalkFileError(t *testing.T) {
+ td, err := ioutil.TempDir("", "walktest")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(td)
+
+ touch(t, filepath.Join(td, "foo"))
+ touch(t, filepath.Join(td, "bar"))
+ dir := filepath.Join(td, "dir")
+ if err := os.MkdirAll(filepath.Join(td, "dir"), 0755); err != nil {
+ t.Fatal(err)
+ }
+ touch(t, filepath.Join(dir, "baz"))
+ touch(t, filepath.Join(dir, "stat-error"))
+ defer func() {
+ *filepath.LstatP = os.Lstat
+ }()
+ statErr := errors.New("some stat error")
+ *filepath.LstatP = func(path string) (os.FileInfo, error) {
+ if strings.HasSuffix(path, "stat-error") {
+ return nil, statErr
+ }
+ return os.Lstat(path)
+ }
+ got := map[string]error{}
+ err = filepath.Walk(td, func(path string, fi os.FileInfo, err error) error {
+ rel, _ := filepath.Rel(td, path)
+ got[filepath.ToSlash(rel)] = err
+ return nil
+ })
+ if err != nil {
+ t.Errorf("Walk error: %v", err)
+ }
+ want := map[string]error{
+ ".": nil,
+ "foo": nil,
+ "bar": nil,
+ "dir": nil,
+ "dir/baz": nil,
+ "dir/stat-error": statErr,
+ }
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("Walked %#v; want %#v", got, want)
+ }
+}
+
var basetests = []PathTest{
{"", "."},
{".", "."},
@@ -571,6 +631,8 @@ var winisabstests = []IsAbsTest{
{`\`, false},
{`\Windows`, false},
{`c:a\b`, false},
+ {`c:\a\b`, true},
+ {`c:/a/b`, true},
{`\\host\share\foo`, true},
{`//host/share/foo/bar`, true},
}
@@ -636,8 +698,9 @@ func simpleJoin(dir, path string) string {
}
func TestEvalSymlinks(t *testing.T) {
- if runtime.GOOS == "plan9" {
- t.Skip("Skipping test: symlinks don't exist under Plan 9")
+ switch runtime.GOOS {
+ case "nacl", "plan9":
+ t.Skipf("skipping on %s", runtime.GOOS)
}
tmpDir, err := ioutil.TempDir("", "evalsymlink")
@@ -660,7 +723,7 @@ func TestEvalSymlinks(t *testing.T) {
if d.dest == "" {
err = os.Mkdir(path, 0755)
} else {
- if runtime.GOOS != "windows" {
+ if supportsSymlinks {
err = os.Symlink(d.dest, path)
}
}
@@ -670,7 +733,9 @@ func TestEvalSymlinks(t *testing.T) {
}
var tests []EvalSymlinksTest
- if runtime.GOOS == "windows" {
+ if supportsSymlinks {
+ tests = EvalSymlinksTests
+ } else {
for _, d := range EvalSymlinksTests {
if d.path == d.dest {
// will test only real files and directories
@@ -683,15 +748,13 @@ func TestEvalSymlinks(t *testing.T) {
tests = append(tests, d2)
}
}
- } else {
- tests = EvalSymlinksTests
}
// Evaluate the symlink farm.
for _, d := range tests {
path := simpleJoin(tmpDir, d.path)
dest := simpleJoin(tmpDir, d.dest)
- if filepath.IsAbs(d.dest) {
+ if filepath.IsAbs(d.dest) || os.IsPathSeparator(d.dest[0]) {
dest = d.dest
}
if p, err := filepath.EvalSymlinks(path); err != nil {
@@ -726,12 +789,6 @@ var absTests = []string{
}
func TestAbs(t *testing.T) {
- oldwd, err := os.Getwd()
- if err != nil {
- t.Fatal("Getwd failed: ", err)
- }
- defer os.Chdir(oldwd)
-
root, err := ioutil.TempDir("", "TestAbs")
if err != nil {
t.Fatal("TempDir failed: ", err)
@@ -755,6 +812,19 @@ func TestAbs(t *testing.T) {
}
}
+ if runtime.GOOS == "windows" {
+ vol := filepath.VolumeName(root)
+ var extra []string
+ for _, path := range absTests {
+ if strings.Index(path, "$") != -1 {
+ continue
+ }
+ path = vol + path
+ extra = append(extra, path)
+ }
+ absTests = append(absTests, extra...)
+ }
+
err = os.Chdir(absTestDirs[0])
if err != nil {
t.Fatal("chdir failed: ", err)
diff --git a/libgo/go/path/filepath/path_unix.go b/libgo/go/path/filepath/path_unix.go
index d927b342be..4e7d0d1b42 100644
--- a/libgo/go/path/filepath/path_unix.go
+++ b/libgo/go/path/filepath/path_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 netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package filepath
@@ -30,3 +30,7 @@ func splitList(path string) []string {
}
return strings.Split(path, string(ListSeparator))
}
+
+func abs(path string) (string, error) {
+ return unixAbs(path)
+}
diff --git a/libgo/go/path/filepath/path_windows.go b/libgo/go/path/filepath/path_windows.go
index e99997257d..ec50f6b264 100644
--- a/libgo/go/path/filepath/path_windows.go
+++ b/libgo/go/path/filepath/path_windows.go
@@ -6,6 +6,7 @@ package filepath
import (
"strings"
+ "syscall"
)
func isSlash(c uint8) bool {
@@ -103,3 +104,7 @@ func splitList(path string) []string {
return list
}
+
+func abs(path string) (string, error) {
+ return syscall.FullPath(path)
+}
diff --git a/libgo/go/path/filepath/symlink.go b/libgo/go/path/filepath/symlink.go
index 307dd0f8fe..df0a9e0c2b 100644
--- a/libgo/go/path/filepath/symlink.go
+++ b/libgo/go/path/filepath/symlink.go
@@ -2,18 +2,17 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !windows
-
package filepath
import (
"bytes"
"errors"
"os"
- "strings"
)
-func evalSymlinks(path string) (string, error) {
+const utf8RuneSelf = 0x80
+
+func walkSymlinks(path string) (string, error) {
const maxIter = 255
originalPath := path
// consume path by taking each frontmost path element,
@@ -25,7 +24,13 @@ func evalSymlinks(path string) (string, error) {
}
// find next path component, p
- i := strings.IndexRune(path, Separator)
+ var i = -1
+ for j, c := range path {
+ if c < utf8RuneSelf && os.IsPathSeparator(uint8(c)) {
+ i = j
+ break
+ }
+ }
var p string
if i == -1 {
p, path = path, ""
@@ -47,7 +52,7 @@ func evalSymlinks(path string) (string, error) {
}
if fi.Mode()&os.ModeSymlink == 0 {
b.WriteString(p)
- if path != "" {
+ if path != "" || (b.Len() == 2 && len(p) == 2 && p[1] == ':') {
b.WriteRune(Separator)
}
continue
@@ -58,7 +63,7 @@ func evalSymlinks(path string) (string, error) {
if err != nil {
return "", err
}
- if IsAbs(dest) {
+ if IsAbs(dest) || os.IsPathSeparator(dest[0]) {
b.Reset()
}
path = dest + string(Separator) + path
diff --git a/libgo/go/path/filepath/symlink_unix.go b/libgo/go/path/filepath/symlink_unix.go
new file mode 100644
index 0000000000..d20e63a987
--- /dev/null
+++ b/libgo/go/path/filepath/symlink_unix.go
@@ -0,0 +1,7 @@
+// +build !windows
+
+package filepath
+
+func evalSymlinks(path string) (string, error) {
+ return walkSymlinks(path)
+}
diff --git a/libgo/go/path/filepath/symlink_windows.go b/libgo/go/path/filepath/symlink_windows.go
index 9adc8a48af..327c2c89a3 100644
--- a/libgo/go/path/filepath/symlink_windows.go
+++ b/libgo/go/path/filepath/symlink_windows.go
@@ -50,6 +50,11 @@ func toLong(path string) (string, error) {
}
func evalSymlinks(path string) (string, error) {
+ path, err := walkSymlinks(path)
+ if err != nil {
+ return "", err
+ }
+
p, err := toShort(path)
if err != nil {
return "", err
diff --git a/libgo/go/path/path.go b/libgo/go/path/path.go
index bdb85c6b92..98a6d52922 100644
--- a/libgo/go/path/path.go
+++ b/libgo/go/path/path.go
@@ -206,13 +206,5 @@ func IsAbs(path string) bool {
// slash.
func Dir(path string) string {
dir, _ := Split(path)
- dir = Clean(dir)
- last := len(dir) - 1
- if last > 0 && dir[last] == '/' {
- dir = dir[:last]
- }
- if dir == "" {
- dir = "."
- }
- return dir
+ return Clean(dir)
}
diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go
index f9700ce2fb..bda87867c7 100644
--- a/libgo/go/reflect/all_test.go
+++ b/libgo/go/reflect/all_test.go
@@ -15,6 +15,7 @@ import (
. "reflect"
"runtime"
"sort"
+ "strings"
"sync"
"testing"
"time"
@@ -678,6 +679,7 @@ var deepEqualTests = []DeepEqualTest{
{1, nil, false},
{fn1, fn3, false},
{fn3, fn3, false},
+ {[][]int{{1}}, [][]int{{2}}, false},
// Nil vs empty: not the same.
{[]int{}, []int(nil), false},
@@ -971,6 +973,31 @@ func TestMap(t *testing.T) {
}
}
+func TestNilMap(t *testing.T) {
+ var m map[string]int
+ mv := ValueOf(m)
+ keys := mv.MapKeys()
+ if len(keys) != 0 {
+ t.Errorf(">0 keys for nil map: %v", keys)
+ }
+
+ // Check that value for missing key is zero.
+ x := mv.MapIndex(ValueOf("hello"))
+ if x.Kind() != Invalid {
+ t.Errorf("m.MapIndex(\"hello\") for nil map = %v, want Invalid Value", x)
+ }
+
+ // Check big value too.
+ var mbig map[string][10 << 20]byte
+ x = ValueOf(mbig).MapIndex(ValueOf("hello"))
+ if x.Kind() != Invalid {
+ t.Errorf("mbig.MapIndex(\"hello\") for nil map = %v, want Invalid Value", x)
+ }
+
+ // Test that deletes from a nil map succeed.
+ mv.SetMapIndex(ValueOf("hi"), Value{})
+}
+
func TestChan(t *testing.T) {
for loop := 0; loop < 2; loop++ {
var c chan int
@@ -1456,31 +1483,25 @@ func takesNonEmpty(n nonEmptyStruct) int {
}
func TestCallWithStruct(t *testing.T) {
- r := ValueOf(returnEmpty).Call([]Value{})
+ r := ValueOf(returnEmpty).Call(nil)
if len(r) != 1 || r[0].Type() != TypeOf(emptyStruct{}) {
- t.Errorf("returning empty struct returned %s instead", r)
+ t.Errorf("returning empty struct returned %#v instead", r)
}
r = ValueOf(takesEmpty).Call([]Value{ValueOf(emptyStruct{})})
if len(r) != 0 {
- t.Errorf("takesEmpty returned values: %s", r)
+ t.Errorf("takesEmpty returned values: %#v", r)
}
r = ValueOf(returnNonEmpty).Call([]Value{ValueOf(42)})
if len(r) != 1 || r[0].Type() != TypeOf(nonEmptyStruct{}) || r[0].Field(0).Int() != 42 {
- t.Errorf("returnNonEmpty returned %s", r)
+ t.Errorf("returnNonEmpty returned %#v", r)
}
r = ValueOf(takesNonEmpty).Call([]Value{ValueOf(nonEmptyStruct{member: 42})})
if len(r) != 1 || r[0].Type() != TypeOf(1) || r[0].Int() != 42 {
- t.Errorf("takesNonEmpty returned %s", r)
+ t.Errorf("takesNonEmpty returned %#v", r)
}
}
func TestMakeFunc(t *testing.T) {
- switch runtime.GOARCH {
- case "amd64", "386":
- default:
- t.Skip("MakeFunc not implemented for " + runtime.GOARCH)
- }
-
f := dummy
fv := MakeFunc(TypeOf(f), func(in []Value) []Value { return in })
ValueOf(&f).Elem().Set(fv)
@@ -1499,12 +1520,6 @@ func TestMakeFunc(t *testing.T) {
}
func TestMakeFuncInterface(t *testing.T) {
- switch runtime.GOARCH {
- case "amd64", "386":
- default:
- t.Skip("MakeFunc not implemented for " + runtime.GOARCH)
- }
-
fn := func(i int) int { return i }
incr := func(in []Value) []Value {
return []Value{ValueOf(int(in[0].Int() + 1))}
@@ -1522,6 +1537,44 @@ func TestMakeFuncInterface(t *testing.T) {
}
}
+func TestMakeFuncVariadic(t *testing.T) {
+ // Test that variadic arguments are packed into a slice and passed as last arg
+ fn := func(_ int, is ...int) []int { return nil }
+ fv := MakeFunc(TypeOf(fn), func(in []Value) []Value { return in[1:2] })
+ ValueOf(&fn).Elem().Set(fv)
+
+ r := fn(1, 2, 3)
+ if r[0] != 2 || r[1] != 3 {
+ t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1])
+ }
+
+ r = fn(1, []int{2, 3}...)
+ if r[0] != 2 || r[1] != 3 {
+ t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1])
+ }
+
+ r = fv.Call([]Value{ValueOf(1), ValueOf(2), ValueOf(3)})[0].Interface().([]int)
+ if r[0] != 2 || r[1] != 3 {
+ t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1])
+ }
+
+ r = fv.CallSlice([]Value{ValueOf(1), ValueOf([]int{2, 3})})[0].Interface().([]int)
+ if r[0] != 2 || r[1] != 3 {
+ t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1])
+ }
+
+ f := fv.Interface().(func(int, ...int) []int)
+
+ r = f(1, 2, 3)
+ if r[0] != 2 || r[1] != 3 {
+ t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1])
+ }
+ r = f(1, []int{2, 3}...)
+ if r[0] != 2 || r[1] != 3 {
+ t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1])
+ }
+}
+
type Point struct {
x, y int
}
@@ -1537,6 +1590,24 @@ func (p Point) Dist(scale int) int {
return p.x*p.x*scale + p.y*p.y*scale
}
+// This will be index 2.
+func (p Point) GCMethod(k int) int {
+ runtime.GC()
+ return k + p.x
+}
+
+// This will be index 3.
+func (p Point) TotalDist(points ...Point) int {
+ tot := 0
+ for _, q := range points {
+ dx := q.x - p.x
+ dy := q.y - p.y
+ tot += dx*dx + dy*dy // Should call Sqrt, but it's just a test.
+
+ }
+ return tot
+}
+
func TestMethod(t *testing.T) {
// Non-curried method of type.
p := Point{3, 4}
@@ -1632,12 +1703,6 @@ func TestMethod(t *testing.T) {
}
func TestMethodValue(t *testing.T) {
- switch runtime.GOARCH {
- case "amd64", "386":
- default:
- t.Skip("reflect method values not implemented for " + runtime.GOARCH)
- }
-
p := Point{3, 4}
var i int64
@@ -1725,6 +1790,37 @@ func TestMethodValue(t *testing.T) {
}
}
+func TestVariadicMethodValue(t *testing.T) {
+ p := Point{3, 4}
+ points := []Point{{20, 21}, {22, 23}, {24, 25}}
+ want := int64(p.TotalDist(points[0], points[1], points[2]))
+
+ // Curried method of value.
+ tfunc := TypeOf((func(...Point) int)(nil))
+ v := ValueOf(p).Method(3)
+ if tt := v.Type(); tt != tfunc {
+ t.Errorf("Variadic Method Type is %s; want %s", tt, tfunc)
+ }
+ i := ValueOf(v.Interface()).Call([]Value{ValueOf(points[0]), ValueOf(points[1]), ValueOf(points[2])})[0].Int()
+ if i != want {
+ t.Errorf("Variadic Method returned %d; want %d", i, want)
+ }
+ i = ValueOf(v.Interface()).CallSlice([]Value{ValueOf(points)})[0].Int()
+ if i != want {
+ t.Errorf("Variadic Method CallSlice returned %d; want %d", i, want)
+ }
+
+ f := v.Interface().(func(...Point) int)
+ i = int64(f(points[0], points[1], points[2]))
+ if i != want {
+ t.Errorf("Variadic Method Interface returned %d; want %d", i, want)
+ }
+ i = int64(f(points...))
+ if i != want {
+ t.Errorf("Variadic Method Interface Slice returned %d; want %d", i, want)
+ }
+}
+
// Reflect version of $GOROOT/test/method5.go
// Concrete types implementing M method.
@@ -1809,12 +1905,6 @@ type Tm4 struct {
func (t4 Tm4) M(x int, b byte) (byte, int) { return b, x + 40 }
func TestMethod5(t *testing.T) {
- switch runtime.GOARCH {
- case "amd64", "386":
- default:
- t.Skip("reflect method values not implemented for " + runtime.GOARCH)
- }
-
CheckF := func(name string, f func(int, byte) (byte, int), inc int) {
b, x := f(1000, 99)
if b != 99 || x != 1000+inc {
@@ -2417,10 +2507,21 @@ func TestAllocations(t *testing.T) {
noAlloc(t, 100, func(j int) {
var i interface{}
var v Value
- i = 42 + j
+
+ // We can uncomment this when compiler escape analysis
+ // is good enough to see that the integer assigned to i
+ // does not escape and therefore need not be allocated.
+ //
+ // i = 42 + j
+ // v = ValueOf(i)
+ // if int(v.Int()) != 42+j {
+ // panic("wrong int")
+ // }
+
+ i = func(j int) int { return j }
v = ValueOf(i)
- if int(v.Int()) != 42+j {
- panic("wrong int")
+ if v.Interface().(func(int) int)(j) != j {
+ panic("wrong result")
}
})
}
@@ -2481,6 +2582,15 @@ func TestSlice(t *testing.T) {
if vs != s[3:5] {
t.Errorf("s.Slice(3, 5) = %q; expected %q", vs, s[3:5])
}
+
+ rv := ValueOf(&xs).Elem()
+ rv = rv.Slice(3, 4)
+ ptr2 := rv.Pointer()
+ rv = rv.Slice(5, 5)
+ ptr3 := rv.Pointer()
+ if ptr3 != ptr2 {
+ t.Errorf("xs.Slice(3,4).Slice3(5,5).Pointer() = %#x, want %#x", ptr3, ptr2)
+ }
}
func TestSlice3(t *testing.T) {
@@ -2519,6 +2629,15 @@ func TestSlice3(t *testing.T) {
s := "hello world"
rv = ValueOf(&s).Elem()
shouldPanic(func() { rv.Slice3(1, 2, 3) })
+
+ rv = ValueOf(&xs).Elem()
+ rv = rv.Slice3(3, 5, 7)
+ ptr2 := rv.Pointer()
+ rv = rv.Slice3(4, 4, 4)
+ ptr3 := rv.Pointer()
+ if ptr3 != ptr2 {
+ t.Errorf("xs.Slice3(3,5,7).Slice3(4,4,4).Pointer() = %#x, want %#x", ptr3, ptr2)
+ }
}
func TestSetLenCap(t *testing.T) {
@@ -2577,6 +2696,26 @@ func TestFuncArg(t *testing.T) {
}
}
+func TestStructArg(t *testing.T) {
+ type padded struct {
+ B string
+ C int32
+ }
+ var (
+ gotA padded
+ gotB uint32
+ wantA = padded{"3", 4}
+ wantB = uint32(5)
+ )
+ f := func(a padded, b uint32) {
+ gotA, gotB = a, b
+ }
+ ValueOf(f).Call([]Value{ValueOf(wantA), ValueOf(wantB)})
+ if gotA != wantA || gotB != wantB {
+ t.Errorf("function called with (%v, %v), want (%v, %v)", gotA, gotB, wantA, wantB)
+ }
+}
+
var tagGetTests = []struct {
Tag StructTag
Key string
@@ -3154,6 +3293,44 @@ func TestConvert(t *testing.T) {
}
}
+type ComparableStruct struct {
+ X int
+}
+
+type NonComparableStruct struct {
+ X int
+ Y map[string]int
+}
+
+var comparableTests = []struct {
+ typ Type
+ ok bool
+}{
+ {TypeOf(1), true},
+ {TypeOf("hello"), true},
+ {TypeOf(new(byte)), true},
+ {TypeOf((func())(nil)), false},
+ {TypeOf([]byte{}), false},
+ {TypeOf(map[string]int{}), false},
+ {TypeOf(make(chan int)), true},
+ {TypeOf(1.5), true},
+ {TypeOf(false), true},
+ {TypeOf(1i), true},
+ {TypeOf(ComparableStruct{}), true},
+ {TypeOf(NonComparableStruct{}), false},
+ {TypeOf([10]map[string]int{}), false},
+ {TypeOf([10]string{}), true},
+ {TypeOf(new(interface{})).Elem(), true},
+}
+
+func TestComparable(t *testing.T) {
+ for _, tt := range comparableTests {
+ if ok := tt.typ.Comparable(); ok != tt.ok {
+ t.Errorf("TypeOf(%v).Comparable() = %v, want %v", tt.typ, ok, tt.ok)
+ }
+ }
+}
+
func TestOverflow(t *testing.T) {
if ovf := V(float64(0)).OverflowFloat(1e300); ovf {
t.Errorf("%v wrongly overflows float64", 1e300)
@@ -3200,6 +3377,9 @@ 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)))
@@ -3687,3 +3867,300 @@ func (x *exhaustive) Choose(max int) int {
func (x *exhaustive) Maybe() bool {
return x.Choose(2) == 1
}
+
+func GCFunc(args []Value) []Value {
+ runtime.GC()
+ return []Value{}
+}
+
+func TestReflectFuncTraceback(t *testing.T) {
+ f := MakeFunc(TypeOf(func() {}), GCFunc)
+ f.Call([]Value{})
+}
+
+func TestReflectMethodTraceback(t *testing.T) {
+ p := Point{3, 4}
+ m := ValueOf(p).MethodByName("GCMethod")
+ i := ValueOf(m.Interface()).Call([]Value{ValueOf(5)})[0].Int()
+ if i != 8 {
+ t.Errorf("Call returned %d; want 8", i)
+ }
+}
+
+func TestBigZero(t *testing.T) {
+ const size = 1 << 10
+ var v [size]byte
+ z := Zero(ValueOf(v).Type()).Interface().([size]byte)
+ for i := 0; i < size; i++ {
+ if z[i] != 0 {
+ t.Fatalf("Zero object not all zero, index %d", i)
+ }
+ }
+}
+
+func TestFieldByIndexNil(t *testing.T) {
+ type P struct {
+ F int
+ }
+ type T struct {
+ *P
+ }
+ v := ValueOf(T{})
+
+ v.FieldByName("P") // should be fine
+
+ defer func() {
+ if err := recover(); err == nil {
+ t.Fatalf("no error")
+ } else if !strings.Contains(fmt.Sprint(err), "nil pointer to embedded struct") {
+ t.Fatalf(`err=%q, wanted error containing "nil pointer to embedded struct"`, err)
+ }
+ }()
+ v.FieldByName("F") // should panic
+
+ t.Fatalf("did not panic")
+}
+
+// Given
+// type Outer struct {
+// *Inner
+// ...
+// }
+// the compiler generates the implementation of (*Outer).M dispatching to the embedded Inner.
+// The implementation is logically:
+// func (p *Outer) M() {
+// (p.Inner).M()
+// }
+// but since the only change here is the replacement of one pointer receiver with another,
+// the actual generated code overwrites the original receiver with the p.Inner pointer and
+// then jumps to the M method expecting the *Inner receiver.
+//
+// During reflect.Value.Call, we create an argument frame and the associated data structures
+// to describe it to the garbage collector, populate the frame, call reflect.call to
+// run a function call using that frame, and then copy the results back out of the frame.
+// The reflect.call function does a memmove of the frame structure onto the
+// stack (to set up the inputs), runs the call, and the memmoves the stack back to
+// the frame structure (to preserve the outputs).
+//
+// Originally reflect.call did not distinguish inputs from outputs: both memmoves
+// were for the full stack frame. However, in the case where the called function was
+// one of these wrappers, the rewritten receiver is almost certainly a different type
+// than the original receiver. This is not a problem on the stack, where we use the
+// program counter to determine the type information and understand that
+// during (*Outer).M the receiver is an *Outer while during (*Inner).M the receiver in the same
+// memory word is now an *Inner. But in the statically typed argument frame created
+// by reflect, the receiver is always an *Outer. Copying the modified receiver pointer
+// off the stack into the frame will store an *Inner there, and then if a garbage collection
+// happens to scan that argument frame before it is discarded, it will scan the *Inner
+// memory as if it were an *Outer. If the two have different memory layouts, the
+// collection will intepret the memory incorrectly.
+//
+// One such possible incorrect interpretation is to treat two arbitrary memory words
+// (Inner.P1 and Inner.P2 below) as an interface (Outer.R below). Because interpreting
+// an interface requires dereferencing the itab word, the misinterpretation will try to
+// deference Inner.P1, causing a crash during garbage collection.
+//
+// This came up in a real program in issue 7725.
+
+type Outer struct {
+ *Inner
+ R io.Reader
+}
+
+type Inner struct {
+ X *Outer
+ P1 uintptr
+ P2 uintptr
+}
+
+func (pi *Inner) M() {
+ // Clear references to pi so that the only way the
+ // garbage collection will find the pointer is in the
+ // argument frame, typed as a *Outer.
+ pi.X.Inner = nil
+
+ // Set up an interface value that will cause a crash.
+ // P1 = 1 is a non-zero, so the interface looks non-nil.
+ // P2 = pi ensures that the data word points into the
+ // allocated heap; if not the collection skips the interface
+ // value as irrelevant, without dereferencing P1.
+ pi.P1 = 1
+ pi.P2 = uintptr(unsafe.Pointer(pi))
+}
+
+func TestCallMethodJump(t *testing.T) {
+ // In reflect.Value.Call, trigger a garbage collection after reflect.call
+ // returns but before the args frame has been discarded.
+ // This is a little clumsy but makes the failure repeatable.
+ *CallGC = true
+
+ p := &Outer{Inner: new(Inner)}
+ p.Inner.X = p
+ ValueOf(p).Method(0).Call(nil)
+
+ // Stop garbage collecting during reflect.call.
+ *CallGC = false
+}
+
+func TestMakeFuncStackCopy(t *testing.T) {
+ target := func(in []Value) []Value {
+ runtime.GC()
+ useStack(16)
+ return []Value{ValueOf(9)}
+ }
+
+ var concrete func(*int, int) int
+ fn := MakeFunc(ValueOf(concrete).Type(), target)
+ ValueOf(&concrete).Elem().Set(fn)
+ x := concrete(nil, 7)
+ if x != 9 {
+ t.Errorf("have %#q want 9", x)
+ }
+}
+
+// use about n KB of stack
+func useStack(n int) {
+ if n == 0 {
+ return
+ }
+ var b [1024]byte // makes frame about 1KB
+ useStack(n - 1 + int(b[99]))
+}
+
+type Impl struct{}
+
+func (Impl) f() {}
+
+func TestValueString(t *testing.T) {
+ rv := ValueOf(Impl{})
+ if rv.String() != "<reflect_test.Impl Value>" {
+ t.Errorf("ValueOf(Impl{}).String() = %q, want %q", rv.String(), "<reflect_test.Impl Value>")
+ }
+
+ method := rv.Method(0)
+ if method.String() != "<func() Value>" {
+ t.Errorf("ValueOf(Impl{}).Method(0).String() = %q, want %q", method.String(), "<func() Value>")
+ }
+}
+
+func TestInvalid(t *testing.T) {
+ // Used to have inconsistency between IsValid() and Kind() != Invalid.
+ type T struct{ v interface{} }
+
+ v := ValueOf(T{}).Field(0)
+ if v.IsValid() != true || v.Kind() != Interface {
+ t.Errorf("field: IsValid=%v, Kind=%v, want true, Interface", v.IsValid(), v.Kind())
+ }
+ v = v.Elem()
+ if v.IsValid() != false || v.Kind() != Invalid {
+ t.Errorf("field elem: IsValid=%v, Kind=%v, want false, Invalid", v.IsValid(), v.Kind())
+ }
+}
+
+// Issue 8917.
+func TestLargeGCProg(t *testing.T) {
+ fv := ValueOf(func([256]*byte) {})
+ fv.Call([]Value{ValueOf([256]*byte{})})
+}
+
+// Issue 9179.
+func TestCallGC(t *testing.T) {
+ f := func(a, b, c, d, e string) {
+ }
+ g := func(in []Value) []Value {
+ runtime.GC()
+ return nil
+ }
+ typ := ValueOf(f).Type()
+ f2 := MakeFunc(typ, g).Interface().(func(string, string, string, string, string))
+ f2("four", "five5", "six666", "seven77", "eight888")
+}
+
+type funcLayoutTest struct {
+ rcvr, t Type
+ argsize, retOffset uintptr
+ stack []byte
+}
+
+var funcLayoutTests []funcLayoutTest
+
+func init() {
+ var argAlign = PtrSize
+ if runtime.GOARCH == "amd64p32" {
+ argAlign = 2 * PtrSize
+ }
+ roundup := func(x uintptr, a uintptr) uintptr {
+ return (x + a - 1) / a * a
+ }
+
+ funcLayoutTests = append(funcLayoutTests,
+ funcLayoutTest{
+ nil,
+ ValueOf(func(a, b string) string { return "" }).Type(),
+ 4 * PtrSize,
+ 4 * PtrSize,
+ []byte{BitsPointer, BitsScalar, BitsPointer},
+ })
+
+ var r []byte
+ if PtrSize == 4 {
+ r = []byte{BitsScalar, BitsScalar, BitsScalar, BitsPointer}
+ } else {
+ r = []byte{BitsScalar, BitsScalar, BitsPointer}
+ }
+ funcLayoutTests = append(funcLayoutTests,
+ funcLayoutTest{
+ nil,
+ ValueOf(func(a, b, c uint32, p *byte, d uint16) {}).Type(),
+ roundup(3*4, PtrSize) + PtrSize + 2,
+ roundup(roundup(3*4, PtrSize)+PtrSize+2, argAlign),
+ r,
+ })
+
+ funcLayoutTests = append(funcLayoutTests,
+ funcLayoutTest{
+ nil,
+ ValueOf(func(a map[int]int, b uintptr, c interface{}) {}).Type(),
+ 4 * PtrSize,
+ 4 * PtrSize,
+ []byte{BitsPointer, BitsScalar, BitsPointer, BitsPointer},
+ })
+
+ type S struct {
+ a, b uintptr
+ c, d *byte
+ }
+ funcLayoutTests = append(funcLayoutTests,
+ funcLayoutTest{
+ nil,
+ ValueOf(func(a S) {}).Type(),
+ 4 * PtrSize,
+ 4 * PtrSize,
+ []byte{BitsScalar, BitsScalar, BitsPointer, BitsPointer},
+ })
+
+ funcLayoutTests = append(funcLayoutTests,
+ funcLayoutTest{
+ ValueOf((*byte)(nil)).Type(),
+ ValueOf(func(a uintptr, b *int) {}).Type(),
+ 3 * PtrSize,
+ roundup(3*PtrSize, argAlign),
+ []byte{BitsPointer, BitsScalar, BitsPointer},
+ })
+}
+
+func TestFuncLayout(t *testing.T) {
+ t.Skip("gccgo does not use funcLayout")
+ for _, lt := range funcLayoutTests {
+ _, argsize, retOffset, stack := FuncLayout(lt.t, lt.rcvr)
+ if argsize != lt.argsize {
+ t.Errorf("funcLayout(%v, %v).argsize=%d, want %d", lt.t, lt.rcvr, argsize, lt.argsize)
+ }
+ if retOffset != lt.retOffset {
+ t.Errorf("funcLayout(%v, %v).retOffset=%d, want %d", lt.t, lt.rcvr, retOffset, lt.retOffset)
+ }
+ if !bytes.Equal(stack, lt.stack) {
+ t.Errorf("funcLayout(%v, %v).stack=%v, want %v", lt.t, lt.rcvr, stack, lt.stack)
+ }
+ }
+}
diff --git a/libgo/go/reflect/deepequal.go b/libgo/go/reflect/deepequal.go
index e3bf3dcac0..f63715c9af 100644
--- a/libgo/go/reflect/deepequal.go
+++ b/libgo/go/reflect/deepequal.go
@@ -62,9 +62,6 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool, depth int) bool {
switch v1.Kind() {
case Array:
- if v1.Len() != v2.Len() {
- return false
- }
for i := 0; i < v1.Len(); i++ {
if !deepValueEqual(v1.Index(i), v2.Index(i), visited, depth+1) {
return false
diff --git a/libgo/go/reflect/export_test.go b/libgo/go/reflect/export_test.go
index cd8cf2cf2c..49c45e82b2 100644
--- a/libgo/go/reflect/export_test.go
+++ b/libgo/go/reflect/export_test.go
@@ -16,3 +16,12 @@ func IsRO(v Value) bool {
}
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) {
+ return
+}
diff --git a/libgo/go/reflect/makefunc.go b/libgo/go/reflect/makefunc.go
index 935a3d3be0..7ec277b864 100644
--- a/libgo/go/reflect/makefunc.go
+++ b/libgo/go/reflect/makefunc.go
@@ -7,16 +7,19 @@
package reflect
import (
- "runtime"
"unsafe"
)
// makeFuncImpl is the closure value implementing the function
// returned by MakeFunc.
type makeFuncImpl struct {
- code uintptr
- typ *funcType
- fn func([]Value) []Value
+ // These first three words are layed out like ffi_go_closure.
+ code uintptr
+ ffi_cif unsafe.Pointer
+ ffi_fun func(unsafe.Pointer, unsafe.Pointer)
+
+ typ *funcType
+ fn func([]Value) []Value
// For gccgo we use the same entry point for functions and for
// method values.
@@ -51,33 +54,20 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
panic("reflect: call of MakeFunc with non-Func type")
}
- switch runtime.GOARCH {
- case "amd64", "386":
- default:
- panic("reflect.MakeFunc not implemented for " + runtime.GOARCH)
- }
-
t := typ.common()
ftyp := (*funcType)(unsafe.Pointer(t))
- // Indirect Go func value (dummy) to obtain
- // actual code address. (A Go func value is a pointer
- // to a C function pointer. http://golang.org/s/go11func.)
- dummy := makeFuncStub
- code := **(**uintptr)(unsafe.Pointer(&dummy))
+ impl := &makeFuncImpl{
+ typ: ftyp,
+ fn: fn,
+ method: -1,
+ }
- impl := &makeFuncImpl{code: code, typ: ftyp, fn: fn, method: -1}
+ makeFuncFFI(ftyp, unsafe.Pointer(impl))
- return Value{t, unsafe.Pointer(&impl), flag(Func<<flagKindShift) | flagIndir}
+ return Value{t, unsafe.Pointer(&impl), flag(Func) | flagIndir}
}
-// makeFuncStub is an assembly function that is the code half of
-// the function returned from MakeFunc. It expects a *callReflectFunc
-// as its context register, and its job is to invoke callReflect(ctxt, frame)
-// where ctxt is the context register and frame is a pointer to the first
-// word in the passed-in argument frame.
-func makeFuncStub()
-
// makeMethodValue converts v from the rcvr+method index representation
// of a method value to an actual method func value, which is
// basically the receiver value with a special bit set, into a true
@@ -87,42 +77,34 @@ func makeFuncStub()
// by code like Convert and Interface and Assign.
func makeMethodValue(op string, v Value) Value {
if v.flag&flagMethod == 0 {
- panic("reflect: internal error: invalid use of makePartialFunc")
- }
-
- switch runtime.GOARCH {
- case "amd64", "386":
- default:
- panic("reflect.makeMethodValue not implemented for " + runtime.GOARCH)
+ panic("reflect: internal error: invalid use of makeMethodValue")
}
// Ignoring the flagMethod bit, v describes the receiver, not the method type.
fl := v.flag & (flagRO | flagAddr | flagIndir)
- fl |= flag(v.typ.Kind()) << flagKindShift
- rcvr := Value{v.typ, v.val, fl}
+ fl |= flag(v.typ.Kind())
+ rcvr := Value{v.typ, v.ptr, fl}
// v.Type returns the actual type of the method value.
ft := v.Type().(*rtype)
- // Indirect Go func value (dummy) to obtain
- // actual code address. (A Go func value is a pointer
- // to a C function pointer. http://golang.org/s/go11func.)
- dummy := makeFuncStub
- code := **(**uintptr)(unsafe.Pointer(&dummy))
-
// Cause panic if method is not appropriate.
// The panic would still happen during the call if we omit this,
// but we want Interface() and other operations to fail early.
- t, _, _ := methodReceiver(op, rcvr, int(v.flag)>>flagMethodShift)
+ _, t, _ := methodReceiver(op, rcvr, int(v.flag)>>flagMethodShift)
+
+ ftyp := (*funcType)(unsafe.Pointer(t))
+ method := int(v.flag) >> flagMethodShift
fv := &makeFuncImpl{
- code: code,
- typ: (*funcType)(unsafe.Pointer(t)),
- method: int(v.flag) >> flagMethodShift,
+ typ: ftyp,
+ method: method,
rcvr: rcvr,
}
- return Value{ft, unsafe.Pointer(&fv), v.flag&flagRO | flag(Func)<<flagKindShift | flagIndir}
+ makeFuncFFI(ftyp, unsafe.Pointer(fv))
+
+ return Value{ft, unsafe.Pointer(&fv), v.flag&flagRO | flag(Func) | flagIndir}
}
// makeValueMethod takes a method function and returns a function that
@@ -137,29 +119,18 @@ func makeValueMethod(v Value) Value {
panic("reflect: call of makeValueMethod with non-MethodFn")
}
- switch runtime.GOARCH {
- case "amd64", "386":
- default:
- panic("reflect.makeValueMethod not implemented for " + runtime.GOARCH)
- }
-
t := typ.common()
ftyp := (*funcType)(unsafe.Pointer(t))
- // Indirect Go func value (dummy) to obtain
- // actual code address. (A Go func value is a pointer
- // to a C function pointer. http://golang.org/s/go11func.)
- dummy := makeFuncStub
- code := **(**uintptr)(unsafe.Pointer(&dummy))
-
impl := &makeFuncImpl{
- code: code,
typ: ftyp,
method: -2,
rcvr: v,
}
- return Value{t, unsafe.Pointer(&impl), flag(Func<<flagKindShift) | flagIndir}
+ makeFuncFFI(ftyp, unsafe.Pointer(impl))
+
+ return Value{t, unsafe.Pointer(&impl), v.flag&flagRO | flag(Func) | flagIndir}
}
// Call the function represented by a makeFuncImpl.
diff --git a/libgo/go/reflect/makefunc_386.S b/libgo/go/reflect/makefunc_386.S
deleted file mode 100644
index 0e2e764653..0000000000
--- a/libgo/go/reflect/makefunc_386.S
+++ /dev/null
@@ -1,230 +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.
-
- MakeFunc 386 assembly code. */
-
-#include "config.h"
-
- .globl reflect.makeFuncStub
-
-#ifdef __ELF__
- .type reflect.makeFuncStub,@function
-#endif
-
-reflect.makeFuncStub:
-.LFB1:
-
- /* Go does not provide any equivalent to the regparm function
- attribute, so on Go we do not need to worry about passing
- parameters in registers. We just pass a pointer to the
- arguments on the stack.
-
- We do need to pick up the return values, though, so we pass
- a pointer to a struct that looks like this.
- struct {
- esp uint32 // 0x0
- eax uint32 // 0x4
- st0 float64 // 0x8
- sr bool // 0x10
- sf bool // 0x11
- }
- The sr field is set by the function to a non-zero value if
- the function takes a struct hidden pointer that must be
- popped off the stack. */
-
- pushl %ebp
-.LCFI0:
- movl %esp, %ebp
-.LCFI1:
- pushl %ebx /* In case this is PIC. */
- subl $36, %esp /* Enough for args and to align stack. */
-.LCFI2:
-
-#ifdef __PIC__
- call __x86.get_pc_thunk.bx
- addl $_GLOBAL_OFFSET_TABLE_, %ebx
-#endif
-
- leal 8(%ebp), %eax /* Set esp field in struct. */
- movl %eax, -24(%ebp)
-
- /* For MakeFunc functions that call recover. */
- movl 4(%ebp), %eax
- movl %eax, (%esp)
-#ifdef __PIC__
- call __go_makefunc_can_recover@PLT
-#else
- call __go_makefunc_can_recover
-#endif
-
-#ifdef __PIC__
- call __go_get_closure@PLT
-#else
- call __go_get_closure
-#endif
-
- movl %eax, 4(%esp)
-
- leal -24(%ebp), %eax
- movl %eax, (%esp)
-
-#ifdef __PIC__
- call reflect.MakeFuncStubGo@PLT
-#else
- call reflect.MakeFuncStubGo
-#endif
-
- /* MakeFunc functions can no longer call recover. */
-#ifdef __PIC__
- call __go_makefunc_returning@PLT
-#else
- call __go_makefunc_returning
-#endif
-
- /* Set return registers. */
-
- movl -20(%ebp), %eax
-
- cmpb $0, -7(%ebp)
- je 2f
-
- fldl -16(%ebp)
-
-#ifdef __SSE2__
- /* In case we are compiling with -msseregparm. This won't work
- correctly if only SSE1 is supported, but that seems unlikely. */
- movsd -16(%ebp), %xmm0
-#endif
-
-2:
- movb -8(%ebp), %dl
-
- addl $36, %esp
- popl %ebx
-.LCFI3:
- popl %ebp
-.LCFI4:
-
- testb %dl,%dl
- jne 1f
- ret
-1:
- ret $4
-.LFE1:
-#ifdef __ELF__
- .size reflect.makeFuncStub, . - reflect.makeFuncStub
-#endif
-
-#ifdef __PIC__
-#ifdef HAVE_AS_COMDAT_GAS
- .section .text.__x86.get_pc_thunk.bx,"axG",@progbits,__x86.get_pc_thunk.bx,comdat
-#else
- /* Sun as needs a different syntax. */
- .section .text.__x86.get_pc_thunk.bx%__x86.get_pc_thunk.bx,"ax",@progbits
- .group __x86.get_pc_thunk.bx,.text.__x86.get_pc_thunk.bx%__x86.get_pc_thunk.bx,#comdat
-#endif
- .globl __x86.get_pc_thunk.bx
- .hidden __x86.get_pc_thunk.bx
-#ifdef __ELF__
- .type __x86.get_pc_thunk.bx, @function
-#endif
-__x86.get_pc_thunk.bx:
-.LFB2:
- movl (%esp), %ebx
- ret
-.LFE2:
-#ifdef __ELF__
- .size __x86.get_pc_thunk.bx, . - __x86.get_pc_thunk.bx
-#endif
-#endif
-
-#ifdef __ELF__
-#if defined __PIC__
-# if defined __sun__ && defined __svr4__
-/* 32-bit Solaris 2/x86 uses datarel encoding for PIC. GNU ld before 2.22
- doesn't correctly sort .eh_frame_hdr with mixed encodings, so match this. */
-# define FDE_ENCODING 0x30 /* datarel */
-# define FDE_ENCODE(X) X@GOTOFF
-# else
-# define FDE_ENCODING 0x1b /* pcrel sdata4 */
-# if defined HAVE_AS_X86_PCREL
-# define FDE_ENCODE(X) X-.
-# else
-# define FDE_ENCODE(X) X@rel
-# endif
-# endif
-#else
-# define FDE_ENCODING 0 /* absolute */
-# define FDE_ENCODE(X) X
-#endif
-
- .section .eh_frame,EH_FRAME_FLAGS,@progbits
-.Lframe1:
- .long .LECIE1-.LSCIE1 /* Length of Common Information Entry */
-.LSCIE1:
- .long 0x0 /* CIE Identifier Tag */
- .byte 0x1 /* CIE Version */
- .ascii "zR\0" /* CIE Augmentation */
- .byte 0x1 /* .uleb128 0x1; CIE Code Alignment Factor */
- .byte 0x7c /* .sleb128 -4; CIE Data Alignment Factor */
- .byte 0x8 /* CIE RA Column */
- .byte 0x1 /* .uleb128 0x1; Augmentation size */
- .byte FDE_ENCODING
- .byte 0xc /* DW_CFA_def_cfa */
- .byte 0x4 /* .uleb128 0x4 */
- .byte 0x4 /* .uleb128 0x4 */
- .byte 0x88 /* DW_CFA_offset, column 0x8 */
- .byte 0x1 /* .uleb128 0x1 */
- .align 4
-.LECIE1:
-.LSFDE1:
- .long .LEFDE1-.LASFDE1 /* FDE Length */
-.LASFDE1:
- .long .LASFDE1-.Lframe1 /* FDE CIE offset */
- .long FDE_ENCODE(.LFB1) /* FDE initial location */
- .long .LFE1-.LFB1 /* FDE address range */
- .byte 0x0 /* .uleb128 0x0; Augmentation size */
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .long .LCFI0-.LFB1
- .byte 0xe /* DW_CFA_def_cfa_offset */
- .byte 0x8 /* .uleb128 0x8 */
- .byte 0x85 /* DW_CFA_offset, column 0x5 */
- .byte 0x2 /* .uleb128 0x2 */
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .long .LCFI1-.LCFI0
- .byte 0xd /* DW_CFA_def_cfa_register */
- .byte 0x5 /* .uleb128 0x5 */
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .long .LCFI2-.LCFI1
- .byte 0x83 /* .DW_CFA_offset, column 0x3 */
- .byte 0x3 /* .uleb128 0x3 */
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .long .LCFI3-.LCFI2
- .byte 0xc3 /* DW_CFA_restore, column 0x3 */
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .long .LCFI4-.LCFI3
- .byte 0xc5 /* DW_CFA_restore, column 0x5 */
- .byte 0xc /* DW_CFA_def_cfa */
- .byte 0x4 /* .uleb128 0x4 */
- .byte 0x4 /* .uleb128 0x4 */
- .align 4
-.LEFDE1:
-#ifdef __PIC__
-.LSFDE2:
- .long .LEFDE2-.LASFDE2 /* FDE Length */
-.LASFDE2:
- .long .LASFDE2-.Lframe1 /* FDE CIE offset */
- .long FDE_ENCODE(.LFB2) /* FDE initial location */
- .long .LFE2-.LFB2 /* FDE address range */
- .byte 0x0 /* .uleb128 0x0; Augmentation size */
- .align 4
-.LEFDE2:
-#endif /* __PIC__ */
-#endif /* __ELF__ */
-
-#if defined(__ELF__) && defined(__linux__)
- .section .note.GNU-stack,"",@progbits
- .section .note.GNU-split-stack,"",@progbits
- .section .note.GNU-no-split-stack,"",@progbits
-#endif
diff --git a/libgo/go/reflect/makefunc_amd64.S b/libgo/go/reflect/makefunc_amd64.S
deleted file mode 100644
index 88302eee1b..0000000000
--- a/libgo/go/reflect/makefunc_amd64.S
+++ /dev/null
@@ -1,177 +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.
-
-# MakeFunc amd64 assembly code.
-
-#include "config.h"
-
- .global reflect.makeFuncStub
-
-#ifdef __ELF__
- .type reflect.makeFuncStub,@function
-#endif
-
-reflect.makeFuncStub:
-.LFB1:
-
- # Store all the parameter registers in a struct that looks
- # like:
- # struct {
- # rax uint64 // 0x0
- # rdi uint64 // 0x8
- # rsi uint64 // 0x10
- # rdx uint64 // 0x18
- # rcx uint64 // 0x20
- # r8 uint64 // 0x28
- # r9 uint64 // 0x30
- # rsp uint64 // 0x38 Pointer to arguments on stack.
- # xmm0 [2]uint64 // 0x40
- # xmm1 [2]uint64 // 0x50
- # xmm2 [2]uint64 // 0x60
- # xmm3 [2]uint64 // 0x70
- # xmm4 [2]uint64 // 0x80
- # xmm5 [2]uint64 // 0x90
- # xmm6 [2]uint64 // 0xa0
- # xmm7 [2]uint64 // 0xb0
- # };
-
- pushq %rbp
-.LCFI0:
- movq %rsp, %rbp
-.LCFI1:
-
- subq $0xc0, %rsp # Space for struct on stack.
-
- movq %rax, 0x0(%rsp)
- movq %rdi, 0x8(%rsp)
- movq %rsi, 0x10(%rsp)
- movq %rdx, 0x18(%rsp)
- movq %rcx, 0x20(%rsp)
- movq %r8, 0x28(%rsp)
- movq %r9, 0x30(%rsp)
- leaq 16(%rbp), %rax
- movq %rax, 0x38(%rsp)
- movdqa %xmm0, 0x40(%rsp)
- movdqa %xmm1, 0x50(%rsp)
- movdqa %xmm2, 0x60(%rsp)
- movdqa %xmm3, 0x70(%rsp)
- movdqa %xmm4, 0x80(%rsp)
- movdqa %xmm5, 0x90(%rsp)
- movdqa %xmm6, 0xa0(%rsp)
- movdqa %xmm7, 0xb0(%rsp)
-
- /* For MakeFunc functions that call recover. */
- movq 8(%rbp), %rdi
-#ifdef __PIC__
- call __go_makefunc_can_recover@PLT
-#else
- call __go_makefunc_can_recover
-#endif
-
- # Get function type.
-#ifdef __PIC__
- call __go_get_closure@PLT
-#else
- call __go_get_closure
-#endif
- movq %rax, %rsi
-
- movq %rsp, %rdi
-
-#ifdef __PIC__
- call reflect.MakeFuncStubGo@PLT
-#else
- call reflect.MakeFuncStubGo
-#endif
-
- /* MakeFunc functions can no longer call recover. */
-#ifdef __PIC__
- call __go_makefunc_returning@PLT
-#else
- call __go_makefunc_returning
-#endif
-
- # The structure will be updated with any return values. Load
- # all possible return registers before returning to the caller.
-
- movq 0x0(%rsp), %rax
- movq 0x18(%rsp), %rdx
- movq 0x8(%rsp), %rdi
- movq 0x10(%rsp), %rsi
- movdqa 0x40(%rsp), %xmm0
- movdqa 0x50(%rsp), %xmm1
-
- # long double values are returned on the floating point stack,
- # but we don't worry about that since Go doesn't have a long
- # double type.
-
- leave
-.LCFI2:
-
- ret
-.LFE1:
-
-#ifdef __ELF__
- .size reflect.makeFuncStub, . - reflect.makeFuncStub
-#endif
-
-#ifdef __ELF__
-#ifdef HAVE_AS_X86_64_UNWIND_SECTION_TYPE
- .section .eh_frame,"a",@unwind
-#else
- .section .eh_frame,"a",@progbits
-#endif
-.Lframe1:
- .long .LECIE1-.LSCIE1 /* Length of Common Information Entry */
-.LSCIE1:
- .long 0x0 /* CIE Identifier Tag */
- .byte 0x1 /* CIE Version */
- .ascii "zR\0" /* CIE Augmentation */
- .uleb128 1 /* CIE Code Alignment Factor */
- .sleb128 -8 /* CIE Data Alignment Factor */
- .byte 0x10 /* CIE RA Column */
- .uleb128 1 /* Augmentation size */
- .byte 0x1b /* FDE Encoding (pcrel sdata4) */
- .byte 0xc /* DW_CFA_def_cfa, %rsp offset 8 */
- .uleb128 7
- .uleb128 8
- .byte 0x80+16 /* DW_CFA_offset, %rip offset 1*-8 */
- .uleb128 1
- .align 8
-.LECIE1:
-.LSFDE1:
- .long .LEFDE1-.LASFDE1 /* FDE Length */
-.LASFDE1:
- .long .LASFDE1-.Lframe1 /* FDE CIE offset */
-#if HAVE_AS_X86_PCREL
- .long .LFB1-. /* FDE initial location */
-#else
- .long .LFB1@rel
-#endif
- .long .LFE1-.LFB1 /* FDE address range */
- .uleb128 0x0 /* Augmentation size */
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .long .LCFI0-.LFB1
- .byte 0xe /* DW_CFA_def_cfa_offset */
- .uleb128 16
- .byte 0x86 /* DW_CFA_offset, column 0x6 */
- .uleb128 2
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .long .LCFI1-.LCFI0
- .byte 0xd /* DW_CFA_def_cfa_register */
- .uleb128 6
- .byte 0x2 /* DW_CFA_advance_loc1 */
- .byte .LCFI2-.LCFI1
- .byte 0xc /* DW_CFA_def_cfa */
- .uleb128 7
- .uleb128 8
- .align 8
-.LEFDE1:
-#endif /* __ELF__ */
-
-#if defined(__ELF__) && defined(__linux__)
- .section .note.GNU-stack,"",@progbits
- .section .note.GNU-split-stack,"",@progbits
- .section .note.GNU-no-split-stack,"",@progbits
-#endif
diff --git a/libgo/go/reflect/makefunc_ffi.go b/libgo/go/reflect/makefunc_ffi.go
new file mode 100644
index 0000000000..c821131bab
--- /dev/null
+++ b/libgo/go/reflect/makefunc_ffi.go
@@ -0,0 +1,63 @@
+// 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 reflect
+
+import (
+ "unsafe"
+)
+
+// The makeFuncFFI function, written in C, fills in an FFI closure.
+// It arranges for ffiCall to be invoked directly from FFI.
+func makeFuncFFI(ftyp *funcType, impl unsafe.Pointer)
+
+// FFICallbackGo implements the Go side of the libffi callback.
+// It is exported so that C code can call it.
+//
+// The call chain arriving here looks like
+// some_go_caller
+// ->some_ffi_internals
+// ->ffi_callback (in C)
+// ->FFICallbackGo
+//
+// The ffi_callback handles __go_makefunc_can_recover, and
+// then passes off the data as received from ffi here.
+
+func FFICallbackGo(results unsafe.Pointer, params unsafe.Pointer, impl *makeFuncImpl) {
+ ftyp := impl.typ
+ in := make([]Value, 0, len(ftyp.in))
+ ap := params
+ for _, rt := range ftyp.in {
+ p := unsafe_New(rt)
+ memmove(p, *(*unsafe.Pointer)(ap), rt.size)
+ v := Value{rt, p, flag(rt.Kind()) | flagIndir}
+ in = append(in, v)
+ ap = (unsafe.Pointer)(uintptr(ap) + ptrSize)
+ }
+
+ out := impl.call(in)
+
+ off := uintptr(0)
+ for i, typ := range ftyp.out {
+ v := out[i]
+ if v.typ != typ {
+ panic("reflect: function created by MakeFunc using " + funcName(impl.fn) +
+ " returned wrong type: have " +
+ out[i].typ.String() + " for " + typ.String())
+ }
+ if v.flag&flagRO != 0 {
+ panic("reflect: function created by MakeFunc using " + funcName(impl.fn) +
+ " returned value obtained from unexported field")
+ }
+
+ off = align(off, uintptr(typ.fieldAlign))
+ addr := unsafe.Pointer(uintptr(results) + off)
+ if v.flag&flagIndir == 0 && (v.kind() == Ptr || v.kind() == UnsafePointer) {
+ *(*unsafe.Pointer)(addr) = v.ptr
+ } else {
+ memmove(addr, v.ptr, typ.size)
+ }
+ off += typ.size
+ }
+}
diff --git a/libgo/go/reflect/makefunc_ffi_c.c b/libgo/go/reflect/makefunc_ffi_c.c
new file mode 100644
index 0000000000..06a41ef2ec
--- /dev/null
+++ b/libgo/go/reflect/makefunc_ffi_c.c
@@ -0,0 +1,93 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "go-type.h"
+#include "go-panic.h"
+
+#ifdef USE_LIBFFI
+
+#include "go-ffi.h"
+
+#if FFI_GO_CLOSURES
+#define USE_LIBFFI_CLOSURES
+#endif
+
+#endif /* defined(USE_LIBFFI) */
+
+/* Declare C functions with the names used to call from Go. */
+
+void makeFuncFFI(const struct __go_func_type *ftyp, void *impl)
+ __asm__ (GOSYM_PREFIX "reflect.makeFuncFFI");
+
+#ifdef USE_LIBFFI_CLOSURES
+
+/* The function that we pass to ffi_prep_closure_loc. This calls the Go
+ function ffiCall with the pointer to the arguments, the results area,
+ and the closure structure. */
+
+void FFICallbackGo(void *result, void **args, ffi_go_closure *closure)
+ __asm__ (GOSYM_PREFIX "reflect.FFICallbackGo");
+
+static void ffi_callback (ffi_cif *, void *, void **, void *)
+ __asm__ ("reflect.ffi_callback");
+
+static void
+ffi_callback (ffi_cif* cif __attribute__ ((unused)), void *results,
+ void **args, void *closure)
+{
+ Location locs[8];
+ int n;
+ int i;
+
+ /* This function is called from some series of FFI closure functions
+ called by a Go function. We want to see whether the caller of
+ the closure functions can recover. Look up the stack and skip
+ the FFI functions. */
+ n = runtime_callers (1, &locs[0], sizeof locs / sizeof locs[0], true);
+ for (i = 0; i < n; i++)
+ {
+ const byte *name;
+
+ if (locs[i].function.len == 0)
+ continue;
+ if (locs[i].function.len < 4)
+ break;
+ name = locs[i].function.str;
+ if (name[0] != 'f' || name[1] != 'f' || name[2] != 'i' || name[3] != '_')
+ break;
+ }
+ if (i < n)
+ __go_makefunc_ffi_can_recover (locs + i, n - i);
+
+ FFICallbackGo(results, args, closure);
+
+ if (i < n)
+ __go_makefunc_returning ();
+}
+
+/* Allocate an FFI closure and arrange to call ffi_callback. */
+
+void
+makeFuncFFI(const struct __go_func_type *ftyp, void *impl)
+{
+ ffi_cif *cif;
+
+ cif = (ffi_cif *) __go_alloc (sizeof (ffi_cif));
+ __go_func_to_cif (ftyp, 0, 0, cif);
+
+ ffi_prep_go_closure(impl, cif, ffi_callback);
+}
+
+#else /* !defined(USE_LIBFFI_CLOSURES) */
+
+void
+makeFuncFFI(const struct __go_func_type *ftyp __attribute__ ((unused)),
+ void *impl __attribute__ ((unused)))
+{
+ runtime_panicstring ("libgo built without FFI does not support "
+ "reflect.MakeFunc");
+}
+
+#endif
diff --git a/libgo/go/reflect/makefuncgo_386.go b/libgo/go/reflect/makefuncgo_386.go
deleted file mode 100644
index 96ca430d09..0000000000
--- a/libgo/go/reflect/makefuncgo_386.go
+++ /dev/null
@@ -1,143 +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.
-
-// MakeFunc 386 implementation.
-
-package reflect
-
-import "unsafe"
-
-// The assembler stub will pass a pointer to this structure. We
-// assume that no parameters are passed in registers--that is, we do
-// not support the -mregparm option. On return we will set the
-// registers that might hold result values.
-type i386Regs struct {
- esp uint32
- eax uint32 // Value to return in %eax.
- st0 float64 // Value to return in %st(0).
- sr bool // Set to true if hidden struct pointer.
- sf bool // Set to true if returning float
-}
-
-// MakeFuncStubGo implements the 386 calling convention for MakeFunc.
-// This should not be called. It is exported so that assembly code
-// can call it.
-
-func MakeFuncStubGo(regs *i386Regs, c *makeFuncImpl) {
- ftyp := c.typ
-
- // See if the result requires a struct. If it does, the first
- // parameter is a pointer to the struct.
- retStruct := false
- retEmpty := false
- switch len(ftyp.out) {
- case 0:
- retEmpty = true
- case 1:
- if ftyp.out[0].size == 0 {
- retEmpty = true
- } else {
- switch ftyp.out[0].Kind() {
- case Complex64, Complex128, Array, Interface, Slice, String, Struct:
- retStruct = true
- }
- }
- default:
- size := uintptr(0)
- for _, typ := range ftyp.out {
- size += typ.size
- }
- if size == 0 {
- retEmpty = true
- } else {
- retStruct = true
- }
- }
-
- in := make([]Value, 0, len(ftyp.in))
- ap := uintptr(regs.esp)
-
- regs.sr = false
- regs.sf = false
- var retPtr unsafe.Pointer
- if retStruct {
- retPtr = *(*unsafe.Pointer)(unsafe.Pointer(ap))
- ap += ptrSize
- regs.sr = true
- }
-
- for _, rt := range ftyp.in {
- ap = align(ap, ptrSize)
-
- // We have to copy the argument onto the heap in case
- // the function hangs on the reflect.Value we pass it.
- p := unsafe_New(rt)
- memmove(p, unsafe.Pointer(ap), rt.size)
-
- v := Value{rt, p, flag(rt.Kind()<<flagKindShift) | flagIndir}
- in = append(in, v)
- ap += rt.size
- }
-
- // Call the real function.
-
- out := c.call(in)
-
- if len(out) != len(ftyp.out) {
- panic("reflect: wrong return count from function created by MakeFunc")
- }
-
- for i, typ := range ftyp.out {
- v := out[i]
- if v.typ != typ {
- panic("reflect: function created by MakeFunc using " + funcName(c.fn) +
- " returned wrong type: have " +
- out[i].typ.String() + " for " + typ.String())
- }
- if v.flag&flagRO != 0 {
- panic("reflect: function created by MakeFunc using " + funcName(c.fn) +
- " returned value obtained from unexported field")
- }
- }
-
- if retEmpty {
- return
- }
-
- if retStruct {
- off := uintptr(0)
- for i, typ := range ftyp.out {
- v := out[i]
- off = align(off, uintptr(typ.fieldAlign))
- addr := unsafe.Pointer(uintptr(retPtr) + off)
- if v.flag&flagIndir == 0 && (v.kind() == Ptr || v.kind() == UnsafePointer) {
- storeIword(addr, iword(v.val), typ.size)
- } else {
- memmove(addr, v.val, typ.size)
- }
- off += typ.size
- }
- regs.eax = uint32(uintptr(retPtr))
- return
- }
-
- if len(ftyp.out) != 1 {
- panic("inconsistency")
- }
-
- v := out[0]
- w := v.iword()
- switch v.Kind() {
- case Ptr, UnsafePointer:
- regs.eax = uint32(uintptr(w))
- case Float32:
- regs.st0 = float64(*(*float32)(unsafe.Pointer(w)))
- regs.sf = true
- case Float64:
- regs.st0 = *(*float64)(unsafe.Pointer(w))
- regs.sf = true
- default:
- regs.eax = uint32(uintptr(loadIword(unsafe.Pointer(w), v.typ.size)))
- }
-}
diff --git a/libgo/go/reflect/makefuncgo_amd64.go b/libgo/go/reflect/makefuncgo_amd64.go
deleted file mode 100644
index 42fe03a931..0000000000
--- a/libgo/go/reflect/makefuncgo_amd64.go
+++ /dev/null
@@ -1,493 +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.
-
-// MakeFunc amd64 implementation.
-
-package reflect
-
-import "unsafe"
-
-// The assembler stub will pass a pointer to this structure.
-// This will come in holding all the registers that might hold
-// function parameters. On return we will set the registers that
-// might hold result values.
-type amd64Regs struct {
- rax uint64
- rdi uint64
- rsi uint64
- rdx uint64
- rcx uint64
- r8 uint64
- r9 uint64
- rsp uint64
- xmm0 [2]uint64
- xmm1 [2]uint64
- xmm2 [2]uint64
- xmm3 [2]uint64
- xmm4 [2]uint64
- xmm5 [2]uint64
- xmm6 [2]uint64
- xmm7 [2]uint64
-}
-
-// Argument classifications. The amd64 ELF ABI uses several more, but
-// these are the only ones that arise for Go types.
-type amd64Class int
-
-const (
- amd64Integer amd64Class = iota
- amd64SSE
- amd64NoClass
- amd64Memory
-)
-
-// amd64Classify returns the one or two register classes needed to
-// pass the value of type. Go types never need more than two
-// registers. amd64Memory means the value is stored in memory.
-// amd64NoClass means the register is not used.
-func amd64Classify(typ *rtype) (amd64Class, amd64Class) {
- switch typ.Kind() {
- default:
- panic("internal error--unknown kind in amd64Classify")
-
- case Bool, Int, Int8, Int16, Int32, Int64,
- Uint, Uint8, Uint16, Uint32, Uint64,
- Uintptr, Chan, Func, Map, Ptr, UnsafePointer:
-
- return amd64Integer, amd64NoClass
-
- case Float32, Float64, Complex64:
- return amd64SSE, amd64NoClass
-
- case Complex128:
- return amd64SSE, amd64SSE
-
- case Array:
- if typ.size == 0 {
- return amd64NoClass, amd64NoClass
- } else if typ.size > 16 {
- return amd64Memory, amd64NoClass
- }
- atyp := (*arrayType)(unsafe.Pointer(typ))
- eclass1, eclass2 := amd64Classify(atyp.elem)
- if eclass1 == amd64Memory {
- return amd64Memory, amd64NoClass
- }
- if eclass2 == amd64NoClass && typ.size > 8 {
- eclass2 = eclass1
- }
- return eclass1, eclass2
-
- case Interface:
- return amd64Integer, amd64Integer
-
- case Slice:
- return amd64Memory, amd64NoClass
-
- case String:
- return amd64Integer, amd64Integer
-
- case Struct:
- if typ.size == 0 {
- return amd64NoClass, amd64NoClass
- } else if typ.size > 16 {
- return amd64Memory, amd64NoClass
- }
- var first, second amd64Class
- f := amd64NoClass
- onFirst := true
- styp := (*structType)(unsafe.Pointer(typ))
- for _, field := range styp.fields {
- if onFirst && field.offset >= 8 {
- first = f
- f = amd64NoClass
- onFirst = false
- }
- fclass1, fclass2 := amd64Classify(field.typ)
- f = amd64MergeClasses(f, fclass1)
- if fclass2 != amd64NoClass {
- if !onFirst {
- panic("amd64Classify inconsistent")
- }
- first = f
- f = fclass2
- onFirst = false
- }
- }
- if onFirst {
- first = f
- second = amd64NoClass
- } else {
- second = f
- }
- if first == amd64Memory || second == amd64Memory {
- return amd64Memory, amd64NoClass
- }
- return first, second
- }
-}
-
-// amd64MergeClasses merges two register classes as described in the
-// amd64 ELF ABI.
-func amd64MergeClasses(c1, c2 amd64Class) amd64Class {
- switch {
- case c1 == c2:
- return c1
- case c1 == amd64NoClass:
- return c2
- case c2 == amd64NoClass:
- return c1
- case c1 == amd64Memory || c2 == amd64Memory:
- return amd64Memory
- case c1 == amd64Integer || c2 == amd64Integer:
- return amd64Integer
- default:
- return amd64SSE
- }
-}
-
-// MakeFuncStubGo implements the amd64 calling convention for
-// MakeFunc. This should not be called. It is exported so that
-// assembly code can call it.
-
-func MakeFuncStubGo(regs *amd64Regs, c *makeFuncImpl) {
- ftyp := c.typ
-
- // See if the result requires a struct. If it does, the first
- // parameter is a pointer to the struct.
- var ret1, ret2 amd64Class
- switch len(ftyp.out) {
- case 0:
- ret1, ret2 = amd64NoClass, amd64NoClass
- case 1:
- ret1, ret2 = amd64Classify(ftyp.out[0])
- default:
- off := uintptr(0)
- f := amd64NoClass
- onFirst := true
- for _, rt := range ftyp.out {
- off = align(off, uintptr(rt.fieldAlign))
-
- if onFirst && off >= 8 {
- ret1 = f
- f = amd64NoClass
- onFirst = false
- }
-
- off += rt.size
- if off > 16 {
- break
- }
-
- fclass1, fclass2 := amd64Classify(rt)
- f = amd64MergeClasses(f, fclass1)
- if fclass2 != amd64NoClass {
- if !onFirst {
- panic("amd64Classify inconsistent")
- }
- ret1 = f
- f = fclass2
- onFirst = false
- }
- }
- if off > 16 {
- ret1, ret2 = amd64Memory, amd64NoClass
- } else {
- if onFirst {
- ret1, ret2 = f, amd64NoClass
- } else {
- ret2 = f
- }
- }
- if ret1 == amd64Memory || ret2 == amd64Memory {
- ret1, ret2 = amd64Memory, amd64NoClass
- }
- }
-
- in := make([]Value, 0, len(ftyp.in))
- intreg := 0
- ssereg := 0
- ap := uintptr(regs.rsp)
-
- maxIntregs := 6 // When we support Windows, this would be 4.
- maxSSEregs := 8
-
- if ret1 == amd64Memory {
- // We are returning a value in memory, which means
- // that the first argument is a hidden parameter
- // pointing to that return area.
- intreg++
- }
-
-argloop:
- for _, rt := range ftyp.in {
- c1, c2 := amd64Classify(rt)
-
- fl := flag(rt.Kind()) << flagKindShift
- if c2 == amd64NoClass {
-
- // Argument is passed in a single register or
- // in memory.
-
- switch c1 {
- case amd64NoClass:
- v := Value{rt, nil, fl | flagIndir}
- in = append(in, v)
- continue argloop
- case amd64Integer:
- if intreg < maxIntregs {
- reg := amd64IntregVal(regs, intreg)
- iw := unsafe.Pointer(reg)
- if k := rt.Kind(); k != Ptr && k != UnsafePointer {
- iw = unsafe.Pointer(&reg)
- fl |= flagIndir
- }
- v := Value{rt, iw, fl}
- in = append(in, v)
- intreg++
- continue argloop
- }
- case amd64SSE:
- if ssereg < maxSSEregs {
- reg := amd64SSEregVal(regs, ssereg)
- v := Value{rt, unsafe.Pointer(&reg), fl | flagIndir}
- in = append(in, v)
- ssereg++
- continue argloop
- }
- }
-
- in, ap = amd64Memarg(in, ap, rt)
- continue argloop
- }
-
- // Argument is passed in two registers.
-
- nintregs := 0
- nsseregs := 0
- switch c1 {
- case amd64Integer:
- nintregs++
- case amd64SSE:
- nsseregs++
- default:
- panic("inconsistent")
- }
- switch c2 {
- case amd64Integer:
- nintregs++
- case amd64SSE:
- nsseregs++
- default:
- panic("inconsistent")
- }
-
- // If the whole argument does not fit in registers, it
- // is passed in memory.
-
- if intreg+nintregs > maxIntregs || ssereg+nsseregs > maxSSEregs {
- in, ap = amd64Memarg(in, ap, rt)
- continue argloop
- }
-
- var word1, word2 uintptr
- switch c1 {
- case amd64Integer:
- word1 = amd64IntregVal(regs, intreg)
- intreg++
- case amd64SSE:
- word1 = amd64SSEregVal(regs, ssereg)
- ssereg++
- }
- switch c2 {
- case amd64Integer:
- word2 = amd64IntregVal(regs, intreg)
- intreg++
- case amd64SSE:
- word2 = amd64SSEregVal(regs, ssereg)
- ssereg++
- }
-
- p := unsafe_New(rt)
- *(*uintptr)(p) = word1
- *(*uintptr)(unsafe.Pointer(uintptr(p) + ptrSize)) = word2
- v := Value{rt, p, fl | flagIndir}
- in = append(in, v)
- }
-
- // All the real arguments have been found and turned into
- // Value's. Call the real function.
-
- out := c.call(in)
-
- if len(out) != len(ftyp.out) {
- panic("reflect: wrong return count from function created by MakeFunc")
- }
-
- for i, typ := range ftyp.out {
- v := out[i]
- if v.typ != typ {
- panic("reflect: function created by MakeFunc using " + funcName(c.fn) +
- " returned wrong type: have " +
- out[i].typ.String() + " for " + typ.String())
- }
- if v.flag&flagRO != 0 {
- panic("reflect: function created by MakeFunc using " + funcName(c.fn) +
- " returned value obtained from unexported field")
- }
- }
-
- if ret1 == amd64NoClass {
- return
- }
-
- if ret1 == amd64Memory {
- // The address of the memory area was passed as a
- // hidden parameter in %rdi.
- ptr := unsafe.Pointer(uintptr(regs.rdi))
- off := uintptr(0)
- for i, typ := range ftyp.out {
- v := out[i]
- off = align(off, uintptr(typ.fieldAlign))
- addr := unsafe.Pointer(uintptr(ptr) + off)
- if v.flag&flagIndir == 0 && (v.kind() == Ptr || v.kind() == UnsafePointer) {
- storeIword(addr, iword(v.val), typ.size)
- } else {
- memmove(addr, v.val, typ.size)
- }
- off += typ.size
- }
- return
- }
-
- if len(out) == 1 && ret2 == amd64NoClass {
- v := out[0]
- w := v.iword()
- if v.Kind() != Ptr && v.Kind() != UnsafePointer {
- w = loadIword(unsafe.Pointer(w), v.typ.size)
- }
- switch ret1 {
- case amd64Integer:
- regs.rax = uint64(uintptr(w))
- case amd64SSE:
- regs.xmm0[0] = uint64(uintptr(w))
- regs.xmm0[1] = 0
- default:
- panic("inconsistency")
- }
- return
- }
-
- var buf [2]unsafe.Pointer
- ptr := unsafe.Pointer(&buf[0])
- off := uintptr(0)
- for i, typ := range ftyp.out {
- v := out[i]
- off = align(off, uintptr(typ.fieldAlign))
- addr := unsafe.Pointer(uintptr(ptr) + off)
- if v.flag&flagIndir == 0 && (v.kind() == Ptr || v.kind() == UnsafePointer) {
- storeIword(addr, iword(v.val), typ.size)
- } else {
- memmove(addr, v.val, typ.size)
- }
- off += uintptr(typ.size)
- }
-
- switch ret1 {
- case amd64Integer:
- regs.rax = *(*uint64)(unsafe.Pointer(&buf[0]))
- case amd64SSE:
- regs.xmm0[0] = *(*uint64)(unsafe.Pointer(&buf[0]))
- regs.xmm0[1] = 0
- default:
- panic("inconsistency")
- }
-
- switch ret2 {
- case amd64Integer:
- reg := *(*uint64)(unsafe.Pointer(&buf[1]))
- if ret1 == amd64Integer {
- regs.rdx = reg
- } else {
- regs.rax = reg
- }
- case amd64SSE:
- reg := *(*uint64)(unsafe.Pointer(&buf[1]))
- if ret1 == amd64Integer {
- regs.xmm0[0] = reg
- regs.xmm0[1] = 0
- } else {
- regs.xmm1[0] = reg
- regs.xmm1[1] = 0
- }
- case amd64NoClass:
- default:
- panic("inconsistency")
- }
-}
-
-// The amd64Memarg function adds an argument passed in memory.
-func amd64Memarg(in []Value, ap uintptr, rt *rtype) ([]Value, uintptr) {
- ap = align(ap, ptrSize)
- ap = align(ap, uintptr(rt.align))
-
- // We have to copy the argument onto the heap in case the
- // function hangs onto the reflect.Value we pass it.
- p := unsafe_New(rt)
- memmove(p, unsafe.Pointer(ap), rt.size)
-
- v := Value{rt, p, flag(rt.Kind()<<flagKindShift) | flagIndir}
- in = append(in, v)
- ap += rt.size
- return in, ap
-}
-
-// The amd64IntregVal function returns the value of integer register i.
-func amd64IntregVal(regs *amd64Regs, i int) uintptr {
- var r uint64
- switch i {
- case 0:
- r = regs.rdi
- case 1:
- r = regs.rsi
- case 2:
- r = regs.rdx
- case 3:
- r = regs.rcx
- case 4:
- r = regs.r8
- case 5:
- r = regs.r9
- default:
- panic("amd64IntregVal: bad index")
- }
- return uintptr(r)
-}
-
-// The amd64SSEregVal function returns the value of SSE register i.
-// Note that although SSE registers can hold two uinptr's, for the
-// types we use in Go we only ever use the least significant one. The
-// most significant one would only be used for 128 bit types.
-func amd64SSEregVal(regs *amd64Regs, i int) uintptr {
- var r uint64
- switch i {
- case 0:
- r = regs.xmm0[0]
- case 1:
- r = regs.xmm1[0]
- case 2:
- r = regs.xmm2[0]
- case 3:
- r = regs.xmm3[0]
- case 4:
- r = regs.xmm4[0]
- case 5:
- r = regs.xmm5[0]
- case 6:
- r = regs.xmm6[0]
- case 7:
- r = regs.xmm7[0]
- }
- return uintptr(r)
-}
diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go
index a930d64607..5cbf7e577a 100644
--- a/libgo/go/reflect/type.go
+++ b/libgo/go/reflect/type.go
@@ -16,6 +16,7 @@
package reflect
import (
+ "runtime"
"strconv"
"sync"
"unsafe"
@@ -98,6 +99,9 @@ type Type interface {
// ConvertibleTo returns true if a value of the type is convertible to type u.
ConvertibleTo(u Type) bool
+ // Comparable returns true if values of this type are comparable.
+ Comparable() bool
+
// Methods applicable only to some types, depending on Kind.
// The methods allowed for each kind are:
//
@@ -244,19 +248,21 @@ const (
// with a unique tag like `reflect:"array"` or `reflect:"ptr"`
// so that code cannot convert from, say, *arrayType to *ptrType.
type rtype struct {
- kind uint8 // enumeration for C
- align int8 // alignment of variable with this type
- fieldAlign uint8 // alignment of struct field with this type
- _ uint8 // unused/padding
- size uintptr // size in bytes
- hash uint32 // hash of type; avoids computation in hash tables
+ kind uint8 // enumeration for C
+ align int8 // alignment of variable with this type
+ fieldAlign uint8 // alignment of struct field with this type
+ _ uint8 // unused/padding
+ size uintptr
+ hash uint32 // hash of type; avoids computation in hash tables
hashfn uintptr // hash function code
equalfn uintptr // equality function code
- string *string // string form; unnecessary but undeniably useful
- *uncommonType // (relatively) uncommon fields
- ptrToThis *rtype // type for pointer to this type, if used in binary or has methods
+ gc unsafe.Pointer // garbage collection data
+ string *string // string form; unnecessary but undeniably useful
+ *uncommonType // (relatively) uncommon fields
+ ptrToThis *rtype // type for pointer to this type, if used in binary or has methods
+ zero unsafe.Pointer // pointer to zero value
}
// Method on non-interface type
@@ -328,8 +334,6 @@ type mapType struct {
rtype `reflect:"map"`
key *rtype // map key type
elem *rtype // map element (value) type
- // bucket *rtype // internal bucket structure
- // hmap *rtype // internal map header
}
// ptrType represents a pointer type.
@@ -398,11 +402,11 @@ type Method struct {
Index int // index for Type.Method
}
-// High bit says whether type has
-// embedded pointers,to help garbage collector.
const (
- kindMask = 0x7f
- kindNoPointers = 0x80
+ kindDirectIface = 1 << 5
+ kindGCProg = 1 << 6 // Type.gc points to GC program
+ kindNoPointers = 1 << 7
+ kindMask = (1 << 5) - 1
)
func (k Kind) String() string {
@@ -498,6 +502,8 @@ func (t *rtype) FieldAlign() int { return int(t.fieldAlign) }
func (t *rtype) Kind() Kind { return Kind(t.kind & kindMask) }
+func (t *rtype) pointers() bool { return t.kind&kindNoPointers == 0 }
+
func (t *rtype) common() *rtype { return t }
func (t *uncommonType) Method(i int) (m Method) {
@@ -508,7 +514,7 @@ func (t *uncommonType) Method(i int) (m Method) {
if p.name != nil {
m.Name = *p.name
}
- fl := flag(Func) << flagKindShift
+ fl := flag(Func)
if p.pkgPath != nil {
m.PkgPath = *p.pkgPath
fl |= flagRO
@@ -1123,12 +1129,24 @@ func (t *rtype) ptrTo() *rtype {
p.uncommonType = nil
p.ptrToThis = nil
+ p.zero = unsafe.Pointer(&make([]byte, p.size)[0])
p.elem = t
+ if t.kind&kindNoPointers != 0 {
+ p.gc = unsafe.Pointer(&ptrDataGCProg)
+ } else {
+ p.gc = unsafe.Pointer(&ptrGC{
+ width: p.size,
+ op: _GC_PTR,
+ off: 0,
+ elemgc: t.gc,
+ end: _GC_END,
+ })
+ }
+
q := canonicalize(&p.rtype)
p = (*ptrType)(unsafe.Pointer(q.(*rtype)))
- ptrMap.m[t] = p
ptrMap.Unlock()
return &p.rtype
}
@@ -1167,6 +1185,34 @@ func (t *rtype) ConvertibleTo(u Type) bool {
return convertOp(uu, t) != nil
}
+func (t *rtype) Comparable() bool {
+ switch t.Kind() {
+ case Bool, Int, Int8, Int16, Int32, Int64,
+ Uint, Uint8, Uint16, Uint32, Uint64, Uintptr,
+ Float32, Float64, Complex64, Complex128,
+ Chan, Interface, Ptr, String, UnsafePointer:
+ return true
+
+ case Func, Map, Slice:
+ return false
+
+ case Array:
+ return (*arrayType)(unsafe.Pointer(t)).elem.Comparable()
+
+ case Struct:
+ tt := (*structType)(unsafe.Pointer(t))
+ for i := range tt.fields {
+ if !tt.fields[i].typ.Comparable() {
+ return false
+ }
+ }
+ return true
+
+ default:
+ panic("reflect: impossible")
+ }
+}
+
// implements returns true if the type V implements the interface type T.
func implements(T, V *rtype) bool {
if T.Kind() != Interface {
@@ -1401,11 +1447,6 @@ type chanGC struct {
end uintptr // _GC_END
}
-type badGC struct {
- width uintptr
- end uintptr
-}
-
// ChanOf returns the channel type with the given direction and element type.
// For example, if t represents int, ChanOf(RecvDir, t) represents <-chan int.
//
@@ -1464,9 +1505,18 @@ func ChanOf(dir ChanDir, t Type) Type {
ch.elem = typ
ch.uncommonType = nil
ch.ptrToThis = nil
+ ch.zero = unsafe.Pointer(&make([]byte, ch.size)[0])
+
+ ch.gc = unsafe.Pointer(&chanGC{
+ width: ch.size,
+ op: _GC_CHAN_PTR,
+ off: 0,
+ typ: &ch.rtype,
+ end: _GC_END,
+ })
// INCORRECT. Uncomment to check that TestChanOfGC fails when ch.gc is wrong.
- //ch.gc = unsafe.Pointer(&badGC{width: ch.size, end: _GC_END})
+ // ch.gc = unsafe.Pointer(&badGC{width: ch.size, end: _GC_END})
return cachePut(ckey, &ch.rtype)
}
@@ -1509,10 +1559,19 @@ func MapOf(key, elem Type) Type {
mt.key = ktyp
mt.elem = etyp
- // mt.bucket = bucketOf(ktyp, etyp)
- // mt.hmap = hMapOf(mt.bucket)
mt.uncommonType = nil
mt.ptrToThis = nil
+ mt.zero = unsafe.Pointer(&make([]byte, mt.size)[0])
+ // mt.gc = unsafe.Pointer(&ptrGC{
+ // width: unsafe.Sizeof(uintptr(0)),
+ // op: _GC_PTR,
+ // off: 0,
+ // elemgc: nil,
+ // end: _GC_END,
+ // })
+
+ // TODO(cmang): Generate GC data for Map elements.
+ mt.gc = unsafe.Pointer(&ptrDataGCProg)
// INCORRECT. Uncomment to check that TestMapOfGC and TestMapOfGCValues
// fail when mt.gc is wrong.
@@ -1521,53 +1580,156 @@ func MapOf(key, elem Type) Type {
return cachePut(ckey, &mt.rtype)
}
-// Make sure these routines stay in sync with ../../pkg/runtime/hashmap.c!
+// 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
+}
+
+func (gc *gcProg) append(v byte) {
+ gc.align(unsafe.Sizeof(uintptr(0)))
+ gc.appendWord(v)
+}
+
+// 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
+ }
+ switch t.Kind() {
+ default:
+ panic("reflect: non-pointer type marked as having pointers")
+ case Ptr, UnsafePointer, Chan, Func, Map:
+ gc.appendWord(bitsPointer)
+ case Slice:
+ gc.appendWord(bitsPointer)
+ gc.appendWord(bitsScalar)
+ gc.appendWord(bitsScalar)
+ case String:
+ gc.appendWord(bitsPointer)
+ gc.appendWord(bitsScalar)
+ case Array:
+ c := t.Len()
+ e := t.Elem().common()
+ for i := 0; i < c; i++ {
+ gc.appendProg(e)
+ }
+ case Interface:
+ gc.appendWord(bitsMultiWord)
+ if t.NumMethod() == 0 {
+ gc.appendWord(bitsEface)
+ } else {
+ gc.appendWord(bitsIface)
+ }
+ case Struct:
+ c := t.NumField()
+ for i := 0; i < c; i++ {
+ gc.appendProg(t.Field(i).Type.common())
+ }
+ gc.align(uintptr(t.align))
+ }
+}
+
+func (gc *gcProg) appendWord(v byte) {
+ ptrsize := unsafe.Sizeof(uintptr(0))
+ if gc.size%ptrsize != 0 {
+ panic("reflect: unaligned GC program")
+ }
+ nptr := gc.size / ptrsize
+ for uintptr(len(gc.gc)) < nptr/2+1 {
+ gc.gc = append(gc.gc, 0x44) // BitsScalar
+ }
+ 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
+ }
+}
+
+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))
+ }
+ }
+ 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 = 8
+ maxKeySize = 128
+ maxValSize = 128
)
func bucketOf(ktyp, etyp *rtype) *rtype {
- if ktyp.size > _MAXKEYSIZE {
+ if ktyp.size > maxKeySize {
ktyp = PtrTo(ktyp).(*rtype)
}
- if etyp.size > _MAXVALSIZE {
+ if etyp.size > maxValSize {
etyp = PtrTo(etyp).(*rtype)
}
ptrsize := unsafe.Sizeof(uintptr(0))
- gc := make([]uintptr, 1) // first entry is size, filled in at the end
- offset := _BUCKETSIZE * unsafe.Sizeof(uint8(0)) // topbits
- gc = append(gc, _GC_PTR, offset, 0 /*self pointer set below*/) // overflow
- offset += ptrsize
-
+ var gc gcProg
+ // topbits
+ for i := 0; i < int(bucketSize*unsafe.Sizeof(uint8(0))/ptrsize); i++ {
+ gc.append(bitsScalar)
+ }
// keys
- if ktyp.kind&kindNoPointers == 0 {
- gc = append(gc, _GC_ARRAY_START, offset, _BUCKETSIZE, ktyp.size)
- gc = appendGCProgram(gc, ktyp)
- gc = append(gc, _GC_ARRAY_NEXT)
+ for i := 0; i < bucketSize; i++ {
+ gc.appendProg(ktyp)
}
- offset += _BUCKETSIZE * ktyp.size
-
// values
- if etyp.kind&kindNoPointers == 0 {
- gc = append(gc, _GC_ARRAY_START, offset, _BUCKETSIZE, etyp.size)
- gc = appendGCProgram(gc, etyp)
- gc = append(gc, _GC_ARRAY_NEXT)
+ for i := 0; i < bucketSize; i++ {
+ gc.appendProg(etyp)
+ }
+ // overflow
+ gc.append(bitsPointer)
+ if runtime.GOARCH == "amd64p32" {
+ gc.append(bitsScalar)
}
- offset += _BUCKETSIZE * etyp.size
-
- gc = append(gc, _GC_END)
- gc[0] = offset
- gc[3] = uintptr(unsafe.Pointer(&gc[0])) // set self pointer
b := new(rtype)
- b.size = offset
- // b.gc = unsafe.Pointer(&gc[0])
+ b.size = gc.size
+ // b.gc[0], _ = gc.finalize()
+ b.kind |= kindGCProg
s := "bucket(" + *ktyp.string + "," + *etyp.string + ")"
b.string = &s
return b
@@ -1575,8 +1737,7 @@ func bucketOf(ktyp, etyp *rtype) *rtype {
// Take the GC program for "t" and append it to the GC program "gc".
func appendGCProgram(gc []uintptr, t *rtype) []uintptr {
- // p := t.gc
- var p unsafe.Pointer
+ p := t.gc
p = unsafe.Pointer(uintptr(p) + unsafe.Sizeof(uintptr(0))) // skip size
loop:
for {
@@ -1687,9 +1848,22 @@ func SliceOf(t Type) Type {
slice.elem = typ
slice.uncommonType = nil
slice.ptrToThis = nil
+ slice.zero = unsafe.Pointer(&make([]byte, slice.size)[0])
+
+ if typ.size == 0 {
+ slice.gc = unsafe.Pointer(&sliceEmptyGCProg)
+ } else {
+ slice.gc = unsafe.Pointer(&sliceGC{
+ width: slice.size,
+ op: _GC_SLICE,
+ off: 0,
+ elemgc: typ.gc,
+ end: _GC_END,
+ })
+ }
// INCORRECT. Uncomment to check that TestSliceOfOfGC fails when slice.gc is wrong.
- //slice.gc = unsafe.Pointer(&badGC{width: slice.size, end: _GC_END})
+ // slice.gc = unsafe.Pointer(&badGC{width: slice.size, end: _GC_END})
return cachePut(ckey, &slice.rtype)
}
@@ -1702,6 +1876,8 @@ func SliceOf(t Type) Type {
//
// 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 {
typ := elem.(*rtype)
slice := SliceOf(elem)
@@ -1720,6 +1896,7 @@ 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.
@@ -1740,8 +1917,10 @@ func arrayOf(count int, elem Type) Type {
array.fieldAlign = typ.fieldAlign
// TODO: array.alg
// TODO: array.gc
+ // TODO:
array.uncommonType = nil
array.ptrToThis = nil
+ array.zero = unsafe.Pointer(&make([]byte, array.size)[0])
array.len = uintptr(count)
array.slice = slice.(*rtype)
@@ -1790,3 +1969,68 @@ func toType(p *rtype) Type {
}
return canonicalize(p)
}
+
+// ifaceIndir reports whether t is stored indirectly in an interface value.
+func ifaceIndir(t *rtype) bool {
+ return t.kind&kindDirectIface == 0
+}
+
+// Layout matches runtime.BitVector (well enough).
+type bitVector struct {
+ n uint32 // number of bits
+ data []byte
+}
+
+// append a bit pair to the bitmap.
+func (bv *bitVector) append2(bits uint8) {
+ // assume bv.n is a multiple of 2, since append2 is the only operation.
+ if bv.n%8 == 0 {
+ bv.data = append(bv.data, 0)
+ }
+ bv.data[bv.n/8] |= bits << (bv.n % 8)
+ bv.n += 2
+}
+
+func addTypeBits(bv *bitVector, offset *uintptr, t *rtype) {
+ *offset = align(*offset, uintptr(t.align))
+ if t.kind&kindNoPointers != 0 {
+ *offset += t.size
+ return
+ }
+
+ switch Kind(t.kind & kindMask) {
+ case Chan, Func, Map, Ptr, Slice, String, UnsafePointer:
+ // 1 pointer at start of representation
+ for bv.n < 2*uint32(*offset/uintptr(ptrSize)) {
+ bv.append2(bitsScalar)
+ }
+ bv.append2(bitsPointer)
+
+ case Interface:
+ // 2 pointers
+ for bv.n < 2*uint32(*offset/uintptr(ptrSize)) {
+ bv.append2(bitsScalar)
+ }
+ bv.append2(bitsPointer)
+ bv.append2(bitsPointer)
+
+ case Array:
+ // repeat inner type
+ tt := (*arrayType)(unsafe.Pointer(t))
+ for i := 0; i < int(tt.len); i++ {
+ addTypeBits(bv, offset, tt.elem)
+ }
+
+ case Struct:
+ // apply fields
+ tt := (*structType)(unsafe.Pointer(t))
+ start := *offset
+ for i := range tt.fields {
+ f := &tt.fields[i]
+ off := start + f.offset
+ addTypeBits(bv, &off, f.typ)
+ }
+ }
+
+ *offset += t.size
+}
diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go
index fc7dfae23d..7cc4f7f8bf 100644
--- a/libgo/go/reflect/value.go
+++ b/libgo/go/reflect/value.go
@@ -7,40 +7,12 @@ package reflect
import (
"math"
"runtime"
- "strconv"
"unsafe"
)
-const bigEndian = false // can be smarter if we find a big-endian machine
const ptrSize = unsafe.Sizeof((*byte)(nil))
const cannotSet = "cannot set value obtained from unexported struct field"
-// TODO: This will have to go away when
-// the new gc goes in.
-func memmove(adst, asrc unsafe.Pointer, n uintptr) {
- dst := uintptr(adst)
- src := uintptr(asrc)
- switch {
- case src < dst && src+n > dst:
- // byte copy backward
- // careful: i is unsigned
- for i := n; i > 0; {
- i--
- *(*byte)(unsafe.Pointer(dst + i)) = *(*byte)(unsafe.Pointer(src + i))
- }
- case (n|src|dst)&(ptrSize-1) != 0:
- // byte copy forward
- for i := uintptr(0); i < n; i++ {
- *(*byte)(unsafe.Pointer(dst + i)) = *(*byte)(unsafe.Pointer(src + i))
- }
- default:
- // word copy forward
- for i := uintptr(0); i < n; i += ptrSize {
- *(*uintptr)(unsafe.Pointer(dst + i)) = *(*uintptr)(unsafe.Pointer(src + i))
- }
- }
-}
-
// Value is the reflection interface to a Go value.
//
// Not all methods apply to all kinds of values. Restrictions,
@@ -62,14 +34,9 @@ type Value struct {
// typ holds the type of the value represented by a Value.
typ *rtype
- // val holds the 1-word representation of the value.
- // If flag's flagIndir bit is set, then val is a pointer to the data.
- // Otherwise val is a word holding the actual data.
- // When the data is smaller than a word, it begins at
- // the first byte (in the memory address sense) of val.
- // We use unsafe.Pointer so that the garbage collector
- // knows that val could be a pointer.
- val unsafe.Pointer
+ // Pointer-valued data or, if flagIndir is set, pointer to data.
+ // Valid when either flagIndir is set or typ.pointers() is true.
+ ptr unsafe.Pointer
// flag holds metadata about the value.
// The lowest bits are flag bits:
@@ -81,7 +48,7 @@ type Value struct {
// This repeats typ.Kind() except for method values.
// The remaining 23+ bits give a method number for method values.
// If flag.kind() != Func, code can assume that flagMethod is unset.
- // If typ.size > ptrSize, code can assume that flagIndir is set.
+ // If ifaceIndir(typ), code can assume that flagIndir is set.
flag
// A method value represents a curried method invocation
@@ -94,19 +61,82 @@ type Value struct {
type flag uintptr
const (
- flagRO flag = 1 << iota
- flagIndir
- flagAddr
- flagMethod
- flagMethodFn // gccgo: first fn parameter is always pointer
- flagKindShift = iota
flagKindWidth = 5 // there are 27 kinds
flagKindMask flag = 1<<flagKindWidth - 1
- flagMethodShift = flagKindShift + flagKindWidth
+ flagRO flag = 1 << 5
+ flagIndir flag = 1 << 6
+ flagAddr flag = 1 << 7
+ flagMethod flag = 1 << 8
+ flagMethodFn flag = 1 << 9 // gccgo: first fn parameter is always pointer
+ flagMethodShift = 10
)
func (f flag) kind() Kind {
- return Kind((f >> flagKindShift) & flagKindMask)
+ return Kind(f & flagKindMask)
+}
+
+// pointer returns the underlying pointer represented by v.
+// v.Kind() must be Ptr, Map, Chan, Func, or UnsafePointer
+func (v Value) pointer() unsafe.Pointer {
+ if v.typ.size != ptrSize || !v.typ.pointers() {
+ panic("can't call pointer on a non-pointer Value")
+ }
+ if v.flag&flagIndir != 0 {
+ return *(*unsafe.Pointer)(v.ptr)
+ }
+ return v.ptr
+}
+
+// packEface converts v to the empty interface.
+func packEface(v Value) interface{} {
+ t := v.typ
+ var i interface{}
+ e := (*emptyInterface)(unsafe.Pointer(&i))
+ // First, fill in the data portion of the interface.
+ switch {
+ case ifaceIndir(t):
+ if v.flag&flagIndir == 0 {
+ panic("bad indir")
+ }
+ // Value is indirect, and so is the interface we're making.
+ ptr := v.ptr
+ if v.flag&flagAddr != 0 {
+ // 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)
+ ptr = c
+ }
+ e.word = ptr
+ case v.flag&flagIndir != 0:
+ // Value is indirect, but interface is direct. We need
+ // to load the data at v.ptr into the interface data word.
+ e.word = *(*unsafe.Pointer)(v.ptr)
+ default:
+ // Value is direct, and so is the interface.
+ e.word = v.ptr
+ }
+ // Now, fill in the type portion. We're very careful here not
+ // to have any operation between the e.word and e.typ assignments
+ // that would let the garbage collector observe the partially-built
+ // interface value.
+ e.typ = t
+ return i
+}
+
+// unpackEface converts the empty interface i to a Value.
+func unpackEface(i interface{}) Value {
+ e := (*emptyInterface)(unsafe.Pointer(&i))
+ // NOTE: don't read e.word until we know whether it is really a pointer or not.
+ t := e.typ
+ if t == nil {
+ return Value{}
+ }
+ f := flag(t.Kind())
+ if ifaceIndir(t) {
+ f |= flagIndir
+ }
+ return Value{t, unsafe.Pointer(e.word), f}
}
// A ValueError occurs when a Value method is invoked on
@@ -135,85 +165,10 @@ func methodName() string {
return f.Name()
}
-// An iword is the word that would be stored in an
-// interface to represent a given value v. Specifically, if v is
-// bigger than a pointer, its word is a pointer to v's data.
-// Otherwise, its word holds the data stored
-// in its leading bytes (so is not a pointer).
-// Because the value sometimes holds a pointer, we use
-// unsafe.Pointer to represent it, so that if iword appears
-// in a struct, the garbage collector knows that might be
-// a pointer.
-type iword unsafe.Pointer
-
-func (v Value) iword() iword {
- if v.flag&flagIndir != 0 && (v.kind() == Ptr || v.kind() == UnsafePointer) {
- // Have indirect but want direct word.
- return loadIword(v.val, v.typ.size)
- }
- return iword(v.val)
-}
-
-// loadIword loads n bytes at p from memory into an iword.
-func loadIword(p unsafe.Pointer, n uintptr) iword {
- // Run the copy ourselves instead of calling memmove
- // to avoid moving w to the heap.
- var w iword
- switch n {
- default:
- panic("reflect: internal error: loadIword of " + strconv.Itoa(int(n)) + "-byte value")
- case 0:
- case 1:
- *(*uint8)(unsafe.Pointer(&w)) = *(*uint8)(p)
- case 2:
- *(*uint16)(unsafe.Pointer(&w)) = *(*uint16)(p)
- case 3:
- *(*[3]byte)(unsafe.Pointer(&w)) = *(*[3]byte)(p)
- case 4:
- *(*uint32)(unsafe.Pointer(&w)) = *(*uint32)(p)
- case 5:
- *(*[5]byte)(unsafe.Pointer(&w)) = *(*[5]byte)(p)
- case 6:
- *(*[6]byte)(unsafe.Pointer(&w)) = *(*[6]byte)(p)
- case 7:
- *(*[7]byte)(unsafe.Pointer(&w)) = *(*[7]byte)(p)
- case 8:
- *(*uint64)(unsafe.Pointer(&w)) = *(*uint64)(p)
- }
- return w
-}
-
-// storeIword stores n bytes from w into p.
-func storeIword(p unsafe.Pointer, w iword, n uintptr) {
- // Run the copy ourselves instead of calling memmove
- // to avoid moving w to the heap.
- switch n {
- default:
- panic("reflect: internal error: storeIword of " + strconv.Itoa(int(n)) + "-byte value")
- case 0:
- case 1:
- *(*uint8)(p) = *(*uint8)(unsafe.Pointer(&w))
- case 2:
- *(*uint16)(p) = *(*uint16)(unsafe.Pointer(&w))
- case 3:
- *(*[3]byte)(p) = *(*[3]byte)(unsafe.Pointer(&w))
- case 4:
- *(*uint32)(p) = *(*uint32)(unsafe.Pointer(&w))
- case 5:
- *(*[5]byte)(p) = *(*[5]byte)(unsafe.Pointer(&w))
- case 6:
- *(*[6]byte)(p) = *(*[6]byte)(unsafe.Pointer(&w))
- case 7:
- *(*[7]byte)(p) = *(*[7]byte)(unsafe.Pointer(&w))
- case 8:
- *(*uint64)(p) = *(*uint64)(unsafe.Pointer(&w))
- }
-}
-
// emptyInterface is the header for an interface{} value.
type emptyInterface struct {
typ *rtype
- word iword
+ word unsafe.Pointer
}
// nonEmptyInterface is the header for a interface value with methods.
@@ -223,7 +178,7 @@ type nonEmptyInterface struct {
typ *rtype // dynamic concrete type
fun [100000]unsafe.Pointer // method table
}
- word iword
+ word unsafe.Pointer
}
// mustBe panics if f's kind is not expected.
@@ -233,9 +188,8 @@ type nonEmptyInterface struct {
// v.flag.mustBe(Bool), which will only bother to copy the
// single important word for the receiver.
func (f flag) mustBe(expected Kind) {
- k := f.kind()
- if k != expected {
- panic(&ValueError{methodName(), k})
+ if f.kind() != expected {
+ panic(&ValueError{methodName(), f.kind()})
}
}
@@ -275,17 +229,14 @@ func (v Value) Addr() Value {
if v.flag&flagAddr == 0 {
panic("reflect.Value.Addr of unaddressable value")
}
- return Value{v.typ.ptrTo(), v.val, (v.flag & flagRO) | flag(Ptr)<<flagKindShift}
+ return Value{v.typ.ptrTo(), v.ptr, (v.flag & flagRO) | flag(Ptr)}
}
// Bool returns v's underlying value.
// It panics if v's kind is not Bool.
func (v Value) Bool() bool {
v.mustBe(Bool)
- if v.flag&flagIndir != 0 {
- return *(*bool)(v.val)
- }
- return *(*bool)(unsafe.Pointer(&v.val))
+ return *(*bool)(v.ptr)
}
// Bytes returns v's underlying value.
@@ -296,7 +247,7 @@ func (v Value) Bytes() []byte {
panic("reflect.Value.Bytes of non-byte slice")
}
// Slice is always bigger than a word; assume flagIndir.
- return *(*[]byte)(v.val)
+ return *(*[]byte)(v.ptr)
}
// runes returns v's underlying value.
@@ -307,7 +258,7 @@ func (v Value) runes() []rune {
panic("reflect.Value.Bytes of non-rune slice")
}
// Slice is always bigger than a word; assume flagIndir.
- return *(*[]rune)(v.val)
+ return *(*[]rune)(v.ptr)
}
// CanAddr returns true if the value's address can be obtained with Addr.
@@ -355,19 +306,22 @@ func (v Value) CallSlice(in []Value) []Value {
return v.call("CallSlice", in)
}
+var callGC bool // for testing; see TestCallMethodJump
+
func (v Value) call(op string, in []Value) []Value {
// Get function pointer, type.
t := v.typ
var (
fn unsafe.Pointer
- rcvr iword
+ rcvr Value
)
if v.flag&flagMethod != 0 {
- t, fn, rcvr = methodReceiver(op, v, int(v.flag)>>flagMethodShift)
+ rcvr = v
+ _, t, fn = methodReceiver(op, v, int(v.flag)>>flagMethodShift)
} else if v.flag&flagIndir != 0 {
- fn = *(*unsafe.Pointer)(v.val)
+ fn = *(*unsafe.Pointer)(v.ptr)
} else {
- fn = v.val
+ fn = v.ptr
}
if fn == nil {
@@ -439,8 +393,14 @@ func (v Value) call(op string, in []Value) []Value {
off := 0
if v.flag&flagMethod != 0 {
// Hard-wired first argument.
- p := new(iword)
- *p = rcvr
+ p := new(unsafe.Pointer)
+ if rcvr.typ.Kind() == Interface {
+ *p = unsafe.Pointer((*nonEmptyInterface)(v.ptr).word)
+ } else if rcvr.typ.Kind() == Ptr || rcvr.typ.Kind() == UnsafePointer {
+ *p = rcvr.pointer()
+ } else {
+ *p = rcvr.ptr
+ }
params[0] = unsafe.Pointer(p)
off = 1
}
@@ -450,10 +410,10 @@ func (v Value) call(op string, in []Value) []Value {
pv = pv.assignTo("reflect.Value.Call", targ, nil)
if pv.flag&flagIndir == 0 {
p := new(unsafe.Pointer)
- *p = pv.val
+ *p = pv.ptr
params[off] = unsafe.Pointer(p)
} else {
- params[off] = pv.val
+ params[off] = pv.ptr
}
if i == 0 && firstPointer {
p := new(unsafe.Pointer)
@@ -482,6 +442,11 @@ func (v Value) call(op string, in []Value) []Value {
call(t, fn, v.flag&flagMethod != 0, firstPointer, pp, pr)
+ // For testing; see TestCallMethodJump.
+ if callGC {
+ runtime.GC()
+ }
+
return ret
}
@@ -489,27 +454,31 @@ func (v Value) call(op string, in []Value) []Value {
// described by v. The Value v may or may not have the
// flagMethod bit set, so the kind cached in v.flag should
// not be used.
-func methodReceiver(op string, v Value, methodIndex int) (t *rtype, fn unsafe.Pointer, rcvr iword) {
+// The return value rcvrtype gives the method's actual receiver type.
+// The return value t gives the method type signature (without the receiver).
+// The return value fn is a pointer to the method code.
+func methodReceiver(op string, v Value, methodIndex int) (rcvrtype, t *rtype, fn unsafe.Pointer) {
i := methodIndex
if v.typ.Kind() == Interface {
tt := (*interfaceType)(unsafe.Pointer(v.typ))
- if i < 0 || i >= len(tt.methods) {
+ if uint(i) >= uint(len(tt.methods)) {
panic("reflect: internal error: invalid method index")
}
m := &tt.methods[i]
if m.pkgPath != nil {
panic("reflect: " + op + " of unexported method")
}
- t = m.typ
- iface := (*nonEmptyInterface)(v.val)
+ iface := (*nonEmptyInterface)(v.ptr)
if iface.itab == nil {
panic("reflect: " + op + " of method on nil interface value")
}
+ rcvrtype = iface.itab.typ
fn = unsafe.Pointer(&iface.itab.fun[i])
- rcvr = iface.word
+ t = m.typ
} else {
+ rcvrtype = v.typ
ut := v.typ.uncommon()
- if ut == nil || i < 0 || i >= len(ut.methods) {
+ if ut == nil || uint(i) >= uint(len(ut.methods)) {
panic("reflect: internal error: invalid method index")
}
m := &ut.methods[i]
@@ -518,17 +487,27 @@ func methodReceiver(op string, v Value, methodIndex int) (t *rtype, fn unsafe.Po
}
fn = unsafe.Pointer(&m.tfn)
t = m.mtyp
- // Can't call iword here, because it checks v.kind,
- // and that is always Func.
- if v.flag&flagIndir != 0 && (v.typ.Kind() == Ptr || v.typ.Kind() == UnsafePointer) {
- rcvr = loadIword(v.val, v.typ.size)
- } else {
- rcvr = iword(v.val)
- }
}
return
}
+// v is a method receiver. Store at p the word which is used to
+// encode that receiver at the start of the argument list.
+// Reflect uses the "interface" calling convention for
+// methods, which always uses one word to record the receiver.
+func storeRcvr(v Value, p unsafe.Pointer) {
+ t := v.typ
+ if t.Kind() == Interface {
+ // the interface data word becomes the receiver word
+ iface := (*nonEmptyInterface)(v.ptr)
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(iface.word)
+ } else if v.flag&flagIndir != 0 && !ifaceIndir(t) {
+ *(*unsafe.Pointer)(p) = *(*unsafe.Pointer)(v.ptr)
+ } else {
+ *(*unsafe.Pointer)(p) = v.ptr
+ }
+}
+
// align returns the result of rounding x up to a multiple of n.
// n must be a power of two.
func align(x, n uintptr) uintptr {
@@ -553,12 +532,12 @@ func (v Value) Cap() int {
case Array:
return v.typ.Len()
case Chan:
- return int(chancap(*(*iword)(v.iword())))
+ return int(chancap(v.pointer()))
case Slice:
// Slice is always bigger than a word; assume flagIndir.
- return (*SliceHeader)(v.val).Cap
+ return (*sliceHeader)(v.ptr).Cap
}
- panic(&ValueError{"reflect.Value.Cap", k})
+ panic(&ValueError{"reflect.Value.Cap", v.kind()})
}
// Close closes the channel v.
@@ -566,7 +545,7 @@ func (v Value) Cap() int {
func (v Value) Close() {
v.mustBe(Chan)
v.mustBeExported()
- chanclose(*(*iword)(v.iword()))
+ chanclose(v.pointer())
}
// Complex returns v's underlying value, as a complex128.
@@ -575,15 +554,11 @@ func (v Value) Complex() complex128 {
k := v.kind()
switch k {
case Complex64:
- if v.flag&flagIndir != 0 {
- return complex128(*(*complex64)(v.val))
- }
- return complex128(*(*complex64)(unsafe.Pointer(&v.val)))
+ return complex128(*(*complex64)(v.ptr))
case Complex128:
- // complex128 is always bigger than a word; assume flagIndir.
- return *(*complex128)(v.val)
+ return *(*complex128)(v.ptr)
}
- panic(&ValueError{"reflect.Value.Complex", k})
+ panic(&ValueError{"reflect.Value.Complex", v.kind()})
}
// Elem returns the value that the interface v contains
@@ -594,94 +569,78 @@ func (v Value) Elem() Value {
k := v.kind()
switch k {
case Interface:
- var (
- typ *rtype
- val unsafe.Pointer
- )
+ var eface interface{}
if v.typ.NumMethod() == 0 {
- eface := (*emptyInterface)(v.val)
- if eface.typ == nil {
- // nil interface value
- return Value{}
- }
- typ = eface.typ
- val = unsafe.Pointer(eface.word)
+ eface = *(*interface{})(v.ptr)
} else {
- iface := (*nonEmptyInterface)(v.val)
- if iface.itab == nil {
- // nil interface value
- return Value{}
- }
- typ = iface.itab.typ
- val = unsafe.Pointer(iface.word)
+ eface = (interface{})(*(*interface {
+ M()
+ })(v.ptr))
}
- fl := v.flag & flagRO
- fl |= flag(typ.Kind()) << flagKindShift
- if typ.Kind() != Ptr && typ.Kind() != UnsafePointer {
- fl |= flagIndir
+ x := unpackEface(eface)
+ if x.flag != 0 {
+ x.flag |= v.flag & flagRO
}
- return Value{typ, val, fl}
-
+ return x
case Ptr:
- val := v.val
+ ptr := v.ptr
if v.flag&flagIndir != 0 {
- val = *(*unsafe.Pointer)(val)
+ ptr = *(*unsafe.Pointer)(ptr)
}
// The returned value's address is v's value.
- if val == nil {
+ if ptr == nil {
return Value{}
}
tt := (*ptrType)(unsafe.Pointer(v.typ))
typ := tt.elem
fl := v.flag&flagRO | flagIndir | flagAddr
- fl |= flag(typ.Kind() << flagKindShift)
- return Value{typ, val, fl}
+ fl |= flag(typ.Kind())
+ return Value{typ, ptr, fl}
}
- panic(&ValueError{"reflect.Value.Elem", k})
+ panic(&ValueError{"reflect.Value.Elem", v.kind()})
}
// Field returns the i'th field of the struct v.
// It panics if v's Kind is not Struct or i is out of range.
func (v Value) Field(i int) Value {
- v.mustBe(Struct)
+ if v.kind() != Struct {
+ panic(&ValueError{"reflect.Value.Field", v.kind()})
+ }
tt := (*structType)(unsafe.Pointer(v.typ))
- if i < 0 || i >= len(tt.fields) {
+ if uint(i) >= uint(len(tt.fields)) {
panic("reflect: Field index out of range")
}
field := &tt.fields[i]
typ := field.typ
// Inherit permission bits from v.
- fl := v.flag & (flagRO | flagIndir | flagAddr)
+ fl := v.flag&(flagRO|flagIndir|flagAddr) | flag(typ.Kind())
// Using an unexported field forces flagRO.
if field.pkgPath != nil {
fl |= flagRO
}
- fl |= flag(typ.Kind()) << flagKindShift
-
- var val unsafe.Pointer
- switch {
- case fl&flagIndir != 0:
- // Indirect. Just bump pointer.
- val = unsafe.Pointer(uintptr(v.val) + field.offset)
- case bigEndian:
- // Direct. Discard leading bytes.
- val = unsafe.Pointer(uintptr(v.val) << (field.offset * 8))
- default:
- // Direct. Discard leading bytes.
- val = unsafe.Pointer(uintptr(v.val) >> (field.offset * 8))
- }
-
- return Value{typ, val, fl}
+ // Either flagIndir is set and v.ptr points at struct,
+ // or flagIndir is not set and v.ptr is the actual struct data.
+ // In the former case, we want v.ptr + offset.
+ // In the latter case, we must be have field.offset = 0,
+ // so v.ptr + field.offset is still okay.
+ ptr := unsafe.Pointer(uintptr(v.ptr) + field.offset)
+ return Value{typ, ptr, fl}
}
// FieldByIndex returns the nested field corresponding to index.
// It panics if v's Kind is not struct.
func (v Value) FieldByIndex(index []int) Value {
+ if len(index) == 1 {
+ return v.Field(index[0])
+ }
v.mustBe(Struct)
for i, x := range index {
if i > 0 {
- if v.Kind() == Ptr && v.Elem().Kind() == Struct {
+ if v.Kind() == Ptr && v.typ.Elem().Kind() == Struct {
+ if v.IsNil() {
+ panic("reflect: indirection through nil pointer to embedded struct")
+ }
v = v.Elem()
}
}
@@ -706,7 +665,6 @@ func (v Value) FieldByName(name string) Value {
// It panics if v's Kind is not struct.
// It returns the zero Value if no field was found.
func (v Value) FieldByNameFunc(match func(string) bool) Value {
- v.mustBe(Struct)
if f, ok := v.typ.FieldByNameFunc(match); ok {
return v.FieldByIndex(f.Index)
}
@@ -719,17 +677,11 @@ func (v Value) Float() float64 {
k := v.kind()
switch k {
case Float32:
- if v.flag&flagIndir != 0 {
- return float64(*(*float32)(v.val))
- }
- return float64(*(*float32)(unsafe.Pointer(&v.val)))
+ return float64(*(*float32)(v.ptr))
case Float64:
- if v.flag&flagIndir != 0 {
- return *(*float64)(v.val)
- }
- return *(*float64)(unsafe.Pointer(&v.val))
+ return *(*float64)(v.ptr)
}
- panic(&ValueError{"reflect.Value.Float", k})
+ panic(&ValueError{"reflect.Value.Float", v.kind()})
}
var uint8Type = TypeOf(uint8(0)).(*rtype)
@@ -737,70 +689,54 @@ var uint8Type = TypeOf(uint8(0)).(*rtype)
// Index returns v's i'th element.
// It panics if v's Kind is not Array, Slice, or String or i is out of range.
func (v Value) Index(i int) Value {
- k := v.kind()
- switch k {
+ switch v.kind() {
case Array:
tt := (*arrayType)(unsafe.Pointer(v.typ))
- if i < 0 || i > int(tt.len) {
+ if uint(i) >= uint(tt.len) {
panic("reflect: array index out of range")
}
typ := tt.elem
- fl := v.flag & (flagRO | flagIndir | flagAddr) // bits same as overall array
- fl |= flag(typ.Kind()) << flagKindShift
offset := uintptr(i) * typ.size
- var val unsafe.Pointer
- switch {
- case fl&flagIndir != 0:
- // Indirect. Just bump pointer.
- val = unsafe.Pointer(uintptr(v.val) + offset)
- case bigEndian:
- // Direct. Discard leading bytes.
- val = unsafe.Pointer(uintptr(v.val) << (offset * 8))
- default:
- // Direct. Discard leading bytes.
- val = unsafe.Pointer(uintptr(v.val) >> (offset * 8))
- }
+ // Either flagIndir is set and v.ptr points at array,
+ // or flagIndir is not set and v.ptr is the actual array data.
+ // In the former case, we want v.ptr + offset.
+ // In the latter case, we must be doing Index(0), so offset = 0,
+ // so v.ptr + offset is still okay.
+ val := unsafe.Pointer(uintptr(v.ptr) + offset)
+ fl := v.flag&(flagRO|flagIndir|flagAddr) | flag(typ.Kind()) // bits same as overall array
return Value{typ, val, fl}
case Slice:
// Element flag same as Elem of Ptr.
// Addressable, indirect, possibly read-only.
- fl := flagAddr | flagIndir | v.flag&flagRO
- s := (*SliceHeader)(v.val)
- if i < 0 || i >= s.Len {
+ s := (*sliceHeader)(v.ptr)
+ if uint(i) >= uint(s.Len) {
panic("reflect: slice index out of range")
}
tt := (*sliceType)(unsafe.Pointer(v.typ))
typ := tt.elem
- fl |= flag(typ.Kind()) << flagKindShift
- val := unsafe.Pointer(s.Data + uintptr(i)*typ.size)
+ val := unsafe.Pointer(uintptr(s.Data) + uintptr(i)*typ.size)
+ fl := flagAddr | flagIndir | v.flag&flagRO | flag(typ.Kind())
return Value{typ, val, fl}
case String:
- fl := v.flag&flagRO | flag(Uint8<<flagKindShift) | flagIndir
- s := (*StringHeader)(v.val)
- if i < 0 || i >= s.Len {
+ s := (*stringHeader)(v.ptr)
+ if uint(i) >= uint(s.Len) {
panic("reflect: string index out of range")
}
- val := *(*byte)(unsafe.Pointer(s.Data + uintptr(i)))
- return Value{uint8Type, unsafe.Pointer(&val), fl}
+ p := unsafe.Pointer(uintptr(s.Data) + uintptr(i))
+ fl := v.flag&flagRO | flag(Uint8) | flagIndir
+ return Value{uint8Type, p, fl}
}
- panic(&ValueError{"reflect.Value.Index", k})
+ panic(&ValueError{"reflect.Value.Index", v.kind()})
}
// Int returns v's underlying value, as an int64.
// It panics if v's Kind is not Int, Int8, Int16, Int32, or Int64.
func (v Value) Int() int64 {
k := v.kind()
- var p unsafe.Pointer
- if v.flag&flagIndir != 0 {
- p = v.val
- } else {
- // The escape analysis is good enough that &v.val
- // does not trigger a heap allocation.
- p = unsafe.Pointer(&v.val)
- }
+ p := v.ptr
switch k {
case Int:
return int64(*(*int)(p))
@@ -813,7 +749,7 @@ func (v Value) Int() int64 {
case Int64:
return int64(*(*int64)(p))
}
- panic(&ValueError{"reflect.Value.Int", k})
+ panic(&ValueError{"reflect.Value.Int", v.kind()})
}
// CanInterface returns true if Interface can be used without panicking.
@@ -857,55 +793,42 @@ func valueInterface(v Value, safe bool) interface{} {
}
}
- k := v.kind()
- if k == Interface {
+ if v.kind() == Interface {
// Special case: return the element inside the interface.
// Empty interface has one layout, all interfaces with
// methods have a second layout.
if v.NumMethod() == 0 {
- return *(*interface{})(v.val)
+ return *(*interface{})(v.ptr)
}
return *(*interface {
M()
- })(v.val)
- }
-
- // Non-interface value.
- var eface emptyInterface
- eface.typ = toType(v.typ).common()
- eface.word = v.iword()
-
- // Don't need to allocate if v is not addressable or fits in one word.
- if v.flag&flagAddr != 0 && v.kind() != Ptr && v.kind() != UnsafePointer {
- // eface.word is a pointer to the actual data,
- // which might be changed. We need to return
- // a pointer to unchanging data, so make a copy.
- ptr := unsafe_New(v.typ)
- memmove(ptr, unsafe.Pointer(eface.word), v.typ.size)
- eface.word = iword(ptr)
+ })(v.ptr)
}
- if v.flag&flagIndir == 0 && v.kind() != Ptr && v.kind() != UnsafePointer {
- panic("missing flagIndir")
- }
-
- return *(*interface{})(unsafe.Pointer(&eface))
+ // TODO: pass safe to packEface so we don't need to copy if safe==true?
+ return packEface(v)
}
// InterfaceData returns the interface v's value as a uintptr pair.
// It panics if v's Kind is not Interface.
func (v Value) InterfaceData() [2]uintptr {
+ // TODO: deprecate this
v.mustBe(Interface)
// We treat this as a read operation, so we allow
// it even for unexported data, because the caller
// has to import "unsafe" to turn it into something
// that can be abused.
// Interface value is always bigger than a word; assume flagIndir.
- return *(*[2]uintptr)(v.val)
+ return *(*[2]uintptr)(v.ptr)
}
-// IsNil returns true if v is a nil value.
-// It panics if v's Kind is not Chan, Func, Interface, Map, Ptr, or Slice.
+// IsNil reports whether its argument v is nil. The argument must be
+// a chan, func, interface, map, pointer, or slice value; if it is
+// not, IsNil panics. Note that IsNil is not always equivalent to a
+// regular comparison with nil in Go. For example, if v was created
+// by calling ValueOf with an uninitialized interface variable i,
+// i==nil will be true but v.IsNil will panic as v will be the zero
+// Value.
func (v Value) IsNil() bool {
k := v.kind()
switch k {
@@ -913,7 +836,7 @@ func (v Value) IsNil() bool {
if v.flag&flagMethod != 0 {
return false
}
- ptr := v.val
+ ptr := v.ptr
if v.flag&flagIndir != 0 {
ptr = *(*unsafe.Pointer)(ptr)
}
@@ -921,9 +844,9 @@ func (v Value) IsNil() bool {
case Interface, Slice:
// Both interface and slice are nil if first word is 0.
// Both are always bigger than a word; assume flagIndir.
- return *(*unsafe.Pointer)(v.val) == nil
+ return *(*unsafe.Pointer)(v.ptr) == nil
}
- panic(&ValueError{"reflect.Value.IsNil", k})
+ panic(&ValueError{"reflect.Value.IsNil", v.kind()})
}
// IsValid returns true if v represents a value.
@@ -950,17 +873,17 @@ func (v Value) Len() int {
tt := (*arrayType)(unsafe.Pointer(v.typ))
return int(tt.len)
case Chan:
- return chanlen(*(*iword)(v.iword()))
+ return chanlen(v.pointer())
case Map:
- return maplen(*(*iword)(v.iword()))
+ return maplen(v.pointer())
case Slice:
// Slice is bigger than a word; assume flagIndir.
- return (*SliceHeader)(v.val).Len
+ return (*sliceHeader)(v.ptr).Len
case String:
// String is bigger than a word; assume flagIndir.
- return (*StringHeader)(v.val).Len
+ return (*stringHeader)(v.ptr).Len
}
- panic(&ValueError{"reflect.Value.Len", k})
+ panic(&ValueError{"reflect.Value.Len", v.kind()})
}
// MapIndex returns the value associated with key in the map v.
@@ -980,17 +903,28 @@ func (v Value) MapIndex(key Value) Value {
// of unexported fields.
key = key.assignTo("reflect.Value.MapIndex", tt.key, nil)
- word, ok := mapaccess(v.typ, *(*iword)(v.iword()), key.iword())
- if !ok {
+ var k unsafe.Pointer
+ if key.flag&flagIndir != 0 {
+ k = key.ptr
+ } else {
+ k = unsafe.Pointer(&key.ptr)
+ }
+ e := mapaccess(v.typ, v.pointer(), k)
+ if e == nil {
return Value{}
}
typ := tt.elem
fl := (v.flag | key.flag) & flagRO
- if typ.Kind() != Ptr && typ.Kind() != UnsafePointer {
- fl |= flagIndir
+ fl |= flag(typ.Kind())
+ if ifaceIndir(typ) {
+ // Copy result so future changes to the map
+ // won't change the underlying value.
+ c := unsafe_New(typ)
+ memmove(c, e, typ.size)
+ return Value{typ, c, fl | flagIndir}
+ } else {
+ return Value{typ, *(*unsafe.Pointer)(e), fl}
}
- fl |= flag(typ.Kind()) << flagKindShift
- return Value{typ, unsafe.Pointer(word), fl}
}
// MapKeys returns a slice containing all the keys present in the map,
@@ -1002,13 +936,9 @@ func (v Value) MapKeys() []Value {
tt := (*mapType)(unsafe.Pointer(v.typ))
keyType := tt.key
- fl := v.flag & flagRO
- fl |= flag(keyType.Kind()) << flagKindShift
- if keyType.Kind() != Ptr && keyType.Kind() != UnsafePointer {
- fl |= flagIndir
- }
+ fl := v.flag&flagRO | flag(keyType.Kind())
- m := *(*iword)(v.iword())
+ m := v.pointer()
mlen := int(0)
if m != nil {
mlen = maplen(m)
@@ -1017,11 +947,22 @@ func (v Value) MapKeys() []Value {
a := make([]Value, mlen)
var i int
for i = 0; i < len(a); i++ {
- keyWord, ok := mapiterkey(it)
- if !ok {
+ key := mapiterkey(it)
+ if key == nil {
+ // Someone deleted an entry from the map since we
+ // called maplen above. It's a data race, but nothing
+ // we can do about it.
break
}
- a[i] = Value{keyType, unsafe.Pointer(keyWord), fl}
+ if ifaceIndir(keyType) {
+ // Copy result so future changes to the map
+ // won't change the underlying value.
+ c := unsafe_New(keyType)
+ memmove(c, key, keyType.size)
+ a[i] = Value{keyType, c, fl | flagIndir}
+ } else {
+ a[i] = Value{keyType, *(*unsafe.Pointer)(key), fl}
+ }
mapiternext(it)
}
return a[:i]
@@ -1035,16 +976,16 @@ func (v Value) Method(i int) Value {
if v.typ == nil {
panic(&ValueError{"reflect.Value.Method", Invalid})
}
- if v.flag&flagMethod != 0 || i < 0 || i >= v.typ.NumMethod() {
+ if v.flag&flagMethod != 0 || uint(i) >= uint(v.typ.NumMethod()) {
panic("reflect: Method index out of range")
}
if v.typ.Kind() == Interface && v.IsNil() {
panic("reflect: Method on nil interface value")
}
fl := v.flag & (flagRO | flagIndir)
- fl |= flag(Func) << flagKindShift
+ fl |= flag(Func)
fl |= flag(i)<<flagMethodShift | flagMethod
- return Value{v.typ, v.val, fl}
+ return Value{v.typ, v.ptr, fl}
}
// NumMethod returns the number of methods in the value's method set.
@@ -1095,7 +1036,7 @@ func (v Value) OverflowComplex(x complex128) bool {
case Complex128:
return false
}
- panic(&ValueError{"reflect.Value.OverflowComplex", k})
+ panic(&ValueError{"reflect.Value.OverflowComplex", v.kind()})
}
// OverflowFloat returns true if the float64 x cannot be represented by v's type.
@@ -1108,7 +1049,7 @@ func (v Value) OverflowFloat(x float64) bool {
case Float64:
return false
}
- panic(&ValueError{"reflect.Value.OverflowFloat", k})
+ panic(&ValueError{"reflect.Value.OverflowFloat", v.kind()})
}
func overflowFloat32(x float64) bool {
@@ -1128,7 +1069,7 @@ func (v Value) OverflowInt(x int64) bool {
trunc := (x << (64 - bitSize)) >> (64 - bitSize)
return x != trunc
}
- panic(&ValueError{"reflect.Value.OverflowInt", k})
+ panic(&ValueError{"reflect.Value.OverflowInt", v.kind()})
}
// OverflowUint returns true if the uint64 x cannot be represented by v's type.
@@ -1141,7 +1082,7 @@ func (v Value) OverflowUint(x uint64) bool {
trunc := (x << (64 - bitSize)) >> (64 - bitSize)
return x != trunc
}
- panic(&ValueError{"reflect.Value.OverflowUint", k})
+ panic(&ValueError{"reflect.Value.OverflowUint", v.kind()})
}
// Pointer returns v's value as a uintptr.
@@ -1154,30 +1095,18 @@ func (v Value) OverflowUint(x uint64) bool {
// code pointer, but not necessarily enough to identify a
// single function uniquely. The only guarantee is that the
// result is zero if and only if v is a nil func Value.
+//
+// If v's Kind is Slice, the returned pointer is to the first
+// element of the slice. If the slice is nil the returned value
+// is 0. If the slice is empty but non-nil the return value is non-zero.
func (v Value) Pointer() uintptr {
+ // TODO: deprecate
k := v.kind()
switch k {
case Chan, Map, Ptr, UnsafePointer:
- p := v.val
- if v.flag&flagIndir != 0 {
- p = *(*unsafe.Pointer)(p)
- }
- return uintptr(p)
+ return uintptr(v.pointer())
case Func:
- if v.flag&flagMethod != 0 {
- // As the doc comment says, the returned pointer is an
- // underlying code pointer but not necessarily enough to
- // identify a single function uniquely. All method expressions
- // created via reflect have the same underlying code pointer,
- // so their Pointers are equal. The function used here must
- // match the one used in makeMethodValue.
- f := makeFuncStub
- return **(**uintptr)(unsafe.Pointer(&f))
- }
- p := v.val
- if v.flag&flagIndir != 0 {
- p = *(*unsafe.Pointer)(p)
- }
+ p := v.pointer()
// Non-nil func value points at data block.
// First word of data block is actual code.
if p != nil {
@@ -1186,9 +1115,9 @@ func (v Value) Pointer() uintptr {
return uintptr(p)
case Slice:
- return (*SliceHeader)(v.val).Data
+ return (*SliceHeader)(v.ptr).Data
}
- panic(&ValueError{"reflect.Value.Pointer", k})
+ panic(&ValueError{"reflect.Value.Pointer", v.kind()})
}
// Recv receives and returns a value from the channel v.
@@ -1209,14 +1138,19 @@ func (v Value) recv(nb bool) (val Value, ok bool) {
if ChanDir(tt.dir)&RecvDir == 0 {
panic("reflect: recv on send-only channel")
}
- word, selected, ok := chanrecv(v.typ, *(*iword)(v.iword()), nb)
- if selected {
- typ := tt.elem
- fl := flag(typ.Kind()) << flagKindShift
- if typ.Kind() != Ptr && typ.Kind() != UnsafePointer {
- fl |= flagIndir
- }
- val = Value{typ, unsafe.Pointer(word), fl}
+ t := tt.elem
+ val = Value{t, nil, flag(t.Kind())}
+ var p unsafe.Pointer
+ if ifaceIndir(t) {
+ p = unsafe_New(t)
+ val.ptr = p
+ val.flag |= flagIndir
+ } else {
+ p = unsafe.Pointer(&val.ptr)
+ }
+ selected, ok := chanrecv(v.typ, v.pointer(), nb, p)
+ if !selected {
+ val = Value{}
}
return
}
@@ -1239,7 +1173,13 @@ func (v Value) send(x Value, nb bool) (selected bool) {
}
x.mustBeExported()
x = x.assignTo("reflect.Value.Send", tt.elem, nil)
- return chansend(v.typ, *(*iword)(v.iword()), x.iword(), nb)
+ var p unsafe.Pointer
+ if x.flag&flagIndir != 0 {
+ p = x.ptr
+ } else {
+ p = unsafe.Pointer(&x.ptr)
+ }
+ return chansend(v.typ, v.pointer(), p, nb)
}
// Set assigns x to the value v.
@@ -1248,15 +1188,15 @@ func (v Value) send(x Value, nb bool) (selected bool) {
func (v Value) Set(x Value) {
v.mustBeAssignable()
x.mustBeExported() // do not let unexported x leak
- var target *interface{}
+ var target unsafe.Pointer
if v.kind() == Interface {
- target = (*interface{})(v.val)
+ target = v.ptr
}
x = x.assignTo("reflect.Set", v.typ, target)
if x.flag&flagIndir != 0 {
- memmove(v.val, x.val, v.typ.size)
+ memmove(v.ptr, x.ptr, v.typ.size)
} else {
- storeIword(v.val, iword(x.val), v.typ.size)
+ *(*unsafe.Pointer)(v.ptr) = x.ptr
}
}
@@ -1265,7 +1205,7 @@ func (v Value) Set(x Value) {
func (v Value) SetBool(x bool) {
v.mustBeAssignable()
v.mustBe(Bool)
- *(*bool)(v.val) = x
+ *(*bool)(v.ptr) = x
}
// SetBytes sets v's underlying value.
@@ -1276,7 +1216,7 @@ func (v Value) SetBytes(x []byte) {
if v.typ.Elem().Kind() != Uint8 {
panic("reflect.Value.SetBytes of non-byte slice")
}
- *(*[]byte)(v.val) = x
+ *(*[]byte)(v.ptr) = x
}
// setRunes sets v's underlying value.
@@ -1287,7 +1227,7 @@ func (v Value) setRunes(x []rune) {
if v.typ.Elem().Kind() != Int32 {
panic("reflect.Value.setRunes of non-rune slice")
}
- *(*[]rune)(v.val) = x
+ *(*[]rune)(v.ptr) = x
}
// SetComplex sets v's underlying value to x.
@@ -1296,11 +1236,11 @@ func (v Value) SetComplex(x complex128) {
v.mustBeAssignable()
switch k := v.kind(); k {
default:
- panic(&ValueError{"reflect.Value.SetComplex", k})
+ panic(&ValueError{"reflect.Value.SetComplex", v.kind()})
case Complex64:
- *(*complex64)(v.val) = complex64(x)
+ *(*complex64)(v.ptr) = complex64(x)
case Complex128:
- *(*complex128)(v.val) = x
+ *(*complex128)(v.ptr) = x
}
}
@@ -1310,11 +1250,11 @@ func (v Value) SetFloat(x float64) {
v.mustBeAssignable()
switch k := v.kind(); k {
default:
- panic(&ValueError{"reflect.Value.SetFloat", k})
+ panic(&ValueError{"reflect.Value.SetFloat", v.kind()})
case Float32:
- *(*float32)(v.val) = float32(x)
+ *(*float32)(v.ptr) = float32(x)
case Float64:
- *(*float64)(v.val) = x
+ *(*float64)(v.ptr) = x
}
}
@@ -1324,17 +1264,17 @@ func (v Value) SetInt(x int64) {
v.mustBeAssignable()
switch k := v.kind(); k {
default:
- panic(&ValueError{"reflect.Value.SetInt", k})
+ panic(&ValueError{"reflect.Value.SetInt", v.kind()})
case Int:
- *(*int)(v.val) = int(x)
+ *(*int)(v.ptr) = int(x)
case Int8:
- *(*int8)(v.val) = int8(x)
+ *(*int8)(v.ptr) = int8(x)
case Int16:
- *(*int16)(v.val) = int16(x)
+ *(*int16)(v.ptr) = int16(x)
case Int32:
- *(*int32)(v.val) = int32(x)
+ *(*int32)(v.ptr) = int32(x)
case Int64:
- *(*int64)(v.val) = x
+ *(*int64)(v.ptr) = x
}
}
@@ -1344,8 +1284,8 @@ func (v Value) SetInt(x int64) {
func (v Value) SetLen(n int) {
v.mustBeAssignable()
v.mustBe(Slice)
- s := (*SliceHeader)(v.val)
- if n < 0 || n > int(s.Cap) {
+ s := (*sliceHeader)(v.ptr)
+ if uint(n) > uint(s.Cap) {
panic("reflect: slice length out of range in SetLen")
}
s.Len = n
@@ -1357,7 +1297,7 @@ func (v Value) SetLen(n int) {
func (v Value) SetCap(n int) {
v.mustBeAssignable()
v.mustBe(Slice)
- s := (*SliceHeader)(v.val)
+ s := (*sliceHeader)(v.ptr)
if n < int(s.Len) || n > int(s.Cap) {
panic("reflect: slice capacity out of range in SetCap")
}
@@ -1367,6 +1307,7 @@ func (v Value) SetCap(n int) {
// SetMapIndex sets the value associated with key in the map v to val.
// It panics if v's Kind is not Map.
// If val is the zero Value, SetMapIndex deletes the key from the map.
+// Otherwise if v holds a nil map, SetMapIndex will panic.
// As in Go, key's value must be assignable to the map's key type,
// and val's value must be assignable to the map's value type.
func (v Value) SetMapIndex(key, val Value) {
@@ -1375,11 +1316,25 @@ func (v Value) SetMapIndex(key, val Value) {
key.mustBeExported()
tt := (*mapType)(unsafe.Pointer(v.typ))
key = key.assignTo("reflect.Value.SetMapIndex", tt.key, nil)
- if val.typ != nil {
- val.mustBeExported()
- val = val.assignTo("reflect.Value.SetMapIndex", tt.elem, nil)
+ var k unsafe.Pointer
+ if key.flag&flagIndir != 0 {
+ k = key.ptr
+ } else {
+ k = unsafe.Pointer(&key.ptr)
+ }
+ if val.typ == nil {
+ mapdelete(v.typ, v.pointer(), k)
+ return
+ }
+ val.mustBeExported()
+ val = val.assignTo("reflect.Value.SetMapIndex", tt.elem, nil)
+ var e unsafe.Pointer
+ if val.flag&flagIndir != 0 {
+ e = val.ptr
+ } else {
+ e = unsafe.Pointer(&val.ptr)
}
- mapassign(v.typ, *(*iword)(v.iword()), key.iword(), val.iword(), val.typ != nil)
+ mapassign(v.typ, v.pointer(), k, e)
}
// SetUint sets v's underlying value to x.
@@ -1388,19 +1343,19 @@ func (v Value) SetUint(x uint64) {
v.mustBeAssignable()
switch k := v.kind(); k {
default:
- panic(&ValueError{"reflect.Value.SetUint", k})
+ panic(&ValueError{"reflect.Value.SetUint", v.kind()})
case Uint:
- *(*uint)(v.val) = uint(x)
+ *(*uint)(v.ptr) = uint(x)
case Uint8:
- *(*uint8)(v.val) = uint8(x)
+ *(*uint8)(v.ptr) = uint8(x)
case Uint16:
- *(*uint16)(v.val) = uint16(x)
+ *(*uint16)(v.ptr) = uint16(x)
case Uint32:
- *(*uint32)(v.val) = uint32(x)
+ *(*uint32)(v.ptr) = uint32(x)
case Uint64:
- *(*uint64)(v.val) = x
+ *(*uint64)(v.ptr) = x
case Uintptr:
- *(*uintptr)(v.val) = uintptr(x)
+ *(*uintptr)(v.ptr) = uintptr(x)
}
}
@@ -1409,7 +1364,7 @@ func (v Value) SetUint(x uint64) {
func (v Value) SetPointer(x unsafe.Pointer) {
v.mustBeAssignable()
v.mustBe(UnsafePointer)
- *(*unsafe.Pointer)(v.val) = x
+ *(*unsafe.Pointer)(v.ptr) = x
}
// SetString sets v's underlying value to x.
@@ -1417,7 +1372,7 @@ func (v Value) SetPointer(x unsafe.Pointer) {
func (v Value) SetString(x string) {
v.mustBeAssignable()
v.mustBe(String)
- *(*string)(v.val) = x
+ *(*string)(v.ptr) = x
}
// Slice returns v[i:j].
@@ -1431,7 +1386,7 @@ func (v Value) Slice(i, j int) Value {
)
switch kind := v.kind(); kind {
default:
- panic(&ValueError{"reflect.Value.Slice", kind})
+ panic(&ValueError{"reflect.Value.Slice", v.kind()})
case Array:
if v.flag&flagAddr == 0 {
@@ -1440,24 +1395,21 @@ func (v Value) Slice(i, j int) Value {
tt := (*arrayType)(unsafe.Pointer(v.typ))
cap = int(tt.len)
typ = (*sliceType)(unsafe.Pointer(tt.slice))
- base = v.val
+ base = v.ptr
case Slice:
typ = (*sliceType)(unsafe.Pointer(v.typ))
- s := (*SliceHeader)(v.val)
+ s := (*sliceHeader)(v.ptr)
base = unsafe.Pointer(s.Data)
cap = s.Cap
case String:
- s := (*StringHeader)(v.val)
+ s := (*stringHeader)(v.ptr)
if i < 0 || j < i || j > s.Len {
panic("reflect.Value.Slice: string slice index out of bounds")
}
- var x string
- val := (*StringHeader)(unsafe.Pointer(&x))
- val.Data = s.Data + uintptr(i)
- val.Len = j - i
- return Value{v.typ, unsafe.Pointer(&x), v.flag}
+ t := stringHeader{unsafe.Pointer(uintptr(s.Data) + uintptr(i)), j - i}
+ return Value{v.typ, unsafe.Pointer(&t), v.flag}
}
if i < 0 || j < i || j > cap {
@@ -1467,13 +1419,18 @@ func (v Value) Slice(i, j int) Value {
// Declare slice so that gc can see the base pointer in it.
var x []unsafe.Pointer
- // Reinterpret as *SliceHeader to edit.
- s := (*SliceHeader)(unsafe.Pointer(&x))
- s.Data = uintptr(base) + uintptr(i)*typ.elem.Size()
+ // Reinterpret as *sliceHeader to edit.
+ s := (*sliceHeader)(unsafe.Pointer(&x))
s.Len = j - i
s.Cap = cap - i
+ if cap-i > 0 {
+ s.Data = unsafe.Pointer(uintptr(base) + uintptr(i)*typ.elem.Size())
+ } else {
+ // do not advance pointer, to avoid pointing beyond end of slice
+ s.Data = base
+ }
- fl := v.flag&flagRO | flagIndir | flag(Slice)<<flagKindShift
+ fl := v.flag&flagRO | flagIndir | flag(Slice)
return Value{typ.common(), unsafe.Pointer(&x), fl}
}
@@ -1488,21 +1445,21 @@ func (v Value) Slice3(i, j, k int) Value {
)
switch kind := v.kind(); kind {
default:
- panic(&ValueError{"reflect.Value.Slice3", kind})
+ panic(&ValueError{"reflect.Value.Slice3", v.kind()})
case Array:
if v.flag&flagAddr == 0 {
- panic("reflect.Value.Slice: slice of unaddressable array")
+ panic("reflect.Value.Slice3: slice of unaddressable array")
}
tt := (*arrayType)(unsafe.Pointer(v.typ))
cap = int(tt.len)
typ = (*sliceType)(unsafe.Pointer(tt.slice))
- base = v.val
+ base = v.ptr
case Slice:
typ = (*sliceType)(unsafe.Pointer(v.typ))
- s := (*SliceHeader)(v.val)
- base = unsafe.Pointer(s.Data)
+ s := (*sliceHeader)(v.ptr)
+ base = s.Data
cap = s.Cap
}
@@ -1514,13 +1471,18 @@ func (v Value) Slice3(i, j, k int) Value {
// can see the base pointer in it.
var x []unsafe.Pointer
- // Reinterpret as *SliceHeader to edit.
- s := (*SliceHeader)(unsafe.Pointer(&x))
- s.Data = uintptr(base) + uintptr(i)*typ.elem.Size()
+ // Reinterpret as *sliceHeader to edit.
+ s := (*sliceHeader)(unsafe.Pointer(&x))
s.Len = j - i
s.Cap = k - i
+ if k-i > 0 {
+ s.Data = unsafe.Pointer(uintptr(base) + uintptr(i)*typ.elem.Size())
+ } else {
+ // do not advance pointer, to avoid pointing beyond end of slice
+ s.Data = base
+ }
- fl := v.flag&flagRO | flagIndir | flag(Slice)<<flagKindShift
+ fl := v.flag&flagRO | flagIndir | flag(Slice)
return Value{typ.common(), unsafe.Pointer(&x), fl}
}
@@ -1533,18 +1495,18 @@ func (v Value) String() string {
case Invalid:
return "<invalid Value>"
case String:
- return *(*string)(v.val)
+ return *(*string)(v.ptr)
}
// If you call String on a reflect.Value of other type, it's better to
// print something than to panic. Useful in debugging.
- return "<" + v.typ.String() + " Value>"
+ return "<" + v.Type().String() + " Value>"
}
// TryRecv attempts to receive a value from the channel v but will not block.
// It panics if v's Kind is not Chan.
-// If the receive cannot finish without blocking, x is the zero Value.
-// The boolean ok is true if the value x corresponds to a send
-// on the channel, false if it is a zero value received because the channel is closed.
+// If the receive delivers a value, x is the transferred value and ok is true.
+// If the receive cannot finish without blocking, x is the zero Value and ok is false.
+// If the channel is closed, x is the zero value for the channel's element type and ok is false.
func (v Value) TryRecv() (x Value, ok bool) {
v.mustBe(Chan)
v.mustBeExported()
@@ -1578,7 +1540,7 @@ func (v Value) Type() Type {
if v.typ.Kind() == Interface {
// Method on interface.
tt := (*interfaceType)(unsafe.Pointer(v.typ))
- if i < 0 || i >= len(tt.methods) {
+ if uint(i) >= uint(len(tt.methods)) {
panic("reflect: internal error: invalid method index")
}
m := &tt.methods[i]
@@ -1586,7 +1548,7 @@ func (v Value) Type() Type {
}
// Method on concrete type.
ut := v.typ.uncommon()
- if ut == nil || i < 0 || i >= len(ut.methods) {
+ if ut == nil || uint(i) >= uint(len(ut.methods)) {
panic("reflect: internal error: invalid method index")
}
m := &ut.methods[i]
@@ -1597,14 +1559,7 @@ func (v Value) Type() Type {
// It panics if v's Kind is not Uint, Uintptr, Uint8, Uint16, Uint32, or Uint64.
func (v Value) Uint() uint64 {
k := v.kind()
- var p unsafe.Pointer
- if v.flag&flagIndir != 0 {
- p = v.val
- } else {
- // The escape analysis is good enough that &v.val
- // does not trigger a heap allocation.
- p = unsafe.Pointer(&v.val)
- }
+ p := v.ptr
switch k {
case Uint:
return uint64(*(*uint)(p))
@@ -1619,20 +1574,21 @@ func (v Value) Uint() uint64 {
case Uintptr:
return uint64(*(*uintptr)(p))
}
- panic(&ValueError{"reflect.Value.Uint", k})
+ panic(&ValueError{"reflect.Value.Uint", v.kind()})
}
// UnsafeAddr returns a pointer to v's data.
// It is for advanced clients that also import the "unsafe" package.
// It panics if v is not addressable.
func (v Value) UnsafeAddr() uintptr {
+ // TODO: deprecate
if v.typ == nil {
panic(&ValueError{"reflect.Value.UnsafeAddr", Invalid})
}
if v.flag&flagAddr == 0 {
panic("reflect.Value.UnsafeAddr of unaddressable value")
}
- return uintptr(v.val)
+ return uintptr(v.ptr)
}
// StringHeader is the runtime representation of a string.
@@ -1646,6 +1602,12 @@ type StringHeader struct {
Len int
}
+// stringHeader is a safe version of StringHeader used within this package.
+type stringHeader struct {
+ Data unsafe.Pointer
+ Len int
+}
+
// SliceHeader is the runtime representation of a slice.
// It cannot be used safely or portably and its representation may
// change in a later release.
@@ -1658,6 +1620,13 @@ type SliceHeader struct {
Cap int
}
+// sliceHeader is a safe version of SliceHeader used within this package.
+type sliceHeader struct {
+ Data unsafe.Pointer
+ Len int
+ Cap int
+}
+
func typesMustMatch(what string, t1, t2 Type) {
if t1 != t2 {
panic(what + ": " + t1.String() + " != " + t2.String())
@@ -1744,50 +1713,44 @@ func Copy(dst, src Value) int {
n = sn
}
- // If sk is an in-line array, cannot take its address.
- // Instead, copy element by element.
- if src.flag&flagIndir == 0 {
- for i := 0; i < n; i++ {
- dst.Index(i).Set(src.Index(i))
- }
- return n
- }
-
// Copy via memmove.
var da, sa unsafe.Pointer
if dk == Array {
- da = dst.val
+ da = dst.ptr
} else {
- da = unsafe.Pointer((*SliceHeader)(dst.val).Data)
+ da = (*sliceHeader)(dst.ptr).Data
}
- if sk == Array {
- sa = src.val
+ if src.flag&flagIndir == 0 {
+ sa = unsafe.Pointer(&src.ptr)
+ } else if sk == Array {
+ sa = src.ptr
} else {
- sa = unsafe.Pointer((*SliceHeader)(src.val).Data)
+ sa = (*sliceHeader)(src.ptr).Data
}
memmove(da, sa, uintptr(n)*de.Size())
return n
}
// A runtimeSelect is a single case passed to rselect.
-// This must match ../runtime/chan.c:/runtimeSelect
+// This must match ../runtime/select.go:/runtimeSelect
type runtimeSelect struct {
- dir uintptr // 0, SendDir, or RecvDir
- typ *rtype // channel type
- ch iword // interface word for channel
- val iword // interface word for value (for SendDir)
+ dir uintptr // 0, SendDir, or RecvDir
+ typ *rtype // channel type
+ ch unsafe.Pointer // channel
+ val unsafe.Pointer // ptr to data (SendDir) or ptr to receive buffer (RecvDir)
}
-// rselect runs a select. It returns the index of the chosen case,
-// and if the case was a receive, the interface word of the received
-// value and the conventional OK bool to indicate whether the receive
-// corresponds to a sent value.
-func rselect([]runtimeSelect) (chosen int, recv iword, recvOK bool)
+// rselect runs a select. It returns the index of the chosen case.
+// If the case was a receive, val is filled in with the received value.
+// The conventional OK bool indicates whether the receive corresponds
+// to a sent value.
+//go:noescape
+func rselect([]runtimeSelect) (chosen int, recvOK bool)
// A SelectDir describes the communication direction of a select case.
type SelectDir int
-// NOTE: These values must match ../runtime/chan.c:/SelectDir.
+// NOTE: These values must match ../runtime/select.go:/selectDir.
const (
_ SelectDir = iota
@@ -1862,7 +1825,7 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) {
if ChanDir(tt.dir)&SendDir == 0 {
panic("reflect.Select: SendDir case using recv-only channel")
}
- rc.ch = *(*iword)(ch.iword())
+ rc.ch = ch.pointer()
rc.typ = &tt.rtype
v := c.Send
if !v.IsValid() {
@@ -1870,7 +1833,11 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) {
}
v.mustBeExported()
v = v.assignTo("reflect.Select", tt.elem, nil)
- rc.val = v.iword()
+ if v.flag&flagIndir != 0 {
+ rc.val = v.ptr
+ } else {
+ rc.val = unsafe.Pointer(&v.ptr)
+ }
case SelectRecv:
if c.Send.IsValid() {
@@ -1883,23 +1850,26 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) {
ch.mustBe(Chan)
ch.mustBeExported()
tt := (*chanType)(unsafe.Pointer(ch.typ))
- rc.typ = &tt.rtype
if ChanDir(tt.dir)&RecvDir == 0 {
panic("reflect.Select: RecvDir case using send-only channel")
}
- rc.ch = *(*iword)(ch.iword())
+ rc.ch = ch.pointer()
+ rc.typ = &tt.rtype
+ rc.val = unsafe_New(tt.elem)
}
}
- chosen, word, recvOK := rselect(runcases)
+ chosen, recvOK = rselect(runcases)
if runcases[chosen].dir == uintptr(SelectRecv) {
tt := (*chanType)(unsafe.Pointer(runcases[chosen].typ))
- typ := tt.elem
- fl := flag(typ.Kind()) << flagKindShift
- if typ.Kind() != Ptr && typ.Kind() != UnsafePointer {
- fl |= flagIndir
+ t := tt.elem
+ p := runcases[chosen].val
+ fl := flag(t.Kind())
+ if ifaceIndir(t) {
+ recv = Value{t, p, fl | flagIndir}
+ } else {
+ recv = Value{t, *(*unsafe.Pointer)(p), fl}
}
- recv = Value{typ, unsafe.Pointer(word), fl}
}
return chosen, recv, recvOK
}
@@ -1928,16 +1898,8 @@ func MakeSlice(typ Type, len, cap int) Value {
panic("reflect.MakeSlice: len > cap")
}
- // Declare slice so that gc can see the base pointer in it.
- var x []unsafe.Pointer
-
- // Reinterpret as *SliceHeader to edit.
- s := (*SliceHeader)(unsafe.Pointer(&x))
- s.Data = uintptr(unsafe_NewArray(typ.Elem().(*rtype), cap))
- s.Len = len
- s.Cap = cap
-
- return Value{typ.common(), unsafe.Pointer(&x), flagIndir | flag(Slice)<<flagKindShift}
+ s := sliceHeader{unsafe_NewArray(typ.Elem().(*rtype), cap), len, cap}
+ return Value{typ.common(), unsafe.Pointer(&s), flagIndir | flag(Slice)}
}
// MakeChan creates a new channel with the specified type and buffer size.
@@ -1952,7 +1914,7 @@ func MakeChan(typ Type, buffer int) Value {
panic("reflect.MakeChan: unidirectional channel type")
}
ch := makechan(typ.(*rtype), uint64(buffer))
- return Value{typ.common(), unsafe.Pointer(ch), flagIndir | (flag(Chan) << flagKindShift)}
+ return Value{typ.common(), unsafe.Pointer(&ch), flag(Chan) | flagIndir}
}
// MakeMap creates a new map of the specified type.
@@ -1961,7 +1923,7 @@ func MakeMap(typ Type) Value {
panic("reflect.MakeMap of non-map type")
}
m := makemap(typ.(*rtype))
- return Value{typ.common(), unsafe.Pointer(m), flagIndir | (flag(Map) << flagKindShift)}
+ return Value{typ.common(), unsafe.Pointer(&m), flag(Map) | flagIndir}
}
// Indirect returns the value that v points to.
@@ -1982,21 +1944,13 @@ func ValueOf(i interface{}) Value {
}
// TODO(rsc): Eliminate this terrible hack.
- // In the call to packValue, eface.typ doesn't escape,
- // and eface.word is an integer. So it looks like
- // i (= eface) doesn't escape. But really it does,
- // because eface.word is actually a pointer.
+ // In the call to unpackEface, i.typ doesn't escape,
+ // and i.word is an integer. So it looks like
+ // i doesn't escape. But really it does,
+ // because i.word is actually a pointer.
escapes(i)
- // For an interface value with the noAddr bit set,
- // the representation is identical to an empty interface.
- eface := *(*emptyInterface)(unsafe.Pointer(&i))
- typ := eface.typ
- fl := flag(typ.Kind()) << flagKindShift
- if typ.Kind() != Ptr && typ.Kind() != UnsafePointer {
- fl |= flagIndir
- }
- return Value{typ, unsafe.Pointer(eface.word), fl}
+ return unpackEface(i)
}
// Zero returns a Value representing the zero value for the specified type.
@@ -2009,35 +1963,35 @@ func Zero(typ Type) Value {
panic("reflect: Zero(nil)")
}
t := typ.common()
- fl := flag(t.Kind()) << flagKindShift
- if t.Kind() == Ptr || t.Kind() == UnsafePointer {
- return Value{t, nil, fl}
+ fl := flag(t.Kind())
+ if ifaceIndir(t) {
+ return Value{t, unsafe_New(typ.(*rtype)), fl | flagIndir}
}
- return Value{t, unsafe_New(typ.(*rtype)), fl | flagIndir}
+ return Value{t, nil, fl}
}
// New returns a Value representing a pointer to a new zero value
-// for the specified type. That is, the returned Value's Type is PtrTo(t).
+// for the specified type. That is, the returned Value's Type is PtrTo(typ).
func New(typ Type) Value {
if typ == nil {
panic("reflect: New(nil)")
}
ptr := unsafe_New(typ.(*rtype))
- fl := flag(Ptr) << flagKindShift
+ fl := flag(Ptr)
return Value{typ.common().ptrTo(), ptr, fl}
}
// NewAt returns a Value representing a pointer to a value of the
// specified type, using p as that pointer.
func NewAt(typ Type, p unsafe.Pointer) Value {
- fl := flag(Ptr) << flagKindShift
+ fl := flag(Ptr)
return Value{typ.common().ptrTo(), p, fl}
}
// assignTo returns a value v that can be assigned directly to typ.
// It panics if v is not assignable to typ.
// For a conversion to an interface type, target is a suggested scratch space to use.
-func (v Value) assignTo(context string, dst *rtype, target *interface{}) Value {
+func (v Value) assignTo(context string, dst *rtype, target unsafe.Pointer) Value {
if v.flag&flagMethod != 0 {
v = makeMethodValue(context, v)
}
@@ -2048,20 +2002,20 @@ func (v Value) assignTo(context string, dst *rtype, target *interface{}) Value {
// Same memory layout, so no harm done.
v.typ = dst
fl := v.flag & (flagRO | flagAddr | flagIndir)
- fl |= flag(dst.Kind()) << flagKindShift
- return Value{dst, v.val, fl}
+ fl |= flag(dst.Kind())
+ return Value{dst, v.ptr, fl}
case implements(dst, v.typ):
if target == nil {
- target = new(interface{})
+ target = unsafe_New(dst)
}
x := valueInterface(v, false)
if dst.NumMethod() == 0 {
- *target = x
+ *(*interface{})(target) = x
} else {
- ifaceE2I(dst, x, unsafe.Pointer(target))
+ ifaceE2I(dst, x, target)
}
- return Value{dst, unsafe.Pointer(target), flagIndir | flag(Interface)<<flagKindShift}
+ return Value{dst, target, flagIndir | flag(Interface)}
}
// Failed.
@@ -2169,86 +2123,66 @@ func convertOp(dst, src *rtype) func(Value, Type) Value {
// where t is a signed or unsigned int type.
func makeInt(f flag, bits uint64, t Type) Value {
typ := t.common()
- if typ.size > ptrSize {
- // Assume ptrSize >= 4, so this must be uint64.
- ptr := unsafe_New(typ)
- *(*uint64)(unsafe.Pointer(ptr)) = bits
- return Value{typ, ptr, f | flagIndir | flag(typ.Kind())<<flagKindShift}
- }
- var w iword
+ ptr := unsafe_New(typ)
switch typ.size {
case 1:
- *(*uint8)(unsafe.Pointer(&w)) = uint8(bits)
+ *(*uint8)(unsafe.Pointer(ptr)) = uint8(bits)
case 2:
- *(*uint16)(unsafe.Pointer(&w)) = uint16(bits)
+ *(*uint16)(unsafe.Pointer(ptr)) = uint16(bits)
case 4:
- *(*uint32)(unsafe.Pointer(&w)) = uint32(bits)
+ *(*uint32)(unsafe.Pointer(ptr)) = uint32(bits)
case 8:
- *(*uint64)(unsafe.Pointer(&w)) = uint64(bits)
+ *(*uint64)(unsafe.Pointer(ptr)) = bits
}
- return Value{typ, unsafe.Pointer(&w), f | flag(typ.Kind())<<flagKindShift | flagIndir}
+ return Value{typ, ptr, f | flagIndir | flag(typ.Kind())}
}
// makeFloat returns a Value of type t equal to v (possibly truncated to float32),
// where t is a float32 or float64 type.
func makeFloat(f flag, v float64, t Type) Value {
typ := t.common()
- if typ.size > ptrSize {
- // Assume ptrSize >= 4, so this must be float64.
- ptr := unsafe_New(typ)
- *(*float64)(unsafe.Pointer(ptr)) = v
- return Value{typ, ptr, f | flagIndir | flag(typ.Kind())<<flagKindShift}
- }
-
- var w iword
+ ptr := unsafe_New(typ)
switch typ.size {
case 4:
- *(*float32)(unsafe.Pointer(&w)) = float32(v)
+ *(*float32)(unsafe.Pointer(ptr)) = float32(v)
case 8:
- *(*float64)(unsafe.Pointer(&w)) = v
+ *(*float64)(unsafe.Pointer(ptr)) = v
}
- return Value{typ, unsafe.Pointer(&w), f | flag(typ.Kind())<<flagKindShift | flagIndir}
+ return Value{typ, ptr, f | flagIndir | flag(typ.Kind())}
}
// makeComplex returns a Value of type t equal to v (possibly truncated to complex64),
// where t is a complex64 or complex128 type.
func makeComplex(f flag, v complex128, t Type) Value {
typ := t.common()
- if typ.size > ptrSize {
- ptr := unsafe_New(typ)
- switch typ.size {
- case 8:
- *(*complex64)(unsafe.Pointer(ptr)) = complex64(v)
- case 16:
- *(*complex128)(unsafe.Pointer(ptr)) = v
- }
- return Value{typ, ptr, f | flagIndir | flag(typ.Kind())<<flagKindShift}
+ ptr := unsafe_New(typ)
+ switch typ.size {
+ case 8:
+ *(*complex64)(unsafe.Pointer(ptr)) = complex64(v)
+ case 16:
+ *(*complex128)(unsafe.Pointer(ptr)) = v
}
-
- // Assume ptrSize <= 8 so this must be complex64.
- var w iword
- *(*complex64)(unsafe.Pointer(&w)) = complex64(v)
- return Value{typ, unsafe.Pointer(&w), f | flag(typ.Kind())<<flagKindShift | flagIndir}
+ return Value{typ, ptr, f | flagIndir | flag(typ.Kind())}
}
func makeString(f flag, v string, t Type) Value {
ret := New(t).Elem()
ret.SetString(v)
- ret.flag = ret.flag&^flagAddr | f | flagIndir
+ ret.flag = ret.flag&^flagAddr | f
return ret
}
func makeBytes(f flag, v []byte, t Type) Value {
ret := New(t).Elem()
ret.SetBytes(v)
- ret.flag = ret.flag&^flagAddr | f | flagIndir
+ ret.flag = ret.flag&^flagAddr | f
return ret
}
func makeRunes(f flag, v []rune, t Type) Value {
ret := New(t).Elem()
ret.setRunes(v)
- ret.flag = ret.flag&^flagAddr | f | flagIndir
+ ret.flag = ret.flag&^flagAddr | f
return ret
}
@@ -2331,27 +2265,27 @@ func cvtStringRunes(v Value, t Type) Value {
func cvtDirect(v Value, typ Type) Value {
f := v.flag
t := typ.common()
- val := v.val
+ ptr := v.ptr
if f&flagAddr != 0 {
// indirect, mutable word - make a copy
- ptr := unsafe_New(t)
- memmove(ptr, val, t.size)
- val = ptr
+ c := unsafe_New(t)
+ memmove(c, ptr, t.size)
+ ptr = c
f &^= flagAddr
}
- return Value{t, val, v.flag&flagRO | f}
+ return Value{t, ptr, v.flag&flagRO | f} // v.flag&flagRO|f == f?
}
// convertOp: concrete -> interface
func cvtT2I(v Value, typ Type) Value {
- target := new(interface{})
+ target := unsafe_New(typ.common())
x := valueInterface(v, false)
if typ.NumMethod() == 0 {
- *target = x
+ *(*interface{})(target) = x
} else {
- ifaceE2I(typ.(*rtype), x, unsafe.Pointer(target))
+ ifaceE2I(typ.(*rtype), x, target)
}
- return Value{typ.common(), unsafe.Pointer(target), v.flag&flagRO | flagIndir | flag(Interface)<<flagKindShift}
+ return Value{typ.common(), target, v.flag&flagRO | flagIndir | flag(Interface)}
}
// convertOp: interface -> interface
@@ -2364,25 +2298,34 @@ func cvtI2I(v Value, typ Type) Value {
return cvtT2I(v.Elem(), typ)
}
-// implemented in ../pkg/runtime
-func chancap(ch iword) int
-func chanclose(ch iword)
-func chanlen(ch iword) int
-func chanrecv(t *rtype, ch iword, nb bool) (val iword, selected, received bool)
-func chansend(t *rtype, ch iword, val iword, nb bool) bool
+// implemented in ../runtime
+func chancap(ch unsafe.Pointer) int
+func chanclose(ch unsafe.Pointer)
+func chanlen(ch unsafe.Pointer) int
+
+//go:noescape
+func chanrecv(t *rtype, ch unsafe.Pointer, nb bool, val unsafe.Pointer) (selected, received bool)
-func makechan(typ *rtype, size uint64) (ch iword)
-func makemap(t *rtype) (m iword)
-func mapaccess(t *rtype, m iword, key iword) (val iword, ok bool)
-func mapassign(t *rtype, m iword, key, val iword, ok bool)
-func mapiterinit(t *rtype, m iword) *byte
-func mapiterkey(it *byte) (key iword, ok bool)
-func mapiternext(it *byte)
-func maplen(m iword) int
+//go:noescape
+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)
+func mapaccess(t *rtype, m unsafe.Pointer, key unsafe.Pointer) (val unsafe.Pointer)
+func mapassign(t *rtype, m unsafe.Pointer, key, val unsafe.Pointer)
+func mapdelete(t *rtype, m unsafe.Pointer, key unsafe.Pointer)
+func mapiterinit(t *rtype, m unsafe.Pointer) unsafe.Pointer
+func mapiterkey(it unsafe.Pointer) (key unsafe.Pointer)
+func mapiternext(it unsafe.Pointer)
+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)
+//go:noescape
+//extern memmove
+func memmove(adst, asrc unsafe.Pointer, n uintptr)
+
// Dummy annotation marking that the value x escapes,
// for use in cases where the reflect code is so clever that
// the compiler cannot follow.
diff --git a/libgo/go/regexp/all_test.go b/libgo/go/regexp/all_test.go
index e914a7ccb4..01ea3742a8 100644
--- a/libgo/go/regexp/all_test.go
+++ b/libgo/go/regexp/all_test.go
@@ -6,6 +6,7 @@ package regexp
import (
"reflect"
+ "regexp/syntax"
"strings"
"testing"
)
@@ -473,6 +474,21 @@ func TestSplit(t *testing.T) {
}
}
+// Check that one-pass cutoff does trigger.
+func TestOnePassCutoff(t *testing.T) {
+ re, err := syntax.Parse(`^x{1,1000}y{1,1000}$`, syntax.Perl)
+ if err != nil {
+ t.Fatalf("parse: %v", err)
+ }
+ p, err := syntax.Compile(re.Simplify())
+ if err != nil {
+ t.Fatalf("compile: %v", err)
+ }
+ if compileOnePass(p) != notOnePass {
+ t.Fatalf("makeOnePass succeeded; wanted notOnePass")
+ }
+}
+
func BenchmarkLiteral(b *testing.B) {
x := strings.Repeat("x", 50) + "y"
b.StopTimer()
@@ -578,3 +594,63 @@ func BenchmarkAnchoredLongMatch(b *testing.B) {
re.Match(x)
}
}
+
+func BenchmarkOnePassShortA(b *testing.B) {
+ b.StopTimer()
+ x := []byte("abcddddddeeeededd")
+ re := MustCompile("^.bc(d|e)*$")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ re.Match(x)
+ }
+}
+
+func BenchmarkNotOnePassShortA(b *testing.B) {
+ b.StopTimer()
+ x := []byte("abcddddddeeeededd")
+ re := MustCompile(".bc(d|e)*$")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ re.Match(x)
+ }
+}
+
+func BenchmarkOnePassShortB(b *testing.B) {
+ b.StopTimer()
+ x := []byte("abcddddddeeeededd")
+ re := MustCompile("^.bc(?:d|e)*$")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ re.Match(x)
+ }
+}
+
+func BenchmarkNotOnePassShortB(b *testing.B) {
+ b.StopTimer()
+ x := []byte("abcddddddeeeededd")
+ re := MustCompile(".bc(?:d|e)*$")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ re.Match(x)
+ }
+}
+
+func BenchmarkOnePassLongPrefix(b *testing.B) {
+ b.StopTimer()
+ x := []byte("abcdefghijklmnopqrstuvwxyz")
+ re := MustCompile("^abcdefghijklmnopqrstuvwxyz.*$")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ re.Match(x)
+ }
+}
+
+func BenchmarkOnePassLongNotPrefix(b *testing.B) {
+ b.StopTimer()
+ x := []byte("abcdefghijklmnopqrstuvwxyz")
+ re := MustCompile("^.bcdefghijklmnopqrstuvwxyz.*$")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ re.Match(x)
+ }
+}
diff --git a/libgo/go/regexp/exec.go b/libgo/go/regexp/exec.go
index 333ca25542..c4cb201f64 100644
--- a/libgo/go/regexp/exec.go
+++ b/libgo/go/regexp/exec.go
@@ -37,6 +37,7 @@ type thread struct {
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
@@ -66,8 +67,8 @@ func (m *machine) newInputReader(r io.RuneReader) input {
}
// progMachine returns a new machine running the prog p.
-func progMachine(p *syntax.Prog) *machine {
- m := &machine{p: p}
+func progMachine(p *syntax.Prog, op *onePassProg) *machine {
+ m := &machine{p: p, op: op}
n := len(m.p.Inst)
m.q0 = queue{make([]uint32, n), make([]entry, 0, n)}
m.q1 = queue{make([]uint32, n), make([]entry, 0, n)}
@@ -312,6 +313,105 @@ func (m *machine) add(q *queue, pc uint32, pos int, cap []int, cond syntax.Empty
return t
}
+// onepass runs the machine over the input starting at pos.
+// It reports whether a match was found.
+// If so, m.matchcap holds the submatch information.
+func (m *machine) onepass(i input, pos int) bool {
+ startCond := m.re.cond
+ if startCond == ^syntax.EmptyOp(0) { // impossible
+ return false
+ }
+ m.matched = false
+ for i := range m.matchcap {
+ m.matchcap[i] = -1
+ }
+ r, r1 := endOfText, endOfText
+ width, width1 := 0, 0
+ r, width = i.step(pos)
+ if r != endOfText {
+ r1, width1 = i.step(pos + width)
+ }
+ var flag syntax.EmptyOp
+ if pos == 0 {
+ flag = syntax.EmptyOpContext(-1, r)
+ } else {
+ flag = i.context(pos)
+ }
+ pc := m.op.Start
+ inst := m.op.Inst[pc]
+ // If there is a simple literal prefix, skip over it.
+ if pos == 0 && syntax.EmptyOp(inst.Arg)&^flag == 0 &&
+ len(m.re.prefix) > 0 && i.canCheckPrefix() {
+ // Match requires literal prefix; fast search for it.
+ if i.hasPrefix(m.re) {
+ pos += len(m.re.prefix)
+ r, width = i.step(pos)
+ r1, width1 = i.step(pos + width)
+ flag = i.context(pos)
+ pc = int(m.re.prefixEnd)
+ } else {
+ return m.matched
+ }
+ }
+ for {
+ inst = m.op.Inst[pc]
+ pc = int(inst.Out)
+ switch inst.Op {
+ default:
+ panic("bad inst")
+ case syntax.InstMatch:
+ m.matched = true
+ if len(m.matchcap) > 0 {
+ m.matchcap[0] = 0
+ m.matchcap[1] = pos
+ }
+ return m.matched
+ case syntax.InstRune:
+ if !inst.MatchRune(r) {
+ return m.matched
+ }
+ case syntax.InstRune1:
+ if r != inst.Rune[0] {
+ return m.matched
+ }
+ case syntax.InstRuneAny:
+ // Nothing
+ case syntax.InstRuneAnyNotNL:
+ if r == '\n' {
+ return m.matched
+ }
+ // peek at the input rune to see which branch of the Alt to take
+ case syntax.InstAlt, syntax.InstAltMatch:
+ pc = int(onePassNext(&inst, r))
+ continue
+ case syntax.InstFail:
+ return m.matched
+ case syntax.InstNop:
+ continue
+ case syntax.InstEmptyWidth:
+ if syntax.EmptyOp(inst.Arg)&^flag != 0 {
+ return m.matched
+ }
+ continue
+ case syntax.InstCapture:
+ if int(inst.Arg) < len(m.matchcap) {
+ m.matchcap[inst.Arg] = pos
+ }
+ continue
+ }
+ if width == 0 {
+ break
+ }
+ flag = syntax.EmptyOpContext(r, r1)
+ pos += width
+ r, width = r1, width1
+ if r != endOfText {
+ r1, width1 = i.step(pos + width)
+ }
+ }
+ return m.matched
+}
+
// empty is a non-nil 0-element slice,
// so doExecute can avoid an allocation
// when 0 captures are requested from a successful match.
@@ -329,16 +429,23 @@ func (re *Regexp) doExecute(r io.RuneReader, b []byte, s string, pos int, ncap i
} else {
i = m.newInputString(s)
}
- m.init(ncap)
- if !m.match(i, pos) {
- re.put(m)
- return nil
+ if m.op != notOnePass {
+ if !m.onepass(i, pos) {
+ re.put(m)
+ return nil
+ }
+ } else {
+ m.init(ncap)
+ if !m.match(i, pos) {
+ re.put(m)
+ return nil
+ }
}
if ncap == 0 {
re.put(m)
return empty // empty but not nil
}
- cap := make([]int, ncap)
+ cap := make([]int, len(m.matchcap))
copy(cap, m.matchcap)
re.put(m)
return cap
diff --git a/libgo/go/regexp/onepass.go b/libgo/go/regexp/onepass.go
new file mode 100644
index 0000000000..e6f4285638
--- /dev/null
+++ b/libgo/go/regexp/onepass.go
@@ -0,0 +1,581 @@
+// 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 regexp
+
+import (
+ "bytes"
+ "regexp/syntax"
+ "sort"
+ "unicode"
+)
+
+// "One-pass" regexp execution.
+// Some regexps can be analyzed to determine that they never need
+// backtracking: they are guaranteed to run in one pass over the string
+// without bothering to save all the usual NFA state.
+// Detect those and execute them more quickly.
+
+// A onePassProg is a compiled one-pass regular expression program.
+// It is the same as syntax.Prog except for the use of onePassInst.
+type onePassProg struct {
+ Inst []onePassInst
+ Start int // index of start instruction
+ NumCap int // number of InstCapture insts in re
+}
+
+// A onePassInst is a single instruction in a one-pass regular expression program.
+// It is the same as syntax.Inst except for the new 'Next' field.
+type onePassInst struct {
+ syntax.Inst
+ Next []uint32
+}
+
+// OnePassPrefix returns a literal string that all matches for the
+// regexp must start with. Complete is true if the prefix
+// is the entire match. Pc is the index of the last rune instruction
+// in the string. The OnePassPrefix skips over the mandatory
+// EmptyBeginText
+func onePassPrefix(p *syntax.Prog) (prefix string, complete bool, pc uint32) {
+ i := &p.Inst[p.Start]
+ if i.Op != syntax.InstEmptyWidth || (syntax.EmptyOp(i.Arg))&syntax.EmptyBeginText == 0 {
+ return "", i.Op == syntax.InstMatch, uint32(p.Start)
+ }
+ pc = i.Out
+ i = &p.Inst[pc]
+ for i.Op == syntax.InstNop {
+ pc = i.Out
+ i = &p.Inst[pc]
+ }
+ // Avoid allocation of buffer if prefix is empty.
+ if iop(i) != syntax.InstRune || len(i.Rune) != 1 {
+ return "", i.Op == syntax.InstMatch, uint32(p.Start)
+ }
+
+ // Have prefix; gather characters.
+ var buf bytes.Buffer
+ for iop(i) == syntax.InstRune && len(i.Rune) == 1 && syntax.Flags(i.Arg)&syntax.FoldCase == 0 {
+ buf.WriteRune(i.Rune[0])
+ pc, i = i.Out, &p.Inst[i.Out]
+ }
+ return buf.String(), i.Op == syntax.InstEmptyWidth && (syntax.EmptyOp(i.Arg))&syntax.EmptyBeginText != 0, pc
+}
+
+// OnePassNext selects the next actionable state of the prog, based on the input character.
+// It should only be called when i.Op == InstAlt or InstAltMatch, and from the one-pass machine.
+// One of the alternates may ultimately lead without input to end of line. If the instruction
+// is InstAltMatch the path to the InstMatch is in i.Out, the normal node in i.Next.
+func onePassNext(i *onePassInst, r rune) uint32 {
+ next := i.MatchRunePos(r)
+ if next >= 0 {
+ return i.Next[next]
+ }
+ if i.Op == syntax.InstAltMatch {
+ return i.Out
+ }
+ return 0
+}
+
+func iop(i *syntax.Inst) syntax.InstOp {
+ op := i.Op
+ switch op {
+ case syntax.InstRune1, syntax.InstRuneAny, syntax.InstRuneAnyNotNL:
+ op = syntax.InstRune
+ }
+ return op
+}
+
+// Sparse Array implementation is used as a queueOnePass.
+type queueOnePass struct {
+ sparse []uint32
+ dense []uint32
+ size, nextIndex uint32
+}
+
+func (q *queueOnePass) empty() bool {
+ return q.nextIndex >= q.size
+}
+
+func (q *queueOnePass) next() (n uint32) {
+ n = q.dense[q.nextIndex]
+ q.nextIndex++
+ return
+}
+
+func (q *queueOnePass) clear() {
+ q.size = 0
+ q.nextIndex = 0
+}
+
+func (q *queueOnePass) reset() {
+ q.nextIndex = 0
+}
+
+func (q *queueOnePass) contains(u uint32) bool {
+ if u >= uint32(len(q.sparse)) {
+ return false
+ }
+ return q.sparse[u] < q.size && q.dense[q.sparse[u]] == u
+}
+
+func (q *queueOnePass) insert(u uint32) {
+ if !q.contains(u) {
+ q.insertNew(u)
+ }
+}
+
+func (q *queueOnePass) insertNew(u uint32) {
+ if u >= uint32(len(q.sparse)) {
+ return
+ }
+ q.sparse[u] = q.size
+ q.dense[q.size] = u
+ q.size++
+}
+
+func newQueue(size int) (q *queueOnePass) {
+ return &queueOnePass{
+ sparse: make([]uint32, size),
+ dense: make([]uint32, size),
+ }
+}
+
+// mergeRuneSets merges two non-intersecting runesets, and returns the merged result,
+// and a NextIp array. The idea is that if a rune matches the OnePassRunes at index
+// i, NextIp[i/2] is the target. If the input sets intersect, an empty runeset and a
+// NextIp array with the single element mergeFailed is returned.
+// The code assumes that both inputs contain ordered and non-intersecting rune pairs.
+const mergeFailed = uint32(0xffffffff)
+
+var (
+ noRune = []rune{}
+ noNext = []uint32{mergeFailed}
+)
+
+func mergeRuneSets(leftRunes, rightRunes *[]rune, leftPC, rightPC uint32) ([]rune, []uint32) {
+ leftLen := len(*leftRunes)
+ rightLen := len(*rightRunes)
+ if leftLen&0x1 != 0 || rightLen&0x1 != 0 {
+ panic("mergeRuneSets odd length []rune")
+ }
+ var (
+ lx, rx int
+ )
+ merged := make([]rune, 0)
+ next := make([]uint32, 0)
+ ok := true
+ defer func() {
+ if !ok {
+ merged = nil
+ next = nil
+ }
+ }()
+
+ ix := -1
+ extend := func(newLow *int, newArray *[]rune, pc uint32) bool {
+ if ix > 0 && (*newArray)[*newLow] <= merged[ix] {
+ return false
+ }
+ merged = append(merged, (*newArray)[*newLow], (*newArray)[*newLow+1])
+ *newLow += 2
+ ix += 2
+ next = append(next, pc)
+ return true
+ }
+
+ for lx < leftLen || rx < rightLen {
+ switch {
+ case rx >= rightLen:
+ ok = extend(&lx, leftRunes, leftPC)
+ case lx >= leftLen:
+ ok = extend(&rx, rightRunes, rightPC)
+ case (*rightRunes)[rx] < (*leftRunes)[lx]:
+ ok = extend(&rx, rightRunes, rightPC)
+ default:
+ ok = extend(&lx, leftRunes, leftPC)
+ }
+ if !ok {
+ return noRune, noNext
+ }
+ }
+ return merged, next
+}
+
+// cleanupOnePass drops working memory, and restores certain shortcut instructions.
+func cleanupOnePass(prog *onePassProg, original *syntax.Prog) {
+ for ix, instOriginal := range original.Inst {
+ switch instOriginal.Op {
+ case syntax.InstAlt, syntax.InstAltMatch, syntax.InstRune:
+ case syntax.InstCapture, syntax.InstEmptyWidth, syntax.InstNop, syntax.InstMatch, syntax.InstFail:
+ prog.Inst[ix].Next = nil
+ case syntax.InstRune1, syntax.InstRuneAny, syntax.InstRuneAnyNotNL:
+ prog.Inst[ix].Next = nil
+ prog.Inst[ix] = onePassInst{Inst: instOriginal}
+ }
+ }
+}
+
+// onePassCopy creates a copy of the original Prog, as we'll be modifying it
+func onePassCopy(prog *syntax.Prog) *onePassProg {
+ p := &onePassProg{
+ Start: prog.Start,
+ NumCap: prog.NumCap,
+ }
+ for _, inst := range prog.Inst {
+ p.Inst = append(p.Inst, onePassInst{Inst: inst})
+ }
+
+ // rewrites one or more common Prog constructs that enable some otherwise
+ // non-onepass Progs to be onepass. A:BD (for example) means an InstAlt at
+ // ip A, that points to ips B & C.
+ // A:BC + B:DA => A:BC + B:CD
+ // A:BC + B:DC => A:DC + B:DC
+ for pc := range p.Inst {
+ switch p.Inst[pc].Op {
+ default:
+ continue
+ case syntax.InstAlt, syntax.InstAltMatch:
+ // A:Bx + B:Ay
+ p_A_Other := &p.Inst[pc].Out
+ p_A_Alt := &p.Inst[pc].Arg
+ // make sure a target is another Alt
+ instAlt := p.Inst[*p_A_Alt]
+ if !(instAlt.Op == syntax.InstAlt || instAlt.Op == syntax.InstAltMatch) {
+ p_A_Alt, p_A_Other = p_A_Other, p_A_Alt
+ instAlt = p.Inst[*p_A_Alt]
+ if !(instAlt.Op == syntax.InstAlt || instAlt.Op == syntax.InstAltMatch) {
+ continue
+ }
+ }
+ instOther := p.Inst[*p_A_Other]
+ // Analyzing both legs pointing to Alts is for another day
+ if instOther.Op == syntax.InstAlt || instOther.Op == syntax.InstAltMatch {
+ // too complicated
+ continue
+ }
+ // simple empty transition loop
+ // A:BC + B:DA => A:BC + B:DC
+ p_B_Alt := &p.Inst[*p_A_Alt].Out
+ p_B_Other := &p.Inst[*p_A_Alt].Arg
+ patch := false
+ if instAlt.Out == uint32(pc) {
+ patch = true
+ } else if instAlt.Arg == uint32(pc) {
+ patch = true
+ p_B_Alt, p_B_Other = p_B_Other, p_B_Alt
+ }
+ if patch {
+ *p_B_Alt = *p_A_Other
+ }
+
+ // empty transition to common target
+ // A:BC + B:DC => A:DC + B:DC
+ if *p_A_Other == *p_B_Alt {
+ *p_A_Alt = *p_B_Other
+ }
+ }
+ }
+ return p
+}
+
+// runeSlice exists to permit sorting the case-folded rune sets.
+type runeSlice []rune
+
+func (p runeSlice) Len() int { return len(p) }
+func (p runeSlice) Less(i, j int) bool { return p[i] < p[j] }
+func (p runeSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+
+// Sort is a convenience method.
+func (p runeSlice) Sort() {
+ sort.Sort(p)
+}
+
+var anyRuneNotNL = []rune{0, '\n' - 1, '\n' + 1, unicode.MaxRune}
+var anyRune = []rune{0, unicode.MaxRune}
+
+// makeOnePass creates a onepass Prog, if possible. It is possible if at any alt,
+// the match engine can always tell which branch to take. The routine may modify
+// p if it is turned into a onepass Prog. If it isn't possible for this to be a
+// onepass Prog, the Prog notOnePass is returned. makeOnePass is recursive
+// to the size of the Prog.
+func makeOnePass(p *onePassProg) *onePassProg {
+ // If the machine is very long, it's not worth the time to check if we can use one pass.
+ if len(p.Inst) >= 1000 {
+ return notOnePass
+ }
+
+ var (
+ instQueue = newQueue(len(p.Inst))
+ visitQueue = newQueue(len(p.Inst))
+ build func(uint32, *queueOnePass)
+ check func(uint32, map[uint32]bool) bool
+ onePassRunes = make([][]rune, len(p.Inst))
+ )
+ build = func(pc uint32, q *queueOnePass) {
+ if q.contains(pc) {
+ return
+ }
+ inst := p.Inst[pc]
+ switch inst.Op {
+ case syntax.InstAlt, syntax.InstAltMatch:
+ q.insert(inst.Out)
+ build(inst.Out, q)
+ q.insert(inst.Arg)
+ case syntax.InstMatch, syntax.InstFail:
+ default:
+ q.insert(inst.Out)
+ }
+ }
+
+ // check that paths from Alt instructions are unambiguous, and rebuild the new
+ // program as a onepass program
+ check = func(pc uint32, m map[uint32]bool) (ok bool) {
+ ok = true
+ inst := &p.Inst[pc]
+ if visitQueue.contains(pc) {
+ return
+ }
+ visitQueue.insert(pc)
+ switch inst.Op {
+ case syntax.InstAlt, syntax.InstAltMatch:
+ ok = check(inst.Out, m) && check(inst.Arg, m)
+ // check no-input paths to InstMatch
+ matchOut := m[inst.Out]
+ matchArg := m[inst.Arg]
+ if matchOut && matchArg {
+ ok = false
+ break
+ }
+ // Match on empty goes in inst.Out
+ if matchArg {
+ inst.Out, inst.Arg = inst.Arg, inst.Out
+ matchOut, matchArg = matchArg, matchOut
+ }
+ if matchOut {
+ m[pc] = true
+ inst.Op = syntax.InstAltMatch
+ }
+
+ // build a dispatch operator from the two legs of the alt.
+ onePassRunes[pc], inst.Next = mergeRuneSets(
+ &onePassRunes[inst.Out], &onePassRunes[inst.Arg], inst.Out, inst.Arg)
+ if len(inst.Next) > 0 && inst.Next[0] == mergeFailed {
+ ok = false
+ break
+ }
+ case syntax.InstCapture, syntax.InstNop:
+ ok = check(inst.Out, m)
+ m[pc] = m[inst.Out]
+ // pass matching runes back through these no-ops.
+ onePassRunes[pc] = append([]rune{}, onePassRunes[inst.Out]...)
+ inst.Next = []uint32{}
+ for i := len(onePassRunes[pc]) / 2; i >= 0; i-- {
+ inst.Next = append(inst.Next, inst.Out)
+ }
+ case syntax.InstEmptyWidth:
+ ok = check(inst.Out, m)
+ m[pc] = m[inst.Out]
+ onePassRunes[pc] = append([]rune{}, onePassRunes[inst.Out]...)
+ inst.Next = []uint32{}
+ for i := len(onePassRunes[pc]) / 2; i >= 0; i-- {
+ inst.Next = append(inst.Next, inst.Out)
+ }
+ case syntax.InstMatch, syntax.InstFail:
+ m[pc] = inst.Op == syntax.InstMatch
+ break
+ case syntax.InstRune:
+ ok = check(inst.Out, m)
+ m[pc] = false
+ if len(inst.Next) > 0 {
+ break
+ }
+ if len(inst.Rune) == 0 {
+ onePassRunes[pc] = []rune{}
+ inst.Next = []uint32{inst.Out}
+ break
+ }
+ runes := make([]rune, 0)
+ if len(inst.Rune) == 1 && syntax.Flags(inst.Arg)&syntax.FoldCase != 0 {
+ r0 := inst.Rune[0]
+ runes = append(runes, r0, r0)
+ for r1 := unicode.SimpleFold(r0); r1 != r0; r1 = unicode.SimpleFold(r1) {
+ runes = append(runes, r1, r1)
+ }
+ sort.Sort(runeSlice(runes))
+ } else {
+ runes = append(runes, inst.Rune...)
+ }
+ onePassRunes[pc] = runes
+ inst.Next = []uint32{}
+ for i := len(onePassRunes[pc]) / 2; i >= 0; i-- {
+ inst.Next = append(inst.Next, inst.Out)
+ }
+ inst.Op = syntax.InstRune
+ case syntax.InstRune1:
+ ok = check(inst.Out, m)
+ m[pc] = false
+ if len(inst.Next) > 0 {
+ break
+ }
+ runes := []rune{}
+ // expand case-folded runes
+ if syntax.Flags(inst.Arg)&syntax.FoldCase != 0 {
+ r0 := inst.Rune[0]
+ runes = append(runes, r0, r0)
+ for r1 := unicode.SimpleFold(r0); r1 != r0; r1 = unicode.SimpleFold(r1) {
+ runes = append(runes, r1, r1)
+ }
+ sort.Sort(runeSlice(runes))
+ } else {
+ runes = append(runes, inst.Rune[0], inst.Rune[0])
+ }
+ onePassRunes[pc] = runes
+ inst.Next = []uint32{}
+ for i := len(onePassRunes[pc]) / 2; i >= 0; i-- {
+ inst.Next = append(inst.Next, inst.Out)
+ }
+ inst.Op = syntax.InstRune
+ case syntax.InstRuneAny:
+ ok = check(inst.Out, m)
+ m[pc] = false
+ if len(inst.Next) > 0 {
+ break
+ }
+ onePassRunes[pc] = append([]rune{}, anyRune...)
+ inst.Next = []uint32{inst.Out}
+ case syntax.InstRuneAnyNotNL:
+ ok = check(inst.Out, m)
+ m[pc] = false
+ if len(inst.Next) > 0 {
+ break
+ }
+ onePassRunes[pc] = append([]rune{}, anyRuneNotNL...)
+ inst.Next = []uint32{}
+ for i := len(onePassRunes[pc]) / 2; i >= 0; i-- {
+ inst.Next = append(inst.Next, inst.Out)
+ }
+ }
+ return
+ }
+
+ instQueue.clear()
+ instQueue.insert(uint32(p.Start))
+ m := make(map[uint32]bool, len(p.Inst))
+ for !instQueue.empty() {
+ pc := instQueue.next()
+ inst := p.Inst[pc]
+ visitQueue.clear()
+ if !check(uint32(pc), m) {
+ p = notOnePass
+ break
+ }
+ switch inst.Op {
+ case syntax.InstAlt, syntax.InstAltMatch:
+ instQueue.insert(inst.Out)
+ instQueue.insert(inst.Arg)
+ case syntax.InstCapture, syntax.InstEmptyWidth, syntax.InstNop:
+ instQueue.insert(inst.Out)
+ case syntax.InstMatch:
+ case syntax.InstFail:
+ case syntax.InstRune, syntax.InstRune1, syntax.InstRuneAny, syntax.InstRuneAnyNotNL:
+ default:
+ }
+ }
+ if p != notOnePass {
+ for i := range p.Inst {
+ p.Inst[i].Rune = onePassRunes[i]
+ }
+ }
+ return p
+}
+
+// walk visits each Inst in the prog once, and applies the argument
+// function(ip, next), in pre-order.
+func walk(prog *syntax.Prog, funcs ...func(ip, next uint32)) {
+ var walk1 func(uint32)
+ progQueue := newQueue(len(prog.Inst))
+ walk1 = func(ip uint32) {
+ if progQueue.contains(ip) {
+ return
+ }
+ progQueue.insert(ip)
+ inst := prog.Inst[ip]
+ switch inst.Op {
+ case syntax.InstAlt, syntax.InstAltMatch:
+ for _, f := range funcs {
+ f(ip, inst.Out)
+ f(ip, inst.Arg)
+ }
+ walk1(inst.Out)
+ walk1(inst.Arg)
+ default:
+ for _, f := range funcs {
+ f(ip, inst.Out)
+ }
+ walk1(inst.Out)
+ }
+ }
+ walk1(uint32(prog.Start))
+}
+
+// find returns the Insts that match the argument predicate function
+func find(prog *syntax.Prog, f func(*syntax.Prog, int) bool) (matches []uint32) {
+ matches = []uint32{}
+
+ for ip := range prog.Inst {
+ if f(prog, ip) {
+ matches = append(matches, uint32(ip))
+ }
+ }
+ return
+}
+
+var notOnePass *onePassProg = nil
+
+// compileOnePass returns a new *syntax.Prog suitable for onePass execution if the original Prog
+// can be recharacterized as a one-pass regexp program, or syntax.notOnePass if the
+// Prog cannot be converted. For a one pass prog, the fundamental condition that must
+// be true is: at any InstAlt, there must be no ambiguity about what branch to take.
+func compileOnePass(prog *syntax.Prog) (p *onePassProg) {
+ if prog.Start == 0 {
+ return notOnePass
+ }
+ // onepass regexp is anchored
+ if prog.Inst[prog.Start].Op != syntax.InstEmptyWidth ||
+ syntax.EmptyOp(prog.Inst[prog.Start].Arg)&syntax.EmptyBeginText != syntax.EmptyBeginText {
+ return notOnePass
+ }
+ // every instruction leading to InstMatch must be EmptyEndText
+ for _, inst := range prog.Inst {
+ opOut := prog.Inst[inst.Out].Op
+ switch inst.Op {
+ default:
+ if opOut == syntax.InstMatch {
+ return notOnePass
+ }
+ case syntax.InstAlt, syntax.InstAltMatch:
+ if opOut == syntax.InstMatch || prog.Inst[inst.Arg].Op == syntax.InstMatch {
+ return notOnePass
+ }
+ case syntax.InstEmptyWidth:
+ if opOut == syntax.InstMatch {
+ if syntax.EmptyOp(inst.Arg)&syntax.EmptyEndText == syntax.EmptyEndText {
+ continue
+ }
+ return notOnePass
+ }
+ }
+ }
+ // Creates a slightly optimized copy of the original Prog
+ // that cleans up some Prog idioms that block valid onepass programs
+ p = onePassCopy(prog)
+
+ // checkAmbiguity on InstAlts, build onepass Prog if possible
+ p = makeOnePass(p)
+
+ if p != notOnePass {
+ cleanupOnePass(p, prog)
+ }
+ return p
+}
diff --git a/libgo/go/regexp/onepass_test.go b/libgo/go/regexp/onepass_test.go
new file mode 100644
index 0000000000..7b2beea67f
--- /dev/null
+++ b/libgo/go/regexp/onepass_test.go
@@ -0,0 +1,208 @@
+// 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 regexp
+
+import (
+ "reflect"
+ "regexp/syntax"
+ "testing"
+)
+
+var runeMergeTests = []struct {
+ left, right, merged []rune
+ next []uint32
+ leftPC, rightPC uint32
+}{
+ {
+ // empty rhs
+ []rune{69, 69},
+ []rune{},
+ []rune{69, 69},
+ []uint32{1},
+ 1, 2,
+ },
+ {
+ // identical runes, identical targets
+ []rune{69, 69},
+ []rune{69, 69},
+ []rune{},
+ []uint32{mergeFailed},
+ 1, 1,
+ },
+ {
+ // identical runes, different targets
+ []rune{69, 69},
+ []rune{69, 69},
+ []rune{},
+ []uint32{mergeFailed},
+ 1, 2,
+ },
+ {
+ // append right-first
+ []rune{69, 69},
+ []rune{71, 71},
+ []rune{69, 69, 71, 71},
+ []uint32{1, 2},
+ 1, 2,
+ },
+ {
+ // append, left-first
+ []rune{71, 71},
+ []rune{69, 69},
+ []rune{69, 69, 71, 71},
+ []uint32{2, 1},
+ 1, 2,
+ },
+ {
+ // successful interleave
+ []rune{60, 60, 71, 71, 101, 101},
+ []rune{69, 69, 88, 88},
+ []rune{60, 60, 69, 69, 71, 71, 88, 88, 101, 101},
+ []uint32{1, 2, 1, 2, 1},
+ 1, 2,
+ },
+ {
+ // left surrounds right
+ []rune{69, 74},
+ []rune{71, 71},
+ []rune{},
+ []uint32{mergeFailed},
+ 1, 2,
+ },
+ {
+ // right surrounds left
+ []rune{69, 74},
+ []rune{68, 75},
+ []rune{},
+ []uint32{mergeFailed},
+ 1, 2,
+ },
+ {
+ // overlap at interval begin
+ []rune{69, 74},
+ []rune{74, 75},
+ []rune{},
+ []uint32{mergeFailed},
+ 1, 2,
+ },
+ {
+ // overlap ar interval end
+ []rune{69, 74},
+ []rune{65, 69},
+ []rune{},
+ []uint32{mergeFailed},
+ 1, 2,
+ },
+ {
+ // overlap from above
+ []rune{69, 74},
+ []rune{71, 74},
+ []rune{},
+ []uint32{mergeFailed},
+ 1, 2,
+ },
+ {
+ // overlap from below
+ []rune{69, 74},
+ []rune{65, 71},
+ []rune{},
+ []uint32{mergeFailed},
+ 1, 2,
+ },
+ {
+ // out of order []rune
+ []rune{69, 74, 60, 65},
+ []rune{66, 67},
+ []rune{},
+ []uint32{mergeFailed},
+ 1, 2,
+ },
+}
+
+func TestMergeRuneSet(t *testing.T) {
+ for ix, test := range runeMergeTests {
+ merged, next := mergeRuneSets(&test.left, &test.right, test.leftPC, test.rightPC)
+ if !reflect.DeepEqual(merged, test.merged) {
+ t.Errorf("mergeRuneSet :%d (%v, %v) merged\n have\n%v\nwant\n%v", ix, test.left, test.right, merged, test.merged)
+ }
+ if !reflect.DeepEqual(next, test.next) {
+ t.Errorf("mergeRuneSet :%d(%v, %v) next\n have\n%v\nwant\n%v", ix, test.left, test.right, next, test.next)
+ }
+ }
+}
+
+const noStr = `!`
+
+var onePass = &onePassProg{}
+
+var onePassTests = []struct {
+ re string
+ onePass *onePassProg
+ prog string
+}{
+ {`^(?:a|(?:a*))$`, notOnePass, noStr},
+ {`^(?:(a)|(?:a*))$`, notOnePass, noStr},
+ {`^(?:(?:(?:.(?:$))?))$`, onePass, `a`},
+ {`^abcd$`, onePass, `abcd`},
+ {`^abcd$`, onePass, `abcde`},
+ {`^(?:(?:a{0,})*?)$`, onePass, `a`},
+ {`^(?:(?:a+)*)$`, onePass, ``},
+ {`^(?:(?:a|(?:aa)))$`, onePass, ``},
+ {`^(?:[^\s\S])$`, onePass, ``},
+ {`^(?:(?:a{3,4}){0,})$`, notOnePass, `aaaaaa`},
+ {`^(?:(?:a+)*)$`, onePass, `a`},
+ {`^(?:(?:(?:a*)+))$`, onePass, noStr},
+ {`^(?:(?:a+)*)$`, onePass, ``},
+ {`^[a-c]+$`, onePass, `abc`},
+ {`^[a-c]*$`, onePass, `abcdabc`},
+ {`^(?:a*)$`, onePass, `aaaaaaa`},
+ {`^(?:(?:aa)|a)$`, onePass, `a`},
+ {`^[a-c]*`, notOnePass, `abcdabc`},
+ {`^[a-c]*$`, onePass, `abc`},
+ {`^...$`, onePass, ``},
+ {`^(?:a|(?:aa))$`, onePass, `a`},
+ {`^[a-c]*`, notOnePass, `abcabc`},
+ {`^a((b))c$`, onePass, noStr},
+ {`^a.[l-nA-Cg-j]?e$`, onePass, noStr},
+ {`^a((b))$`, onePass, noStr},
+ {`^a(?:(b)|(c))c$`, onePass, noStr},
+ {`^a(?:(b*)|(c))c$`, notOnePass, noStr},
+ {`^a(?:b|c)$`, onePass, noStr},
+ {`^a(?:b?|c)$`, onePass, noStr},
+ {`^a(?:b?|c?)$`, notOnePass, noStr},
+ {`^a(?:b?|c+)$`, onePass, noStr},
+ {`^a(?:b+|(bc))d$`, notOnePass, noStr},
+ {`^a(?:bc)+$`, onePass, noStr},
+ {`^a(?:[bcd])+$`, onePass, noStr},
+ {`^a((?:[bcd])+)$`, onePass, noStr},
+ {`^a(:?b|c)*d$`, onePass, `abbbccbbcbbd"`},
+ {`^.bc(d|e)*$`, onePass, `abcddddddeeeededd`},
+ {`^(?:(?:aa)|.)$`, notOnePass, `a`},
+ {`^(?:(?:a{1,2}){1,2})$`, notOnePass, `aaaa`},
+}
+
+func TestCompileOnePass(t *testing.T) {
+ var (
+ p *syntax.Prog
+ re *syntax.Regexp
+ err error
+ )
+ for _, test := range onePassTests {
+ if re, err = syntax.Parse(test.re, syntax.Perl); err != nil {
+ t.Errorf("Parse(%q) got err:%s, want success", test.re, err)
+ continue
+ }
+ // needs to be done before compile...
+ re = re.Simplify()
+ if p, err = syntax.Compile(re); err != nil {
+ t.Errorf("Compile(%q) got err:%s, want success", test.re, err)
+ continue
+ }
+ onePass = compileOnePass(p)
+ if (onePass == notOnePass) != (test.onePass == notOnePass) {
+ t.Errorf("CompileOnePass(%q) got %v, expected %v", test.re, onePass, test.onePass)
+ }
+ }
+}
diff --git a/libgo/go/regexp/regexp.go b/libgo/go/regexp/regexp.go
index 0046026eae..b615acdf0e 100644
--- a/libgo/go/regexp/regexp.go
+++ b/libgo/go/regexp/regexp.go
@@ -11,6 +11,14 @@
// For an overview of the syntax, run
// godoc regexp/syntax
//
+// The regexp implementation provided by this package is
+// guaranteed to run in time linear in the size of the input.
+// (This is a property not guaranteed by most open source
+// implementations of regular expressions.) For more information
+// about this property, see
+// http://swtch.com/~rsc/regexp/regexp1.html
+// or any book about automata theory.
+//
// All characters are UTF-8-encoded code points.
//
// There are 16 methods of Regexp that match a regular expression and identify
@@ -70,16 +78,17 @@ import (
var debug = false
// Regexp is the representation of a compiled regular expression.
-// The public interface is entirely through methods.
// A Regexp is safe for concurrent use by multiple goroutines.
type Regexp struct {
// read-only after Compile
expr string // as passed to Compile
prog *syntax.Prog // compiled program
+ onepass *onePassProg // onpass program or nil
prefix string // required prefix in unanchored matches
prefixBytes []byte // prefix, as a []byte
prefixComplete bool // prefix is the entire regexp
prefixRune rune // first rune in prefix
+ prefixEnd uint32 // pc for last rune in prefix
cond syntax.EmptyOp // empty-width conditions required at start of match
numSubexp int
subexpNames []string
@@ -156,12 +165,17 @@ func compile(expr string, mode syntax.Flags, longest bool) (*Regexp, error) {
regexp := &Regexp{
expr: expr,
prog: prog,
+ onepass: compileOnePass(prog),
numSubexp: maxCap,
subexpNames: capNames,
cond: prog.StartCond(),
longest: longest,
}
- regexp.prefix, regexp.prefixComplete = prog.Prefix()
+ if regexp.onepass == notOnePass {
+ regexp.prefix, regexp.prefixComplete = prog.Prefix()
+ } else {
+ regexp.prefix, regexp.prefixComplete, regexp.prefixEnd = onePassPrefix(prog)
+ }
if regexp.prefix != "" {
// TODO(rsc): Remove this allocation by adding
// IndexString to package bytes.
@@ -183,7 +197,7 @@ func (re *Regexp) get() *machine {
return z
}
re.mu.Unlock()
- z := progMachine(re.prog)
+ z := progMachine(re.prog, re.onepass)
z.re = re
return z
}
@@ -438,7 +452,7 @@ func (re *Regexp) ReplaceAllString(src, repl string) string {
return string(b)
}
-// ReplaceAllStringLiteral returns a copy of src, replacing matches of the Regexp
+// ReplaceAllLiteralString returns a copy of src, replacing matches of the Regexp
// with the replacement string repl. The replacement repl is substituted directly,
// without using Expand.
func (re *Regexp) ReplaceAllLiteralString(src, repl string) string {
diff --git a/libgo/go/regexp/syntax/doc.go b/libgo/go/regexp/syntax/doc.go
index e52632ef72..e5e71f14f5 100644
--- a/libgo/go/regexp/syntax/doc.go
+++ b/libgo/go/regexp/syntax/doc.go
@@ -21,8 +21,8 @@ Single characters:
[^xyz] negated character class
\d Perl character class
\D negated Perl character class
- [:alpha:] ASCII character class
- [:^alpha:] negated ASCII character class
+ [[:alpha:]] ASCII character class
+ [[:^alpha:]] negated ASCII character class
\pN Unicode character class (one-letter name)
\p{Greek} Unicode character class
\PN negated Unicode character class (one-letter name)
@@ -46,10 +46,14 @@ Repetitions:
x{n,}? n or more x, prefer fewer
x{n}? exactly n x
+Implementation restriction: The counting forms x{n,m}, x{n,}, and x{n}
+reject forms that create a minimum or maximum repetition count above 1000.
+Unlimited repetitions are not subject to this restriction.
+
Grouping:
(re) numbered capturing group (submatch)
(?P<name>re) named & numbered capturing group (submatch)
- (?:re) non-capturing group (submatch)
+ (?:re) non-capturing group
(?flags) set flags within current group; non-capturing
(?flags:re) set flags during re; non-capturing
@@ -65,7 +69,7 @@ Empty strings:
$ at end of text (like \z not \Z) or line (flag m=true)
\A at beginning of text
\b at ASCII word boundary (\w on one side and \W, \A, or \z on the other)
- \B not an ASCII word boundary
+ \B not at ASCII word boundary
\z at end of text
Escape sequences:
@@ -99,29 +103,29 @@ Named character classes as character class elements:
[\p{Name}] named Unicode property inside character class (== \p{Name})
[^\p{Name}] named Unicode property inside negated character class (== \P{Name})
-Perl character classes:
+Perl character classes (all ASCII-only):
\d digits (== [0-9])
\D not digits (== [^0-9])
\s whitespace (== [\t\n\f\r ])
\S not whitespace (== [^\t\n\f\r ])
- \w ASCII word characters (== [0-9A-Za-z_])
- \W not ASCII word characters (== [^0-9A-Za-z_])
+ \w word characters (== [0-9A-Za-z_])
+ \W not word characters (== [^0-9A-Za-z_])
ASCII character classes:
- [:alnum:] alphanumeric (== [0-9A-Za-z])
- [:alpha:] alphabetic (== [A-Za-z])
- [:ascii:] ASCII (== [\x00-\x7F])
- [:blank:] blank (== [\t ])
- [:cntrl:] control (== [\x00-\x1F\x7F])
- [:digit:] digits (== [0-9])
- [:graph:] graphical (== [!-~] == [A-Za-z0-9!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~])
- [:lower:] lower case (== [a-z])
- [:print:] printable (== [ -~] == [ [:graph:]])
- [:punct:] punctuation (== [!-/:-@[-`{-~])
- [:space:] whitespace (== [\t\n\v\f\r ])
- [:upper:] upper case (== [A-Z])
- [:word:] word characters (== [0-9A-Za-z_])
- [:xdigit:] hex digit (== [0-9A-Fa-f])
+ [[:alnum:]] alphanumeric (== [0-9A-Za-z])
+ [[:alpha:]] alphabetic (== [A-Za-z])
+ [[:ascii:]] ASCII (== [\x00-\x7F])
+ [[:blank:]] blank (== [\t ])
+ [[:cntrl:]] control (== [\x00-\x1F\x7F])
+ [[:digit:]] digits (== [0-9])
+ [[:graph:]] graphical (== [!-~] == [A-Za-z0-9!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~])
+ [[:lower:]] lower case (== [a-z])
+ [[:print:]] printable (== [ -~] == [ [:graph:]])
+ [[:punct:]] punctuation (== [!-/:-@[-`{-~])
+ [[:space:]] whitespace (== [\t\n\v\f\r ])
+ [[:upper:]] upper case (== [A-Z])
+ [[:word:]] word characters (== [0-9A-Za-z_])
+ [[:xdigit:]] hex digit (== [0-9A-Fa-f])
*/
package syntax
diff --git a/libgo/go/regexp/syntax/parse.go b/libgo/go/regexp/syntax/parse.go
index 42d0bf4a16..d579a4069b 100644
--- a/libgo/go/regexp/syntax/parse.go
+++ b/libgo/go/regexp/syntax/parse.go
@@ -244,6 +244,7 @@ func (p *parser) repeat(op Op, min, max int, before, after, lastRepeat string) (
if sub.Op >= opPseudo {
return "", &Error{ErrMissingRepeatArgument, before[:len(before)-len(after)]}
}
+
re := p.newRegexp(op)
re.Min = min
re.Max = max
@@ -251,9 +252,47 @@ func (p *parser) repeat(op Op, min, max int, before, after, lastRepeat string) (
re.Sub = re.Sub0[:1]
re.Sub[0] = sub
p.stack[n-1] = re
+
+ if op == OpRepeat && (min >= 2 || max >= 2) && !repeatIsValid(re, 1000) {
+ return "", &Error{ErrInvalidRepeatSize, before[:len(before)-len(after)]}
+ }
+
return after, nil
}
+// repeatIsValid reports whether the repetition re is valid.
+// Valid means that the combination of the top-level repetition
+// and any inner repetitions does not exceed n copies of the
+// innermost thing.
+// This function rewalks the regexp tree and is called for every repetition,
+// so we have to worry about inducing quadratic behavior in the parser.
+// We avoid this by only calling repeatIsValid when min or max >= 2.
+// In that case the depth of any >= 2 nesting can only get to 9 without
+// triggering a parse error, so each subtree can only be rewalked 9 times.
+func repeatIsValid(re *Regexp, n int) bool {
+ if re.Op == OpRepeat {
+ m := re.Max
+ if m == 0 {
+ return true
+ }
+ if m < 0 {
+ m = re.Min
+ }
+ if m > n {
+ return false
+ }
+ if m > 0 {
+ n /= m
+ }
+ }
+ for _, sub := range re.Sub {
+ if !repeatIsValid(sub, n) {
+ return false
+ }
+ }
+ return true
+}
+
// concat replaces the top of the stack (above the topmost '|' or '(') with its concatenation.
func (p *parser) concat() *Regexp {
p.maybeConcat(-1, 0)
@@ -668,7 +707,6 @@ func Parse(s string, flags Flags) (*Regexp, error) {
c rune
op Op
lastRepeat string
- min, max int
)
p.flags = flags
p.wholeRegexp = s
@@ -740,7 +778,7 @@ func Parse(s string, flags Flags) (*Regexp, error) {
op = OpQuest
}
after := t[1:]
- if after, err = p.repeat(op, min, max, before, after, lastRepeat); err != nil {
+ if after, err = p.repeat(op, 0, 0, before, after, lastRepeat); err != nil {
return nil, err
}
repeat = before
@@ -1640,7 +1678,7 @@ const (
// minimum and maximum runes involved in folding.
// checked during test.
minFold = 0x0041
- maxFold = 0x1044f
+ maxFold = 0x118df
)
// appendFoldedRange returns the result of appending the range lo-hi
diff --git a/libgo/go/regexp/syntax/parse_test.go b/libgo/go/regexp/syntax/parse_test.go
index 269d6c3b87..c4a1117ff8 100644
--- a/libgo/go/regexp/syntax/parse_test.go
+++ b/libgo/go/regexp/syntax/parse_test.go
@@ -100,12 +100,12 @@ var parseTests = []parseTest{
{`\P{Braille}`, `cc{0x0-0x27ff 0x2900-0x10ffff}`},
{`\p{^Braille}`, `cc{0x0-0x27ff 0x2900-0x10ffff}`},
{`\P{^Braille}`, `cc{0x2800-0x28ff}`},
- {`\pZ`, `cc{0x20 0xa0 0x1680 0x180e 0x2000-0x200a 0x2028-0x2029 0x202f 0x205f 0x3000}`},
+ {`\pZ`, `cc{0x20 0xa0 0x1680 0x2000-0x200a 0x2028-0x2029 0x202f 0x205f 0x3000}`},
{`[\p{Braille}]`, `cc{0x2800-0x28ff}`},
{`[\P{Braille}]`, `cc{0x0-0x27ff 0x2900-0x10ffff}`},
{`[\p{^Braille}]`, `cc{0x0-0x27ff 0x2900-0x10ffff}`},
{`[\P{^Braille}]`, `cc{0x2800-0x28ff}`},
- {`[\pZ]`, `cc{0x20 0xa0 0x1680 0x180e 0x2000-0x200a 0x2028-0x2029 0x202f 0x205f 0x3000}`},
+ {`[\pZ]`, `cc{0x20 0xa0 0x1680 0x2000-0x200a 0x2028-0x2029 0x202f 0x205f 0x3000}`},
{`\p{Lu}`, mkCharClass(unicode.IsUpper)},
{`[\p{Lu}]`, mkCharClass(unicode.IsUpper)},
{`(?i)[\p{Lu}]`, mkCharClass(isUpperFold)},
@@ -200,6 +200,10 @@ var parseTests = []parseTest{
`cat{rep{2,2 lit{x}}alt{emp{}cc{0x30-0x39}}}`},
{`x{2}y|x{2}[0-9]y`,
`cat{rep{2,2 lit{x}}alt{lit{y}cat{cc{0x30-0x39}lit{y}}}}`},
+
+ // Valid repetitions.
+ {`((((((((((x{2}){2}){2}){2}){2}){2}){2}){2}){2}))`, ``},
+ {`((((((((((x{1}){2}){2}){2}){2}){2}){2}){2}){2}){2})`, ``},
}
const testFlags = MatchNL | PerlX | UnicodeGroups
@@ -262,6 +266,10 @@ func testParseDump(t *testing.T, tests []parseTest, flags Flags) {
t.Errorf("Parse(%#q): %v", tt.Regexp, err)
continue
}
+ if tt.Dump == "" {
+ // It parsed. That's all we care about.
+ continue
+ }
d := dump(re)
if d != tt.Dump {
t.Errorf("Parse(%#q).Dump() = %#q want %#q", tt.Regexp, d, tt.Dump)
@@ -470,6 +478,7 @@ var invalidRegexps = []string{
`(?i)[a-Z]`,
`a{100000}`,
`a{100000,}`,
+ "((((((((((x{2}){2}){2}){2}){2}){2}){2}){2}){2}){2})",
}
var onlyPerl = []string{
@@ -527,6 +536,10 @@ func TestToStringEquivalentParse(t *testing.T) {
t.Errorf("Parse(%#q): %v", tt.Regexp, err)
continue
}
+ if tt.Dump == "" {
+ // It parsed. That's all we care about.
+ continue
+ }
d := dump(re)
if d != tt.Dump {
t.Errorf("Parse(%#q).Dump() = %#q want %#q", tt.Regexp, d, tt.Dump)
diff --git a/libgo/go/regexp/syntax/perl_groups.go b/libgo/go/regexp/syntax/perl_groups.go
index 1a11ca62f0..effe4e6862 100644
--- a/libgo/go/regexp/syntax/perl_groups.go
+++ b/libgo/go/regexp/syntax/perl_groups.go
@@ -1,3 +1,7 @@
+// 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.
+
// GENERATED BY make_perl_groups.pl; DO NOT EDIT.
// make_perl_groups.pl >perl_groups.go
diff --git a/libgo/go/regexp/syntax/prog.go b/libgo/go/regexp/syntax/prog.go
index a482a82f21..29bd282d0d 100644
--- a/libgo/go/regexp/syntax/prog.go
+++ b/libgo/go/regexp/syntax/prog.go
@@ -37,6 +37,27 @@ const (
InstRuneAnyNotNL
)
+var instOpNames = []string{
+ "InstAlt",
+ "InstAltMatch",
+ "InstCapture",
+ "InstEmptyWidth",
+ "InstMatch",
+ "InstFail",
+ "InstNop",
+ "InstRune",
+ "InstRune1",
+ "InstRuneAny",
+ "InstRuneAnyNotNL",
+}
+
+func (i InstOp) String() string {
+ if uint(i) >= uint(len(instOpNames)) {
+ return ""
+ }
+ return instOpNames[i]
+}
+
// An EmptyOp specifies a kind or mixture of zero-width assertions.
type EmptyOp uint8
@@ -103,13 +124,13 @@ func (p *Prog) String() string {
// skipNop follows any no-op or capturing instructions
// and returns the resulting pc.
-func (p *Prog) skipNop(pc uint32) *Inst {
+func (p *Prog) skipNop(pc uint32) (*Inst, uint32) {
i := &p.Inst[pc]
for i.Op == InstNop || i.Op == InstCapture {
pc = i.Out
i = &p.Inst[pc]
}
- return i
+ return i, pc
}
// op returns i.Op but merges all the Rune special cases into InstRune
@@ -126,7 +147,7 @@ func (i *Inst) op() InstOp {
// regexp must start with. Complete is true if the prefix
// is the entire match.
func (p *Prog) Prefix() (prefix string, complete bool) {
- i := p.skipNop(uint32(p.Start))
+ i, _ := p.skipNop(uint32(p.Start))
// Avoid allocation of buffer if prefix is empty.
if i.op() != InstRune || len(i.Rune) != 1 {
@@ -137,7 +158,7 @@ func (p *Prog) Prefix() (prefix string, complete bool) {
var buf bytes.Buffer
for i.op() == InstRune && len(i.Rune) == 1 && Flags(i.Arg)&FoldCase == 0 {
buf.WriteRune(i.Rune[0])
- i = p.skipNop(i.Out)
+ i, _ = p.skipNop(i.Out)
}
return buf.String(), i.Op == InstMatch
}
@@ -166,35 +187,46 @@ Loop:
return flag
}
+const noMatch = -1
+
// MatchRune returns true if 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
+}
+
+// MatchRunePos checks whether the instruction matches (and consumes) r.
+// If so, MatchRunePos returns the index of the matching rune pair
+// (or, when len(i.Rune) == 1, rune singleton).
+// If not, MatchRunePos returns -1.
+// MatchRunePos should only be called when i.Op == InstRune.
+func (i *Inst) MatchRunePos(r rune) int {
rune := i.Rune
// Special case: single-rune slice is from literal string, not char class.
if len(rune) == 1 {
r0 := rune[0]
if r == r0 {
- return true
+ return 0
}
if Flags(i.Arg)&FoldCase != 0 {
for r1 := unicode.SimpleFold(r0); r1 != r0; r1 = unicode.SimpleFold(r1) {
if r == r1 {
- return true
+ return 0
}
}
}
- return false
+ return noMatch
}
// Peek at the first few pairs.
// Should handle ASCII well.
for j := 0; j < len(rune) && j <= 8; j += 2 {
if r < rune[j] {
- return false
+ return noMatch
}
if r <= rune[j+1] {
- return true
+ return j / 2
}
}
@@ -205,14 +237,14 @@ func (i *Inst) MatchRune(r rune) bool {
m := lo + (hi-lo)/2
if c := rune[2*m]; c <= r {
if r <= rune[2*m+1] {
- return true
+ return m
}
lo = m + 1
} else {
hi = m
}
}
- return false
+ return noMatch
}
// As per re2's Prog::IsWordChar. Determines whether rune is an ASCII word char.
diff --git a/libgo/go/regexp/syntax/prog_test.go b/libgo/go/regexp/syntax/prog_test.go
index cd71abc2a4..50bfa3d4be 100644
--- a/libgo/go/regexp/syntax/prog_test.go
+++ b/libgo/go/regexp/syntax/prog_test.go
@@ -4,9 +4,7 @@
package syntax
-import (
- "testing"
-)
+import "testing"
var compileTests = []struct {
Regexp string
diff --git a/libgo/go/regexp/syntax/regexp.go b/libgo/go/regexp/syntax/regexp.go
index 329a90e012..cea7d9e04f 100644
--- a/libgo/go/regexp/syntax/regexp.go
+++ b/libgo/go/regexp/syntax/regexp.go
@@ -39,7 +39,7 @@ const (
OpEmptyMatch // matches empty string
OpLiteral // matches Runes sequence
OpCharClass // matches Runes interpreted as range pair list
- OpAnyCharNotNL // matches any character
+ OpAnyCharNotNL // matches any character except newline
OpAnyChar // matches any character
OpBeginLine // matches empty string at beginning of line
OpEndLine // matches empty string at end of line
diff --git a/libgo/go/runtime/append_test.go b/libgo/go/runtime/append_test.go
index 937c8259fd..a67dc9b494 100644
--- a/libgo/go/runtime/append_test.go
+++ b/libgo/go/runtime/append_test.go
@@ -19,6 +19,25 @@ func BenchmarkAppend(b *testing.B) {
}
}
+func BenchmarkAppendGrowByte(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ var x []byte
+ for j := 0; j < 1<<20; j++ {
+ x = append(x, byte(j))
+ }
+ }
+}
+
+func BenchmarkAppendGrowString(b *testing.B) {
+ var s string
+ for i := 0; i < b.N; i++ {
+ var x []string
+ for j := 0; j < 1<<20; j++ {
+ x = append(x, s)
+ }
+ }
+}
+
func benchmarkAppendBytes(b *testing.B, length int) {
b.StopTimer()
x := make([]byte, 0, N)
diff --git a/libgo/go/runtime/arch_386.go b/libgo/go/runtime/arch_386.go
new file mode 100644
index 0000000000..79d38c7ab1
--- /dev/null
+++ b/libgo/go/runtime/arch_386.go
@@ -0,0 +1,8 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+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
new file mode 100644
index 0000000000..270cd7b957
--- /dev/null
+++ b/libgo/go/runtime/arch_amd64.go
@@ -0,0 +1,8 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+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
new file mode 100644
index 0000000000..5c636aeab2
--- /dev/null
+++ b/libgo/go/runtime/arch_amd64p32.go
@@ -0,0 +1,8 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+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
new file mode 100644
index 0000000000..79d38c7ab1
--- /dev/null
+++ b/libgo/go/runtime/arch_arm.go
@@ -0,0 +1,8 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+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
new file mode 100644
index 0000000000..7e9d9b3aad
--- /dev/null
+++ b/libgo/go/runtime/atomic.go
@@ -0,0 +1,51 @@
+// 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
new file mode 100644
index 0000000000..7fd91469eb
--- /dev/null
+++ b/libgo/go/runtime/cgocall.go
@@ -0,0 +1,279 @@
+// 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
new file mode 100644
index 0000000000..2c89143208
--- /dev/null
+++ b/libgo/go/runtime/cgocallback.go
@@ -0,0 +1,40 @@
+// 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
new file mode 100644
index 0000000000..0eb87df74f
--- /dev/null
+++ b/libgo/go/runtime/chan.go
@@ -0,0 +1,655 @@
+// 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 eb2c7c60d0..4fb305c8ae 100644
--- a/libgo/go/runtime/chan_test.go
+++ b/libgo/go/runtime/chan_test.go
@@ -9,8 +9,352 @@ import (
"sync"
"sync/atomic"
"testing"
+ "time"
)
+func TestChan(t *testing.T) {
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
+ N := 200
+ if testing.Short() {
+ N = 20
+ }
+ for chanCap := 0; chanCap < N; chanCap++ {
+ {
+ // Ensure that receive from empty chan blocks.
+ c := make(chan int, chanCap)
+ recv1 := false
+ go func() {
+ _ = <-c
+ recv1 = true
+ }()
+ recv2 := false
+ go func() {
+ _, _ = <-c
+ recv2 = true
+ }()
+ time.Sleep(time.Millisecond)
+ if recv1 || recv2 {
+ t.Fatalf("chan[%d]: receive from empty chan", chanCap)
+ }
+ // Ensure that non-blocking receive does not block.
+ select {
+ case _ = <-c:
+ t.Fatalf("chan[%d]: receive from empty chan", chanCap)
+ default:
+ }
+ select {
+ case _, _ = <-c:
+ t.Fatalf("chan[%d]: receive from empty chan", chanCap)
+ default:
+ }
+ c <- 0
+ c <- 0
+ }
+
+ {
+ // Ensure that send to full chan blocks.
+ c := make(chan int, chanCap)
+ for i := 0; i < chanCap; i++ {
+ c <- i
+ }
+ sent := uint32(0)
+ go func() {
+ c <- 0
+ atomic.StoreUint32(&sent, 1)
+ }()
+ time.Sleep(time.Millisecond)
+ if atomic.LoadUint32(&sent) != 0 {
+ t.Fatalf("chan[%d]: send to full chan", chanCap)
+ }
+ // Ensure that non-blocking send does not block.
+ select {
+ case c <- 0:
+ t.Fatalf("chan[%d]: send to full chan", chanCap)
+ default:
+ }
+ <-c
+ }
+
+ {
+ // Ensure that we receive 0 from closed chan.
+ c := make(chan int, chanCap)
+ for i := 0; i < chanCap; i++ {
+ c <- i
+ }
+ close(c)
+ for i := 0; i < chanCap; i++ {
+ v := <-c
+ if v != i {
+ t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, i)
+ }
+ }
+ if v := <-c; v != 0 {
+ t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, 0)
+ }
+ if v, ok := <-c; v != 0 || ok {
+ t.Fatalf("chan[%d]: received %v/%v, expected %v/%v", chanCap, v, ok, 0, false)
+ }
+ }
+
+ {
+ // Ensure that close unblocks receive.
+ c := make(chan int, chanCap)
+ done := make(chan bool)
+ go func() {
+ v, ok := <-c
+ done <- v == 0 && ok == false
+ }()
+ time.Sleep(time.Millisecond)
+ close(c)
+ if !<-done {
+ t.Fatalf("chan[%d]: received non zero from closed chan", chanCap)
+ }
+ }
+
+ {
+ // Send 100 integers,
+ // ensure that we receive them non-corrupted in FIFO order.
+ c := make(chan int, chanCap)
+ go func() {
+ for i := 0; i < 100; i++ {
+ c <- i
+ }
+ }()
+ for i := 0; i < 100; i++ {
+ v := <-c
+ if v != i {
+ t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, i)
+ }
+ }
+
+ // Same, but using recv2.
+ go func() {
+ for i := 0; i < 100; i++ {
+ c <- i
+ }
+ }()
+ for i := 0; i < 100; i++ {
+ v, ok := <-c
+ if !ok {
+ t.Fatalf("chan[%d]: receive failed, expected %v", chanCap, i)
+ }
+ if v != i {
+ t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, i)
+ }
+ }
+
+ // Send 1000 integers in 4 goroutines,
+ // ensure that we receive what we send.
+ const P = 4
+ const L = 1000
+ for p := 0; p < P; p++ {
+ go func() {
+ for i := 0; i < L; i++ {
+ c <- i
+ }
+ }()
+ }
+ done := make(chan map[int]int)
+ for p := 0; p < P; p++ {
+ go func() {
+ recv := make(map[int]int)
+ for i := 0; i < L; i++ {
+ v := <-c
+ recv[v] = recv[v] + 1
+ }
+ done <- recv
+ }()
+ }
+ recv := make(map[int]int)
+ for p := 0; p < P; p++ {
+ for k, v := range <-done {
+ recv[k] = recv[k] + v
+ }
+ }
+ if len(recv) != L {
+ t.Fatalf("chan[%d]: received %v values, expected %v", chanCap, len(recv), L)
+ }
+ for _, v := range recv {
+ if v != P {
+ t.Fatalf("chan[%d]: received %v values, expected %v", chanCap, v, P)
+ }
+ }
+ }
+
+ {
+ // Test len/cap.
+ c := make(chan int, chanCap)
+ if len(c) != 0 || cap(c) != chanCap {
+ t.Fatalf("chan[%d]: bad len/cap, expect %v/%v, got %v/%v", chanCap, 0, chanCap, len(c), cap(c))
+ }
+ for i := 0; i < chanCap; i++ {
+ c <- i
+ }
+ if len(c) != chanCap || cap(c) != chanCap {
+ t.Fatalf("chan[%d]: bad len/cap, expect %v/%v, got %v/%v", chanCap, chanCap, chanCap, len(c), cap(c))
+ }
+ }
+
+ }
+}
+
+func TestNonblockRecvRace(t *testing.T) {
+ n := 10000
+ if testing.Short() {
+ n = 100
+ } else {
+ if runtime.GOARCH == "s390" {
+ // Test uses too much address space on 31-bit S390.
+ t.Skip("skipping long test on s390")
+ }
+ }
+ for i := 0; i < n; i++ {
+ c := make(chan int, 1)
+ c <- 1
+ go func() {
+ select {
+ case <-c:
+ default:
+ t.Fatal("chan is not ready")
+ }
+ }()
+ close(c)
+ <-c
+ }
+}
+
+func TestSelfSelect(t *testing.T) {
+ // Ensure that send/recv on the same chan in select
+ // does not crash nor deadlock.
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
+ for _, chanCap := range []int{0, 10} {
+ var wg sync.WaitGroup
+ wg.Add(2)
+ c := make(chan int, chanCap)
+ for p := 0; p < 2; p++ {
+ p := p
+ go func() {
+ defer wg.Done()
+ for i := 0; i < 1000; i++ {
+ if p == 0 || i%2 == 0 {
+ select {
+ case c <- p:
+ case v := <-c:
+ if chanCap == 0 && v == p {
+ t.Fatalf("self receive")
+ }
+ }
+ } else {
+ select {
+ case v := <-c:
+ if chanCap == 0 && v == p {
+ t.Fatalf("self receive")
+ }
+ case c <- p:
+ }
+ }
+ }
+ }()
+ }
+ wg.Wait()
+ }
+}
+
+func TestSelectStress(t *testing.T) {
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(10))
+ var c [4]chan int
+ c[0] = make(chan int)
+ c[1] = make(chan int)
+ c[2] = make(chan int, 2)
+ c[3] = make(chan int, 3)
+ N := int(1e5)
+ if testing.Short() {
+ N /= 10
+ }
+ // There are 4 goroutines that send N values on each of the chans,
+ // + 4 goroutines that receive N values on each of the chans,
+ // + 1 goroutine that sends N values on each of the chans in a single select,
+ // + 1 goroutine that receives N values on each of the chans in a single select.
+ // All these sends, receives and selects interact chaotically at runtime,
+ // but we are careful that this whole construct does not deadlock.
+ var wg sync.WaitGroup
+ wg.Add(10)
+ for k := 0; k < 4; k++ {
+ k := k
+ go func() {
+ for i := 0; i < N; i++ {
+ c[k] <- 0
+ }
+ wg.Done()
+ }()
+ go func() {
+ for i := 0; i < N; i++ {
+ <-c[k]
+ }
+ wg.Done()
+ }()
+ }
+ go func() {
+ var n [4]int
+ c1 := c
+ for i := 0; i < 4*N; i++ {
+ select {
+ case c1[3] <- 0:
+ n[3]++
+ if n[3] == N {
+ c1[3] = nil
+ }
+ case c1[2] <- 0:
+ n[2]++
+ if n[2] == N {
+ c1[2] = nil
+ }
+ case c1[0] <- 0:
+ n[0]++
+ if n[0] == N {
+ c1[0] = nil
+ }
+ case c1[1] <- 0:
+ n[1]++
+ if n[1] == N {
+ c1[1] = nil
+ }
+ }
+ }
+ wg.Done()
+ }()
+ go func() {
+ var n [4]int
+ c1 := c
+ for i := 0; i < 4*N; i++ {
+ select {
+ case <-c1[0]:
+ n[0]++
+ if n[0] == N {
+ c1[0] = nil
+ }
+ case <-c1[1]:
+ n[1]++
+ if n[1] == N {
+ c1[1] = nil
+ }
+ case <-c1[2]:
+ n[2]++
+ if n[2] == N {
+ c1[2] = nil
+ }
+ case <-c1[3]:
+ n[3]++
+ if n[3] == N {
+ c1[3] = nil
+ }
+ }
+ }
+ wg.Done()
+ }()
+ wg.Wait()
+}
+
func TestChanSendInterface(t *testing.T) {
type mt struct{}
m := &mt{}
@@ -29,34 +373,35 @@ func TestChanSendInterface(t *testing.T) {
func TestPseudoRandomSend(t *testing.T) {
n := 100
- c := make(chan int)
- l := make([]int, n)
- var m sync.Mutex
- m.Lock()
- go func() {
+ for _, chanCap := range []int{0, n} {
+ c := make(chan int, chanCap)
+ l := make([]int, n)
+ var m sync.Mutex
+ m.Lock()
+ go func() {
+ for i := 0; i < n; i++ {
+ runtime.Gosched()
+ l[i] = <-c
+ }
+ m.Unlock()
+ }()
for i := 0; i < n; i++ {
- runtime.Gosched()
- l[i] = <-c
+ select {
+ case c <- 1:
+ case c <- 0:
+ }
}
- m.Unlock()
- }()
- for i := 0; i < n; i++ {
- select {
- case c <- 0:
- case c <- 1:
+ m.Lock() // wait
+ n0 := 0
+ n1 := 0
+ for _, i := range l {
+ n0 += (i + 1) % 2
+ n1 += i
}
- }
- m.Lock() // wait
- n0 := 0
- n1 := 0
- for _, i := range l {
- n0 += (i + 1) % 2
- n1 += i
- if n0 > n/10 && n1 > n/10 {
- return
+ if n0 <= n/10 || n1 <= n/10 {
+ t.Errorf("Want pseudorandom, got %d zeros and %d ones (chan cap %d)", n0, n1, chanCap)
}
}
- t.Errorf("Want pseudo random, got %d zeros and %d ones", n0, n1)
}
func TestMultiConsumer(t *testing.T) {
@@ -110,147 +455,195 @@ 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
+ // is set to >= 1.
+ const n = 10
+ c := make(chan int)
+ done := make(chan struct{})
+
+ go func() {
+ for i := 0; i < n; i++ {
+ c <- i
+ // use lots of stack, briefly.
+ stackGrowthRecursive(20)
+ }
+ done <- struct{}{}
+ }()
+
+ for i := 0; i < n; i++ {
+ x := <-c
+ if x != i {
+ t.Errorf("bad channel read: want %d, got %d", i, x)
+ }
+ // Waste some time so sender can finish using lots of stack
+ // and block in channel send.
+ time.Sleep(1 * time.Millisecond)
+ // trigger GC which will shrink the stack of the sender.
+ runtime.GC()
+ }
+ <-done
+}
+
+func TestSelectDuplicateChannel(t *testing.T) {
+ // This test makes sure we can queue a G on
+ // the same channel multiple times.
+ c := make(chan int)
+ d := make(chan int)
+ e := make(chan int)
+
+ // goroutine A
+ go func() {
+ select {
+ case <-c:
+ case <-c:
+ case <-d:
+ }
+ e <- 9
+ }()
+ time.Sleep(time.Millisecond) // make sure goroutine A gets qeueued first on c
+
+ // goroutine B
+ go func() {
+ <-c
+ }()
+ time.Sleep(time.Millisecond) // make sure goroutine B gets queued on c before continuing
+
+ d <- 7 // wake up A, it dequeues itself from c. This operation used to corrupt c.recvq.
+ <-e // A tells us it's done
+ c <- 8 // wake up B. This operation used to fail because c.recvq was corrupted (it tries to wake up an already running G instead of B)
+}
+
+func BenchmarkChanNonblocking(b *testing.B) {
+ myc := make(chan int)
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ select {
+ case <-myc:
+ default:
+ }
+ }
+ })
+}
+
func BenchmarkSelectUncontended(b *testing.B) {
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
- for p := 0; p < procs; p++ {
+ b.RunParallel(func(pb *testing.PB) {
+ myc1 := make(chan int, 1)
+ myc2 := make(chan int, 1)
+ myc1 <- 0
+ for pb.Next() {
+ select {
+ case <-myc1:
+ myc2 <- 0
+ case <-myc2:
+ myc1 <- 0
+ }
+ }
+ })
+}
+
+func BenchmarkSelectSyncContended(b *testing.B) {
+ myc1 := make(chan int)
+ myc2 := make(chan int)
+ myc3 := make(chan int)
+ done := make(chan int)
+ b.RunParallel(func(pb *testing.PB) {
go func() {
- myc1 := make(chan int, 1)
- myc2 := make(chan int, 1)
- myc1 <- 0
- for atomic.AddInt32(&N, -1) >= 0 {
- for g := 0; g < CallsPerSched; g++ {
- select {
- case <-myc1:
- myc2 <- 0
- case <-myc2:
- myc1 <- 0
- }
+ for {
+ select {
+ case myc1 <- 0:
+ case myc2 <- 0:
+ case myc3 <- 0:
+ case <-done:
+ return
}
}
- c <- true
}()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ for pb.Next() {
+ select {
+ case <-myc1:
+ case <-myc2:
+ case <-myc3:
+ }
+ }
+ })
+ close(done)
}
-func BenchmarkSelectContended(b *testing.B) {
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
+func BenchmarkSelectAsyncContended(b *testing.B) {
+ procs := runtime.GOMAXPROCS(0)
myc1 := make(chan int, procs)
myc2 := make(chan int, procs)
- for p := 0; p < procs; p++ {
+ b.RunParallel(func(pb *testing.PB) {
myc1 <- 0
- go func() {
- for atomic.AddInt32(&N, -1) >= 0 {
- for g := 0; g < CallsPerSched; g++ {
- select {
- case <-myc1:
- myc2 <- 0
- case <-myc2:
- myc1 <- 0
- }
- }
+ for pb.Next() {
+ select {
+ case <-myc1:
+ myc2 <- 0
+ case <-myc2:
+ myc1 <- 0
}
- c <- true
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ }
+ })
}
func BenchmarkSelectNonblock(b *testing.B) {
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
- for p := 0; p < procs; p++ {
- go func() {
- myc1 := make(chan int)
- myc2 := make(chan int)
- myc3 := make(chan int, 1)
- myc4 := make(chan int, 1)
- for atomic.AddInt32(&N, -1) >= 0 {
- for g := 0; g < CallsPerSched; g++ {
- select {
- case <-myc1:
- default:
- }
- select {
- case myc2 <- 0:
- default:
- }
- select {
- case <-myc3:
- default:
- }
- select {
- case myc4 <- 0:
- default:
- }
- }
+ myc1 := make(chan int)
+ myc2 := make(chan int)
+ myc3 := make(chan int, 1)
+ myc4 := make(chan int, 1)
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ select {
+ case <-myc1:
+ default:
}
- c <- true
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ select {
+ case myc2 <- 0:
+ default:
+ }
+ select {
+ case <-myc3:
+ default:
+ }
+ select {
+ case myc4 <- 0:
+ default:
+ }
+ }
+ })
}
func BenchmarkChanUncontended(b *testing.B) {
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
- for p := 0; p < procs; p++ {
- go func() {
- myc := make(chan int, CallsPerSched)
- for atomic.AddInt32(&N, -1) >= 0 {
- for g := 0; g < CallsPerSched; g++ {
- myc <- 0
- }
- for g := 0; g < CallsPerSched; g++ {
- <-myc
- }
+ const C = 100
+ b.RunParallel(func(pb *testing.PB) {
+ myc := make(chan int, C)
+ for pb.Next() {
+ for i := 0; i < C; i++ {
+ myc <- 0
}
- c <- true
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ for i := 0; i < C; i++ {
+ <-myc
+ }
+ }
+ })
}
func BenchmarkChanContended(b *testing.B) {
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
- myc := make(chan int, procs*CallsPerSched)
- for p := 0; p < procs; p++ {
- go func() {
- for atomic.AddInt32(&N, -1) >= 0 {
- for g := 0; g < CallsPerSched; g++ {
- myc <- 0
- }
- for g := 0; g < CallsPerSched; g++ {
- <-myc
- }
+ const C = 100
+ myc := make(chan int, C*runtime.GOMAXPROCS(0))
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ for i := 0; i < C; i++ {
+ myc <- 0
}
- c <- true
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ for i := 0; i < C; i++ {
+ <-myc
+ }
+ }
+ })
}
func BenchmarkChanSync(b *testing.B) {
@@ -350,33 +743,83 @@ func BenchmarkChanProdConsWork100(b *testing.B) {
benchmarkChanProdCons(b, 100, 100)
}
-func BenchmarkChanCreation(b *testing.B) {
+func BenchmarkSelectProdCons(b *testing.B) {
const CallsPerSched = 1000
procs := runtime.GOMAXPROCS(-1)
N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
+ c := make(chan bool, 2*procs)
+ myc := make(chan int, 128)
+ myclose := make(chan bool)
for p := 0; p < procs; p++ {
go func() {
+ // Producer: sends to myc.
+ foo := 0
+ // Intended to not fire during benchmarking.
+ mytimer := time.After(time.Hour)
for atomic.AddInt32(&N, -1) >= 0 {
for g := 0; g < CallsPerSched; g++ {
- myc := make(chan int, 1)
- myc <- 0
- <-myc
+ // Model some local work.
+ for i := 0; i < 100; i++ {
+ foo *= 2
+ foo /= 2
+ }
+ select {
+ case myc <- 1:
+ case <-mytimer:
+ case <-myclose:
+ }
}
}
- c <- true
+ myc <- 0
+ c <- foo == 42
+ }()
+ go func() {
+ // Consumer: receives from myc.
+ foo := 0
+ // Intended to not fire during benchmarking.
+ mytimer := time.After(time.Hour)
+ loop:
+ for {
+ select {
+ case v := <-myc:
+ if v == 0 {
+ break loop
+ }
+ case <-mytimer:
+ case <-myclose:
+ }
+ // Model some local work.
+ for i := 0; i < 100; i++ {
+ foo *= 2
+ foo /= 2
+ }
+ }
+ c <- foo == 42
}()
}
for p := 0; p < procs; p++ {
<-c
+ <-c
}
}
+func BenchmarkChanCreation(b *testing.B) {
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ myc := make(chan int, 1)
+ myc <- 0
+ <-myc
+ }
+ })
+}
+
func BenchmarkChanSem(b *testing.B) {
type Empty struct{}
- c := make(chan Empty, 1)
- for i := 0; i < b.N; i++ {
- c <- Empty{}
- <-c
- }
+ myc := make(chan Empty, runtime.GOMAXPROCS(0))
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ myc <- Empty{}
+ <-myc
+ }
+ })
}
diff --git a/libgo/go/runtime/complex.go b/libgo/go/runtime/complex.go
new file mode 100644
index 0000000000..ec50f89470
--- /dev/null
+++ b/libgo/go/runtime/complex.go
@@ -0,0 +1,52 @@
+// 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
new file mode 100644
index 0000000000..8b1c1c6327
--- /dev/null
+++ b/libgo/go/runtime/cpuprof.go
@@ -0,0 +1,425 @@
+// 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 b534b89e55..29f90fa36d 100644
--- a/libgo/go/runtime/crash_cgo_test.go
+++ b/libgo/go/runtime/crash_cgo_test.go
@@ -7,7 +7,9 @@
package runtime_test
import (
+ "os/exec"
"runtime"
+ "strings"
"testing"
)
@@ -19,7 +21,6 @@ func TestCgoSignalDeadlock(t *testing.T) {
if testing.Short() && runtime.GOOS == "windows" {
t.Skip("Skipping in short mode") // takes up to 64 seconds
}
- t.Skip("gccgo does not have a go command")
got := executeTest(t, cgoSignalDeadlockSource, nil)
want := "OK\n"
if got != want {
@@ -35,6 +36,45 @@ func TestCgoTraceback(t *testing.T) {
}
}
+func TestCgoExternalThreadPanic(t *testing.T) {
+ if runtime.GOOS == "plan9" {
+ t.Skipf("no pthreads on %s", runtime.GOOS)
+ }
+ csrc := cgoExternalThreadPanicC
+ if runtime.GOOS == "windows" {
+ csrc = cgoExternalThreadPanicC_windows
+ }
+ got := executeTest(t, cgoExternalThreadPanicSource, nil, "main.c", csrc)
+ want := "panic: BOOM"
+ if !strings.Contains(got, want) {
+ t.Fatalf("want failure containing %q. output:\n%s\n", want, got)
+ }
+}
+
+func TestCgoExternalThreadSIGPROF(t *testing.T) {
+ // issue 9456.
+ switch runtime.GOOS {
+ 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")
+ }
+ }
+ got := executeTest(t, cgoExternalThreadSIGPROFSource, nil)
+ want := "OK\n"
+ if got != want {
+ t.Fatalf("expected %q, but got %q", want, got)
+ }
+}
+
const cgoSignalDeadlockSource = `
package main
@@ -118,3 +158,107 @@ func main() {
fmt.Printf("OK\n")
}
`
+
+const cgoExternalThreadPanicSource = `
+package main
+
+// void start(void);
+import "C"
+
+func main() {
+ C.start()
+ select {}
+}
+
+//export gopanic
+func gopanic() {
+ panic("BOOM")
+}
+`
+
+const cgoExternalThreadPanicC = `
+#include <stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+
+void gopanic(void);
+
+static void*
+die(void* x)
+{
+ gopanic();
+ return 0;
+}
+
+void
+start(void)
+{
+ pthread_t t;
+ if(pthread_create(&t, 0, die, 0) != 0)
+ printf("pthread_create failed\n");
+}
+`
+
+const cgoExternalThreadPanicC_windows = `
+#include <stdlib.h>
+#include <stdio.h>
+
+void gopanic(void);
+
+static void*
+die(void* x)
+{
+ gopanic();
+ return 0;
+}
+
+void
+start(void)
+{
+ if(_beginthreadex(0, 0, die, 0, 0, 0) != 0)
+ printf("_beginthreadex failed\n");
+}
+`
+
+const cgoExternalThreadSIGPROFSource = `
+package main
+
+/*
+#include <stdint.h>
+#include <signal.h>
+#include <pthread.h>
+
+volatile int32_t spinlock;
+
+static void *thread1(void *p) {
+ (void)p;
+ while (spinlock == 0)
+ ;
+ pthread_kill(pthread_self(), SIGPROF);
+ spinlock = 0;
+ return NULL;
+}
+__attribute__((constructor)) void issue9456() {
+ pthread_t tid;
+ pthread_create(&tid, 0, thread1, NULL);
+}
+*/
+import "C"
+
+import (
+ "runtime"
+ "sync/atomic"
+ "unsafe"
+)
+
+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.
+ atomic.StoreInt32((*int32)(unsafe.Pointer(&C.spinlock)), 1)
+ for atomic.LoadInt32((*int32)(unsafe.Pointer(&C.spinlock))) == 1 {
+ runtime.Gosched()
+ }
+ println("OK")
+}
+`
diff --git a/libgo/go/runtime/crash_test.go b/libgo/go/runtime/crash_test.go
index d8bfdbdad6..7e8a2e45f0 100644
--- a/libgo/go/runtime/crash_test.go
+++ b/libgo/go/runtime/crash_test.go
@@ -9,6 +9,7 @@ import (
"os"
"os/exec"
"path/filepath"
+ "runtime"
"strings"
"testing"
"text/template"
@@ -30,8 +31,13 @@ func testEnv(cmd *exec.Cmd) *exec.Cmd {
return cmd
}
-func executeTest(t *testing.T, templ string, data interface{}) string {
+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)
+ }
+
checkStaleRuntime(t)
st := template.Must(template.New("crashSource").Parse(templ))
@@ -56,7 +62,20 @@ func executeTest(t *testing.T, templ string, data interface{}) string {
t.Fatalf("failed to close file: %v", err)
}
- got, _ := testEnv(exec.Command("go", "run", src)).CombinedOutput()
+ for i := 0; i < len(extra); i += 2 {
+ if err := ioutil.WriteFile(filepath.Join(dir, extra[i]), []byte(extra[i+1]), 0666); err != nil {
+ t.Fatal(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)
+ }
+
+ got, _ := testEnv(exec.Command(filepath.Join(dir, "a.exe"))).CombinedOutput()
return string(got)
}
@@ -112,8 +131,9 @@ func TestLockedDeadlock2(t *testing.T) {
func TestGoexitDeadlock(t *testing.T) {
output := executeTest(t, goexitDeadlockSource, nil)
- if output != "" {
- t.Fatalf("expected no output, got:\n%s", output)
+ want := "no goroutines (main called runtime.Goexit) - deadlock!"
+ if !strings.Contains(output, want) {
+ t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
}
}
@@ -133,6 +153,66 @@ func TestThreadExhaustion(t *testing.T) {
}
}
+func TestRecursivePanic(t *testing.T) {
+ output := executeTest(t, recursivePanicSource, nil)
+ want := `wrap: bad
+panic: again
+
+`
+ if !strings.HasPrefix(output, want) {
+ t.Fatalf("output does not start with %q:\n%s", want, output)
+ }
+
+}
+
+func TestGoexitCrash(t *testing.T) {
+ output := executeTest(t, goexitExitSource, nil)
+ want := "no goroutines (main called runtime.Goexit) - deadlock!"
+ if !strings.Contains(output, want) {
+ t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
+ }
+}
+
+func TestGoexitDefer(t *testing.T) {
+ c := make(chan struct{})
+ go func() {
+ defer func() {
+ r := recover()
+ if r != nil {
+ t.Errorf("non-nil recover during Goexit")
+ }
+ c <- struct{}{}
+ }()
+ runtime.Goexit()
+ }()
+ // Note: if the defer fails to run, we will get a deadlock here
+ <-c
+}
+
+func TestGoNil(t *testing.T) {
+ output := executeTest(t, goNilSource, nil)
+ want := "go of nil func value"
+ if !strings.Contains(output, want) {
+ t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
+ }
+}
+
+func TestMainGoroutineId(t *testing.T) {
+ output := executeTest(t, mainGoroutineIdSource, nil)
+ want := "panic: test\n\ngoroutine 1 [running]:\n"
+ if !strings.HasPrefix(output, want) {
+ t.Fatalf("output does not start with %q:\n%s", want, output)
+ }
+}
+
+func TestBreakpoint(t *testing.T) {
+ output := executeTest(t, breakpointSource, nil)
+ want := "runtime.Breakpoint()"
+ if !strings.Contains(output, want) {
+ t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
+ }
+}
+
const crashSource = `
package main
@@ -273,3 +353,164 @@ func main() {
}
}
`
+
+const recursivePanicSource = `
+package main
+
+import (
+ "fmt"
+)
+
+func main() {
+ func() {
+ defer func() {
+ fmt.Println(recover())
+ }()
+ var x [8192]byte
+ func(x [8192]byte) {
+ defer func() {
+ if err := recover(); err != nil {
+ panic("wrap: " + err.(string))
+ }
+ }()
+ panic("bad")
+ }(x)
+ }()
+ panic("again")
+}
+`
+
+const goexitExitSource = `
+package main
+
+import (
+ "runtime"
+ "time"
+)
+
+func main() {
+ go func() {
+ time.Sleep(time.Millisecond)
+ }()
+ i := 0
+ runtime.SetFinalizer(&i, func(p *int) {})
+ runtime.GC()
+ runtime.Goexit()
+}
+`
+
+const goNilSource = `
+package main
+
+func main() {
+ defer func() {
+ recover()
+ }()
+ var f func()
+ go f()
+ select{}
+}
+`
+
+const mainGoroutineIdSource = `
+package main
+func main() {
+ panic("test")
+}
+`
+
+const breakpointSource = `
+package main
+import "runtime"
+func main() {
+ runtime.Breakpoint()
+}
+`
+
+func TestGoexitInPanic(t *testing.T) {
+ // see issue 8774: this code used to trigger an infinite recursion
+ output := executeTest(t, goexitInPanicSource, nil)
+ want := "fatal error: no goroutines (main called runtime.Goexit) - deadlock!"
+ if !strings.HasPrefix(output, want) {
+ t.Fatalf("output does not start with %q:\n%s", want, output)
+ }
+}
+
+const goexitInPanicSource = `
+package main
+import "runtime"
+func main() {
+ go func() {
+ defer func() {
+ runtime.Goexit()
+ }()
+ panic("hello")
+ }()
+ runtime.Goexit()
+}
+`
+
+func TestPanicAfterGoexit(t *testing.T) {
+ // an uncaught panic should still work after goexit
+ output := executeTest(t, panicAfterGoexitSource, nil)
+ want := "panic: hello"
+ if !strings.HasPrefix(output, want) {
+ t.Fatalf("output does not start with %q:\n%s", want, output)
+ }
+}
+
+const panicAfterGoexitSource = `
+package main
+import "runtime"
+func main() {
+ defer func() {
+ panic("hello")
+ }()
+ runtime.Goexit()
+}
+`
+
+func TestRecoveredPanicAfterGoexit(t *testing.T) {
+ output := executeTest(t, recoveredPanicAfterGoexitSource, nil)
+ want := "fatal error: no goroutines (main called runtime.Goexit) - deadlock!"
+ if !strings.HasPrefix(output, want) {
+ t.Fatalf("output does not start with %q:\n%s", want, output)
+ }
+}
+
+const recoveredPanicAfterGoexitSource = `
+package main
+import "runtime"
+func main() {
+ defer func() {
+ defer func() {
+ r := recover()
+ if r == nil {
+ panic("bad recover")
+ }
+ }()
+ panic("hello")
+ }()
+ runtime.Goexit()
+}
+`
+
+func TestRecoverBeforePanicAfterGoexit(t *testing.T) {
+ // 1. defer a function that recovers
+ // 2. defer a function that panics
+ // 3. call goexit
+ // Goexit should run the #2 defer. Its panic
+ // should be caught by the #1 defer, and execution
+ // should resume in the caller. Like the Goexit
+ // never happened!
+ defer func() {
+ r := recover()
+ if r == nil {
+ panic("bad recover")
+ }
+ }()
+ defer func() {
+ panic("hello")
+ }()
+ runtime.Goexit()
+}
diff --git a/libgo/go/runtime/debug/garbage.go b/libgo/go/runtime/debug/garbage.go
index 8337d5d5b3..edb3643871 100644
--- a/libgo/go/runtime/debug/garbage.go
+++ b/libgo/go/runtime/debug/garbage.go
@@ -91,7 +91,9 @@ func (x byDuration) Less(i, j int) bool { return x[i] < x[j] }
// at startup, or 100 if the variable is not set.
// A negative percentage disables garbage collection.
func SetGCPercent(percent int) int {
- return setGCPercent(percent)
+ old := setGCPercent(percent)
+ runtime.GC()
+ return old
}
// FreeOSMemory forces a garbage collection followed by an
@@ -133,3 +135,19 @@ func SetMaxStack(bytes int) int {
func SetMaxThreads(threads int) int {
return setMaxThreads(threads)
}
+
+// SetPanicOnFault controls the runtime's behavior when a program faults
+// at an unexpected (non-nil) address. Such faults are typically caused by
+// bugs such as runtime memory corruption, so the default response is to crash
+// the program. Programs working with memory-mapped files or unsafe
+// manipulation of memory may cause faults at non-nil addresses in less
+// dramatic situations; SetPanicOnFault allows such programs to request
+// that the runtime trigger only a panic, not a crash.
+// SetPanicOnFault applies only to the current goroutine.
+// It returns the previous setting.
+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.
+func WriteHeapDump(fd uintptr)
diff --git a/libgo/go/runtime/debug/heapdump_test.go b/libgo/go/runtime/debug/heapdump_test.go
new file mode 100644
index 0000000000..9201901151
--- /dev/null
+++ b/libgo/go/runtime/debug/heapdump_test.go
@@ -0,0 +1,33 @@
+// 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 debug
+
+import (
+ "io/ioutil"
+ "os"
+ "runtime"
+ "testing"
+)
+
+func TestWriteHeapDumpNonempty(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()
+ WriteHeapDump(f.Fd())
+ fi, err := f.Stat()
+ if err != nil {
+ t.Fatalf("Stat failed: %v", err)
+ }
+ const minSize = 1
+ if size := fi.Size(); size < minSize {
+ t.Fatalf("Heap dump size %d bytes, expected at least %d bytes", size, minSize)
+ }
+}
diff --git a/libgo/go/runtime/debug/stack.go b/libgo/go/runtime/debug/stack.go
index 2896b21417..c29b0a226a 100644
--- a/libgo/go/runtime/debug/stack.go
+++ b/libgo/go/runtime/debug/stack.go
@@ -18,6 +18,7 @@ var (
dunno = []byte("???")
centerDot = []byte("·")
dot = []byte(".")
+ slash = []byte("/")
)
// PrintStack prints to standard error the stack trace returned by Stack.
@@ -84,6 +85,11 @@ func function(pc uintptr) []byte {
// runtime/debug.*T·ptrmethod
// and want
// *T.ptrmethod
+ // Since the package path might contains dots (e.g. code.google.com/...),
+ // we first remove the path prefix if there is one.
+ if lastslash := bytes.LastIndex(name, slash); lastslash >= 0 {
+ name = name[lastslash+1:]
+ }
if period := bytes.Index(name, dot); period >= 0 {
name = name[period+1:]
}
diff --git a/libgo/go/runtime/env_posix.go b/libgo/go/runtime/env_posix.go
new file mode 100644
index 0000000000..8b1dbb7994
--- /dev/null
+++ b/libgo/go/runtime/env_posix.go
@@ -0,0 +1,58 @@
+// 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/error.go b/libgo/go/runtime/error.go
index 88d5df5e41..d759a54a51 100644
--- a/libgo/go/runtime/error.go
+++ b/libgo/go/runtime/error.go
@@ -107,19 +107,20 @@ func NewErrorString(s string, ret *interface{}) {
}
// An errorCString represents a runtime error described by a single C string.
-type errorCString uintptr
+// Not "type errorCString uintptr" because of http://golang.org/issue/7084.
+type errorCString struct{ cstr uintptr }
func (e errorCString) RuntimeError() {}
func cstringToGo(uintptr) string
func (e errorCString) Error() string {
- return "runtime error: " + cstringToGo(uintptr(e))
+ return "runtime error: " + cstringToGo(e.cstr)
}
// For calling from C.
func NewErrorCString(s uintptr, ret *interface{}) {
- *ret = errorCString(s)
+ *ret = errorCString{s}
}
type stringer interface {
diff --git a/libgo/go/runtime/export_test.go b/libgo/go/runtime/export_test.go
index 2f678b6bc9..165bebf631 100644
--- a/libgo/go/runtime/export_test.go
+++ b/libgo/go/runtime/export_test.go
@@ -29,11 +29,11 @@ type LFNode struct {
Pushcnt uintptr
}
-func lfstackpush(head *uint64, node *LFNode)
-func lfstackpop2(head *uint64) *LFNode
+func lfstackpush_go(head *uint64, node *LFNode)
+func lfstackpop_go(head *uint64) *LFNode
-var LFStackPush = lfstackpush
-var LFStackPop = lfstackpop2
+var LFStackPush = lfstackpush_go
+var LFStackPop = lfstackpop_go
type ParFor struct {
body *byte
@@ -46,17 +46,17 @@ type ParFor struct {
wait bool
}
-func parforalloc2(nthrmax uint32) *ParFor
-func parforsetup2(desc *ParFor, nthr, n uint32, ctx *byte, wait bool, body func(*ParFor, uint32))
-func parfordo(desc *ParFor)
-func parforiters(desc *ParFor, tid uintptr) (uintptr, uintptr)
+func newParFor(nthrmax uint32) *ParFor
+func parForSetup(desc *ParFor, nthr, n uint32, ctx *byte, wait bool, body func(*ParFor, uint32))
+func parForDo(desc *ParFor)
+func parForIters(desc *ParFor, tid uintptr) (uintptr, uintptr)
-var NewParFor = parforalloc2
-var ParForSetup = parforsetup2
-var ParForDo = parfordo
+var NewParFor = newParFor
+var ParForSetup = parForSetup
+var ParForDo = parForDo
func ParForIters(desc *ParFor, tid uint32) (uint32, uint32) {
- begin, end := parforiters(desc, uintptr(tid))
+ begin, end := parForIters(desc, uintptr(tid))
return uint32(begin), uint32(end)
}
@@ -78,7 +78,13 @@ var TestSchedLocalQueueSteal1 = testSchedLocalQueueSteal
// var Int32Hash = int32Hash
// var Int64Hash = int64Hash
-// func GogoBytes() int32
-
var hashLoad float64 // declared in hashmap.c
var HashLoad = &hashLoad
+
+func memclrBytes(b []byte)
+
+var MemclrBytes = memclrBytes
+
+// func gogoBytes() int32
+
+// var GogoBytes = gogoBytes
diff --git a/libgo/go/runtime/extern.go b/libgo/go/runtime/extern.go
index f45104fcfc..3c3e427a05 100644
--- a/libgo/go/runtime/extern.go
+++ b/libgo/go/runtime/extern.go
@@ -24,18 +24,32 @@ percentage at run time. See http://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:
+ allocfreetrace: setting allocfreetrace=1 causes every allocation to be
+ profiled and a stack trace printed on each object's allocation and free.
+
+ efence: setting efence=1 causes the allocator to run in a mode
+ where each object is allocated on a unique page and addresses are
+ never recycled.
+
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.
- schedtrace: setting schedtrace=X causes the scheduler to emit a single line to standard
- error every X milliseconds, summarizing the scheduler state.
+ gcdead: setting gcdead=1 causes the garbage collector to clobber all stack slots
+ that it thinks are dead.
+
+ 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.
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.
+ schedtrace: setting schedtrace=X causes the scheduler to emit a single line to standard
+ error every X milliseconds, summarizing the scheduler state.
+
The GOMAXPROCS variable limits the number of operating system threads that
can execute user-level Go code simultaneously. There is no limit to the number of threads
that can be blocked in system calls on behalf of Go code; those do not count against
@@ -69,6 +83,11 @@ func Gosched()
// Goexit terminates the goroutine that calls it. No other goroutine is affected.
// Goexit runs all deferred calls before terminating the goroutine.
+//
+// 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()
// Caller reports file and line number information about function invocations on
@@ -153,6 +172,9 @@ func funcentry_go(*Func) uintptr
// 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.
+//
// 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.
@@ -172,10 +194,8 @@ func GOROOT() string {
}
// Version returns the Go tree's version string.
-// It is either a sequence number or, when possible,
-// a release tag like "release.2010-03-04".
-// A trailing + indicates that the tree had local modifications
-// at the time of the build.
+// It is either the commit hash and date at the time of the build or,
+// when possible, a release tag like "go1.3".
func Version() string {
return theVersion
}
@@ -185,5 +205,8 @@ func Version() string {
const GOOS string = theGoos
// GOARCH is the running program's architecture target:
-// 386, amd64, arm or arm64.
+// 386, amd64, arm, arm64, ppc64, ppc64le.
const GOARCH string = theGoarch
+
+// GCCGOTOOLDIR is the Tool Dir for the gccgo build
+const GCCGOTOOLDIR string = theGccgoToolDir
diff --git a/libgo/go/runtime/gc_test.go b/libgo/go/runtime/gc_test.go
index 1b3ccbf7d9..fe9e839020 100644
--- a/libgo/go/runtime/gc_test.go
+++ b/libgo/go/runtime/gc_test.go
@@ -9,6 +9,8 @@ import (
"runtime"
"runtime/debug"
"testing"
+ "time"
+ "unsafe"
)
func TestGcSys(t *testing.T) {
@@ -153,3 +155,140 @@ func TestGcRescan(t *testing.T) {
}
}
}
+
+func TestGcLastTime(t *testing.T) {
+ ms := new(runtime.MemStats)
+ t0 := time.Now().UnixNano()
+ runtime.GC()
+ t1 := time.Now().UnixNano()
+ runtime.ReadMemStats(ms)
+ last := int64(ms.LastGC)
+ if t0 > last || last > t1 {
+ t.Fatalf("bad last GC time: got %v, want [%v, %v]", last, t0, t1)
+ }
+ pause := ms.PauseNs[(ms.NumGC+255)%256]
+ // Due to timer granularity, pause can actually be 0 on windows
+ // or on virtualized environments.
+ if pause == 0 {
+ t.Logf("last GC pause was 0")
+ } else if pause > 10e9 {
+ t.Logf("bad last GC pause: got %v, want [0, 10e9]", pause)
+ }
+}
+
+var hugeSink interface{}
+
+func TestHugeGCInfo(t *testing.T) {
+ // The test ensures that compiler can chew these huge types even on weakest machines.
+ // The types are not allocated at runtime.
+ if hugeSink != nil {
+ // 400MB on 32 bots, 4TB on 64-bits.
+ const n = (400 << 20) + (unsafe.Sizeof(uintptr(0))-4)<<40
+ hugeSink = new([n]*byte)
+ hugeSink = new([n]uintptr)
+ hugeSink = new(struct {
+ x float64
+ y [n]*byte
+ z []string
+ })
+ hugeSink = new(struct {
+ x float64
+ y [n]uintptr
+ z []string
+ })
+ }
+}
+
+func BenchmarkSetTypeNoPtr1(b *testing.B) {
+ type NoPtr1 struct {
+ p uintptr
+ }
+ var p *NoPtr1
+ for i := 0; i < b.N; i++ {
+ p = &NoPtr1{}
+ }
+ _ = p
+}
+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 BenchmarkSetTypePtr1(b *testing.B) {
+ type Ptr1 struct {
+ p *byte
+ }
+ var p *Ptr1
+ for i := 0; i < b.N; i++ {
+ p = &Ptr1{}
+ }
+ _ = p
+}
+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 BenchmarkAllocation(b *testing.B) {
+ type T struct {
+ x, y *byte
+ }
+ ngo := runtime.GOMAXPROCS(0)
+ work := make(chan bool, b.N+ngo)
+ result := make(chan *T)
+ for i := 0; i < b.N; i++ {
+ work <- true
+ }
+ for i := 0; i < ngo; i++ {
+ work <- false
+ }
+ for i := 0; i < ngo; i++ {
+ go func() {
+ var x *T
+ for <-work {
+ for i := 0; i < 1000; i++ {
+ x = &T{}
+ }
+ }
+ result <- x
+ }()
+ }
+ for i := 0; i < ngo; i++ {
+ <-result
+ }
+}
+
+func TestPrintGC(t *testing.T) {
+ if testing.Short() {
+ t.Skip("Skipping in short mode")
+ }
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
+ done := make(chan bool)
+ go func() {
+ for {
+ select {
+ case <-done:
+ return
+ default:
+ runtime.GC()
+ }
+ }
+ }()
+ for i := 0; i < 1e4; i++ {
+ func() {
+ defer print("")
+ }()
+ }
+ close(done)
+}
diff --git a/libgo/go/runtime/gcinfo_test.go b/libgo/go/runtime/gcinfo_test.go
new file mode 100644
index 0000000000..00449929c9
--- /dev/null
+++ b/libgo/go/runtime/gcinfo_test.go
@@ -0,0 +1,194 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime_test
+
+import (
+ "bytes"
+ "runtime"
+ "testing"
+)
+
+// 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 ScalarPtr", new(ScalarPtr), infoScalarPtr)
+ verifyGCInfo(t, "stack PtrScalar", new(PtrScalar), infoPtrScalar)
+ verifyGCInfo(t, "stack BigStruct", new(BigStruct), infoBigStruct())
+ verifyGCInfo(t, "stack string", new(string), infoString)
+ verifyGCInfo(t, "stack slice", new([]string), infoSlice)
+ verifyGCInfo(t, "stack eface", new(interface{}), infoEface)
+ 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))
+ }
+
+}
+
+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)]
+ }
+ 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
+ }
+ return mask1
+}
+
+var gcinfoSink interface{}
+
+func escape(p interface{}) interface{} {
+ gcinfoSink = p
+ return p
+}
+
+const (
+ BitsDead = iota
+ BitsScalar
+ BitsPointer
+ BitsMultiWord
+)
+
+const (
+ BitsString = iota // unused
+ BitsSlice // unused
+ BitsIface
+ BitsEface
+)
+
+type ScalarPtr struct {
+ q int
+ w *int
+ e int
+ r *int
+ t int
+ y *int
+}
+
+var infoScalarPtr = []byte{BitsScalar, BitsPointer, BitsScalar, BitsPointer, BitsScalar, BitsPointer}
+
+type PtrScalar struct {
+ q *int
+ w int
+ e *int
+ r int
+ t *int
+ y int
+}
+
+var infoPtrScalar = []byte{BitsPointer, BitsScalar, BitsPointer, BitsScalar, BitsPointer, BitsScalar}
+
+type BigStruct struct {
+ q *int
+ w byte
+ e [17]byte
+ r []byte
+ t int
+ y uint16
+ u uint64
+ i string
+}
+
+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
+ }
+ case "amd64":
+ 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
+ }
+ 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
+ }
+ default:
+ panic("unknown arch")
+ }
+}
+
+type Iface interface {
+ f()
+}
+
+type IfaceImpl int
+
+func (IfaceImpl) f() {
+}
+
+var (
+ // BSS
+ bssScalarPtr ScalarPtr
+ bssPtrScalar PtrScalar
+ bssBigStruct BigStruct
+ bssString string
+ bssSlice []string
+ bssEface interface{}
+ bssIface Iface
+
+ // DATA
+ dataScalarPtr = ScalarPtr{q: 1}
+ dataPtrScalar = PtrScalar{w: 1}
+ dataBigStruct = BigStruct{w: 1}
+ dataString = "foo"
+ dataSlice = []string{"foo"}
+ dataEface interface{} = 42
+ dataIface Iface = IfaceImpl(42)
+
+ infoString = []byte{BitsPointer, BitsDead}
+ infoSlice = []byte{BitsPointer, BitsDead, BitsDead}
+ infoEface = []byte{BitsMultiWord, BitsEface}
+ infoIface = []byte{BitsMultiWord, BitsIface}
+)
diff --git a/libgo/go/runtime/hashmap.go b/libgo/go/runtime/hashmap.go
new file mode 100644
index 0000000000..791af8cf36
--- /dev/null
+++ b/libgo/go/runtime/hashmap.go
@@ -0,0 +1,960 @@
+// 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)<<B); B++ {
+ }
+
+ // allocate initial hash table
+ // if B == 0, the buckets field is allocated lazily later (in mapassign)
+ // If hint is large zeroing this memory could take a while.
+ var buckets unsafe.Pointer
+ if B != 0 {
+ if checkgc {
+ memstats.next_gc = memstats.heap_alloc
+ }
+ buckets = newarray(t.bucket, uintptr(1)<<B)
+ }
+
+ // initialize Hmap
+ if checkgc {
+ memstats.next_gc = memstats.heap_alloc
+ }
+ h := (*hmap)(newobject(t.hmap))
+ h.count = 0
+ h.B = B
+ h.flags = 0
+ h.hash0 = fastrand1()
+ h.buckets = buckets
+ h.oldbuckets = nil
+ h.nevacuate = 0
+
+ return h
+}
+
+// mapaccess1 returns a pointer to h[key]. Never returns nil, instead
+// it will return a reference to the zero object for the value type if
+// the key is not in the map.
+// NOTE: The returned pointer may keep the whole map live, so don't
+// hold onto it for very long.
+func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
+ if raceenabled && h != nil {
+ callerpc := getcallerpc(unsafe.Pointer(&t))
+ pc := funcPC(mapaccess1)
+ racereadpc(unsafe.Pointer(h), callerpc, pc)
+ raceReadObjectPC(t.key, key, callerpc, pc)
+ }
+ if h == nil || h.count == 0 {
+ return unsafe.Pointer(t.elem.zero)
+ }
+ alg := goalg(t.key.alg)
+ hash := alg.hash(key, uintptr(t.key.size), uintptr(h.hash0))
+ m := uintptr(1)<<h.B - 1
+ b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
+ if c := h.oldbuckets; c != nil {
+ oldb := (*bmap)(add(c, (hash&(m>>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)<<h.B - 1
+ b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + (hash&m)*uintptr(t.bucketsize)))
+ if c := h.oldbuckets; c != nil {
+ oldb := (*bmap)(unsafe.Pointer(uintptr(c) + (hash&(m>>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)<<h.B - 1
+ b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + (hash&m)*uintptr(t.bucketsize)))
+ if c := h.oldbuckets; c != nil {
+ oldb := (*bmap)(unsafe.Pointer(uintptr(c) + (hash&(m>>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)<<h.B - 1)
+ if h.oldbuckets != nil {
+ growWork(t, h, bucket)
+ }
+ b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(t.bucketsize)))
+ top := uint8(hash >> (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)<<h.B)) && h.count >= 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)<<h.B - 1)
+ if h.oldbuckets != nil {
+ growWork(t, h, bucket)
+ }
+ b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(t.bucketsize)))
+ 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))
+ 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 - 1)
+ it.offset = uint8(r >> 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 {
+ bucket = 0
+ it.wrapped = true
+ }
+ i = 0
+ }
+ for ; i < bucketCnt; i++ {
+ offi := (i + it.offset) & (bucketCnt - 1)
+ k := add(unsafe.Pointer(b), dataOffset+uintptr(offi)*uintptr(t.keysize))
+ v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+uintptr(offi)*uintptr(t.valuesize))
+ if b.tophash[offi] != empty && b.tophash[offi] != evacuatedEmpty {
+ if checkBucket != noCheck {
+ // Special case: iterator was started during a grow and the
+ // grow is not done yet. We're working on a bucket whose
+ // oldbucket has not been evacuated yet. Or at least, it wasn't
+ // evacuated when we started the bucket. So we're iterating
+ // through the oldbucket, skipping any keys that will go
+ // to the other new bucket (each oldbucket expands to two
+ // buckets during a grow).
+ k2 := k
+ if t.indirectkey {
+ k2 = *((*unsafe.Pointer)(k2))
+ }
+ if alg.equal(k2, k2, uintptr(t.key.size)) {
+ // If the item in the oldbucket is not destined for
+ // the current new bucket in the iteration, skip it.
+ hash := alg.hash(k2, uintptr(t.key.size), uintptr(h.hash0))
+ if hash&(uintptr(1)<<it.B-1) != checkBucket {
+ continue
+ }
+ } else {
+ // Hash isn't repeatable if k != k (NaNs). We need a
+ // repeatable and randomish choice of which direction
+ // to send NaNs during evacuation. We'll use the low
+ // bit of tophash to decide which way NaNs go.
+ // NOTE: this case is why we need two evacuate tophash
+ // values, evacuatedX and evacuatedY, that differ in
+ // their low bit.
+ if checkBucket>>(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
new file mode 100644
index 0000000000..afa6ecc99a
--- /dev/null
+++ b/libgo/go/runtime/hashmap_fast.go
@@ -0,0 +1,379 @@
+// 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)<<h.B - 1
+ b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
+ if c := h.oldbuckets; c != nil {
+ oldb := (*bmap)(add(c, (hash&(m>>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)<<h.B - 1
+ b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
+ if c := h.oldbuckets; c != nil {
+ oldb := (*bmap)(add(c, (hash&(m>>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)<<h.B - 1
+ b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
+ if c := h.oldbuckets; c != nil {
+ oldb := (*bmap)(add(c, (hash&(m>>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)<<h.B - 1
+ b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
+ if c := h.oldbuckets; c != nil {
+ oldb := (*bmap)(add(c, (hash&(m>>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)<<h.B - 1
+ b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
+ if c := h.oldbuckets; c != nil {
+ oldb := (*bmap)(add(c, (hash&(m>>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)<<h.B - 1
+ b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
+ if c := h.oldbuckets; c != nil {
+ oldb := (*bmap)(add(c, (hash&(m>>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/lfstack_test.go b/libgo/go/runtime/lfstack_test.go
index 505aae6055..e518777045 100644
--- a/libgo/go/runtime/lfstack_test.go
+++ b/libgo/go/runtime/lfstack_test.go
@@ -71,6 +71,8 @@ func TestLFStack(t *testing.T) {
}
}
+var stress []*MyNode
+
func TestLFStackStress(t *testing.T) {
const K = 100
P := 4 * GOMAXPROCS(-1)
@@ -80,14 +82,15 @@ func TestLFStackStress(t *testing.T) {
}
// Create 2 stacks.
stacks := [2]*uint64{new(uint64), new(uint64)}
- // Need to keep additional referenfces to nodes, the stack is not all that type-safe.
- var nodes []*MyNode
+ // Need to keep additional references to nodes,
+ // the lock-free stack is not type-safe.
+ stress = nil
// Push K elements randomly onto the stacks.
sum := 0
for i := 0; i < K; i++ {
sum += i
node := &MyNode{data: i}
- nodes = append(nodes, node)
+ stress = append(stress, node)
LFStackPush(stacks[i%2], fromMyNode(node))
}
c := make(chan bool, P)
@@ -127,4 +130,7 @@ func TestLFStackStress(t *testing.T) {
if sum2 != sum {
t.Fatalf("Wrong sum %d/%d", sum2, sum)
}
+
+ // Let nodes be collected now.
+ stress = nil
}
diff --git a/libgo/go/runtime/lock_futex.go b/libgo/go/runtime/lock_futex.go
new file mode 100644
index 0000000000..725962341d
--- /dev/null
+++ b/libgo/go/runtime/lock_futex.go
@@ -0,0 +1,205 @@
+// 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
new file mode 100644
index 0000000000..d136b82806
--- /dev/null
+++ b/libgo/go/runtime/lock_sema.go
@@ -0,0 +1,270 @@
+// 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
new file mode 100644
index 0000000000..1170449440
--- /dev/null
+++ b/libgo/go/runtime/malloc.go
@@ -0,0 +1,837 @@
+// 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/malloc1.go b/libgo/go/runtime/malloc1.go
deleted file mode 100644
index da92f4c2fb..0000000000
--- a/libgo/go/runtime/malloc1.go
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build ignore
-
-// trivial malloc test
-
-package main
-
-import (
- "flag"
- "fmt"
- "runtime"
-)
-
-var chatty = flag.Bool("v", false, "chatty")
-
-func main() {
- memstats := new(runtime.MemStats)
- runtime.Free(runtime.Alloc(1))
- runtime.ReadMemStats(memstats)
- if *chatty {
- fmt.Printf("%+v %v\n", memstats, uint64(0))
- }
-}
diff --git a/libgo/go/runtime/mallocrand.go b/libgo/go/runtime/mallocrand.go
deleted file mode 100644
index f1bcb89cfa..0000000000
--- a/libgo/go/runtime/mallocrand.go
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build ignore
-
-// Random malloc test.
-
-package main
-
-import (
- "flag"
- "math/rand"
- "runtime"
- "unsafe"
-)
-
-var chatty = flag.Bool("v", false, "chatty")
-
-var footprint uint64
-var allocated uint64
-
-func bigger() {
- memstats := new(runtime.MemStats)
- runtime.ReadMemStats(memstats)
- if f := memstats.Sys; footprint < f {
- footprint = f
- if *chatty {
- println("Footprint", footprint, " for ", allocated)
- }
- if footprint > 1e9 {
- println("too big")
- panic("fail")
- }
- }
-}
-
-// Prime the data structures by allocating one of
-// each block in order. After this, there should be
-// little reason to ask for more memory from the OS.
-func prime() {
- for i := 0; i < 16; i++ {
- b := runtime.Alloc(1 << uint(i))
- runtime.Free(b)
- }
- for i := uintptr(0); i < 256; i++ {
- b := runtime.Alloc(i << 12)
- runtime.Free(b)
- }
-}
-
-func memset(b *byte, c byte, n uintptr) {
- np := uintptr(n)
- for i := uintptr(0); i < np; i++ {
- *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(b)) + i)) = c
- }
-}
-
-func main() {
- flag.Parse()
- // prime()
- var blocks [1]struct {
- base *byte
- siz uintptr
- }
- for i := 0; i < 1<<10; i++ {
- if i%(1<<10) == 0 && *chatty {
- println(i)
- }
- b := rand.Int() % len(blocks)
- if blocks[b].base != nil {
- // println("Free", blocks[b].siz, blocks[b].base)
- runtime.Free(blocks[b].base)
- blocks[b].base = nil
- allocated -= uint64(blocks[b].siz)
- continue
- }
- siz := uintptr(rand.Int() >> (11 + rand.Uint32()%20))
- base := runtime.Alloc(siz)
- // ptr := uintptr(syscall.BytePtr(base))+uintptr(siz/2)
- // obj, size, ref, ok := allocator.find(ptr)
- // if obj != base || *ref != 0 || !ok {
- // println("find", siz, obj, ref, ok)
- // panic("fail")
- // }
- blocks[b].base = base
- blocks[b].siz = siz
- allocated += uint64(siz)
- // println("Alloc", siz, base)
- memset(base, 0xbb, siz)
- bigger()
- }
-}
diff --git a/libgo/go/runtime/mallocrep.go b/libgo/go/runtime/mallocrep.go
deleted file mode 100644
index 03ee71edb4..0000000000
--- a/libgo/go/runtime/mallocrep.go
+++ /dev/null
@@ -1,72 +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.
-
-// Repeated malloc test.
-
-// +build ignore
-
-package main
-
-import (
- "flag"
- "runtime"
-)
-
-var chatty = flag.Bool("v", false, "chatty")
-
-var oldsys uint64
-var memstats runtime.MemStats
-
-func bigger() {
- st := &memstats
- runtime.ReadMemStats(st)
- if oldsys < st.Sys {
- oldsys = st.Sys
- if *chatty {
- println(st.Sys, " system bytes for ", st.Alloc, " Go bytes")
- }
- if st.Sys > 1e9 {
- println("too big")
- panic("fail")
- }
- }
-}
-
-func main() {
- runtime.GC() // clean up garbage from init
- runtime.ReadMemStats(&memstats) // first call can do some allocations
- runtime.MemProfileRate = 0 // disable profiler
- stacks := memstats.Alloc // ignore stacks
- flag.Parse()
- for i := 0; i < 1<<7; i++ {
- for j := 1; j <= 1<<22; j <<= 1 {
- if i == 0 && *chatty {
- println("First alloc:", j)
- }
- if a := memstats.Alloc - stacks; a != 0 {
- println("no allocations but stats report", a, "bytes allocated")
- panic("fail")
- }
- b := runtime.Alloc(uintptr(j))
- runtime.ReadMemStats(&memstats)
- during := memstats.Alloc - stacks
- runtime.Free(b)
- runtime.ReadMemStats(&memstats)
- if a := memstats.Alloc - stacks; a != 0 {
- println("allocated ", j, ": wrong stats: during=", during, " after=", a, " (want 0)")
- panic("fail")
- }
- bigger()
- }
- if i%(1<<10) == 0 && *chatty {
- println(i)
- }
- if i == 0 {
- if *chatty {
- println("Primed", i)
- }
- // runtime.frozen = true
- }
- }
-}
diff --git a/libgo/go/runtime/mallocrep1.go b/libgo/go/runtime/mallocrep1.go
deleted file mode 100644
index bc33e3a6b4..0000000000
--- a/libgo/go/runtime/mallocrep1.go
+++ /dev/null
@@ -1,144 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build ignore
-
-// Repeated malloc test.
-
-package main
-
-import (
- "flag"
- "fmt"
- "runtime"
- "strconv"
-)
-
-var chatty = flag.Bool("v", false, "chatty")
-var reverse = flag.Bool("r", false, "reverse")
-var longtest = flag.Bool("l", false, "long test")
-
-var b []*byte
-var stats = new(runtime.MemStats)
-
-func OkAmount(size, n uintptr) bool {
- if n < size {
- return false
- }
- if size < 16*8 {
- if n > size+16 {
- return false
- }
- } else {
- if n > size*9/8 {
- return false
- }
- }
- return true
-}
-
-func AllocAndFree(size, count int) {
- defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
- if *chatty {
- fmt.Printf("size=%d count=%d ...\n", size, count)
- }
- runtime.ReadMemStats(stats)
- n1 := stats.Alloc
- for i := 0; i < count; i++ {
- b[i] = runtime.Alloc(uintptr(size))
- base, n := runtime.Lookup(b[i])
- if base != b[i] || !OkAmount(uintptr(size), n) {
- println("lookup failed: got", base, n, "for", b[i])
- panic("fail")
- }
- runtime.ReadMemStats(stats)
- if stats.Sys > 1e9 {
- println("too much memory allocated")
- panic("fail")
- }
- }
- runtime.ReadMemStats(stats)
- n2 := stats.Alloc
- if *chatty {
- fmt.Printf("size=%d count=%d stats=%+v\n", size, count, *stats)
- }
- n3 := stats.Alloc
- for j := 0; j < count; j++ {
- i := j
- if *reverse {
- i = count - 1 - j
- }
- alloc := uintptr(stats.Alloc)
- base, n := runtime.Lookup(b[i])
- if base != b[i] || !OkAmount(uintptr(size), n) {
- println("lookup failed: got", base, n, "for", b[i])
- panic("fail")
- }
- runtime.Free(b[i])
- runtime.ReadMemStats(stats)
- if stats.Alloc != uint64(alloc-n) {
- println("free alloc got", stats.Alloc, "expected", alloc-n, "after free of", n)
- panic("fail")
- }
- if stats.Sys > 1e9 {
- println("too much memory allocated")
- panic("fail")
- }
- }
- runtime.ReadMemStats(stats)
- n4 := stats.Alloc
-
- if *chatty {
- fmt.Printf("size=%d count=%d stats=%+v\n", size, count, *stats)
- }
- if n2-n1 != n3-n4 {
- println("wrong alloc count: ", n2-n1, n3-n4)
- panic("fail")
- }
-}
-
-func atoi(s string) int {
- i, _ := strconv.Atoi(s)
- return i
-}
-
-func main() {
- runtime.MemProfileRate = 0 // disable profiler
- flag.Parse()
- b = make([]*byte, 10000)
- if flag.NArg() > 0 {
- AllocAndFree(atoi(flag.Arg(0)), atoi(flag.Arg(1)))
- return
- }
- maxb := 1 << 22
- if !*longtest {
- maxb = 1 << 19
- }
- for j := 1; j <= maxb; j <<= 1 {
- n := len(b)
- max := uintptr(1 << 28)
- if !*longtest {
- max = uintptr(maxb)
- }
- if uintptr(j)*uintptr(n) > max {
- n = int(max / uintptr(j))
- }
- if n < 10 {
- n = 10
- }
- for m := 1; m <= n; {
- AllocAndFree(j, m)
- if m == n {
- break
- }
- m = 5 * m / 4
- if m < 4 {
- m++
- }
- if m > n {
- m = n
- }
- }
- }
-}
diff --git a/libgo/go/runtime/map_test.go b/libgo/go/runtime/map_test.go
index c53066aea6..9ed183bb9d 100644
--- a/libgo/go/runtime/map_test.go
+++ b/libgo/go/runtime/map_test.go
@@ -243,7 +243,12 @@ func TestIterGrowWithGC(t *testing.T) {
func testConcurrentReadsAfterGrowth(t *testing.T, useReflect bool) {
if runtime.GOMAXPROCS(-1) == 1 {
- defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(16))
+ if runtime.GOARCH == "s390" {
+ // Test uses too much address space on 31-bit S390.
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(8))
+ } else {
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(16))
+ }
}
numLoop := 10
numGrowStep := 250
@@ -260,7 +265,7 @@ func testConcurrentReadsAfterGrowth(t *testing.T, useReflect bool) {
for nr := 0; nr < numReader; nr++ {
go func() {
defer wg.Done()
- for _ = range m {
+ for range m {
}
}()
go func() {
@@ -416,3 +421,139 @@ func TestMapNanGrowIterator(t *testing.T) {
t.Fatalf("missing value")
}
}
+
+func TestMapIterOrder(t *testing.T) {
+ if runtime.Compiler == "gccgo" {
+ t.Skip("skipping for gccgo")
+ }
+
+ for _, n := range [...]int{3, 7, 9, 15} {
+ for i := 0; i < 1000; i++ {
+ // Make m be {0: true, 1: true, ..., n-1: true}.
+ m := make(map[int]bool)
+ for i := 0; i < n; i++ {
+ m[i] = true
+ }
+ // Check that iterating over the map produces at least two different orderings.
+ ord := func() []int {
+ var s []int
+ for key := range m {
+ s = append(s, key)
+ }
+ return s
+ }
+ first := ord()
+ ok := false
+ for try := 0; try < 100; try++ {
+ if !reflect.DeepEqual(first, ord()) {
+ ok = true
+ break
+ }
+ }
+ if !ok {
+ t.Errorf("Map with n=%d elements had consistent iteration order: %v", n, first)
+ break
+ }
+ }
+ }
+}
+
+// Issue 8410
+func TestMapSparseIterOrder(t *testing.T) {
+ // Run several rounds to increase the probability
+ // of failure. One is not enough.
+ if runtime.Compiler == "gccgo" {
+ t.Skip("skipping for gccgo")
+ }
+NextRound:
+ for round := 0; round < 10; round++ {
+ m := make(map[int]bool)
+ // Add 1000 items, remove 980.
+ for i := 0; i < 1000; i++ {
+ m[i] = true
+ }
+ for i := 20; i < 1000; i++ {
+ delete(m, i)
+ }
+
+ var first []int
+ for i := range m {
+ first = append(first, i)
+ }
+
+ // 800 chances to get a different iteration order.
+ // See bug 8736 for why we need so many tries.
+ for n := 0; n < 800; n++ {
+ idx := 0
+ for i := range m {
+ if i != first[idx] {
+ // iteration order changed.
+ continue NextRound
+ }
+ idx++
+ }
+ }
+ t.Fatalf("constant iteration order on round %d: %v", round, first)
+ }
+}
+
+func TestMapStringBytesLookup(t *testing.T) {
+ if runtime.Compiler == "gccgo" {
+ t.Skip("skipping for gccgo")
+ }
+ // Use large string keys to avoid small-allocation coalescing,
+ // which can cause AllocsPerRun to report lower counts than it should.
+ m := map[string]int{
+ "1000000000000000000000000000000000000000000000000": 1,
+ "2000000000000000000000000000000000000000000000000": 2,
+ }
+ buf := []byte("1000000000000000000000000000000000000000000000000")
+ if x := m[string(buf)]; x != 1 {
+ t.Errorf(`m[string([]byte("1"))] = %d, want 1`, x)
+ }
+ buf[0] = '2'
+ if x := m[string(buf)]; x != 2 {
+ t.Errorf(`m[string([]byte("2"))] = %d, want 2`, x)
+ }
+
+ var x int
+ n := testing.AllocsPerRun(100, func() {
+ x += m[string(buf)]
+ })
+ if n != 0 {
+ t.Errorf("AllocsPerRun for m[string(buf)] = %v, want 0", n)
+ }
+
+ x = 0
+ n = testing.AllocsPerRun(100, func() {
+ y, ok := m[string(buf)]
+ if !ok {
+ panic("!ok")
+ }
+ x += y
+ })
+ if n != 0 {
+ t.Errorf("AllocsPerRun for x,ok = m[string(buf)] = %v, want 0", n)
+ }
+}
+
+func benchmarkMapPop(b *testing.B, n int) {
+ m := map[int]int{}
+ for i := 0; i < b.N; i++ {
+ for j := 0; j < n; j++ {
+ m[j] = j
+ }
+ for j := 0; j < n; j++ {
+ // Use iterator to pop an element.
+ // We want this to be fast, see issue 8412.
+ for k := range m {
+ delete(m, k)
+ break
+ }
+ }
+ }
+}
+
+func BenchmarkMapPop100(b *testing.B) { benchmarkMapPop(b, 100) }
+func BenchmarkMapPop1000(b *testing.B) { benchmarkMapPop(b, 1000) }
+func BenchmarkMapPop10000(b *testing.B) { benchmarkMapPop(b, 10000) }
diff --git a/libgo/go/runtime/mapspeed_test.go b/libgo/go/runtime/mapspeed_test.go
index d643d98985..119eb3f39c 100644
--- a/libgo/go/runtime/mapspeed_test.go
+++ b/libgo/go/runtime/mapspeed_test.go
@@ -241,7 +241,7 @@ func BenchmarkMapIter(b *testing.B) {
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
- for _, _ = range m {
+ for range m {
}
}
}
@@ -250,7 +250,7 @@ func BenchmarkMapIterEmpty(b *testing.B) {
m := make(map[int]bool)
b.ResetTimer()
for i := 0; i < b.N; i++ {
- for _, _ = range m {
+ for range m {
}
}
}
@@ -268,3 +268,33 @@ func BenchmarkSameLengthMap(b *testing.B) {
_ = m[s1]
}
}
+
+type BigKey [3]int64
+
+func BenchmarkBigKeyMap(b *testing.B) {
+ m := make(map[BigKey]bool)
+ k := BigKey{3, 4, 5}
+ m[k] = true
+ for i := 0; i < b.N; i++ {
+ _ = m[k]
+ }
+}
+
+type BigVal [3]int64
+
+func BenchmarkBigValMap(b *testing.B) {
+ m := make(map[BigKey]BigVal)
+ k := BigKey{3, 4, 5}
+ m[k] = BigVal{6, 7, 8}
+ for i := 0; i < b.N; i++ {
+ _ = m[k]
+ }
+}
+
+func BenchmarkSmallKeyMap(b *testing.B) {
+ m := make(map[int16]bool)
+ m[5] = true
+ for i := 0; i < b.N; i++ {
+ _ = m[5]
+ }
+}
diff --git a/libgo/go/runtime/mem.go b/libgo/go/runtime/mem.go
index ba6d1cf6ab..fb35535c3a 100644
--- a/libgo/go/runtime/mem.go
+++ b/libgo/go/runtime/mem.go
@@ -60,11 +60,10 @@ type MemStats struct {
var Sizeof_C_MStats uintptr // filled in by malloc.goc
-var VmemStats MemStats
-
func init() {
- if Sizeof_C_MStats != unsafe.Sizeof(VmemStats) {
- println(Sizeof_C_MStats, unsafe.Sizeof(VmemStats))
+ var memStats MemStats
+ if Sizeof_C_MStats != unsafe.Sizeof(memStats) {
+ println(Sizeof_C_MStats, unsafe.Sizeof(memStats))
panic("MStats vs MemStatsType size mismatch")
}
}
diff --git a/libgo/go/runtime/memmove_test.go b/libgo/go/runtime/memmove_test.go
index 9525f06826..ffda4fe6c5 100644
--- a/libgo/go/runtime/memmove_test.go
+++ b/libgo/go/runtime/memmove_test.go
@@ -5,6 +5,7 @@
package runtime_test
import (
+ . "runtime"
"testing"
)
@@ -80,7 +81,7 @@ func TestMemmoveAlias(t *testing.T) {
}
}
-func bmMemmove(n int, b *testing.B) {
+func bmMemmove(b *testing.B, n int) {
x := make([]byte, n)
y := make([]byte, n)
b.SetBytes(int64(n))
@@ -89,28 +90,206 @@ func bmMemmove(n int, b *testing.B) {
}
}
-func BenchmarkMemmove0(b *testing.B) { bmMemmove(0, b) }
-func BenchmarkMemmove1(b *testing.B) { bmMemmove(1, b) }
-func BenchmarkMemmove2(b *testing.B) { bmMemmove(2, b) }
-func BenchmarkMemmove3(b *testing.B) { bmMemmove(3, b) }
-func BenchmarkMemmove4(b *testing.B) { bmMemmove(4, b) }
-func BenchmarkMemmove5(b *testing.B) { bmMemmove(5, b) }
-func BenchmarkMemmove6(b *testing.B) { bmMemmove(6, b) }
-func BenchmarkMemmove7(b *testing.B) { bmMemmove(7, b) }
-func BenchmarkMemmove8(b *testing.B) { bmMemmove(8, b) }
-func BenchmarkMemmove9(b *testing.B) { bmMemmove(9, b) }
-func BenchmarkMemmove10(b *testing.B) { bmMemmove(10, b) }
-func BenchmarkMemmove11(b *testing.B) { bmMemmove(11, b) }
-func BenchmarkMemmove12(b *testing.B) { bmMemmove(12, b) }
-func BenchmarkMemmove13(b *testing.B) { bmMemmove(13, b) }
-func BenchmarkMemmove14(b *testing.B) { bmMemmove(14, b) }
-func BenchmarkMemmove15(b *testing.B) { bmMemmove(15, b) }
-func BenchmarkMemmove16(b *testing.B) { bmMemmove(16, b) }
-func BenchmarkMemmove32(b *testing.B) { bmMemmove(32, b) }
-func BenchmarkMemmove64(b *testing.B) { bmMemmove(64, b) }
-func BenchmarkMemmove128(b *testing.B) { bmMemmove(128, b) }
-func BenchmarkMemmove256(b *testing.B) { bmMemmove(256, b) }
-func BenchmarkMemmove512(b *testing.B) { bmMemmove(512, b) }
-func BenchmarkMemmove1024(b *testing.B) { bmMemmove(1024, b) }
-func BenchmarkMemmove2048(b *testing.B) { bmMemmove(2048, b) }
-func BenchmarkMemmove4096(b *testing.B) { bmMemmove(4096, b) }
+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 6efef9bb03..ab7c8aefb3 100644
--- a/libgo/go/runtime/mfinal_test.go
+++ b/libgo/go/runtime/mfinal_test.go
@@ -6,10 +6,9 @@ package runtime_test
import (
"runtime"
- "sync"
- "sync/atomic"
"testing"
"time"
+ "unsafe"
)
type Tintptr *int // assignable to *int
@@ -25,6 +24,9 @@ func TestFinalizerType(t *testing.T) {
if runtime.GOARCH != "amd64" {
t.Skipf("Skipping on non-amd64 machine")
}
+ if runtime.Compiler == "gccgo" {
+ t.Skip("skipping for gccgo")
+ }
ch := make(chan bool, 10)
finalize := func(x *int) {
@@ -45,19 +47,28 @@ func TestFinalizerType(t *testing.T) {
{func(x *int) interface{} { return (*Tint)(x) }, func(v Tinter) { finalize((*int)(v.(*Tint))) }},
}
- for _, tt := range finalizerTests {
+ for i, tt := range finalizerTests {
+ done := make(chan bool, 1)
go func() {
- v := new(int)
+ // allocate struct with pointer to avoid hitting tinyalloc.
+ // Otherwise we can't be sure when the allocation will
+ // be freed.
+ type T struct {
+ v int
+ p unsafe.Pointer
+ }
+ v := &new(T).v
*v = 97531
runtime.SetFinalizer(tt.convert(v), tt.finalizer)
v = nil
+ done <- true
}()
- time.Sleep(1 * time.Second)
+ <-done
runtime.GC()
select {
case <-ch:
case <-time.After(time.Second * 4):
- t.Errorf("finalizer for type %T didn't run", tt.finalizer)
+ t.Errorf("#%d: finalizer for type %T didn't run", i, tt.finalizer)
}
}
}
@@ -72,7 +83,11 @@ func TestFinalizerInterfaceBig(t *testing.T) {
if runtime.GOARCH != "amd64" {
t.Skipf("Skipping on non-amd64 machine")
}
+ if runtime.Compiler == "gccgo" {
+ t.Skip("skipping for gccgo")
+ }
ch := make(chan bool)
+ done := make(chan bool, 1)
go func() {
v := &bigValue{0xDEADBEEFDEADBEEF, true, "It matters not how strait the gate"}
old := *v
@@ -87,8 +102,9 @@ func TestFinalizerInterfaceBig(t *testing.T) {
close(ch)
})
v = nil
+ done <- true
}()
- time.Sleep(1 * time.Second)
+ <-done
runtime.GC()
select {
case <-ch:
@@ -100,51 +116,144 @@ func TestFinalizerInterfaceBig(t *testing.T) {
func fin(v *int) {
}
+// Verify we don't crash at least. golang.org/issue/6857
+func TestFinalizerZeroSizedStruct(t *testing.T) {
+ type Z struct{}
+ z := new(Z)
+ runtime.SetFinalizer(z, func(*Z) {})
+}
+
func BenchmarkFinalizer(b *testing.B) {
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- var wg sync.WaitGroup
- wg.Add(procs)
- for p := 0; p < procs; p++ {
- go func() {
- var data [CallsPerSched]*int
- for i := 0; i < CallsPerSched; i++ {
- data[i] = new(int)
+ const Batch = 1000
+ b.RunParallel(func(pb *testing.PB) {
+ var data [Batch]*int
+ for i := 0; i < Batch; i++ {
+ data[i] = new(int)
+ }
+ for pb.Next() {
+ for i := 0; i < Batch; i++ {
+ runtime.SetFinalizer(data[i], fin)
}
- for atomic.AddInt32(&N, -1) >= 0 {
- runtime.Gosched()
- for i := 0; i < CallsPerSched; i++ {
- runtime.SetFinalizer(data[i], fin)
- }
- for i := 0; i < CallsPerSched; i++ {
- runtime.SetFinalizer(data[i], nil)
- }
+ for i := 0; i < Batch; i++ {
+ runtime.SetFinalizer(data[i], nil)
}
- wg.Done()
- }()
- }
- wg.Wait()
+ }
+ })
}
func BenchmarkFinalizerRun(b *testing.B) {
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- var wg sync.WaitGroup
- wg.Add(procs)
- for p := 0; p < procs; p++ {
- go func() {
- for atomic.AddInt32(&N, -1) >= 0 {
- runtime.Gosched()
- for i := 0; i < CallsPerSched; i++ {
- v := new(int)
- runtime.SetFinalizer(v, fin)
- }
- runtime.GC()
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ v := new(int)
+ runtime.SetFinalizer(v, fin)
+ }
+ })
+}
+
+// One chunk must be exactly one sizeclass in size.
+// It should be a sizeclass not used much by others, so we
+// have a greater chance of finding adjacent ones.
+// size class 19: 320 byte objects, 25 per page, 1 page alloc at a time
+const objsize = 320
+
+type objtype [objsize]byte
+
+func adjChunks() (*objtype, *objtype) {
+ var s []*objtype
+
+ for {
+ c := new(objtype)
+ for _, d := range s {
+ if uintptr(unsafe.Pointer(c))+unsafe.Sizeof(*c) == uintptr(unsafe.Pointer(d)) {
+ return c, d
}
- wg.Done()
- }()
+ if uintptr(unsafe.Pointer(d))+unsafe.Sizeof(*c) == uintptr(unsafe.Pointer(c)) {
+ return d, c
+ }
+ }
+ s = append(s, c)
}
- wg.Wait()
}
+
+// 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")
+ }
+ x, y := adjChunks()
+
+ // the pointer inside xs points to y.
+ xs := x[objsize:] // change objsize to objsize-1 and the test passes
+
+ fin := make(chan bool, 1)
+ runtime.SetFinalizer(y, func(z *objtype) { fin <- true })
+ runtime.GC()
+ select {
+ case <-fin:
+ case <-time.After(4 * time.Second):
+ t.Errorf("finalizer of next object in memory didn't run")
+ }
+ xsglobal = xs // keep empty slice alive until here
+}
+
+var xsglobal []byte
+
+func adjStringChunk() (string, *objtype) {
+ b := make([]byte, objsize)
+ for {
+ s := string(b)
+ t := new(objtype)
+ p := *(*uintptr)(unsafe.Pointer(&s))
+ q := uintptr(unsafe.Pointer(t))
+ if p+objsize == q {
+ return s, t
+ }
+ }
+}
+
+// Make sure an empty string on the stack doesn't pin the next object in memory.
+func TestEmptyString(t *testing.T) {
+ if runtime.Compiler == "gccgo" {
+ t.Skip("skipping for gccgo")
+ }
+
+ x, y := adjStringChunk()
+
+ ss := x[objsize:] // change objsize to objsize-1 and the test passes
+ fin := make(chan bool, 1)
+ // set finalizer on string contents of y
+ runtime.SetFinalizer(y, func(z *objtype) { fin <- true })
+ runtime.GC()
+ select {
+ case <-fin:
+ case <-time.After(4 * time.Second):
+ t.Errorf("finalizer of next string in memory didn't run")
+ }
+ ssglobal = ss // keep 0-length string live until here
+}
+
+var ssglobal string
+
+// Test for issue 7656.
+func TestFinalizerOnGlobal(t *testing.T) {
+ runtime.SetFinalizer(Foo1, func(p *Object1) {})
+ runtime.SetFinalizer(Foo2, func(p *Object2) {})
+ runtime.SetFinalizer(Foo1, nil)
+ runtime.SetFinalizer(Foo2, nil)
+}
+
+type Object1 struct {
+ Something []byte
+}
+
+type Object2 struct {
+ Something byte
+}
+
+var (
+ Foo2 = &Object2{}
+ Foo1 = &Object1{}
+)
diff --git a/libgo/go/runtime/mgc0.go b/libgo/go/runtime/mgc0.go
index b150546622..cbf5e9cfde 100644
--- a/libgo/go/runtime/mgc0.go
+++ b/libgo/go/runtime/mgc0.go
@@ -4,12 +4,149 @@
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
new file mode 100644
index 0000000000..f4da45f5c3
--- /dev/null
+++ b/libgo/go/runtime/mprof.go
@@ -0,0 +1,668 @@
+// 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
new file mode 100644
index 0000000000..3456e02081
--- /dev/null
+++ b/libgo/go/runtime/netpoll.go
@@ -0,0 +1,455 @@
+// 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
new file mode 100644
index 0000000000..ecfc9cdde8
--- /dev/null
+++ b/libgo/go/runtime/netpoll_epoll.go
@@ -0,0 +1,97 @@
+// 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
new file mode 100644
index 0000000000..d6d55b97b8
--- /dev/null
+++ b/libgo/go/runtime/netpoll_kqueue.go
@@ -0,0 +1,101 @@
+// 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
new file mode 100644
index 0000000000..5cbc300321
--- /dev/null
+++ b/libgo/go/runtime/netpoll_nacl.go
@@ -0,0 +1,26 @@
+// 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
new file mode 100644
index 0000000000..dd3ef82676
--- /dev/null
+++ b/libgo/go/runtime/noasm_arm.go
@@ -0,0 +1,54 @@
+// 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 a3d5b00860..3b171877a6 100644
--- a/libgo/go/runtime/norace_test.go
+++ b/libgo/go/runtime/norace_test.go
@@ -9,7 +9,6 @@ package runtime_test
import (
"runtime"
- "sync/atomic"
"testing"
)
@@ -31,28 +30,17 @@ func BenchmarkSyscallExcessWork(b *testing.B) {
}
func benchmarkSyscall(b *testing.B, work, excess int) {
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1) * excess
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
- for p := 0; p < procs; p++ {
- go func() {
- foo := 42
- for atomic.AddInt32(&N, -1) >= 0 {
- runtime.Gosched()
- for g := 0; g < CallsPerSched; g++ {
- runtime.Entersyscall()
- for i := 0; i < work; i++ {
- foo *= 2
- foo /= 2
- }
- runtime.Exitsyscall()
- }
+ b.SetParallelism(excess)
+ b.RunParallel(func(pb *testing.PB) {
+ foo := 42
+ for pb.Next() {
+ runtime.Entersyscall()
+ for i := 0; i < work; i++ {
+ foo *= 2
+ foo /= 2
}
- c <- foo == 42
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ runtime.Exitsyscall()
+ }
+ _ = foo
+ })
}
diff --git a/libgo/go/runtime/os_darwin.go b/libgo/go/runtime/os_darwin.go
new file mode 100644
index 0000000000..4327ced914
--- /dev/null
+++ b/libgo/go/runtime/os_darwin.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.
+
+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
new file mode 100644
index 0000000000..cdaa06986e
--- /dev/null
+++ b/libgo/go/runtime/os_dragonfly.go
@@ -0,0 +1,20 @@
+// 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
new file mode 100644
index 0000000000..59708049c8
--- /dev/null
+++ b/libgo/go/runtime/os_freebsd.go
@@ -0,0 +1,17 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+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
new file mode 100644
index 0000000000..41123ad570
--- /dev/null
+++ b/libgo/go/runtime/os_linux.go
@@ -0,0 +1,17 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+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
new file mode 100644
index 0000000000..8dd43ff06f
--- /dev/null
+++ b/libgo/go/runtime/os_nacl.go
@@ -0,0 +1,39 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package 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
new file mode 100644
index 0000000000..f000c5e9f6
--- /dev/null
+++ b/libgo/go/runtime/os_netbsd.go
@@ -0,0 +1,20 @@
+// 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
new file mode 100644
index 0000000000..a000f963e3
--- /dev/null
+++ b/libgo/go/runtime/os_openbsd.go
@@ -0,0 +1,17 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+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
new file mode 100644
index 0000000000..10e5531ecc
--- /dev/null
+++ b/libgo/go/runtime/os_plan9.go
@@ -0,0 +1,105 @@
+// 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
new file mode 100644
index 0000000000..ca13151204
--- /dev/null
+++ b/libgo/go/runtime/os_solaris.go
@@ -0,0 +1,100 @@
+// 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
new file mode 100644
index 0000000000..1528d2fd13
--- /dev/null
+++ b/libgo/go/runtime/os_windows.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 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
new file mode 100644
index 0000000000..86a1906c0c
--- /dev/null
+++ b/libgo/go/runtime/os_windows_386.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.
+
+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
new file mode 100644
index 0000000000..3f4d4d07cb
--- /dev/null
+++ b/libgo/go/runtime/os_windows_amd64.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.
+
+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
new file mode 100644
index 0000000000..685ff5ca0b
--- /dev/null
+++ b/libgo/go/runtime/panic.go
@@ -0,0 +1,505 @@
+// 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/pprof/mprof_test.go b/libgo/go/runtime/pprof/mprof_test.go
new file mode 100644
index 0000000000..44a3850882
--- /dev/null
+++ b/libgo/go/runtime/pprof/mprof_test.go
@@ -0,0 +1,101 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pprof_test
+
+import (
+ "bytes"
+ "fmt"
+ "regexp"
+ "runtime"
+ . "runtime/pprof"
+ "testing"
+ "unsafe"
+)
+
+var memSink interface{}
+
+func allocateTransient1M() {
+ for i := 0; i < 1024; i++ {
+ memSink = &struct{ x [1024]byte }{}
+ }
+}
+
+func allocateTransient2M() {
+ // prevent inlining
+ if memSink == nil {
+ panic("bad")
+ }
+ memSink = make([]byte, 2<<20)
+}
+
+type Obj32 struct {
+ link *Obj32
+ pad [32 - unsafe.Sizeof(uintptr(0))]byte
+}
+
+var persistentMemSink *Obj32
+
+func allocatePersistent1K() {
+ for i := 0; i < 32; i++ {
+ // Can't use slice because that will introduce implicit allocations.
+ obj := &Obj32{link: persistentMemSink}
+ persistentMemSink = obj
+ }
+}
+
+var memoryProfilerRun = 0
+
+func TestMemoryProfiler(t *testing.T) {
+ // Disable sampling, otherwise it's difficult to assert anything.
+ oldRate := runtime.MemProfileRate
+ runtime.MemProfileRate = 1
+ defer func() {
+ runtime.MemProfileRate = oldRate
+ }()
+
+ // Allocate a meg to ensure that mcache.next_sample is updated to 1.
+ for i := 0; i < 1024; i++ {
+ memSink = make([]byte, 1024)
+ }
+
+ // Do the interesting allocations.
+ allocateTransient1M()
+ allocateTransient2M()
+ allocatePersistent1K()
+ memSink = nil
+
+ runtime.GC() // materialize stats
+ var buf bytes.Buffer
+ if err := Lookup("heap").WriteTo(&buf, 1); err != nil {
+ t.Fatalf("failed to write heap profile: %v", err)
+ }
+
+ memoryProfilerRun++
+
+ tests := []string{
+ fmt.Sprintf(`%v: %v \[%v: %v\] @ 0x[0-9,a-f x]+
+# 0x[0-9,a-f]+ pprof_test\.allocatePersistent1K\+0x[0-9,a-f]+ .*/mprof_test\.go:43
+# 0x[0-9,a-f]+ runtime_pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/mprof_test\.go:66
+`, 32*memoryProfilerRun, 1024*memoryProfilerRun, 32*memoryProfilerRun, 1024*memoryProfilerRun),
+
+ fmt.Sprintf(`0: 0 \[%v: %v\] @ 0x[0-9,a-f x]+
+# 0x[0-9,a-f]+ pprof_test\.allocateTransient1M\+0x[0-9,a-f]+ .*/mprof_test.go:21
+# 0x[0-9,a-f]+ runtime_pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/mprof_test.go:64
+`, (1<<10)*memoryProfilerRun, (1<<20)*memoryProfilerRun),
+
+ // This should start with "0: 0" but gccgo's imprecise
+ // GC means that sometimes the value is not collected.
+ fmt.Sprintf(`(0|%v): (0|%v) \[%v: %v\] @ 0x[0-9,a-f x]+
+# 0x[0-9,a-f]+ pprof_test\.allocateTransient2M\+0x[0-9,a-f]+ .*/mprof_test.go:30
+# 0x[0-9,a-f]+ runtime_pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/mprof_test.go:65
+`, memoryProfilerRun, (2<<20)*memoryProfilerRun, memoryProfilerRun, (2<<20)*memoryProfilerRun),
+ }
+
+ for _, test := range tests {
+ if !regexp.MustCompile(test).Match(buf.Bytes()) {
+ t.Fatalf("The entry did not match:\n%v\n\nProfile:\n%v\n", test, buf.String())
+ }
+ }
+}
diff --git a/libgo/go/runtime/pprof/pprof.go b/libgo/go/runtime/pprof/pprof.go
index 3b8428519d..38593afb6f 100644
--- a/libgo/go/runtime/pprof/pprof.go
+++ b/libgo/go/runtime/pprof/pprof.go
@@ -20,7 +20,7 @@ import (
"text/tabwriter"
)
-// BUG(rsc): Profiles are incomplete and inaccuate on NetBSD, OpenBSD, and OS X.
+// BUG(rsc): Profiles are incomplete and inaccurate on NetBSD and OS X.
// See http://golang.org/issue/6047 for details.
// A Profile is a collection of stack traces showing the call sequences
@@ -331,6 +331,11 @@ func printStackRecord(w io.Writer, stk []uintptr, allFrames bool) {
if i > 0 && pc > f.Entry() && !wasPanic {
if runtime.GOARCH == "386" || runtime.GOARCH == "amd64" {
tracepc--
+ } else if runtime.GOARCH == "s390" || runtime.GOARCH == "s390x" {
+ // only works if function was called
+ // with the brasl instruction (or a
+ // different 6-byte instruction).
+ tracepc -= 6
} else {
tracepc -= 4 // arm, etc
}
@@ -340,7 +345,14 @@ func printStackRecord(w io.Writer, stk []uintptr, allFrames bool) {
// Hide runtime.goexit and any runtime functions at the beginning.
// This is useful mainly for allocation traces.
wasPanic = name == "runtime.panic"
- if name == "runtime.goexit" || !show && strings.HasPrefix(name, "runtime.") {
+ if name == "runtime.goexit" || !show && (strings.HasPrefix(name, "runtime.") || strings.HasPrefix(name, "runtime_")) {
+ continue
+ }
+ if !show && !strings.Contains(name, ".") && strings.HasPrefix(name, "__go_") {
+ continue
+ }
+ if !show && name == "" {
+ // This can happen due to http://gcc.gnu.org/PR65797.
continue
}
show = true
@@ -574,12 +586,6 @@ func StartCPUProfile(w io.Writer) error {
// each client to specify the frequency, we hard code it.
const hz = 100
- // Avoid queueing behind StopCPUProfile.
- // Could use TryLock instead if we had it.
- if cpu.profiling {
- return fmt.Errorf("cpu profiling already in use")
- }
-
cpu.Lock()
defer cpu.Unlock()
if cpu.done == nil {
diff --git a/libgo/go/runtime/pprof/pprof_test.go b/libgo/go/runtime/pprof/pprof_test.go
index 52d63b2e22..1069963720 100644
--- a/libgo/go/runtime/pprof/pprof_test.go
+++ b/libgo/go/runtime/pprof/pprof_test.go
@@ -2,12 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build !nacl
+
package pprof_test
import (
"bytes"
"fmt"
- "hash/crc32"
"math/big"
"os/exec"
"regexp"
@@ -20,35 +21,65 @@ import (
"unsafe"
)
-func TestCPUProfile(t *testing.T) {
- buf := make([]byte, 100000)
- testCPUProfile(t, []string{"crc32.update"}, func() {
- // This loop takes about a quarter second on a 2 GHz laptop.
- // We only need to get one 100 Hz clock tick, so we've got
- // a 25x safety buffer.
- for i := 0; i < 1000; i++ {
- crc32.ChecksumIEEE(buf)
+func cpuHogger(f func()) {
+ // We only need to get one 100 Hz clock tick, so we've got
+ // a 25x safety buffer.
+ // But do at least 500 iterations (which should take about 100ms),
+ // otherwise TestCPUProfileMultithreaded can fail if only one
+ // thread is scheduled during the 250ms period.
+ t0 := time.Now()
+ for i := 0; i < 500 || time.Since(t0) < 250*time.Millisecond; i++ {
+ f()
+ }
+}
+
+var (
+ salt1 = 0
+ salt2 = 0
+)
+
+// The actual CPU hogging function.
+// Must not call other functions nor access heap/globals in the loop,
+// otherwise under race detector the samples will be in the race runtime.
+func cpuHog1() {
+ foo := salt1
+ for i := 0; i < 1e5; i++ {
+ if foo > 0 {
+ foo *= foo
+ } else {
+ foo *= foo + 1
}
+ }
+ salt1 = foo
+}
+
+func cpuHog2() {
+ foo := salt2
+ for i := 0; i < 1e5; i++ {
+ if foo > 0 {
+ foo *= foo
+ } else {
+ foo *= foo + 2
+ }
+ }
+ salt2 = foo
+}
+
+func TestCPUProfile(t *testing.T) {
+ testCPUProfile(t, []string{"pprof_test.cpuHog1"}, func() {
+ cpuHogger(cpuHog1)
})
}
func TestCPUProfileMultithreaded(t *testing.T) {
- buf := make([]byte, 100000)
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
- testCPUProfile(t, []string{"crc32.update"}, func() {
+ testCPUProfile(t, []string{"pprof_test.cpuHog1", "pprof_test.cpuHog2"}, func() {
c := make(chan int)
go func() {
- for i := 0; i < 2000; i++ {
- crc32.Update(0, crc32.IEEETable, buf)
- }
+ cpuHogger(cpuHog1)
c <- 1
}()
- // This loop takes about a quarter second on a 2 GHz laptop.
- // We only need to get one 100 Hz clock tick, so we've got
- // a 25x safety buffer.
- for i := 0; i < 2000; i++ {
- crc32.ChecksumIEEE(buf)
- }
+ cpuHogger(cpuHog2)
<-c
})
}
@@ -108,7 +139,7 @@ func testCPUProfile(t *testing.T, need []string, f func()) {
f()
StopCPUProfile()
- // Check that profile is well formed and contains ChecksumIEEE.
+ // Check that profile is well formed and contains need.
have := make([]uintptr, len(need))
parseProfile(t, prof.Bytes(), func(count uintptr, stk []uintptr) {
for _, pc := range stk {
@@ -116,6 +147,7 @@ func testCPUProfile(t *testing.T, need []string, f func()) {
if f == nil {
continue
}
+ t.Log(f.Name(), count)
for i, name := range need {
if strings.Contains(f.Name(), name) {
have[i] += count
@@ -138,7 +170,11 @@ func testCPUProfile(t *testing.T, need []string, f func()) {
t.Logf("no CPU profile samples collected")
ok = false
}
- min := total / uintptr(len(have)) / 3
+ // We'd like to check a reasonable minimum, like
+ // total / len(have) / smallconstant, but this test is
+ // pretty flaky (see bug 7095). So we'll just test to
+ // make sure we got at least one sample.
+ min := uintptr(1)
for i, name := range need {
if have[i] < min {
t.Logf("%s has %d samples out of %d, want at least %d, ideally %d", name, have[i], total, min, total/uintptr(len(have)))
@@ -189,9 +225,6 @@ func TestCPUProfileWithFork(t *testing.T) {
// If it did, it would see inconsistent state and would either record an incorrect stack
// or crash because the stack was malformed.
func TestGoroutineSwitch(t *testing.T) {
- if runtime.GOOS == "windows" {
- t.Skip("flaky test; see http://golang.org/issue/6417")
- }
// How much to try. These defaults take about 1 seconds
// on a 2012 MacBook Pro. The ones in short mode take
// about 0.1 seconds.
@@ -217,7 +250,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" {
+ if f != nil && (f.Name() == "System" || f.Name() == "ExternalCode" || f.Name() == "GC") {
return
}
}
@@ -264,9 +297,9 @@ func TestMathBigDivide(t *testing.T) {
// Operating systems that are expected to fail the tests. See issue 6047.
var badOS = map[string]bool{
- "darwin": true,
- "netbsd": true,
- "openbsd": true,
+ "darwin": true,
+ "netbsd": true,
+ "plan9": true,
}
func TestBlockProfile(t *testing.T) {
@@ -279,39 +312,45 @@ func TestBlockProfile(t *testing.T) {
tests := [...]TestCase{
{"chan recv", blockChanRecv, `
[0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
-# 0x[0-9,a-f]+ runtime\.chanrecv1\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.c:[0-9]+
-# 0x[0-9,a-f]+ runtime/pprof_test\.blockChanRecv\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
-# 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
+# 0x[0-9,a-f]+ runtime\.chanrecv1\+0x[0-9,a-f]+ .*/src/runtime/chan.go:[0-9]+
+# 0x[0-9,a-f]+ runtime/pprof_test\.blockChanRecv\+0x[0-9,a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+
+# 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+
`},
{"chan send", blockChanSend, `
[0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
-# 0x[0-9,a-f]+ runtime\.chansend1\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.c:[0-9]+
-# 0x[0-9,a-f]+ runtime/pprof_test\.blockChanSend\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
-# 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
+# 0x[0-9,a-f]+ runtime\.chansend1\+0x[0-9,a-f]+ .*/src/runtime/chan.go:[0-9]+
+# 0x[0-9,a-f]+ runtime/pprof_test\.blockChanSend\+0x[0-9,a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+
+# 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+
`},
{"chan close", blockChanClose, `
[0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
-# 0x[0-9,a-f]+ runtime\.chanrecv1\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.c:[0-9]+
-# 0x[0-9,a-f]+ runtime/pprof_test\.blockChanClose\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
-# 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
+# 0x[0-9,a-f]+ runtime\.chanrecv1\+0x[0-9,a-f]+ .*/src/runtime/chan.go:[0-9]+
+# 0x[0-9,a-f]+ runtime/pprof_test\.blockChanClose\+0x[0-9,a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+
+# 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+
`},
{"select recv async", blockSelectRecvAsync, `
[0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
-# 0x[0-9,a-f]+ runtime\.selectgo\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.c:[0-9]+
-# 0x[0-9,a-f]+ runtime/pprof_test\.blockSelectRecvAsync\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
-# 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
+# 0x[0-9,a-f]+ runtime\.selectgo\+0x[0-9,a-f]+ .*/src/runtime/select.go:[0-9]+
+# 0x[0-9,a-f]+ runtime/pprof_test\.blockSelectRecvAsync\+0x[0-9,a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+
+# 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+
`},
{"select send sync", blockSelectSendSync, `
[0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
-# 0x[0-9,a-f]+ runtime\.selectgo\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.c:[0-9]+
-# 0x[0-9,a-f]+ runtime/pprof_test\.blockSelectSendSync\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
-# 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
+# 0x[0-9,a-f]+ runtime\.selectgo\+0x[0-9,a-f]+ .*/src/runtime/select.go:[0-9]+
+# 0x[0-9,a-f]+ runtime/pprof_test\.blockSelectSendSync\+0x[0-9,a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+
+# 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+
`},
{"mutex", blockMutex, `
[0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
-# 0x[0-9,a-f]+ sync\.\(\*Mutex\)\.Lock\+0x[0-9,a-f]+ .*/src/pkg/sync/mutex\.go:[0-9]+
-# 0x[0-9,a-f]+ runtime/pprof_test\.blockMutex\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
-# 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
+# 0x[0-9,a-f]+ sync\.\(\*Mutex\)\.Lock\+0x[0-9,a-f]+ .*/src/sync/mutex\.go:[0-9]+
+# 0x[0-9,a-f]+ runtime/pprof_test\.blockMutex\+0x[0-9,a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+
+# 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+
+`},
+ {"cond", blockCond, `
+[0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
+# 0x[0-9,a-f]+ sync\.\(\*Cond\)\.Wait\+0x[0-9,a-f]+ .*/src/sync/cond\.go:[0-9]+
+# 0x[0-9,a-f]+ runtime/pprof_test\.blockCond\+0x[0-9,a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+
+# 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+
`},
}
@@ -399,3 +438,17 @@ func blockMutex() {
}()
mu.Lock()
}
+
+func blockCond() {
+ var mu sync.Mutex
+ c := sync.NewCond(&mu)
+ mu.Lock()
+ go func() {
+ time.Sleep(blockDelay)
+ mu.Lock()
+ c.Signal()
+ mu.Unlock()
+ }()
+ c.Wait()
+ mu.Unlock()
+}
diff --git a/libgo/go/runtime/print1.go b/libgo/go/runtime/print1.go
new file mode 100644
index 0000000000..8f8268873b
--- /dev/null
+++ b/libgo/go/runtime/print1.go
@@ -0,0 +1,323 @@
+// 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
new file mode 100644
index 0000000000..517ca03df6
--- /dev/null
+++ b/libgo/go/runtime/proc.go
@@ -0,0 +1,246 @@
+// 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 29f71e7448..4f364dc463 100644
--- a/libgo/go/runtime/proc_test.go
+++ b/libgo/go/runtime/proc_test.go
@@ -246,6 +246,49 @@ func TestPreemptionGC(t *testing.T) {
atomic.StoreUint32(&stop, 1)
}
+func TestGCFairness(t *testing.T) {
+ output := executeTest(t, testGCFairnessSource, nil)
+ want := "OK\n"
+ if output != want {
+ t.Fatalf("want %s, got %s\n", want, output)
+ }
+}
+
+const testGCFairnessSource = `
+package main
+
+import (
+ "fmt"
+ "os"
+ "runtime"
+ "time"
+)
+
+func main() {
+ runtime.GOMAXPROCS(1)
+ f, err := os.Open("/dev/null")
+ if os.IsNotExist(err) {
+ // This test tests what it is intended to test only if writes are fast.
+ // If there is no /dev/null, we just don't execute the test.
+ fmt.Println("OK")
+ return
+ }
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+ for i := 0; i < 2; i++ {
+ go func() {
+ for {
+ f.Write([]byte("."))
+ }
+ }()
+ }
+ time.Sleep(10 * time.Millisecond)
+ fmt.Println("OK")
+}
+`
+
func stackGrowthRecursive(i int) {
var pad [128]uint64
if i != 0 && pad[0] == 0 {
@@ -330,24 +373,11 @@ func TestSchedLocalQueueSteal(t *testing.T) {
}
func benchmarkStackGrowth(b *testing.B, rec int) {
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
- for p := 0; p < procs; p++ {
- go func() {
- for atomic.AddInt32(&N, -1) >= 0 {
- runtime.Gosched()
- for g := 0; g < CallsPerSched; g++ {
- stackGrowthRecursive(rec)
- }
- }
- c <- true
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ stackGrowthRecursive(rec)
+ }
+ })
}
func BenchmarkStackGrowth(b *testing.B) {
diff --git a/libgo/go/runtime/race0.go b/libgo/go/runtime/race0.go
new file mode 100644
index 0000000000..5d90cc859a
--- /dev/null
+++ b/libgo/go/runtime/race0.go
@@ -0,0 +1,37 @@
+// 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
new file mode 100644
index 0000000000..e5e691122c
--- /dev/null
+++ b/libgo/go/runtime/rdebug.go
@@ -0,0 +1,37 @@
+// 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
new file mode 100644
index 0000000000..a9f6835818
--- /dev/null
+++ b/libgo/go/runtime/rune.go
@@ -0,0 +1,219 @@
+/*
+ * 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
new file mode 100644
index 0000000000..4e4e1d17a5
--- /dev/null
+++ b/libgo/go/runtime/runtime.go
@@ -0,0 +1,60 @@
+// 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 d121929561..8059d1ad9a 100644
--- a/libgo/go/runtime/runtime_test.go
+++ b/libgo/go/runtime/runtime_test.go
@@ -9,10 +9,12 @@ import (
// "io/ioutil"
// "os"
// "os/exec"
- // . "runtime"
+ . "runtime"
+ "runtime/debug"
// "strconv"
// "strings"
"testing"
+ "unsafe"
)
var errf error
@@ -95,18 +97,23 @@ func BenchmarkDeferMany(b *testing.B) {
// 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()
+ 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", "-S", dir+"/hello").CombinedOutput()
+ out, err = exec.Command("go", "tool", "nm", "-size", dir+"/hello").CombinedOutput()
if err != nil {
t.Fatalf("go tool nm: %v\n%s", err, out)
}
@@ -125,3 +132,121 @@ func TestRuntimeGogoBytes(t *testing.T) {
t.Fatalf("go tool nm did not report size for runtime.gogo")
}
*/
+
+// golang.org/issue/7063
+func TestStopCPUProfilingWithProfilerOff(t *testing.T) {
+ SetCPUProfileRate(0)
+}
+
+// Addresses to test for faulting behavior.
+// This is less a test of SetPanicOnFault and more a check that
+// the operating system and the runtime can process these faults
+// correctly. That is, we're indirectly testing that without SetPanicOnFault
+// these would manage to turn into ordinary crashes.
+// Note that these are truncated on 32-bit systems, so the bottom 32 bits
+// of the larger addresses must themselves be invalid addresses.
+// We might get unlucky and the OS might have mapped one of these
+// addresses, but probably not: they're all in the first page, very high
+// adderesses that normally an OS would reserve for itself, or malformed
+// addresses. Even so, we might have to remove one or two on different
+// systems. We will see.
+
+var faultAddrs = []uint64{
+ // low addresses
+ 0,
+ 1,
+ 0xfff,
+ // high (kernel) addresses
+ // or else malformed.
+ 0xffffffffffffffff,
+ 0xfffffffffffff001,
+ 0xffffffffffff0001,
+ 0xfffffffffff00001,
+ 0xffffffffff000001,
+ 0xfffffffff0000001,
+ 0xffffffff00000001,
+ 0xfffffff000000001,
+ 0xffffff0000000001,
+ 0xfffff00000000001,
+ 0xffff000000000001,
+ 0xfff0000000000001,
+ 0xff00000000000001,
+ 0xf000000000000001,
+ 0x8000000000000001,
+}
+
+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)
+
+ nfault := 0
+ for _, addr := range faultAddrs {
+ testSetPanicOnFault(t, uintptr(addr), &nfault)
+ }
+ if nfault == 0 {
+ t.Fatalf("none of the addresses faulted")
+ }
+}
+
+func testSetPanicOnFault(t *testing.T, addr uintptr, nfault *int) {
+ if GOOS == "nacl" {
+ t.Skip("nacl doesn't seem to fault on high addresses")
+ }
+
+ defer func() {
+ if err := recover(); err != nil {
+ *nfault++
+ }
+ }()
+
+ // The read should fault, except that sometimes we hit
+ // addresses that have had C or kernel pages mapped there
+ // readable by user code. So just log the content.
+ // If no addresses fault, we'll fail the test.
+ v := *(*byte)(unsafe.Pointer(addr))
+ t.Logf("addr %#x: %#x\n", addr, v)
+}
+
+func eqstring_generic(s1, s2 string) bool {
+ if len(s1) != len(s2) {
+ return false
+ }
+ // optimization in assembly versions:
+ // if s1.str == s2.str { return true }
+ for i := 0; i < len(s1); i++ {
+ if s1[i] != s2[i] {
+ return false
+ }
+ }
+ return true
+}
+
+func TestEqString(t *testing.T) {
+ // This isn't really an exhaustive test of eqstring, it's
+ // just a convenient way of documenting (via eqstring_generic)
+ // what eqstring does.
+ s := []string{
+ "",
+ "a",
+ "c",
+ "aaa",
+ "ccc",
+ "cccc"[:3], // same contents, different string
+ "1234567890",
+ }
+ for _, s1 := range s {
+ for _, s2 := range s {
+ x := s1 == s2
+ y := eqstring_generic(s1, s2)
+ if x != y {
+ t.Errorf(`eqstring("%s","%s") = %t, want %t`, s1, s2, x, y)
+ }
+ }
+ }
+}
diff --git a/libgo/go/runtime/runtime_unix_test.go b/libgo/go/runtime/runtime_unix_test.go
new file mode 100644
index 0000000000..963de8cdb8
--- /dev/null
+++ b/libgo/go/runtime/runtime_unix_test.go
@@ -0,0 +1,56 @@
+// 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.
+
+// Only works on systems with syscall.Close.
+// We need a fast system call to provoke the race,
+// and Close(-1) is nearly universally fast.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd plan9
+
+package runtime_test
+
+import (
+ "runtime"
+ "sync"
+ "sync/atomic"
+ "syscall"
+ "testing"
+)
+
+func TestGoroutineProfile(t *testing.T) {
+ // GoroutineProfile used to use the wrong starting sp for
+ // goroutines coming out of system calls, causing possible
+ // crashes.
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(100))
+
+ var stop uint32
+ defer atomic.StoreUint32(&stop, 1) // in case of panic
+
+ var wg sync.WaitGroup
+ for i := 0; i < 4; i++ {
+ wg.Add(1)
+ go func() {
+ for atomic.LoadUint32(&stop) == 0 {
+ syscall.Close(-1)
+ }
+ wg.Done()
+ }()
+ }
+
+ max := 10000
+ if testing.Short() {
+ max = 100
+ }
+ stk := make([]runtime.StackRecord, 100)
+ for n := 0; n < max; n++ {
+ _, ok := runtime.GoroutineProfile(stk)
+ if !ok {
+ t.Fatalf("GoroutineProfile failed")
+ }
+ }
+
+ // If the program didn't crash, we passed.
+ atomic.StoreUint32(&stop, 1)
+ wg.Wait()
+}
diff --git a/libgo/go/runtime/select.go b/libgo/go/runtime/select.go
new file mode 100644
index 0000000000..f735a71e2f
--- /dev/null
+++ b/libgo/go/runtime/select.go
@@ -0,0 +1,651 @@
+// 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
new file mode 100644
index 0000000000..26dbd30ea3
--- /dev/null
+++ b/libgo/go/runtime/sema.go
@@ -0,0 +1,275 @@
+// 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
new file mode 100644
index 0000000000..ba77b6e7be
--- /dev/null
+++ b/libgo/go/runtime/signal_unix.go
@@ -0,0 +1,13 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +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
new file mode 100644
index 0000000000..68079859b0
--- /dev/null
+++ b/libgo/go/runtime/sigpanic_unix.go
@@ -0,0 +1,40 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package runtime
+
+func signame(int32) *byte
+
+func sigpanic() {
+ g := getg()
+ if !canpanic(g) {
+ gothrow("unexpected signal during runtime execution")
+ }
+
+ switch g.sig {
+ case _SIGBUS:
+ if g.sigcode0 == _BUS_ADRERR && g.sigcode1 < 0x1000 || g.paniconfault {
+ panicmem()
+ }
+ print("unexpected fault address ", hex(g.sigcode1), "\n")
+ gothrow("fault")
+ case _SIGSEGV:
+ if (g.sigcode0 == 0 || g.sigcode0 == _SEGV_MAPERR || g.sigcode0 == _SEGV_ACCERR) && g.sigcode1 < 0x1000 || g.paniconfault {
+ panicmem()
+ }
+ print("unexpected fault address ", hex(g.sigcode1), "\n")
+ gothrow("fault")
+ case _SIGFPE:
+ switch g.sigcode0 {
+ case _FPE_INTDIV:
+ panicdivide()
+ case _FPE_INTOVF:
+ panicoverflow()
+ }
+ panicfloat()
+ }
+ panic(errorString(gostringnocopy(signame(g.sig))))
+}
diff --git a/libgo/go/runtime/sigqueue.go b/libgo/go/runtime/sigqueue.go
new file mode 100644
index 0000000000..fed4560fe3
--- /dev/null
+++ b/libgo/go/runtime/sigqueue.go
@@ -0,0 +1,182 @@
+// 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
new file mode 100644
index 0000000000..171087d7f6
--- /dev/null
+++ b/libgo/go/runtime/slice.go
@@ -0,0 +1,139 @@
+// 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/stack.go b/libgo/go/runtime/stack.go
new file mode 100644
index 0000000000..f1b7d32d20
--- /dev/null
+++ b/libgo/go/runtime/stack.go
@@ -0,0 +1,13 @@
+// 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
new file mode 100644
index 0000000000..0809f89bc1
--- /dev/null
+++ b/libgo/go/runtime/string.go
@@ -0,0 +1,298 @@
+// 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/stubs.go b/libgo/go/runtime/stubs.go
new file mode 100644
index 0000000000..fe8f9c9222
--- /dev/null
+++ b/libgo/go/runtime/stubs.go
@@ -0,0 +1,316 @@
+// 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/syscall_windows.go b/libgo/go/runtime/syscall_windows.go
new file mode 100644
index 0000000000..51004b78a0
--- /dev/null
+++ b/libgo/go/runtime/syscall_windows.go
@@ -0,0 +1,174 @@
+// 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
new file mode 100644
index 0000000000..11862c7e23
--- /dev/null
+++ b/libgo/go/runtime/time.go
@@ -0,0 +1,289 @@
+// 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/type.go b/libgo/go/runtime/type.go
deleted file mode 100644
index eba34e4a6b..0000000000
--- a/libgo/go/runtime/type.go
+++ /dev/null
@@ -1,55 +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.
-
-/*
- * Runtime type representation.
- * This file exists only to provide types that 6l can turn into
- * DWARF information for use by gdb. Nothing else uses these.
- * They should match the same types in ../reflect/type.go.
- * For comments see ../reflect/type.go.
- */
-
-package runtime
-
-import "unsafe"
-
-type rtype struct {
- Kind uint8
- align uint8
- fieldAlign uint8
- size uintptr
- hash uint32
-
- hashfn func(unsafe.Pointer, uintptr) uintptr
- equalfn func(unsafe.Pointer, unsafe.Pointer, uintptr) bool
-
- string *string
- *uncommonType
- ptrToThis *rtype
-}
-
-type _method struct {
- name *string
- pkgPath *string
- mtyp *rtype
- typ *rtype
- tfn unsafe.Pointer
-}
-
-type uncommonType struct {
- name *string
- pkgPath *string
- methods []_method
-}
-
-type _imethod struct {
- name *string
- pkgPath *string
- typ *rtype
-}
-
-type interfaceType struct {
- rtype
- methods []_imethod
-}
diff --git a/libgo/go/runtime/typekind.go b/libgo/go/runtime/typekind.go
new file mode 100644
index 0000000000..b64ec44f9e
--- /dev/null
+++ b/libgo/go/runtime/typekind.go
@@ -0,0 +1,44 @@
+// 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/vlrt.go b/libgo/go/runtime/vlrt.go
new file mode 100644
index 0000000000..6370732ca0
--- /dev/null
+++ b/libgo/go/runtime/vlrt.go
@@ -0,0 +1,258 @@
+// Inferno's libkern/vlrt-arm.c
+// http://code.google.com/p/inferno-os/source/browse/libkern/vlrt-arm.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+// Portions Copyright 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+// +build arm 386
+
+package runtime
+
+import "unsafe"
+
+const (
+ sign32 = 1 << (32 - 1)
+ sign64 = 1 << (64 - 1)
+)
+
+func float64toint64(d float64) (y uint64) {
+ _d2v(&y, d)
+ return
+}
+
+func float64touint64(d float64) (y uint64) {
+ _d2v(&y, d)
+ return
+}
+
+func int64tofloat64(y int64) float64 {
+ if y < 0 {
+ return -uint64tofloat64(-uint64(y))
+ }
+ return uint64tofloat64(uint64(y))
+}
+
+func uint64tofloat64(y uint64) float64 {
+ hi := float64(uint32(y >> 32))
+ lo := float64(uint32(y))
+ d := hi*(1<<32) + lo
+ return d
+}
+
+func _d2v(y *uint64, d float64) {
+ x := *(*uint64)(unsafe.Pointer(&d))
+
+ xhi := uint32(x>>32)&0xfffff | 0x100000
+ xlo := uint32(x)
+ sh := 1075 - int32(uint32(x>>52)&0x7ff)
+
+ var ylo, yhi uint32
+ if sh >= 0 {
+ sh := uint32(sh)
+ /* v = (hi||lo) >> sh */
+ if sh < 32 {
+ if sh == 0 {
+ ylo = xlo
+ yhi = xhi
+ } else {
+ ylo = xlo>>sh | xhi<<(32-sh)
+ yhi = xhi >> sh
+ }
+ } else {
+ if sh == 32 {
+ ylo = xhi
+ } else if sh < 64 {
+ ylo = xhi >> (sh - 32)
+ }
+ }
+ } else {
+ /* v = (hi||lo) << -sh */
+ sh := uint32(-sh)
+ if sh <= 11 {
+ ylo = xlo << sh
+ yhi = xhi<<sh | xlo>>(32-sh)
+ } else {
+ /* overflow */
+ yhi = uint32(d) /* causes something awful */
+ }
+ }
+ if x&sign64 != 0 {
+ if ylo != 0 {
+ ylo = -ylo
+ yhi = ^yhi
+ } else {
+ yhi = -yhi
+ }
+ }
+
+ *y = uint64(yhi)<<32 | uint64(ylo)
+}
+
+func uint64div(n, d uint64) uint64 {
+ // Check for 32 bit operands
+ if uint32(n>>32) == 0 && uint32(d>>32) == 0 {
+ if uint32(d) == 0 {
+ panicdivide()
+ }
+ return uint64(uint32(n) / uint32(d))
+ }
+ q, _ := dodiv(n, d)
+ return q
+}
+
+func uint64mod(n, d uint64) uint64 {
+ // Check for 32 bit operands
+ if uint32(n>>32) == 0 && uint32(d>>32) == 0 {
+ if uint32(d) == 0 {
+ panicdivide()
+ }
+ return uint64(uint32(n) % uint32(d))
+ }
+ _, r := dodiv(n, d)
+ return r
+}
+
+func int64div(n, d int64) int64 {
+ // Check for 32 bit operands
+ if int64(int32(n)) == n && int64(int32(d)) == d {
+ if int32(n) == -0x80000000 && int32(d) == -1 {
+ // special case: 32-bit -0x80000000 / -1 = -0x80000000,
+ // but 64-bit -0x80000000 / -1 = 0x80000000.
+ return 0x80000000
+ }
+ if int32(d) == 0 {
+ panicdivide()
+ }
+ return int64(int32(n) / int32(d))
+ }
+
+ nneg := n < 0
+ dneg := d < 0
+ if nneg {
+ n = -n
+ }
+ if dneg {
+ d = -d
+ }
+ uq, _ := dodiv(uint64(n), uint64(d))
+ q := int64(uq)
+ if nneg != dneg {
+ q = -q
+ }
+ return q
+}
+
+func int64mod(n, d int64) int64 {
+ // Check for 32 bit operands
+ if int64(int32(n)) == n && int64(int32(d)) == d {
+ if int32(d) == 0 {
+ panicdivide()
+ }
+ return int64(int32(n) % int32(d))
+ }
+
+ nneg := n < 0
+ if nneg {
+ n = -n
+ }
+ if d < 0 {
+ d = -d
+ }
+ _, ur := dodiv(uint64(n), uint64(d))
+ r := int64(ur)
+ if nneg {
+ r = -r
+ }
+ return r
+}
+
+//go:noescape
+func _mul64by32(lo64 *uint64, a uint64, b uint32) (hi32 uint32)
+
+//go:noescape
+func _div64by32(a uint64, b uint32, r *uint32) (q uint32)
+
+func dodiv(n, d uint64) (q, r uint64) {
+ if GOARCH == "arm" {
+ // arm doesn't have a division instruction, so
+ // slowdodiv is the best that we can do.
+ // TODO: revisit for arm64.
+ return slowdodiv(n, d)
+ }
+
+ if d > n {
+ return 0, n
+ }
+
+ if uint32(d>>32) != 0 {
+ t := uint32(n>>32) / uint32(d>>32)
+ var lo64 uint64
+ hi32 := _mul64by32(&lo64, d, t)
+ if hi32 != 0 || lo64 > n {
+ return slowdodiv(n, d)
+ }
+ return uint64(t), n - lo64
+ }
+
+ // d is 32 bit
+ var qhi uint32
+ if uint32(n>>32) >= uint32(d) {
+ if uint32(d) == 0 {
+ panicdivide()
+ }
+ qhi = uint32(n>>32) / uint32(d)
+ n -= uint64(uint32(d)*qhi) << 32
+ } else {
+ qhi = 0
+ }
+
+ var rlo uint32
+ qlo := _div64by32(n, uint32(d), &rlo)
+ return uint64(qhi)<<32 + uint64(qlo), uint64(rlo)
+}
+
+func slowdodiv(n, d uint64) (q, r uint64) {
+ if d == 0 {
+ panicdivide()
+ }
+
+ // Set up the divisor and find the number of iterations needed.
+ capn := n
+ if n >= sign64 {
+ capn = sign64
+ }
+ i := 0
+ for d < capn {
+ d <<= 1
+ i++
+ }
+
+ for ; i >= 0; i-- {
+ q <<= 1
+ if n >= d {
+ n -= d
+ q |= 1
+ }
+ d >>= 1
+ }
+ return q, n
+}
diff --git a/libgo/go/sort/sort.go b/libgo/go/sort/sort.go
index f06eb3827a..e980c295c3 100644
--- a/libgo/go/sort/sort.go
+++ b/libgo/go/sort/sort.go
@@ -287,9 +287,9 @@ func StringsAreSorted(a []string) bool { return IsSorted(StringSlice(a)) }
// Notes on stable sorting:
// The used algorithms are simple and provable correct on all input and use
// only logarithmic additional stack space. They perform well if compared
-// experimentaly to other stable in-place sorting algorithms.
+// experimentally to other stable in-place sorting algorithms.
//
-// Remarks on other algoritms evaluated:
+// Remarks on other algorithms evaluated:
// - GCC's 4.6.3 stable_sort with merge_without_buffer from libstdc++:
// Not faster.
// - GCC's __rotate for block rotations: Not faster.
@@ -349,7 +349,7 @@ func Stable(data Interface) {
// The algorithm needs O((M+N)*log(M)) calls to data.Swap.
//
// The paper gives O((M+N)*log(M)) as the number of assignments assuming a
-// rotation algorithm wich uses O(M+N+gcd(M+N)) assignments. The argumentation
+// 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.
func symMerge(data Interface, a, m, b int) {
diff --git a/libgo/go/strconv/atob_test.go b/libgo/go/strconv/atob_test.go
index a7c1454eb1..28f469f585 100644
--- a/libgo/go/strconv/atob_test.go
+++ b/libgo/go/strconv/atob_test.go
@@ -5,6 +5,7 @@
package strconv_test
import (
+ "bytes"
. "strconv"
"testing"
)
@@ -55,3 +56,36 @@ func TestParseBool(t *testing.T) {
}
}
}
+
+var boolString = map[bool]string{
+ true: "true",
+ false: "false",
+}
+
+func TestFormatBool(t *testing.T) {
+ for b, s := range boolString {
+ if f := FormatBool(b); f != s {
+ t.Errorf(`FormatBool(%v): expected %q but got %q`, b, s, f)
+ }
+ }
+}
+
+type appendBoolTest struct {
+ b bool
+ in []byte
+ out []byte
+}
+
+var appendBoolTests = []appendBoolTest{
+ {true, []byte("foo "), []byte("foo true")},
+ {false, []byte("foo "), []byte("foo false")},
+}
+
+func TestAppendBool(t *testing.T) {
+ for _, test := range appendBoolTests {
+ b := AppendBool(test.in, test.b)
+ if !bytes.Equal(b, test.out) {
+ t.Errorf("AppendBool(%q, %v): expected %q but got %q", test.in, test.b, test.out, b)
+ }
+ }
+}
diff --git a/libgo/go/strconv/atof.go b/libgo/go/strconv/atof.go
index 1dc521f270..beaa68d71f 100644
--- a/libgo/go/strconv/atof.go
+++ b/libgo/go/strconv/atof.go
@@ -354,17 +354,6 @@ out:
return bits, overflow
}
-func (d *decimal) atof32int() float32 {
- f := float32(0)
- for i := 0; i < d.nd; i++ {
- f = f*10 + float32(d.d[i]-'0')
- }
- if d.neg {
- f = -f
- }
- return f
-}
-
// Exact powers of 10.
var float64pow10 = []float64{
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
diff --git a/libgo/go/strconv/atoi.go b/libgo/go/strconv/atoi.go
index 2d0db7155f..9ecec5a58b 100644
--- a/libgo/go/strconv/atoi.go
+++ b/libgo/go/strconv/atoi.go
@@ -31,7 +31,7 @@ func rangeError(fn, str string) *NumError {
return &NumError{fn, str, ErrRange}
}
-const intSize = 32 << uint(^uint(0)>>63)
+const intSize = 32 << (^uint(0) >> 63)
// IntSize is the size in bits of an int or uint value.
const IntSize = intSize
@@ -142,9 +142,11 @@ Error:
//
// The errors that ParseInt returns have concrete type *NumError
// and include err.Num = s. If s is empty or contains invalid
-// digits, err.Err = ErrSyntax; if the value corresponding
-// to s cannot be represented by a signed integer of the
-// given size, err.Err = ErrRange.
+// digits, err.Err = ErrSyntax and the returned value is 0;
+// if the value corresponding to s cannot be represented by a
+// signed integer of the given size, err.Err = ErrRange and the
+// returned value is the maximum magnitude integer of the
+// appropriate bitSize and sign.
func ParseInt(s string, base int, bitSize int) (i int64, err error) {
const fnParseInt = "ParseInt"
diff --git a/libgo/go/strconv/isprint.go b/libgo/go/strconv/isprint.go
index db5f0fbae0..80738ed711 100644
--- a/libgo/go/strconv/isprint.go
+++ b/libgo/go/strconv/isprint.go
@@ -1,18 +1,21 @@
+// 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.
+
// DO NOT EDIT. GENERATED BY
-// go run makeisprint.go >x && mv x isprint.go
+// go run makeisprint.go -output isprint.go
package strconv
-// (470+136+60)*2 + (218)*4 = 2204 bytes
+// (468+138+67)*2 + (326)*4 = 2650 bytes
var isPrint16 = []uint16{
0x0020, 0x007e,
0x00a1, 0x0377,
- 0x037a, 0x037e,
- 0x0384, 0x0527,
- 0x0531, 0x0556,
+ 0x037a, 0x037f,
+ 0x0384, 0x0556,
0x0559, 0x058a,
- 0x058f, 0x05c7,
+ 0x058d, 0x05c7,
0x05d0, 0x05ea,
0x05f0, 0x05f4,
0x0606, 0x061b,
@@ -23,7 +26,7 @@ var isPrint16 = []uint16{
0x0800, 0x082d,
0x0830, 0x085b,
0x085e, 0x085e,
- 0x08a0, 0x08ac,
+ 0x08a0, 0x08b2,
0x08e4, 0x098c,
0x098f, 0x0990,
0x0993, 0x09b2,
@@ -68,18 +71,17 @@ var isPrint16 = []uint16{
0x0bd0, 0x0bd0,
0x0bd7, 0x0bd7,
0x0be6, 0x0bfa,
- 0x0c01, 0x0c39,
+ 0x0c00, 0x0c39,
0x0c3d, 0x0c4d,
0x0c55, 0x0c59,
0x0c60, 0x0c63,
0x0c66, 0x0c6f,
- 0x0c78, 0x0c7f,
- 0x0c82, 0x0cb9,
+ 0x0c78, 0x0cb9,
0x0cbc, 0x0ccd,
0x0cd5, 0x0cd6,
0x0cde, 0x0ce3,
0x0ce6, 0x0cf2,
- 0x0d02, 0x0d3a,
+ 0x0d01, 0x0d3a,
0x0d3d, 0x0d4e,
0x0d57, 0x0d57,
0x0d60, 0x0d63,
@@ -90,6 +92,7 @@ var isPrint16 = []uint16{
0x0dc0, 0x0dc6,
0x0dca, 0x0dca,
0x0dcf, 0x0ddf,
+ 0x0de6, 0x0def,
0x0df2, 0x0df4,
0x0e01, 0x0e3a,
0x0e3f, 0x0e5b,
@@ -116,7 +119,7 @@ var isPrint16 = []uint16{
0x1380, 0x1399,
0x13a0, 0x13f4,
0x1400, 0x169c,
- 0x16a0, 0x16f0,
+ 0x16a0, 0x16f8,
0x1700, 0x1714,
0x1720, 0x1736,
0x1740, 0x1753,
@@ -129,8 +132,7 @@ var isPrint16 = []uint16{
0x1820, 0x1877,
0x1880, 0x18aa,
0x18b0, 0x18f5,
- 0x1900, 0x191c,
- 0x1920, 0x192b,
+ 0x1900, 0x192b,
0x1930, 0x193b,
0x1940, 0x1940,
0x1944, 0x196d,
@@ -143,6 +145,7 @@ var isPrint16 = []uint16{
0x1a7f, 0x1a89,
0x1a90, 0x1a99,
0x1aa0, 0x1aad,
+ 0x1ab0, 0x1abe,
0x1b00, 0x1b4b,
0x1b50, 0x1b7c,
0x1b80, 0x1bf3,
@@ -150,8 +153,8 @@ var isPrint16 = []uint16{
0x1c3b, 0x1c49,
0x1c4d, 0x1c7f,
0x1cc0, 0x1cc7,
- 0x1cd0, 0x1cf6,
- 0x1d00, 0x1de6,
+ 0x1cd0, 0x1cf9,
+ 0x1d00, 0x1df5,
0x1dfc, 0x1f15,
0x1f18, 0x1f1d,
0x1f20, 0x1f45,
@@ -164,21 +167,23 @@ var isPrint16 = []uint16{
0x2030, 0x205e,
0x2070, 0x2071,
0x2074, 0x209c,
- 0x20a0, 0x20ba,
+ 0x20a0, 0x20bd,
0x20d0, 0x20f0,
0x2100, 0x2189,
- 0x2190, 0x23f3,
+ 0x2190, 0x23fa,
0x2400, 0x2426,
0x2440, 0x244a,
- 0x2460, 0x2b4c,
- 0x2b50, 0x2b59,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2b95,
+ 0x2b98, 0x2bb9,
+ 0x2bbd, 0x2bd1,
0x2c00, 0x2cf3,
0x2cf9, 0x2d27,
0x2d2d, 0x2d2d,
0x2d30, 0x2d67,
0x2d6f, 0x2d70,
0x2d7f, 0x2d96,
- 0x2da0, 0x2e3b,
+ 0x2da0, 0x2e42,
0x2e80, 0x2ef3,
0x2f00, 0x2fd5,
0x2ff0, 0x2ffb,
@@ -192,11 +197,10 @@ var isPrint16 = []uint16{
0xa000, 0xa48c,
0xa490, 0xa4c6,
0xa4d0, 0xa62b,
- 0xa640, 0xa697,
- 0xa69f, 0xa6f7,
- 0xa700, 0xa793,
- 0xa7a0, 0xa7aa,
- 0xa7f8, 0xa82b,
+ 0xa640, 0xa6f7,
+ 0xa700, 0xa7ad,
+ 0xa7b0, 0xa7b1,
+ 0xa7f7, 0xa82b,
0xa830, 0xa839,
0xa840, 0xa877,
0xa880, 0xa8c4,
@@ -205,17 +209,16 @@ var isPrint16 = []uint16{
0xa900, 0xa953,
0xa95f, 0xa97c,
0xa980, 0xa9d9,
- 0xa9de, 0xa9df,
- 0xaa00, 0xaa36,
+ 0xa9de, 0xaa36,
0xaa40, 0xaa4d,
0xaa50, 0xaa59,
- 0xaa5c, 0xaa7b,
- 0xaa80, 0xaac2,
+ 0xaa5c, 0xaac2,
0xaadb, 0xaaf6,
0xab01, 0xab06,
0xab09, 0xab0e,
0xab11, 0xab16,
- 0xab20, 0xab2e,
+ 0xab20, 0xab5f,
+ 0xab64, 0xab65,
0xabc0, 0xabed,
0xabf0, 0xabf9,
0xac00, 0xd7a3,
@@ -231,7 +234,7 @@ var isPrint16 = []uint16{
0xfd92, 0xfdc7,
0xfdf0, 0xfdfd,
0xfe00, 0xfe19,
- 0xfe20, 0xfe26,
+ 0xfe20, 0xfe2d,
0xfe30, 0xfe6b,
0xfe70, 0xfefc,
0xff01, 0xffbe,
@@ -248,15 +251,12 @@ var isNotPrint16 = []uint16{
0x038b,
0x038d,
0x03a2,
+ 0x0530,
0x0560,
0x0588,
0x0590,
0x06dd,
0x083f,
- 0x08a1,
- 0x08ff,
- 0x0978,
- 0x0980,
0x0984,
0x09a9,
0x09b1,
@@ -290,10 +290,10 @@ var isNotPrint16 = []uint16{
0x0c0d,
0x0c11,
0x0c29,
- 0x0c34,
0x0c45,
0x0c49,
0x0c57,
+ 0x0c80,
0x0c84,
0x0c8d,
0x0c91,
@@ -341,7 +341,9 @@ var isNotPrint16 = []uint16{
0x170d,
0x176d,
0x1771,
+ 0x191f,
0x1a5f,
+ 0x1cf7,
0x1f58,
0x1f5a,
0x1f5c,
@@ -351,7 +353,7 @@ var isNotPrint16 = []uint16{
0x1fdc,
0x1ff5,
0x208f,
- 0x2700,
+ 0x2bc9,
0x2c2f,
0x2c5f,
0x2d26,
@@ -368,9 +370,12 @@ var isNotPrint16 = []uint16{
0x318f,
0x321f,
0x32ff,
+ 0xa69e,
0xa78f,
0xa9ce,
+ 0xa9ff,
0xab27,
+ 0xab2f,
0xfb37,
0xfb3d,
0xfb3f,
@@ -388,21 +393,31 @@ var isPrint32 = []uint32{
0x010080, 0x0100fa,
0x010100, 0x010102,
0x010107, 0x010133,
- 0x010137, 0x01018a,
+ 0x010137, 0x01018c,
0x010190, 0x01019b,
+ 0x0101a0, 0x0101a0,
0x0101d0, 0x0101fd,
0x010280, 0x01029c,
0x0102a0, 0x0102d0,
+ 0x0102e0, 0x0102fb,
0x010300, 0x010323,
0x010330, 0x01034a,
+ 0x010350, 0x01037a,
0x010380, 0x0103c3,
0x0103c8, 0x0103d5,
0x010400, 0x01049d,
0x0104a0, 0x0104a9,
+ 0x010500, 0x010527,
+ 0x010530, 0x010563,
+ 0x01056f, 0x01056f,
+ 0x010600, 0x010736,
+ 0x010740, 0x010755,
+ 0x010760, 0x010767,
0x010800, 0x010805,
0x010808, 0x010838,
0x01083c, 0x01083c,
- 0x01083f, 0x01085f,
+ 0x01083f, 0x01089e,
+ 0x0108a7, 0x0108af,
0x010900, 0x01091b,
0x01091f, 0x010939,
0x01093f, 0x01093f,
@@ -413,32 +428,72 @@ var isPrint32 = []uint32{
0x010a38, 0x010a3a,
0x010a3f, 0x010a47,
0x010a50, 0x010a58,
- 0x010a60, 0x010a7f,
+ 0x010a60, 0x010a9f,
+ 0x010ac0, 0x010ae6,
+ 0x010aeb, 0x010af6,
0x010b00, 0x010b35,
0x010b39, 0x010b55,
0x010b58, 0x010b72,
- 0x010b78, 0x010b7f,
+ 0x010b78, 0x010b91,
+ 0x010b99, 0x010b9c,
+ 0x010ba9, 0x010baf,
0x010c00, 0x010c48,
0x010e60, 0x010e7e,
0x011000, 0x01104d,
0x011052, 0x01106f,
- 0x011080, 0x0110c1,
+ 0x01107f, 0x0110c1,
0x0110d0, 0x0110e8,
0x0110f0, 0x0110f9,
0x011100, 0x011143,
+ 0x011150, 0x011176,
0x011180, 0x0111c8,
- 0x0111d0, 0x0111d9,
+ 0x0111cd, 0x0111cd,
+ 0x0111d0, 0x0111da,
+ 0x0111e1, 0x0111f4,
+ 0x011200, 0x01123d,
+ 0x0112b0, 0x0112ea,
+ 0x0112f0, 0x0112f9,
+ 0x011301, 0x01130c,
+ 0x01130f, 0x011310,
+ 0x011313, 0x011339,
+ 0x01133c, 0x011344,
+ 0x011347, 0x011348,
+ 0x01134b, 0x01134d,
+ 0x011357, 0x011357,
+ 0x01135d, 0x011363,
+ 0x011366, 0x01136c,
+ 0x011370, 0x011374,
+ 0x011480, 0x0114c7,
+ 0x0114d0, 0x0114d9,
+ 0x011580, 0x0115b5,
+ 0x0115b8, 0x0115c9,
+ 0x011600, 0x011644,
+ 0x011650, 0x011659,
0x011680, 0x0116b7,
0x0116c0, 0x0116c9,
- 0x012000, 0x01236e,
- 0x012400, 0x012462,
- 0x012470, 0x012473,
+ 0x0118a0, 0x0118f2,
+ 0x0118ff, 0x0118ff,
+ 0x011ac0, 0x011af8,
+ 0x012000, 0x012398,
+ 0x012400, 0x012474,
0x013000, 0x01342e,
0x016800, 0x016a38,
+ 0x016a40, 0x016a69,
+ 0x016a6e, 0x016a6f,
+ 0x016ad0, 0x016aed,
+ 0x016af0, 0x016af5,
+ 0x016b00, 0x016b45,
+ 0x016b50, 0x016b77,
+ 0x016b7d, 0x016b8f,
0x016f00, 0x016f44,
0x016f50, 0x016f7e,
0x016f8f, 0x016f9f,
0x01b000, 0x01b001,
+ 0x01bc00, 0x01bc6a,
+ 0x01bc70, 0x01bc7c,
+ 0x01bc80, 0x01bc88,
+ 0x01bc90, 0x01bc99,
+ 0x01bc9c, 0x01bc9f,
0x01d000, 0x01d0f5,
0x01d100, 0x01d126,
0x01d129, 0x01d172,
@@ -454,6 +509,8 @@ var isPrint32 = []uint32{
0x01d54a, 0x01d6a5,
0x01d6a8, 0x01d7cb,
0x01d7ce, 0x01d7ff,
+ 0x01e800, 0x01e8c4,
+ 0x01e8c7, 0x01e8d6,
0x01ee00, 0x01ee24,
0x01ee27, 0x01ee3b,
0x01ee42, 0x01ee42,
@@ -465,28 +522,30 @@ var isPrint32 = []uint32{
0x01f000, 0x01f02b,
0x01f030, 0x01f093,
0x01f0a0, 0x01f0ae,
- 0x01f0b1, 0x01f0be,
- 0x01f0c1, 0x01f0df,
- 0x01f100, 0x01f10a,
+ 0x01f0b1, 0x01f0f5,
+ 0x01f100, 0x01f10c,
0x01f110, 0x01f16b,
0x01f170, 0x01f19a,
0x01f1e6, 0x01f202,
0x01f210, 0x01f23a,
0x01f240, 0x01f248,
0x01f250, 0x01f251,
- 0x01f300, 0x01f320,
- 0x01f330, 0x01f37c,
- 0x01f380, 0x01f393,
- 0x01f3a0, 0x01f3ca,
- 0x01f3e0, 0x01f3f0,
- 0x01f400, 0x01f4fc,
- 0x01f500, 0x01f53d,
- 0x01f540, 0x01f543,
- 0x01f550, 0x01f567,
- 0x01f5fb, 0x01f640,
- 0x01f645, 0x01f64f,
- 0x01f680, 0x01f6c5,
+ 0x01f300, 0x01f32c,
+ 0x01f330, 0x01f37d,
+ 0x01f380, 0x01f3ce,
+ 0x01f3d4, 0x01f3f7,
+ 0x01f400, 0x01f54a,
+ 0x01f550, 0x01f642,
+ 0x01f645, 0x01f6cf,
+ 0x01f6e0, 0x01f6ec,
+ 0x01f6f0, 0x01f6f3,
0x01f700, 0x01f773,
+ 0x01f780, 0x01f7d4,
+ 0x01f800, 0x01f80b,
+ 0x01f810, 0x01f847,
+ 0x01f850, 0x01f859,
+ 0x01f860, 0x01f887,
+ 0x01f890, 0x01f8ad,
0x020000, 0x02a6d6,
0x02a700, 0x02b734,
0x02b740, 0x02b81d,
@@ -499,7 +558,6 @@ var isNotPrint32 = []uint16{ // add 0x10000 to each entry
0x0027,
0x003b,
0x003e,
- 0x031f,
0x039e,
0x0809,
0x0836,
@@ -509,6 +567,15 @@ var isNotPrint32 = []uint16{ // add 0x10000 to each entry
0x0a18,
0x10bd,
0x1135,
+ 0x1212,
+ 0x1304,
+ 0x1329,
+ 0x1331,
+ 0x1334,
+ 0x246f,
+ 0x6a5f,
+ 0x6b5a,
+ 0x6b62,
0xd455,
0xd49d,
0xd4ad,
@@ -548,11 +615,10 @@ var isNotPrint32 = []uint16{ // add 0x10000 to each entry
0xee8a,
0xeea4,
0xeeaa,
+ 0xf0c0,
0xf0d0,
0xf12f,
- 0xf336,
- 0xf3c5,
- 0xf43f,
- 0xf441,
- 0xf4f8,
+ 0xf4ff,
+ 0xf57a,
+ 0xf5a4,
}
diff --git a/libgo/go/strconv/makeisprint.go b/libgo/go/strconv/makeisprint.go
index 8a6699bdb5..588d0a00b5 100644
--- a/libgo/go/strconv/makeisprint.go
+++ b/libgo/go/strconv/makeisprint.go
@@ -4,15 +4,26 @@
// +build ignore
-// makeisprint generates the tables for strconv's compact isPrint.
+//
+// usage:
+//
+// go run makeisprint.go -output isprint.go
+//
+
package main
import (
+ "bytes"
+ "flag"
"fmt"
- "os"
+ "go/format"
+ "io/ioutil"
+ "log"
"unicode"
)
+var filename = flag.String("output", "isprint.go", "output file name")
+
var (
range16 []uint16
except16 []uint16
@@ -110,6 +121,8 @@ func to16(x []uint32) []uint16 {
}
func main() {
+ flag.Parse()
+
rang, except := scan(0, 0xFFFF)
range16 = to16(rang)
except16 = to16(except)
@@ -117,46 +130,58 @@ func main() {
for i := rune(0); i <= unicode.MaxRune; i++ {
if isPrint(i) != unicode.IsPrint(i) {
- fmt.Fprintf(os.Stderr, "%U: isPrint=%v, want %v\n", i, isPrint(i), unicode.IsPrint(i))
- return
+ log.Fatalf("%U: isPrint=%v, want %v\n", i, isPrint(i), unicode.IsPrint(i))
}
}
- fmt.Printf("// DO NOT EDIT. GENERATED BY\n")
- fmt.Printf("// go run makeisprint.go >x && mv x isprint.go\n\n")
- fmt.Printf("package strconv\n\n")
+ var buf bytes.Buffer
+
+ fmt.Fprintf(&buf, `// 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.`+"\n\n")
+ fmt.Fprintf(&buf, "// DO NOT EDIT. GENERATED BY\n")
+ fmt.Fprintf(&buf, "// go run makeisprint.go -output isprint.go\n\n")
+ fmt.Fprintf(&buf, "package strconv\n\n")
- fmt.Printf("// (%d+%d+%d)*2 + (%d)*4 = %d bytes\n\n",
+ fmt.Fprintf(&buf, "// (%d+%d+%d)*2 + (%d)*4 = %d bytes\n\n",
len(range16), len(except16), len(except32),
len(range32),
(len(range16)+len(except16)+len(except32))*2+
(len(range32))*4)
- fmt.Printf("var isPrint16 = []uint16{\n")
+ fmt.Fprintf(&buf, "var isPrint16 = []uint16{\n")
for i := 0; i < len(range16); i += 2 {
- fmt.Printf("\t%#04x, %#04x,\n", range16[i], range16[i+1])
+ fmt.Fprintf(&buf, "\t%#04x, %#04x,\n", range16[i], range16[i+1])
}
- fmt.Printf("}\n\n")
+ fmt.Fprintf(&buf, "}\n\n")
- fmt.Printf("var isNotPrint16 = []uint16{\n")
+ fmt.Fprintf(&buf, "var isNotPrint16 = []uint16{\n")
for _, r := range except16 {
- fmt.Printf("\t%#04x,\n", r)
+ fmt.Fprintf(&buf, "\t%#04x,\n", r)
}
- fmt.Printf("}\n\n")
+ fmt.Fprintf(&buf, "}\n\n")
- fmt.Printf("var isPrint32 = []uint32{\n")
+ fmt.Fprintf(&buf, "var isPrint32 = []uint32{\n")
for i := 0; i < len(range32); i += 2 {
- fmt.Printf("\t%#06x, %#06x,\n", range32[i], range32[i+1])
+ fmt.Fprintf(&buf, "\t%#06x, %#06x,\n", range32[i], range32[i+1])
}
- fmt.Printf("}\n\n")
+ fmt.Fprintf(&buf, "}\n\n")
- fmt.Printf("var isNotPrint32 = []uint16{ // add 0x10000 to each entry\n")
+ fmt.Fprintf(&buf, "var isNotPrint32 = []uint16{ // add 0x10000 to each entry\n")
for _, r := range except32 {
if r >= 0x20000 {
- fmt.Fprintf(os.Stderr, "%U too big for isNotPrint32\n", r)
- return
+ log.Fatalf("%U too big for isNotPrint32\n", r)
}
- fmt.Printf("\t%#04x,\n", r-0x10000)
+ fmt.Fprintf(&buf, "\t%#04x,\n", r-0x10000)
+ }
+ fmt.Fprintf(&buf, "}\n")
+
+ data, err := format.Source(buf.Bytes())
+ if err != nil {
+ log.Fatal(err)
+ }
+ err = ioutil.WriteFile(*filename, data, 0644)
+ if err != nil {
+ log.Fatal(err)
}
- fmt.Printf("}\n")
}
diff --git a/libgo/go/strconv/quote.go b/libgo/go/strconv/quote.go
index 7d6cdcf0b5..53d51b5a46 100644
--- a/libgo/go/strconv/quote.go
+++ b/libgo/go/strconv/quote.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 makeisprint.go -output isprint.go
+
package strconv
import (
@@ -141,10 +143,21 @@ func AppendQuoteRuneToASCII(dst []byte, r rune) []byte {
// CanBackquote reports whether the string s can be represented
// unchanged as a single-line backquoted string without control
-// characters other than space and tab.
+// characters other than tab.
func CanBackquote(s string) bool {
- for i := 0; i < len(s); i++ {
- if (s[i] < ' ' && s[i] != '\t') || s[i] == '`' {
+ for len(s) > 0 {
+ r, wid := utf8.DecodeRuneInString(s)
+ s = s[wid:]
+ if wid > 1 {
+ if r == '\ufeff' {
+ return false // BOMs are invisible and should not be quoted.
+ }
+ continue // All other multibyte runes are correctly encoded and assumed printable.
+ }
+ if r == utf8.RuneError {
+ return false
+ }
+ if (r < ' ' && r != '\t') || r == '`' || r == '\u007F' {
return false
}
}
diff --git a/libgo/go/strconv/quote_example_test.go b/libgo/go/strconv/quote_example_test.go
new file mode 100644
index 0000000000..405a57eb57
--- /dev/null
+++ b/libgo/go/strconv/quote_example_test.go
@@ -0,0 +1,35 @@
+// 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/strconv/quote_test.go b/libgo/go/strconv/quote_test.go
index 61d9bf9a57..3bf162f987 100644
--- a/libgo/go/strconv/quote_test.go
+++ b/libgo/go/strconv/quote_test.go
@@ -140,11 +140,16 @@ var canbackquotetests = []canBackquoteTest{
{string(29), false},
{string(30), false},
{string(31), false},
+ {string(0x7F), false},
{`' !"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, true},
{`0123456789`, true},
{`ABCDEFGHIJKLMNOPQRSTUVWXYZ`, true},
{`abcdefghijklmnopqrstuvwxyz`, true},
{`☺`, true},
+ {"\x80", false},
+ {"a\xe0\xa0z", false},
+ {"\ufeffabc", false},
+ {"a\ufeffz", false},
}
func TestCanBackquote(t *testing.T) {
diff --git a/libgo/go/strings/example_test.go b/libgo/go/strings/example_test.go
index 36e0a42fb0..7243e16b12 100644
--- a/libgo/go/strings/example_test.go
+++ b/libgo/go/strings/example_test.go
@@ -7,6 +7,7 @@ package strings_test
import (
"fmt"
"strings"
+ "unicode"
)
func ExampleFields() {
@@ -14,6 +15,14 @@ func ExampleFields() {
// Output: Fields are: ["foo" "bar" "baz"]
}
+func ExampleFieldsFunc() {
+ f := func(c rune) bool {
+ return !unicode.IsLetter(c) && !unicode.IsNumber(c)
+ }
+ fmt.Printf("Fields are: %q", strings.FieldsFunc(" foo1;bar2,baz3...", f))
+ // Output: Fields are: ["foo1" "bar2" "baz3"]
+}
+
func ExampleContains() {
fmt.Println(strings.Contains("seafood", "foo"))
fmt.Println(strings.Contains("seafood", "bar"))
@@ -59,6 +68,25 @@ func ExampleIndex() {
// -1
}
+func ExampleIndexFunc() {
+ f := func(c rune) bool {
+ return unicode.Is(unicode.Han, c)
+ }
+ fmt.Println(strings.IndexFunc("Hello, 世界", f))
+ fmt.Println(strings.IndexFunc("Hello, world", f))
+ // Output:
+ // 7
+ // -1
+}
+
+func ExampleIndexAny() {
+ fmt.Println(strings.IndexAny("chicken", "aeiouy"))
+ fmt.Println(strings.IndexAny("crwth", "aeiouy"))
+ // Output:
+ // 2
+ // -1
+}
+
func ExampleIndexRune() {
fmt.Println(strings.IndexRune("chicken", 'k'))
fmt.Println(strings.IndexRune("chicken", 'd'))
@@ -141,8 +169,8 @@ func ExampleToTitle() {
}
func ExampleTrim() {
- fmt.Printf("[%q]", strings.Trim(" !!! Achtung !!! ", "! "))
- // Output: ["Achtung"]
+ fmt.Printf("[%q]", strings.Trim(" !!! Achtung! Achtung! !!! ", "! "))
+ // Output: ["Achtung! Achtung"]
}
func ExampleMap() {
diff --git a/libgo/go/strings/reader.go b/libgo/go/strings/reader.go
index 11240efc07..82df974398 100644
--- a/libgo/go/strings/reader.go
+++ b/libgo/go/strings/reader.go
@@ -15,40 +15,41 @@ import (
// from a string.
type Reader struct {
s string
- i int // current reading index
- prevRune int // index of previous rune; or < 0
+ i int64 // current reading index
+ prevRune int // index of previous rune; or < 0
}
// Len returns the number of bytes of the unread portion of the
// string.
func (r *Reader) Len() int {
- if r.i >= len(r.s) {
+ if r.i >= int64(len(r.s)) {
return 0
}
- return len(r.s) - r.i
+ return int(int64(len(r.s)) - r.i)
}
func (r *Reader) Read(b []byte) (n int, err error) {
if len(b) == 0 {
return 0, nil
}
- if r.i >= len(r.s) {
+ if r.i >= int64(len(r.s)) {
return 0, io.EOF
}
- n = copy(b, r.s[r.i:])
- r.i += n
r.prevRune = -1
+ n = copy(b, r.s[r.i:])
+ r.i += int64(n)
return
}
func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) {
+ // cannot modify state - see io.ReaderAt
if off < 0 {
- return 0, errors.New("strings: invalid offset")
+ return 0, errors.New("strings.Reader.ReadAt: negative offset")
}
if off >= int64(len(r.s)) {
return 0, io.EOF
}
- n = copy(b, r.s[int(off):])
+ n = copy(b, r.s[off:])
if n < len(b) {
err = io.EOF
}
@@ -56,49 +57,51 @@ func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) {
}
func (r *Reader) ReadByte() (b byte, err error) {
- if r.i >= len(r.s) {
+ r.prevRune = -1
+ if r.i >= int64(len(r.s)) {
return 0, io.EOF
}
b = r.s[r.i]
r.i++
- r.prevRune = -1
return
}
func (r *Reader) UnreadByte() error {
+ r.prevRune = -1
if r.i <= 0 {
- return errors.New("strings.Reader: at beginning of string")
+ return errors.New("strings.Reader.UnreadByte: at beginning of string")
}
r.i--
- r.prevRune = -1
return nil
}
func (r *Reader) ReadRune() (ch rune, size int, err error) {
- if r.i >= len(r.s) {
+ if r.i >= int64(len(r.s)) {
+ r.prevRune = -1
return 0, 0, io.EOF
}
- r.prevRune = r.i
+ r.prevRune = int(r.i)
if c := r.s[r.i]; c < utf8.RuneSelf {
r.i++
return rune(c), 1, nil
}
ch, size = utf8.DecodeRuneInString(r.s[r.i:])
- r.i += size
+ r.i += int64(size)
return
}
func (r *Reader) UnreadRune() error {
if r.prevRune < 0 {
- return errors.New("strings.Reader: previous operation was not ReadRune")
+ return errors.New("strings.Reader.UnreadRune: previous operation was not ReadRune")
}
- r.i = r.prevRune
+ r.i = int64(r.prevRune)
r.prevRune = -1
return nil
}
// Seek implements the io.Seeker interface.
func (r *Reader) Seek(offset int64, whence int) (int64, error) {
+ r.prevRune = -1
var abs int64
switch whence {
case 0:
@@ -108,22 +111,19 @@ func (r *Reader) Seek(offset int64, whence int) (int64, error) {
case 2:
abs = int64(len(r.s)) + offset
default:
- return 0, errors.New("strings: invalid whence")
+ return 0, errors.New("strings.Reader.Seek: invalid whence")
}
if abs < 0 {
- return 0, errors.New("strings: negative position")
- }
- if abs >= 1<<31 {
- return 0, errors.New("strings: position out of range")
+ return 0, errors.New("strings.Reader.Seek: negative position")
}
- r.i = int(abs)
+ r.i = abs
return abs, nil
}
// WriteTo implements the io.WriterTo interface.
func (r *Reader) WriteTo(w io.Writer) (n int64, err error) {
r.prevRune = -1
- if r.i >= len(r.s) {
+ if r.i >= int64(len(r.s)) {
return 0, nil
}
s := r.s[r.i:]
@@ -131,7 +131,7 @@ func (r *Reader) WriteTo(w io.Writer) (n int64, err error) {
if m > len(s) {
panic("strings.Reader.WriteTo: invalid WriteString count")
}
- r.i += m
+ r.i += int64(m)
n = int64(m)
if m != len(s) && err == nil {
err = io.ErrShortWrite
diff --git a/libgo/go/strings/reader_test.go b/libgo/go/strings/reader_test.go
index 4fdddcdb58..bee90eb258 100644
--- a/libgo/go/strings/reader_test.go
+++ b/libgo/go/strings/reader_test.go
@@ -10,6 +10,7 @@ import (
"io"
"os"
"strings"
+ "sync"
"testing"
)
@@ -26,9 +27,9 @@ func TestReader(t *testing.T) {
{seek: os.SEEK_SET, off: 0, n: 20, want: "0123456789"},
{seek: os.SEEK_SET, off: 1, n: 1, want: "1"},
{seek: os.SEEK_CUR, off: 1, wantpos: 3, n: 2, want: "34"},
- {seek: os.SEEK_SET, off: -1, seekerr: "strings: negative position"},
- {seek: os.SEEK_SET, off: 1<<31 - 1},
- {seek: os.SEEK_CUR, off: 1, seekerr: "strings: position out of range"},
+ {seek: os.SEEK_SET, off: -1, seekerr: "strings.Reader.Seek: negative position"},
+ {seek: os.SEEK_SET, off: 1 << 33, wantpos: 1 << 33},
+ {seek: os.SEEK_CUR, off: 1, wantpos: 1<<33 + 1},
{seek: os.SEEK_SET, n: 5, want: "01234"},
{seek: os.SEEK_CUR, n: 5, want: "56789"},
{seek: os.SEEK_END, off: -1, n: 1, wantpos: 9, want: "9"},
@@ -60,6 +61,16 @@ func TestReader(t *testing.T) {
}
}
+func TestReadAfterBigSeek(t *testing.T) {
+ r := strings.NewReader("0123456789")
+ if _, err := r.Seek(1<<31+5, os.SEEK_SET); err != nil {
+ t.Fatal(err)
+ }
+ if n, err := r.Read(make([]byte, 10)); n != 0 || err != io.EOF {
+ t.Errorf("Read = %d, %v; want 0, EOF", n, err)
+ }
+}
+
func TestReaderAt(t *testing.T) {
r := strings.NewReader("0123456789")
tests := []struct {
@@ -73,7 +84,7 @@ func TestReaderAt(t *testing.T) {
{1, 9, "123456789", nil},
{11, 10, "", io.EOF},
{0, 0, "", nil},
- {-1, 0, "", "strings: invalid offset"},
+ {-1, 0, "", "strings.Reader.ReadAt: negative offset"},
}
for i, tt := range tests {
b := make([]byte, tt.n)
@@ -88,6 +99,43 @@ func TestReaderAt(t *testing.T) {
}
}
+func TestReaderAtConcurrent(t *testing.T) {
+ // Test for the race detector, to verify ReadAt doesn't mutate
+ // any state.
+ r := strings.NewReader("0123456789")
+ var wg sync.WaitGroup
+ for i := 0; i < 5; i++ {
+ wg.Add(1)
+ go func(i int) {
+ defer wg.Done()
+ var buf [1]byte
+ r.ReadAt(buf[:], int64(i))
+ }(i)
+ }
+ wg.Wait()
+}
+
+func TestEmptyReaderConcurrent(t *testing.T) {
+ // Test for the race detector, to verify a Read that doesn't yield any bytes
+ // is okay to use from multiple goroutines. This was our historic behavior.
+ // See golang.org/issue/7856
+ r := strings.NewReader("")
+ var wg sync.WaitGroup
+ for i := 0; i < 5; i++ {
+ wg.Add(2)
+ go func() {
+ defer wg.Done()
+ var buf [1]byte
+ r.Read(buf[:])
+ }()
+ go func() {
+ defer wg.Done()
+ r.Read(nil)
+ }()
+ }
+ wg.Wait()
+}
+
func TestWriteTo(t *testing.T) {
const str = "0123456789"
for i := 0; i <= len(str); i++ {
diff --git a/libgo/go/strings/replace.go b/libgo/go/strings/replace.go
index 54c9323e04..4752641be0 100644
--- a/libgo/go/strings/replace.go
+++ b/libgo/go/strings/replace.go
@@ -6,7 +6,8 @@ package strings
import "io"
-// A Replacer replaces a list of strings with replacements.
+// Replacer replaces a list of strings with replacements.
+// It is safe for concurrent use by multiple goroutines.
type Replacer struct {
r replacer
}
@@ -17,15 +18,6 @@ type replacer interface {
WriteString(w io.Writer, s string) (n int, err error)
}
-// byteBitmap represents bytes which are sought for replacement.
-// byteBitmap is 256 bits wide, with a bit set for each old byte to be
-// replaced.
-type byteBitmap [256 / 32]uint32
-
-func (m *byteBitmap) set(b byte) {
- m[b>>5] |= uint32(1 << (b & 31))
-}
-
// NewReplacer returns a new Replacer from a list of old, new string pairs.
// Replacements are performed in order, without overlapping matches.
func NewReplacer(oldnew ...string) *Replacer {
@@ -48,30 +40,29 @@ func NewReplacer(oldnew ...string) *Replacer {
}
if allNewBytes {
- bb := &byteReplacer{}
- for i := 0; i < len(oldnew); i += 2 {
- o, n := oldnew[i][0], oldnew[i+1][0]
- if bb.old[o>>5]&uint32(1<<(o&31)) != 0 {
- // Later old->new maps do not override previous ones with the same old string.
- continue
- }
- bb.old.set(o)
- bb.new[o] = n
+ r := byteReplacer{}
+ for i := range r {
+ r[i] = byte(i)
}
- return &Replacer{r: bb}
+ // The first occurrence of old->new map takes precedence
+ // over the others with the same old string.
+ for i := len(oldnew) - 2; i >= 0; i -= 2 {
+ o := oldnew[i][0]
+ n := oldnew[i+1][0]
+ r[o] = n
+ }
+ return &Replacer{r: &r}
}
- bs := &byteStringReplacer{}
- for i := 0; i < len(oldnew); i += 2 {
- o, new := oldnew[i][0], oldnew[i+1]
- if bs.old[o>>5]&uint32(1<<(o&31)) != 0 {
- // Later old->new maps do not override previous ones with the same old string.
- continue
- }
- bs.old.set(o)
- bs.new[o] = []byte(new)
+ r := byteStringReplacer{}
+ // The first occurrence of old->new map takes precedence
+ // over the others with the same old string.
+ for i := len(oldnew) - 2; i >= 0; i -= 2 {
+ o := oldnew[i][0]
+ n := oldnew[i+1]
+ r[o] = []byte(n)
}
- return &Replacer{r: bs}
+ return &Replacer{r: &r}
}
// Replace returns a copy of s with all replacements performed.
@@ -323,6 +314,15 @@ func (r *genericReplacer) WriteString(w io.Writer, s string) (n int, err error)
var last, wn int
var prevMatchEmpty bool
for i := 0; i <= len(s); {
+ // Fast path: s[i] is not a prefix of any pattern.
+ if i != len(s) && r.root.priority == 0 {
+ index := int(r.mapping[s[i]])
+ if index == r.tableSize || r.root.table[index] == nil {
+ i++
+ continue
+ }
+ }
+
// Ignore the empty match iff the previous loop found the empty match.
val, keylen, match := r.lookup(s[i:], prevMatchEmpty)
prevMatchEmpty = match && keylen == 0
@@ -409,24 +409,18 @@ func (r *singleStringReplacer) WriteString(w io.Writer, s string) (n int, err er
// byteReplacer is the implementation that's used when all the "old"
// and "new" values are single ASCII bytes.
-type byteReplacer struct {
- // old has a bit set for each old byte that should be replaced.
- old byteBitmap
-
- // replacement byte, indexed by old byte. only valid if
- // corresponding old bit is set.
- new [256]byte
-}
+// The array contains replacement bytes indexed by old byte.
+type byteReplacer [256]byte
func (r *byteReplacer) Replace(s string) string {
var buf []byte // lazily allocated
for i := 0; i < len(s); i++ {
b := s[i]
- if r.old[b>>5]&uint32(1<<(b&31)) != 0 {
+ if r[b] != b {
if buf == nil {
buf = []byte(s)
}
- buf[i] = r.new[b]
+ buf[i] = r[b]
}
}
if buf == nil {
@@ -447,9 +441,7 @@ func (r *byteReplacer) WriteString(w io.Writer, s string) (n int, err error) {
ncopy := copy(buf, s[:])
s = s[ncopy:]
for i, b := range buf[:ncopy] {
- if r.old[b>>5]&uint32(1<<(b&31)) != 0 {
- buf[i] = r.new[b]
- }
+ buf[i] = r[b]
}
wn, err := w.Write(buf[:ncopy])
n += wn
@@ -461,27 +453,20 @@ func (r *byteReplacer) WriteString(w io.Writer, s string) (n int, err error) {
}
// byteStringReplacer is the implementation that's used when all the
-// "old" values are single ASCII bytes but the "new" values vary in
-// size.
-type byteStringReplacer struct {
- // old has a bit set for each old byte that should be replaced.
- old byteBitmap
-
- // replacement string, indexed by old byte. only valid if
- // corresponding old bit is set.
- new [256][]byte
-}
+// "old" values are single ASCII bytes but the "new" values vary in size.
+// The array contains replacement byte slices indexed by old byte.
+// A nil []byte means that the old byte should not be replaced.
+type byteStringReplacer [256][]byte
func (r *byteStringReplacer) Replace(s string) string {
- newSize := 0
+ newSize := len(s)
anyChanges := false
for i := 0; i < len(s); i++ {
b := s[i]
- if r.old[b>>5]&uint32(1<<(b&31)) != 0 {
+ if r[b] != nil {
anyChanges = true
- newSize += len(r.new[b])
- } else {
- newSize++
+ // The -1 is because we are replacing 1 byte with len(r[b]) bytes.
+ newSize += len(r[b]) - 1
}
}
if !anyChanges {
@@ -491,8 +476,8 @@ func (r *byteStringReplacer) Replace(s string) string {
bi := buf
for i := 0; i < len(s); i++ {
b := s[i]
- if r.old[b>>5]&uint32(1<<(b&31)) != 0 {
- n := copy(bi[:], r.new[b])
+ if r[b] != nil {
+ n := copy(bi, r[b])
bi = bi[n:]
} else {
bi[0] = b
@@ -502,48 +487,32 @@ func (r *byteStringReplacer) Replace(s string) string {
return string(buf)
}
-// WriteString maintains one buffer that's at most 32KB. The bytes in
-// s are enumerated and the buffer is filled. If it reaches its
-// capacity or a byte has a replacement, the buffer is flushed to w.
func (r *byteStringReplacer) WriteString(w io.Writer, s string) (n int, err error) {
- // TODO(bradfitz): use io.WriteString with slices of s instead.
- bufsize := 32 << 10
- if len(s) < bufsize {
- bufsize = len(s)
- }
- buf := make([]byte, bufsize)
- bi := buf[:0]
-
+ sw := getStringWriter(w)
+ last := 0
for i := 0; i < len(s); i++ {
b := s[i]
- var new []byte
- if r.old[b>>5]&uint32(1<<(b&31)) != 0 {
- new = r.new[b]
- } else {
- bi = append(bi, b)
- }
- if len(bi) == cap(bi) || (len(bi) > 0 && len(new) > 0) {
- nw, err := w.Write(bi)
- n += nw
- if err != nil {
- return n, err
- }
- bi = buf[:0]
+ if r[b] == nil {
+ continue
}
- if len(new) > 0 {
- nw, err := w.Write(new)
+ if last != i {
+ nw, err := sw.WriteString(s[last:i])
n += nw
if err != nil {
return n, err
}
}
- }
- if len(bi) > 0 {
- nw, err := w.Write(bi)
+ last = i + 1
+ nw, err := w.Write(r[b])
n += nw
if err != nil {
return n, err
}
}
- return n, nil
+ if last != len(s) {
+ var nw int
+ nw, err = sw.WriteString(s[last:])
+ n += nw
+ }
+ return
}
diff --git a/libgo/go/strings/replace_test.go b/libgo/go/strings/replace_test.go
index 82e4b6ef08..77e48b988b 100644
--- a/libgo/go/strings/replace_test.go
+++ b/libgo/go/strings/replace_test.go
@@ -308,20 +308,21 @@ func TestReplacer(t *testing.T) {
}
}
+var algorithmTestCases = []struct {
+ r *Replacer
+ want string
+}{
+ {capitalLetters, "*strings.byteReplacer"},
+ {htmlEscaper, "*strings.byteStringReplacer"},
+ {NewReplacer("12", "123"), "*strings.singleStringReplacer"},
+ {NewReplacer("1", "12"), "*strings.byteStringReplacer"},
+ {NewReplacer("", "X"), "*strings.genericReplacer"},
+ {NewReplacer("a", "1", "b", "12", "cde", "123"), "*strings.genericReplacer"},
+}
+
// TestPickAlgorithm tests that NewReplacer picks the correct algorithm.
func TestPickAlgorithm(t *testing.T) {
- testCases := []struct {
- r *Replacer
- want string
- }{
- {capitalLetters, "*strings.byteReplacer"},
- {htmlEscaper, "*strings.byteStringReplacer"},
- {NewReplacer("12", "123"), "*strings.singleStringReplacer"},
- {NewReplacer("1", "12"), "*strings.byteStringReplacer"},
- {NewReplacer("", "X"), "*strings.genericReplacer"},
- {NewReplacer("a", "1", "b", "12", "cde", "123"), "*strings.genericReplacer"},
- }
- for i, tc := range testCases {
+ for i, tc := range algorithmTestCases {
got := fmt.Sprintf("%T", tc.r.Replacer())
if got != tc.want {
t.Errorf("%d. algorithm = %s, want %s", i, got, tc.want)
@@ -329,6 +330,23 @@ func TestPickAlgorithm(t *testing.T) {
}
}
+type errWriter struct{}
+
+func (errWriter) Write(p []byte) (n int, err error) {
+ return 0, fmt.Errorf("unwritable")
+}
+
+// TestWriteStringError tests that WriteString returns an error
+// received from the underlying io.Writer.
+func TestWriteStringError(t *testing.T) {
+ for i, tc := range algorithmTestCases {
+ n, err := tc.r.WriteString(errWriter{}, "abc")
+ if n != 0 || err == nil || err.Error() != "unwritable" {
+ t.Errorf("%d. WriteStringError = %d, %v, want 0, unwritable", i, n, err)
+ }
+ }
+}
+
// TestGenericTrieBuilding verifies the structure of the generated trie. There
// is one node per line, and the key ending with the current line is in the
// trie if it ends with a "+".
@@ -480,6 +498,24 @@ func BenchmarkHTMLEscapeOld(b *testing.B) {
}
}
+func BenchmarkByteStringReplacerWriteString(b *testing.B) {
+ str := Repeat("I <3 to escape HTML & other text too.", 100)
+ buf := new(bytes.Buffer)
+ for i := 0; i < b.N; i++ {
+ htmlEscaper.WriteString(buf, str)
+ buf.Reset()
+ }
+}
+
+func BenchmarkByteReplacerWriteString(b *testing.B) {
+ str := Repeat("abcdefghijklmnopqrstuvwxyz", 100)
+ buf := new(bytes.Buffer)
+ for i := 0; i < b.N; i++ {
+ capitalLetters.WriteString(buf, str)
+ buf.Reset()
+ }
+}
+
// BenchmarkByteByteReplaces compares byteByteImpl against multiple Replaces.
func BenchmarkByteByteReplaces(b *testing.B) {
str := Repeat("a", 100) + Repeat("b", 100)
diff --git a/libgo/go/strings/strings.go b/libgo/go/strings/strings.go
index 5d46211d84..27d384983e 100644
--- a/libgo/go/strings/strings.go
+++ b/libgo/go/strings/strings.go
@@ -43,13 +43,29 @@ func explode(s string, n int) []string {
// primeRK is the prime base used in Rabin-Karp algorithm.
const primeRK = 16777619
-// hashstr returns the hash and the appropriate multiplicative
+// hashStr returns the hash and the appropriate multiplicative
// factor for use in Rabin-Karp algorithm.
-func hashstr(sep string) (uint32, uint32) {
+func hashStr(sep string) (uint32, uint32) {
hash := uint32(0)
for i := 0; i < len(sep); i++ {
hash = hash*primeRK + uint32(sep[i])
+ }
+ var pow, sq uint32 = 1, primeRK
+ for i := len(sep); i > 0; i >>= 1 {
+ if i&1 != 0 {
+ pow *= sq
+ }
+ sq *= sq
+ }
+ return hash, pow
+}
+// hashStrRev returns the hash of the reverse of sep and the
+// appropriate multiplicative factor for use in Rabin-Karp algorithm.
+func hashStrRev(sep string) (uint32, uint32) {
+ hash := uint32(0)
+ for i := len(sep) - 1; i >= 0; i-- {
+ hash = hash*primeRK + uint32(sep[i])
}
var pow, sq uint32 = 1, primeRK
for i := len(sep); i > 0; i >>= 1 {
@@ -85,7 +101,8 @@ func Count(s, sep string) int {
}
return 0
}
- hashsep, pow := hashstr(sep)
+ // Rabin-Karp search
+ hashsep, pow := hashStr(sep)
h := uint32(0)
for i := 0; i < len(sep); i++ {
h = h*primeRK + uint32(s[i])
@@ -139,8 +156,8 @@ func Index(s, sep string) int {
case n > len(s):
return -1
}
- // Hash sep.
- hashsep, pow := hashstr(sep)
+ // Rabin-Karp search
+ hashsep, pow := hashStr(sep)
var h uint32
for i := 0; i < n; i++ {
h = h*primeRK + uint32(s[i])
@@ -163,22 +180,41 @@ func Index(s, sep string) int {
// LastIndex returns the index of the last instance of sep in s, or -1 if sep is not present in s.
func LastIndex(s, sep string) int {
n := len(sep)
- if n == 0 {
+ switch {
+ case n == 0:
return len(s)
- }
- c := sep[0]
- if n == 1 {
+ 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
+ case n == len(s):
+ if sep == s {
+ return 0
+ }
+ return -1
+ case n > len(s):
+ return -1
+ }
+ // Rabin-Karp search from the end of the string
+ hashsep, pow := hashStrRev(sep)
+ last := len(s) - n
+ var h uint32
+ for i := len(s) - 1; i >= last; i-- {
+ h = h*primeRK + uint32(s[i])
+ }
+ if h == hashsep && s[last:] == sep {
+ return last
}
- // n > 1
- for i := len(s) - n; i >= 0; i-- {
- if s[i] == c && s[i:i+n] == sep {
+ for i := last - 1; i >= 0; i-- {
+ h *= primeRK
+ h += uint32(s[i])
+ h -= pow * uint32(s[i+n])
+ if h == hashsep && s[i:i+n] == sep {
return i
}
}
@@ -189,13 +225,8 @@ func LastIndex(s, sep string) int {
// r, or -1 if rune is not present in s.
func IndexRune(s string, r rune) int {
switch {
- case r < 0x80:
- b := byte(r)
- for i := 0; i < len(s); i++ {
- if s[i] == b {
- return i
- }
- }
+ case r < utf8.RuneSelf:
+ return IndexByte(s, byte(r))
default:
for i, c := range s {
if c == r {
@@ -311,6 +342,8 @@ func Fields(s string) []string {
// FieldsFunc splits the string s at each run of Unicode code points c satisfying f(c)
// and returns an array of slices of s. If all code points in s satisfy f(c) or the
// string is empty, an empty slice is returned.
+// FieldsFunc makes no guarantees about the order in which it calls f(c).
+// If f does not return consistent results for a given c, FieldsFunc may crash.
func FieldsFunc(s string, f func(rune) bool) []string {
// First count the fields.
n := 0
@@ -423,9 +456,10 @@ func Map(mapping func(rune) rune, s string) string {
// Repeat returns a new string consisting of count copies of the string s.
func Repeat(s string, count int) string {
b := make([]byte, len(s)*count)
- bp := 0
- for i := 0; i < count; i++ {
- bp += copy(b[bp:], s)
+ bp := copy(b, s)
+ for bp < len(b) {
+ copy(b[bp:], b[:bp])
+ bp *= 2
}
return string(b)
}
@@ -634,6 +668,9 @@ func TrimSuffix(s, suffix string) string {
// Replace returns a copy of the string s with the first n
// non-overlapping instances of old replaced by new.
+// If old is empty, it matches at the beginning of the string
+// and after each UTF-8 sequence, yielding up to k+1 replacements
+// for a k-rune string.
// If n < 0, there is no limit on the number of replacements.
func Replace(s, old, new string, n int) string {
if old == new || n == 0 {
diff --git a/libgo/go/strings/strings_test.go b/libgo/go/strings/strings_test.go
index df0dd7165a..7bb81ef3ca 100644
--- a/libgo/go/strings/strings_test.go
+++ b/libgo/go/strings/strings_test.go
@@ -168,6 +168,15 @@ func BenchmarkIndex(b *testing.B) {
}
}
+func BenchmarkLastIndex(b *testing.B) {
+ if got := Index(benchmarkString, "v"); got != 17 {
+ b.Fatalf("wrong index: expected 17, got=%d", got)
+ }
+ for i := 0; i < b.N; i++ {
+ LastIndex(benchmarkString, "v")
+ }
+}
+
func BenchmarkIndexByte(b *testing.B) {
if got := IndexByte(benchmarkString, 'v'); got != 17 {
b.Fatalf("wrong index: expected 17, got=%d", got)
@@ -652,7 +661,7 @@ func equal(m string, s1, s2 string, t *testing.T) bool {
e1 := Split(s1, "")
e2 := Split(s2, "")
for i, c1 := range e1 {
- if i > len(e2) {
+ if i >= len(e2) {
break
}
r1, _ := utf8.DecodeRuneInString(c1)
@@ -858,6 +867,32 @@ func TestReadRune(t *testing.T) {
}
}
+var UnreadRuneErrorTests = []struct {
+ name string
+ f func(*Reader)
+}{
+ {"Read", func(r *Reader) { r.Read([]byte{0}) }},
+ {"ReadByte", func(r *Reader) { r.ReadByte() }},
+ {"UnreadRune", func(r *Reader) { r.UnreadRune() }},
+ {"Seek", func(r *Reader) { r.Seek(0, 1) }},
+ {"WriteTo", func(r *Reader) { r.WriteTo(&bytes.Buffer{}) }},
+}
+
+func TestUnreadRuneError(t *testing.T) {
+ for _, tt := range UnreadRuneErrorTests {
+ reader := NewReader("0123456789")
+ if _, _, err := reader.ReadRune(); err != nil {
+ // should not happen
+ t.Fatal(err)
+ }
+ tt.f(reader)
+ err := reader.UnreadRune()
+ if err == nil {
+ t.Errorf("Unreading after %s: expected error", tt.name)
+ }
+ }
+}
+
var ReplaceTests = []struct {
in string
old, new string
@@ -903,6 +938,8 @@ var TitleTests = []struct {
{"123a456", "123a456"},
{"double-blind", "Double-Blind"},
{"ÿøû", "Ÿøû"},
+ {"with_underscore", "With_underscore"},
+ {"unicode \xe2\x80\xa8 line separator", "Unicode \xe2\x80\xa8 Line Separator"},
}
func TestTitle(t *testing.T) {
@@ -1041,8 +1078,11 @@ func makeBenchInputHard() string {
"hello", "world",
}
x := make([]byte, 0, 1<<20)
- for len(x) < 1<<20 {
+ for {
i := rand.Intn(len(tokens))
+ if len(x)+len(tokens[i]) >= 1<<20 {
+ break
+ }
x = append(x, tokens[i]...)
}
return string(x)
@@ -1056,6 +1096,12 @@ func benchmarkIndexHard(b *testing.B, sep string) {
}
}
+func benchmarkLastIndexHard(b *testing.B, sep string) {
+ for i := 0; i < b.N; i++ {
+ LastIndex(benchInputHard, sep)
+ }
+}
+
func benchmarkCountHard(b *testing.B, sep string) {
for i := 0; i < b.N; i++ {
Count(benchInputHard, sep)
@@ -1066,6 +1112,10 @@ func BenchmarkIndexHard1(b *testing.B) { benchmarkIndexHard(b, "<>") }
func BenchmarkIndexHard2(b *testing.B) { benchmarkIndexHard(b, "</pre>") }
func BenchmarkIndexHard3(b *testing.B) { benchmarkIndexHard(b, "<b>hello world</b>") }
+func BenchmarkLastIndexHard1(b *testing.B) { benchmarkLastIndexHard(b, "<>") }
+func BenchmarkLastIndexHard2(b *testing.B) { benchmarkLastIndexHard(b, "</pre>") }
+func BenchmarkLastIndexHard3(b *testing.B) { benchmarkLastIndexHard(b, "<b>hello world</b>") }
+
func BenchmarkCountHard1(b *testing.B) { benchmarkCountHard(b, "<>") }
func BenchmarkCountHard2(b *testing.B) { benchmarkCountHard(b, "</pre>") }
func BenchmarkCountHard3(b *testing.B) { benchmarkCountHard(b, "<b>hello world</b>") }
@@ -1146,3 +1196,9 @@ func BenchmarkSplit3(b *testing.B) {
Split(benchInputHard, "hello")
}
}
+
+func BenchmarkRepeat(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Repeat("-", 80)
+ }
+}
diff --git a/libgo/go/sync/atomic/64bit_arm.go b/libgo/go/sync/atomic/64bit_arm.go
index c08f214c7e..b98e60827e 100644
--- a/libgo/go/sync/atomic/64bit_arm.go
+++ b/libgo/go/sync/atomic/64bit_arm.go
@@ -44,3 +44,15 @@ func swapUint64(addr *uint64, new uint64) (old uint64) {
}
return
}
+
+// Additional ARM-specific assembly routines.
+// Declaration here to give assembly routines correct stack maps for arguments.
+func armCompareAndSwapUint32(addr *uint32, old, new uint32) (swapped bool)
+func armCompareAndSwapUint64(addr *uint64, old, new uint64) (swapped bool)
+func generalCAS64(addr *uint64, old, new uint64) (swapped bool)
+func armAddUint32(addr *uint32, delta uint32) (new uint32)
+func armAddUint64(addr *uint64, delta uint64) (new uint64)
+func armSwapUint32(addr *uint32, new uint32) (old uint32)
+func armSwapUint64(addr *uint64, new uint64) (old uint64)
+func armLoadUint64(addr *uint64) (val uint64)
+func armStoreUint64(addr *uint64, val uint64)
diff --git a/libgo/go/sync/atomic/atomic_test.go b/libgo/go/sync/atomic/atomic_test.go
index 06dd5f7ce8..eaa3b6b5c9 100644
--- a/libgo/go/sync/atomic/atomic_test.go
+++ b/libgo/go/sync/atomic/atomic_test.go
@@ -813,7 +813,7 @@ func hammerSwapUintptr32(uaddr *uint32, count int) {
new := uintptr(seed+i)<<16 | uintptr(seed+i)<<16>>16
old := SwapUintptr(addr, new)
if old>>16 != old<<16>>16 {
- panic(fmt.Sprintf("SwapUintptr is not atomic: %v", old))
+ panic(fmt.Sprintf("SwapUintptr is not atomic: %#08x", old))
}
}
}
@@ -827,7 +827,7 @@ func hammerSwapPointer32(uaddr *uint32, count int) {
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: %v", old))
+ panic(fmt.Sprintf("SwapPointer is not atomic: %#08x", old))
}
}
}
@@ -858,7 +858,7 @@ func hammerCompareAndSwapInt32(uaddr *uint32, count int) {
addr := (*int32)(unsafe.Pointer(uaddr))
for i := 0; i < count; i++ {
for {
- v := *addr
+ v := LoadInt32(addr)
if CompareAndSwapInt32(addr, v, v+1) {
break
}
@@ -869,7 +869,7 @@ func hammerCompareAndSwapInt32(uaddr *uint32, count int) {
func hammerCompareAndSwapUint32(addr *uint32, count int) {
for i := 0; i < count; i++ {
for {
- v := *addr
+ v := LoadUint32(addr)
if CompareAndSwapUint32(addr, v, v+1) {
break
}
@@ -883,7 +883,7 @@ func hammerCompareAndSwapUintptr32(uaddr *uint32, count int) {
addr := (*uintptr)(unsafe.Pointer(uaddr))
for i := 0; i < count; i++ {
for {
- v := *addr
+ v := LoadUintptr(addr)
if CompareAndSwapUintptr(addr, v, v+1) {
break
}
@@ -897,7 +897,7 @@ func hammerCompareAndSwapPointer32(uaddr *uint32, count int) {
addr := (*unsafe.Pointer)(unsafe.Pointer(uaddr))
for i := 0; i < count; i++ {
for {
- v := *addr
+ v := LoadPointer(addr)
if CompareAndSwapPointer(addr, v, unsafe.Pointer(uintptr(v)+1)) {
break
}
@@ -1039,7 +1039,7 @@ func hammerCompareAndSwapInt64(uaddr *uint64, count int) {
addr := (*int64)(unsafe.Pointer(uaddr))
for i := 0; i < count; i++ {
for {
- v := *addr
+ v := LoadInt64(addr)
if CompareAndSwapInt64(addr, v, v+1) {
break
}
@@ -1050,7 +1050,7 @@ func hammerCompareAndSwapInt64(uaddr *uint64, count int) {
func hammerCompareAndSwapUint64(addr *uint64, count int) {
for i := 0; i < count; i++ {
for {
- v := *addr
+ v := LoadUint64(addr)
if CompareAndSwapUint64(addr, v, v+1) {
break
}
@@ -1064,7 +1064,7 @@ func hammerCompareAndSwapUintptr64(uaddr *uint64, count int) {
addr := (*uintptr)(unsafe.Pointer(uaddr))
for i := 0; i < count; i++ {
for {
- v := *addr
+ v := LoadUintptr(addr)
if CompareAndSwapUintptr(addr, v, v+1) {
break
}
@@ -1078,7 +1078,7 @@ func hammerCompareAndSwapPointer64(uaddr *uint64, count int) {
addr := (*unsafe.Pointer)(unsafe.Pointer(uaddr))
for i := 0; i < count; i++ {
for {
- v := *addr
+ v := LoadPointer(addr)
if CompareAndSwapPointer(addr, v, unsafe.Pointer(uintptr(v)+1)) {
break
}
@@ -1465,6 +1465,9 @@ 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/atomic/doc.go b/libgo/go/sync/atomic/doc.go
index 17ba72fa17..10fb8c9177 100644
--- a/libgo/go/sync/atomic/doc.go
+++ b/libgo/go/sync/atomic/doc.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.
-// +build !race
-
// Package atomic provides low-level atomic memory primitives
// useful for implementing synchronization algorithms.
//
diff --git a/libgo/go/sync/atomic/race.go b/libgo/go/sync/atomic/race.go
deleted file mode 100644
index 6cbbf12cb6..0000000000
--- a/libgo/go/sync/atomic/race.go
+++ /dev/null
@@ -1,276 +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 race
-
-package atomic
-
-import (
- "runtime"
- "unsafe"
-)
-
-// We use runtime.RaceRead() inside of atomic operations to catch races
-// between atomic and non-atomic operations. It will also catch races
-// between Mutex.Lock() and mutex overwrite (mu = Mutex{}). Since we use
-// only RaceRead() we won't catch races with non-atomic loads.
-// Otherwise (if we use RaceWrite()) we will report races
-// between atomic operations (false positives).
-
-var mtx uint32 = 1 // same for all
-
-func SwapInt32(addr *int32, new int32) (old int32) {
- return int32(SwapUint32((*uint32)(unsafe.Pointer(addr)), uint32(new)))
-}
-
-func SwapUint32(addr *uint32, new uint32) (old uint32) {
- _ = *addr
- runtime.RaceSemacquire(&mtx)
- runtime.RaceRead(unsafe.Pointer(addr))
- runtime.RaceAcquire(unsafe.Pointer(addr))
- old = *addr
- *addr = new
- runtime.RaceReleaseMerge(unsafe.Pointer(addr))
- runtime.RaceSemrelease(&mtx)
- return
-}
-
-func SwapInt64(addr *int64, new int64) (old int64) {
- return int64(SwapUint64((*uint64)(unsafe.Pointer(addr)), uint64(new)))
-}
-
-func SwapUint64(addr *uint64, new uint64) (old uint64) {
- _ = *addr
- runtime.RaceSemacquire(&mtx)
- runtime.RaceRead(unsafe.Pointer(addr))
- runtime.RaceAcquire(unsafe.Pointer(addr))
- old = *addr
- *addr = new
- runtime.RaceReleaseMerge(unsafe.Pointer(addr))
- runtime.RaceSemrelease(&mtx)
- return
-}
-
-func SwapUintptr(addr *uintptr, new uintptr) (old uintptr) {
- return uintptr(SwapPointer((*unsafe.Pointer)(unsafe.Pointer(addr)), unsafe.Pointer(new)))
-}
-
-func SwapPointer(addr *unsafe.Pointer, new unsafe.Pointer) (old unsafe.Pointer) {
- _ = *addr
- runtime.RaceSemacquire(&mtx)
- runtime.RaceRead(unsafe.Pointer(addr))
- runtime.RaceAcquire(unsafe.Pointer(addr))
- old = *addr
- *addr = new
- runtime.RaceReleaseMerge(unsafe.Pointer(addr))
- runtime.RaceSemrelease(&mtx)
- return
-}
-
-func CompareAndSwapInt32(val *int32, old, new int32) bool {
- return CompareAndSwapUint32((*uint32)(unsafe.Pointer(val)), uint32(old), uint32(new))
-}
-
-func CompareAndSwapUint32(val *uint32, old, new uint32) (swapped bool) {
- _ = *val
- swapped = false
- runtime.RaceSemacquire(&mtx)
- runtime.RaceRead(unsafe.Pointer(val))
- runtime.RaceAcquire(unsafe.Pointer(val))
- if *val == old {
- *val = new
- swapped = true
- runtime.RaceReleaseMerge(unsafe.Pointer(val))
- }
- runtime.RaceSemrelease(&mtx)
- return
-}
-
-func CompareAndSwapInt64(val *int64, old, new int64) bool {
- return CompareAndSwapUint64((*uint64)(unsafe.Pointer(val)), uint64(old), uint64(new))
-}
-
-func CompareAndSwapUint64(val *uint64, old, new uint64) (swapped bool) {
- _ = *val
- swapped = false
- runtime.RaceSemacquire(&mtx)
- runtime.RaceRead(unsafe.Pointer(val))
- runtime.RaceAcquire(unsafe.Pointer(val))
- if *val == old {
- *val = new
- swapped = true
- runtime.RaceReleaseMerge(unsafe.Pointer(val))
- }
- runtime.RaceSemrelease(&mtx)
- return
-}
-
-func CompareAndSwapPointer(val *unsafe.Pointer, old, new unsafe.Pointer) (swapped bool) {
- _ = *val
- swapped = false
- runtime.RaceSemacquire(&mtx)
- runtime.RaceRead(unsafe.Pointer(val))
- runtime.RaceAcquire(unsafe.Pointer(val))
- if *val == old {
- *val = new
- swapped = true
- runtime.RaceReleaseMerge(unsafe.Pointer(val))
- }
- runtime.RaceSemrelease(&mtx)
- return
-}
-
-func CompareAndSwapUintptr(val *uintptr, old, new uintptr) (swapped bool) {
- _ = *val
- swapped = false
- runtime.RaceSemacquire(&mtx)
- runtime.RaceRead(unsafe.Pointer(val))
- runtime.RaceAcquire(unsafe.Pointer(val))
- if *val == old {
- *val = new
- swapped = true
- runtime.RaceReleaseMerge(unsafe.Pointer(val))
- }
- runtime.RaceSemrelease(&mtx)
- return
-}
-
-func AddInt32(val *int32, delta int32) int32 {
- return int32(AddUint32((*uint32)(unsafe.Pointer(val)), uint32(delta)))
-}
-
-func AddUint32(val *uint32, delta uint32) (new uint32) {
- _ = *val
- runtime.RaceSemacquire(&mtx)
- runtime.RaceRead(unsafe.Pointer(val))
- runtime.RaceAcquire(unsafe.Pointer(val))
- *val = *val + delta
- new = *val
- runtime.RaceReleaseMerge(unsafe.Pointer(val))
- runtime.RaceSemrelease(&mtx)
-
- return
-}
-
-func AddInt64(val *int64, delta int64) int64 {
- return int64(AddUint64((*uint64)(unsafe.Pointer(val)), uint64(delta)))
-}
-
-func AddUint64(val *uint64, delta uint64) (new uint64) {
- _ = *val
- runtime.RaceSemacquire(&mtx)
- runtime.RaceRead(unsafe.Pointer(val))
- runtime.RaceAcquire(unsafe.Pointer(val))
- *val = *val + delta
- new = *val
- runtime.RaceReleaseMerge(unsafe.Pointer(val))
- runtime.RaceSemrelease(&mtx)
-
- return
-}
-
-func AddUintptr(val *uintptr, delta uintptr) (new uintptr) {
- _ = *val
- runtime.RaceSemacquire(&mtx)
- runtime.RaceRead(unsafe.Pointer(val))
- runtime.RaceAcquire(unsafe.Pointer(val))
- *val = *val + delta
- new = *val
- runtime.RaceReleaseMerge(unsafe.Pointer(val))
- runtime.RaceSemrelease(&mtx)
-
- return
-}
-
-func LoadInt32(addr *int32) int32 {
- return int32(LoadUint32((*uint32)(unsafe.Pointer(addr))))
-}
-
-func LoadUint32(addr *uint32) (val uint32) {
- _ = *addr
- runtime.RaceSemacquire(&mtx)
- runtime.RaceRead(unsafe.Pointer(addr))
- runtime.RaceAcquire(unsafe.Pointer(addr))
- val = *addr
- runtime.RaceSemrelease(&mtx)
- return
-}
-
-func LoadInt64(addr *int64) int64 {
- return int64(LoadUint64((*uint64)(unsafe.Pointer(addr))))
-}
-
-func LoadUint64(addr *uint64) (val uint64) {
- _ = *addr
- runtime.RaceSemacquire(&mtx)
- runtime.RaceRead(unsafe.Pointer(addr))
- runtime.RaceAcquire(unsafe.Pointer(addr))
- val = *addr
- runtime.RaceSemrelease(&mtx)
- return
-}
-
-func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer) {
- _ = *addr
- runtime.RaceSemacquire(&mtx)
- runtime.RaceRead(unsafe.Pointer(addr))
- runtime.RaceAcquire(unsafe.Pointer(addr))
- val = *addr
- runtime.RaceSemrelease(&mtx)
- return
-}
-
-func LoadUintptr(addr *uintptr) (val uintptr) {
- _ = *addr
- runtime.RaceSemacquire(&mtx)
- runtime.RaceRead(unsafe.Pointer(addr))
- runtime.RaceAcquire(unsafe.Pointer(addr))
- val = *addr
- runtime.RaceSemrelease(&mtx)
- return
-}
-
-func StoreInt32(addr *int32, val int32) {
- StoreUint32((*uint32)(unsafe.Pointer(addr)), uint32(val))
-}
-
-func StoreUint32(addr *uint32, val uint32) {
- _ = *addr
- runtime.RaceSemacquire(&mtx)
- runtime.RaceRead(unsafe.Pointer(addr))
- *addr = val
- runtime.RaceRelease(unsafe.Pointer(addr))
- runtime.RaceSemrelease(&mtx)
-}
-
-func StoreInt64(addr *int64, val int64) {
- StoreUint64((*uint64)(unsafe.Pointer(addr)), uint64(val))
-}
-
-func StoreUint64(addr *uint64, val uint64) {
- _ = *addr
- runtime.RaceSemacquire(&mtx)
- runtime.RaceRead(unsafe.Pointer(addr))
- *addr = val
- runtime.RaceRelease(unsafe.Pointer(addr))
- runtime.RaceSemrelease(&mtx)
-}
-
-func StorePointer(addr *unsafe.Pointer, val unsafe.Pointer) {
- _ = *addr
- runtime.RaceSemacquire(&mtx)
- runtime.RaceRead(unsafe.Pointer(addr))
- *addr = val
- runtime.RaceRelease(unsafe.Pointer(addr))
- runtime.RaceSemrelease(&mtx)
-}
-
-func StoreUintptr(addr *uintptr, val uintptr) {
- _ = *addr
- runtime.RaceSemacquire(&mtx)
- runtime.RaceRead(unsafe.Pointer(addr))
- *addr = val
- runtime.RaceRelease(unsafe.Pointer(addr))
- runtime.RaceSemrelease(&mtx)
-}
diff --git a/libgo/go/sync/atomic/value.go b/libgo/go/sync/atomic/value.go
new file mode 100644
index 0000000000..ab3aa11285
--- /dev/null
+++ b/libgo/go/sync/atomic/value.go
@@ -0,0 +1,85 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package atomic
+
+import (
+ "unsafe"
+)
+
+// A Value provides an atomic load and store of a consistently typed value.
+// Values can be created as part of other data structures.
+// The zero value for a Value returns nil from Load.
+// Once Store has been called, a Value must not be copied.
+type Value struct {
+ v interface{}
+}
+
+// ifaceWords is interface{} internal representation.
+type ifaceWords struct {
+ typ unsafe.Pointer
+ data unsafe.Pointer
+}
+
+// Load returns the value set by the most recent Store.
+// It returns nil if there has been no call to Store for this Value.
+func (v *Value) Load() (x interface{}) {
+ vp := (*ifaceWords)(unsafe.Pointer(v))
+ typ := LoadPointer(&vp.typ)
+ if typ == nil || uintptr(typ) == ^uintptr(0) {
+ // First store not yet completed.
+ return nil
+ }
+ data := LoadPointer(&vp.data)
+ xp := (*ifaceWords)(unsafe.Pointer(&x))
+ xp.typ = typ
+ xp.data = data
+ return
+}
+
+// Store sets the value of the Value to x.
+// All calls to Store for a given Value must use values of the same concrete type.
+// Store of an inconsistent type panics, as does Store(nil).
+func (v *Value) Store(x interface{}) {
+ if x == nil {
+ panic("sync/atomic: store of nil value into Value")
+ }
+ vp := (*ifaceWords)(unsafe.Pointer(v))
+ xp := (*ifaceWords)(unsafe.Pointer(&x))
+ for {
+ typ := LoadPointer(&vp.typ)
+ if typ == nil {
+ // Attempt to start first store.
+ // Disable preemption so that other goroutines can use
+ // active spin wait to wait for completion; and so that
+ // GC does not see the fake type accidentally.
+ runtime_procPin()
+ if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(^uintptr(0))) {
+ runtime_procUnpin()
+ continue
+ }
+ // Complete first store.
+ StorePointer(&vp.data, xp.data)
+ StorePointer(&vp.typ, xp.typ)
+ runtime_procUnpin()
+ return
+ }
+ if uintptr(typ) == ^uintptr(0) {
+ // First store in progress. Wait.
+ // Since we disable preemption around the first store,
+ // we can wait with active spinning.
+ continue
+ }
+ // First store completed. Check type and overwrite data.
+ if typ != xp.typ {
+ panic("sync/atomic: store of inconsistently typed value into Value")
+ }
+ StorePointer(&vp.data, xp.data)
+ return
+ }
+}
+
+// Disable/enable preemption, implemented in runtime.
+func runtime_procPin()
+func runtime_procUnpin()
diff --git a/libgo/go/sync/atomic/value_test.go b/libgo/go/sync/atomic/value_test.go
new file mode 100644
index 0000000000..382dc6854d
--- /dev/null
+++ b/libgo/go/sync/atomic/value_test.go
@@ -0,0 +1,195 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package atomic_test
+
+import (
+ "math/rand"
+ "runtime"
+ "sync"
+ . "sync/atomic"
+ "testing"
+ "time"
+)
+
+func TestValue(t *testing.T) {
+ var v Value
+ if v.Load() != nil {
+ t.Fatal("initial Value is not nil")
+ }
+ v.Store(42)
+ x := v.Load()
+ if xx, ok := x.(int); !ok || xx != 42 {
+ t.Fatalf("wrong value: got %+v, want 42", x)
+ }
+ v.Store(84)
+ x = v.Load()
+ if xx, ok := x.(int); !ok || xx != 84 {
+ t.Fatalf("wrong value: got %+v, want 84", x)
+ }
+}
+
+func TestValueLarge(t *testing.T) {
+ var v Value
+ v.Store("foo")
+ x := v.Load()
+ if xx, ok := x.(string); !ok || xx != "foo" {
+ t.Fatalf("wrong value: got %+v, want foo", x)
+ }
+ v.Store("barbaz")
+ x = v.Load()
+ if xx, ok := x.(string); !ok || xx != "barbaz" {
+ t.Fatalf("wrong value: got %+v, want barbaz", x)
+ }
+}
+
+func TestValuePanic(t *testing.T) {
+ const nilErr = "sync/atomic: store of nil value into Value"
+ const badErr = "sync/atomic: store of inconsistently typed value into Value"
+ var v Value
+ func() {
+ defer func() {
+ err := recover()
+ if err != nilErr {
+ t.Fatalf("inconsistent store panic: got '%v', want '%v'", err, nilErr)
+ }
+ }()
+ v.Store(nil)
+ }()
+ v.Store(42)
+ func() {
+ defer func() {
+ err := recover()
+ if err != badErr {
+ t.Fatalf("inconsistent store panic: got '%v', want '%v'", err, badErr)
+ }
+ }()
+ v.Store("foo")
+ }()
+ func() {
+ defer func() {
+ err := recover()
+ if err != nilErr {
+ t.Fatalf("inconsistent store panic: got '%v', want '%v'", err, nilErr)
+ }
+ }()
+ v.Store(nil)
+ }()
+}
+
+func TestValueConcurrent(t *testing.T) {
+ tests := [][]interface{}{
+ {uint16(0), ^uint16(0), uint16(1 + 2<<8), uint16(3 + 4<<8)},
+ {uint32(0), ^uint32(0), uint32(1 + 2<<16), uint32(3 + 4<<16)},
+ {uint64(0), ^uint64(0), uint64(1 + 2<<32), uint64(3 + 4<<32)},
+ {complex(0, 0), complex(1, 2), complex(3, 4), complex(5, 6)},
+ }
+ p := 4 * runtime.GOMAXPROCS(0)
+ for _, test := range tests {
+ var v Value
+ done := make(chan bool)
+ for i := 0; i < p; i++ {
+ go func() {
+ r := rand.New(rand.NewSource(rand.Int63()))
+ loop:
+ for j := 0; j < 1e5; j++ {
+ x := test[r.Intn(len(test))]
+ v.Store(x)
+ x = v.Load()
+ for _, x1 := range test {
+ if x == x1 {
+ continue loop
+ }
+ }
+ t.Logf("loaded unexpected value %+v, want %+v", x, test)
+ done <- false
+ }
+ done <- true
+ }()
+ }
+ for i := 0; i < p; i++ {
+ if !<-done {
+ t.FailNow()
+ }
+ }
+ }
+}
+
+func BenchmarkValueRead(b *testing.B) {
+ var v Value
+ v.Store(new(int))
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ x := v.Load().(*int)
+ if *x != 0 {
+ b.Fatalf("wrong value: got %v, want 0", *x)
+ }
+ }
+ })
+}
+
+// The following example shows how to use Value for periodic program config updates
+// and propagation of the changes to worker goroutines.
+func ExampleValue_config() {
+ var config Value // holds current server configuration
+ // Create initial config value and store into config.
+ config.Store(loadConfig())
+ go func() {
+ // Reload config every 10 seconds
+ // and update config value with the new version.
+ for {
+ time.Sleep(10 * time.Second)
+ config.Store(loadConfig())
+ }
+ }()
+ // Create worker goroutines that handle incoming requests
+ // using the latest config value.
+ for i := 0; i < 10; i++ {
+ go func() {
+ for r := range requests() {
+ c := config.Load()
+ // Handle request r using config c.
+ _, _ = r, c
+ }
+ }()
+ }
+}
+
+func loadConfig() map[string]string {
+ return make(map[string]string)
+}
+
+func requests() chan int {
+ return make(chan int)
+}
+
+// The following example shows how to maintain a scalable frequently read,
+// but infrequently updated data structure using copy-on-write idiom.
+func ExampleValue_readMostly() {
+ type Map map[string]string
+ var m Value
+ m.Store(make(Map))
+ var mu sync.Mutex // used only by writers
+ // read function can be used to read the data without further synchronization
+ read := func(key string) (val string) {
+ m1 := m.Load().(Map)
+ return m1[key]
+ }
+ // insert function can be used to update the data without further synchronization
+ insert := func(key, val string) {
+ mu.Lock() // synchronize with other potential writers
+ defer mu.Unlock()
+ m1 := m.Load().(Map) // load current value of the data structure
+ m2 := make(Map) // create a new value
+ for k, v := range m1 {
+ m2[k] = v // copy all data from the current object to the new one
+ }
+ m2[key] = val // do the update that we need
+ m.Store(m2) // atomically replace the current object with the new one
+ // At this point all new readers start working with the new version.
+ // The old version will be garbage collected once the existing readers
+ // (if any) are done with it.
+ }
+ _, _ = read, insert
+}
diff --git a/libgo/go/sync/mutex_test.go b/libgo/go/sync/mutex_test.go
index bf78c6f609..151b25c10f 100644
--- a/libgo/go/sync/mutex_test.go
+++ b/libgo/go/sync/mutex_test.go
@@ -9,7 +9,6 @@ package sync_test
import (
"runtime"
. "sync"
- "sync/atomic"
"testing"
)
@@ -90,63 +89,34 @@ func BenchmarkMutexUncontended(b *testing.B) {
Mutex
pad [128]uint8
}
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
- for p := 0; p < procs; p++ {
- go func() {
- var mu PaddedMutex
- for atomic.AddInt32(&N, -1) >= 0 {
- runtime.Gosched()
- for g := 0; g < CallsPerSched; g++ {
- mu.Lock()
- mu.Unlock()
- }
- }
- c <- true
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ b.RunParallel(func(pb *testing.PB) {
+ var mu PaddedMutex
+ for pb.Next() {
+ mu.Lock()
+ mu.Unlock()
+ }
+ })
}
func benchmarkMutex(b *testing.B, slack, work bool) {
- const (
- CallsPerSched = 1000
- LocalWork = 100
- GoroutineSlack = 10
- )
- procs := runtime.GOMAXPROCS(-1)
+ var mu Mutex
if slack {
- procs *= GoroutineSlack
+ b.SetParallelism(10)
}
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
- var mu Mutex
- for p := 0; p < procs; p++ {
- go func() {
- foo := 0
- for atomic.AddInt32(&N, -1) >= 0 {
- runtime.Gosched()
- for g := 0; g < CallsPerSched; g++ {
- mu.Lock()
- mu.Unlock()
- if work {
- for i := 0; i < LocalWork; i++ {
- foo *= 2
- foo /= 2
- }
- }
+ b.RunParallel(func(pb *testing.PB) {
+ foo := 0
+ for pb.Next() {
+ mu.Lock()
+ mu.Unlock()
+ if work {
+ for i := 0; i < 100; i++ {
+ foo *= 2
+ foo /= 2
}
}
- c <- foo == 42
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ }
+ _ = foo
+ })
}
func BenchmarkMutex(b *testing.B) {
diff --git a/libgo/go/sync/once.go b/libgo/go/sync/once.go
index 161ae3b3e9..10b42fddc2 100644
--- a/libgo/go/sync/once.go
+++ b/libgo/go/sync/once.go
@@ -15,7 +15,7 @@ type Once struct {
}
// Do calls the function f if and only if Do is being called for the
-// first time for this instance of Once. In other words, given
+// first time for this instance of Once. In other words, given
// var once Once
// if once.Do(f) is called multiple times, only the first call will invoke f,
// even if f has a different value in each invocation. A new instance of
@@ -29,6 +29,9 @@ type Once struct {
// Because no call to Do returns until the one call to f returns, if f causes
// Do to be called, it will deadlock.
//
+// If f panics, Do considers it to have returned; future calls of Do return
+// without calling f.
+//
func (o *Once) Do(f func()) {
if atomic.LoadUint32(&o.done) == 1 {
return
@@ -37,7 +40,7 @@ func (o *Once) Do(f func()) {
o.m.Lock()
defer o.m.Unlock()
if o.done == 0 {
+ defer atomic.StoreUint32(&o.done, 1)
f()
- atomic.StoreUint32(&o.done, 1)
}
}
diff --git a/libgo/go/sync/once_test.go b/libgo/go/sync/once_test.go
index 183069a1a2..1eec8d18ea 100644
--- a/libgo/go/sync/once_test.go
+++ b/libgo/go/sync/once_test.go
@@ -5,9 +5,7 @@
package sync_test
import (
- "runtime"
. "sync"
- "sync/atomic"
"testing"
)
@@ -42,44 +40,29 @@ func TestOnce(t *testing.T) {
}
func TestOncePanic(t *testing.T) {
- once := new(Once)
- for i := 0; i < 2; i++ {
- func() {
- defer func() {
- if recover() == nil {
- t.Fatalf("Once.Do() has not panic'ed")
- }
- }()
- once.Do(func() {
- panic("failed")
- })
+ var once Once
+ func() {
+ defer func() {
+ if r := recover(); r == nil {
+ t.Fatalf("Once.Do did not panic")
+ }
}()
- }
- once.Do(func() {})
+ once.Do(func() {
+ panic("failed")
+ })
+ }()
+
once.Do(func() {
- t.Fatalf("Once called twice")
+ t.Fatalf("Once.Do called twice")
})
}
func BenchmarkOnce(b *testing.B) {
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
var once Once
f := func() {}
- c := make(chan bool, procs)
- for p := 0; p < procs; p++ {
- go func() {
- for atomic.AddInt32(&N, -1) >= 0 {
- runtime.Gosched()
- for g := 0; g < CallsPerSched; g++ {
- once.Do(f)
- }
- }
- c <- true
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ once.Do(f)
+ }
+ })
}
diff --git a/libgo/go/sync/pool.go b/libgo/go/sync/pool.go
new file mode 100644
index 0000000000..0cf0637024
--- /dev/null
+++ b/libgo/go/sync/pool.go
@@ -0,0 +1,225 @@
+// 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 sync
+
+import (
+ "runtime"
+ "sync/atomic"
+ "unsafe"
+)
+
+// A Pool is a set of temporary objects that may be individually saved and
+// retrieved.
+//
+// Any item stored in the Pool may be removed automatically at any time without
+// notification. If the Pool holds the only reference when this happens, the
+// item might be deallocated.
+//
+// A Pool is safe for use by multiple goroutines simultaneously.
+//
+// Pool's purpose is to cache allocated but unused items for later reuse,
+// relieving pressure on the garbage collector. That is, it makes it easy to
+// build efficient, thread-safe free lists. However, it is not suitable for all
+// free lists.
+//
+// An appropriate use of a Pool is to manage a group of temporary items
+// silently shared among and potentially reused by concurrent independent
+// clients of a package. Pool provides a way to amortize allocation overhead
+// across many clients.
+//
+// An example of good use of a Pool is in the fmt package, which maintains a
+// dynamically-sized store of temporary output buffers. The store scales under
+// load (when many goroutines are actively printing) and shrinks when
+// quiescent.
+//
+// On the other hand, a free list maintained as part of a short-lived object is
+// not a suitable use for a Pool, since the overhead does not amortize well in
+// that scenario. It is more efficient to have such objects implement their own
+// free list.
+//
+type Pool struct {
+ local unsafe.Pointer // local fixed-size per-P pool, actual type is [P]poolLocal
+ localSize uintptr // size of the local array
+
+ // New optionally specifies a function to generate
+ // a value when Get would otherwise return nil.
+ // It may not be changed concurrently with calls to Get.
+ New func() interface{}
+}
+
+// Local per-P Pool appendix.
+type poolLocal struct {
+ private interface{} // Can be used only by the respective P.
+ shared []interface{} // Can be used by any P.
+ Mutex // Protects shared.
+ pad [128]byte // Prevents false sharing.
+}
+
+// Put adds x to the pool.
+func (p *Pool) Put(x interface{}) {
+ if raceenabled {
+ // Under race detector the Pool degenerates into no-op.
+ // It's conforming, simple and does not introduce excessive
+ // happens-before edges between unrelated goroutines.
+ return
+ }
+ if x == nil {
+ return
+ }
+ l := p.pin()
+ if l.private == nil {
+ l.private = x
+ x = nil
+ }
+ runtime_procUnpin()
+ if x == nil {
+ return
+ }
+ l.Lock()
+ l.shared = append(l.shared, x)
+ l.Unlock()
+}
+
+// Get selects an arbitrary item from the Pool, removes it from the
+// Pool, and returns it to the caller.
+// Get may choose to ignore the pool and treat it as empty.
+// Callers should not assume any relation between values passed to Put and
+// the values returned by Get.
+//
+// If Get would otherwise return nil and p.New is non-nil, Get returns
+// the result of calling p.New.
+func (p *Pool) Get() interface{} {
+ if raceenabled {
+ if p.New != nil {
+ return p.New()
+ }
+ return nil
+ }
+ l := p.pin()
+ x := l.private
+ l.private = nil
+ runtime_procUnpin()
+ if x != nil {
+ return x
+ }
+ l.Lock()
+ last := len(l.shared) - 1
+ if last >= 0 {
+ x = l.shared[last]
+ l.shared = l.shared[:last]
+ }
+ l.Unlock()
+ if x != nil {
+ return x
+ }
+ return p.getSlow()
+}
+
+func (p *Pool) getSlow() (x interface{}) {
+ // See the comment in pin regarding ordering of the loads.
+ size := atomic.LoadUintptr(&p.localSize) // load-acquire
+ local := p.local // load-consume
+ // Try to steal one element from other procs.
+ pid := runtime_procPin()
+ runtime_procUnpin()
+ for i := 0; i < int(size); i++ {
+ l := indexLocal(local, (pid+i+1)%int(size))
+ l.Lock()
+ last := len(l.shared) - 1
+ if last >= 0 {
+ x = l.shared[last]
+ l.shared = l.shared[:last]
+ l.Unlock()
+ break
+ }
+ l.Unlock()
+ }
+
+ if x == nil && p.New != nil {
+ x = p.New()
+ }
+ return x
+}
+
+// pin pins the current goroutine to P, disables preemption and returns poolLocal pool for the P.
+// Caller must call runtime_procUnpin() when done with the pool.
+func (p *Pool) pin() *poolLocal {
+ pid := runtime_procPin()
+ // In pinSlow we store to localSize and then to local, here we load in opposite order.
+ // Since we've disabled preemption, GC can not happen in between.
+ // Thus here we must observe local at least as large localSize.
+ // We can observe a newer/larger local, it is fine (we must observe its zero-initialized-ness).
+ s := atomic.LoadUintptr(&p.localSize) // load-acquire
+ l := p.local // load-consume
+ if uintptr(pid) < s {
+ return indexLocal(l, pid)
+ }
+ return p.pinSlow()
+}
+
+func (p *Pool) pinSlow() *poolLocal {
+ // Retry under the mutex.
+ // Can not lock the mutex while pinned.
+ runtime_procUnpin()
+ allPoolsMu.Lock()
+ defer allPoolsMu.Unlock()
+ pid := runtime_procPin()
+ // poolCleanup won't be called while we are pinned.
+ s := p.localSize
+ l := p.local
+ if uintptr(pid) < s {
+ return indexLocal(l, pid)
+ }
+ if p.local == nil {
+ allPools = append(allPools, p)
+ }
+ // If GOMAXPROCS changes between GCs, we re-allocate the array and lose the old one.
+ size := runtime.GOMAXPROCS(0)
+ local := make([]poolLocal, size)
+ atomic.StorePointer((*unsafe.Pointer)(&p.local), unsafe.Pointer(&local[0])) // store-release
+ atomic.StoreUintptr(&p.localSize, uintptr(size)) // store-release
+ return &local[pid]
+}
+
+func poolCleanup() {
+ // This function is called with the world stopped, at the beginning of a garbage collection.
+ // It must not allocate and probably should not call any runtime functions.
+ // Defensively zero out everything, 2 reasons:
+ // 1. To prevent false retention of whole Pools.
+ // 2. If GC happens while a goroutine works with l.shared in Put/Get,
+ // it will retain whole Pool. So next cycle memory consumption would be doubled.
+ for i, p := range allPools {
+ allPools[i] = nil
+ for i := 0; i < int(p.localSize); i++ {
+ l := indexLocal(p.local, i)
+ l.private = nil
+ for j := range l.shared {
+ l.shared[j] = nil
+ }
+ l.shared = nil
+ }
+ p.local = nil
+ p.localSize = 0
+ }
+ allPools = []*Pool{}
+}
+
+var (
+ allPoolsMu Mutex
+ allPools []*Pool
+)
+
+func init() {
+ runtime_registerPoolCleanup(poolCleanup)
+}
+
+func indexLocal(l unsafe.Pointer, i int) *poolLocal {
+ return &(*[1000000]poolLocal)(l)[i]
+}
+
+// Implemented in runtime.
+func runtime_registerPoolCleanup(cleanup func())
+func runtime_procPin() int
+func runtime_procUnpin()
diff --git a/libgo/go/sync/pool_test.go b/libgo/go/sync/pool_test.go
new file mode 100644
index 0000000000..051bb17533
--- /dev/null
+++ b/libgo/go/sync/pool_test.go
@@ -0,0 +1,164 @@
+// 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.
+
+// Pool is no-op under race detector, so all these tests do not work.
+// +build !race
+
+package sync_test
+
+import (
+ "runtime"
+ "runtime/debug"
+ . "sync"
+ "sync/atomic"
+ "testing"
+ "time"
+)
+
+func TestPool(t *testing.T) {
+ // disable GC so we can control when it happens.
+ defer debug.SetGCPercent(debug.SetGCPercent(-1))
+ var p Pool
+ if p.Get() != nil {
+ t.Fatal("expected empty")
+ }
+ p.Put("a")
+ p.Put("b")
+ if g := p.Get(); g != "a" {
+ t.Fatalf("got %#v; want a", g)
+ }
+ if g := p.Get(); g != "b" {
+ t.Fatalf("got %#v; want b", g)
+ }
+ if g := p.Get(); g != nil {
+ t.Fatalf("got %#v; want nil", g)
+ }
+
+ p.Put("c")
+ debug.SetGCPercent(100) // to allow following GC to actually run
+ runtime.GC()
+ if g := p.Get(); g != nil {
+ t.Fatalf("got %#v; want nil after GC", g)
+ }
+}
+
+func TestPoolNew(t *testing.T) {
+ // disable GC so we can control when it happens.
+ defer debug.SetGCPercent(debug.SetGCPercent(-1))
+
+ i := 0
+ p := Pool{
+ New: func() interface{} {
+ i++
+ return i
+ },
+ }
+ if v := p.Get(); v != 1 {
+ t.Fatalf("got %v; want 1", v)
+ }
+ if v := p.Get(); v != 2 {
+ t.Fatalf("got %v; want 2", v)
+ }
+ p.Put(42)
+ if v := p.Get(); v != 42 {
+ t.Fatalf("got %v; want 42", v)
+ }
+ if v := p.Get(); v != 3 {
+ t.Fatalf("got %v; want 3", v)
+ }
+}
+
+// Test that Pool does not hold pointers to previously cached resources.
+func TestPoolGC(t *testing.T) {
+ testPool(t, true)
+}
+
+// Test that Pool releases resources on GC.
+func TestPoolRelease(t *testing.T) {
+ testPool(t, false)
+}
+
+func testPool(t *testing.T, drain bool) {
+ t.Skip("gccgo imprecise GC breaks this test")
+ var p Pool
+ const N = 100
+loop:
+ for try := 0; try < 3; try++ {
+ var fin, fin1 uint32
+ for i := 0; i < N; i++ {
+ v := new(string)
+ runtime.SetFinalizer(v, func(vv *string) {
+ atomic.AddUint32(&fin, 1)
+ })
+ p.Put(v)
+ }
+ if drain {
+ for i := 0; i < N; i++ {
+ p.Get()
+ }
+ }
+ for i := 0; i < 5; i++ {
+ runtime.GC()
+ time.Sleep(time.Duration(i*100+10) * time.Millisecond)
+ // 1 pointer can remain on stack or elsewhere
+ if fin1 = atomic.LoadUint32(&fin); fin1 >= N-1 {
+ continue loop
+ }
+ }
+ t.Fatalf("only %v out of %v resources are finalized on try %v", fin1, N, try)
+ }
+}
+
+func TestPoolStress(t *testing.T) {
+ const P = 10
+ N := int(1e6)
+ if testing.Short() {
+ N /= 100
+ }
+ var p Pool
+ done := make(chan bool)
+ for i := 0; i < P; i++ {
+ go func() {
+ var v interface{} = 0
+ for j := 0; j < N; j++ {
+ if v == nil {
+ v = 0
+ }
+ p.Put(v)
+ v = p.Get()
+ if v != nil && v.(int) != 0 {
+ t.Fatalf("expect 0, got %v", v)
+ }
+ }
+ done <- true
+ }()
+ }
+ for i := 0; i < P; i++ {
+ <-done
+ }
+}
+
+func BenchmarkPool(b *testing.B) {
+ var p Pool
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ p.Put(1)
+ p.Get()
+ }
+ })
+}
+
+func BenchmarkPoolOverflow(b *testing.B) {
+ var p Pool
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ for b := 0; b < 100; b++ {
+ p.Put(1)
+ }
+ for b := 0; b < 100; b++ {
+ p.Get()
+ }
+ }
+ })
+}
diff --git a/libgo/go/sync/runtime.go b/libgo/go/sync/runtime.go
index 3bf47ea52a..3b866303a9 100644
--- a/libgo/go/sync/runtime.go
+++ b/libgo/go/sync/runtime.go
@@ -19,8 +19,12 @@ func runtime_Semacquire(s *uint32)
// library and should not be used directly.
func runtime_Semrelease(s *uint32)
-// Opaque representation of SyncSema in runtime/sema.goc.
-type syncSema [3]uintptr
+// Approximation of syncSema in runtime/sema.go.
+type syncSema struct {
+ lock uintptr
+ head unsafe.Pointer
+ tail unsafe.Pointer
+}
// Syncsemacquire waits for a pairing Syncsemrelease on the same semaphore s.
func runtime_Syncsemacquire(s *syncSema)
diff --git a/libgo/go/sync/runtime_sema_test.go b/libgo/go/sync/runtime_sema_test.go
index 57a8dbee78..5b7dd3df3f 100644
--- a/libgo/go/sync/runtime_sema_test.go
+++ b/libgo/go/sync/runtime_sema_test.go
@@ -7,7 +7,6 @@ package sync_test
import (
"runtime"
. "sync"
- "sync/atomic"
"testing"
)
@@ -16,72 +15,44 @@ func BenchmarkSemaUncontended(b *testing.B) {
sem uint32
pad [32]uint32
}
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
- for p := 0; p < procs; p++ {
- go func() {
- sem := new(PaddedSem)
- for atomic.AddInt32(&N, -1) >= 0 {
- runtime.Gosched()
- for g := 0; g < CallsPerSched; g++ {
- Runtime_Semrelease(&sem.sem)
- Runtime_Semacquire(&sem.sem)
- }
- }
- c <- true
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ b.RunParallel(func(pb *testing.PB) {
+ sem := new(PaddedSem)
+ for pb.Next() {
+ Runtime_Semrelease(&sem.sem)
+ Runtime_Semacquire(&sem.sem)
+ }
+ })
}
func benchmarkSema(b *testing.B, block, work bool) {
- const CallsPerSched = 1000
- const LocalWork = 100
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
- c2 := make(chan bool, procs/2)
sem := uint32(0)
if block {
- for p := 0; p < procs/2; p++ {
- go func() {
- Runtime_Semacquire(&sem)
- c2 <- true
- }()
- }
- }
- for p := 0; p < procs; p++ {
+ done := make(chan bool)
go func() {
- foo := 0
- for atomic.AddInt32(&N, -1) >= 0 {
- runtime.Gosched()
- for g := 0; g < CallsPerSched; g++ {
- Runtime_Semrelease(&sem)
- if work {
- for i := 0; i < LocalWork; i++ {
- foo *= 2
- foo /= 2
- }
- }
- Runtime_Semacquire(&sem)
- }
+ for p := 0; p < runtime.GOMAXPROCS(0)/2; p++ {
+ Runtime_Semacquire(&sem)
}
- c <- foo == 42
- Runtime_Semrelease(&sem)
+ done <- true
+ }()
+ defer func() {
+ <-done
}()
}
- if block {
- for p := 0; p < procs/2; p++ {
- <-c2
+ b.RunParallel(func(pb *testing.PB) {
+ foo := 0
+ for pb.Next() {
+ Runtime_Semrelease(&sem)
+ if work {
+ for i := 0; i < 100; i++ {
+ foo *= 2
+ foo /= 2
+ }
+ }
+ Runtime_Semacquire(&sem)
}
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ _ = foo
+ Runtime_Semrelease(&sem)
+ })
}
func BenchmarkSemaSyntNonblock(b *testing.B) {
diff --git a/libgo/go/sync/rwmutex.go b/libgo/go/sync/rwmutex.go
index 3db5419957..0e8a58e5f0 100644
--- a/libgo/go/sync/rwmutex.go
+++ b/libgo/go/sync/rwmutex.go
@@ -51,7 +51,11 @@ func (rw *RWMutex) RUnlock() {
raceReleaseMerge(unsafe.Pointer(&rw.writerSem))
raceDisable()
}
- if atomic.AddInt32(&rw.readerCount, -1) < 0 {
+ if r := atomic.AddInt32(&rw.readerCount, -1); r < 0 {
+ if r+1 == 0 || r+1 == -rwmutexMaxReaders {
+ raceEnable()
+ panic("sync: RUnlock of unlocked RWMutex")
+ }
// A writer is pending.
if atomic.AddInt32(&rw.readerWait, -1) == 0 {
// The last reader unblocks the writer.
@@ -105,6 +109,10 @@ func (rw *RWMutex) Unlock() {
// Announce to readers there is no active writer.
r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)
+ if r >= rwmutexMaxReaders {
+ raceEnable()
+ panic("sync: Unlock of unlocked RWMutex")
+ }
// Unblock blocked readers, if any.
for i := 0; i < int(r); i++ {
runtime_Semrelease(&rw.readerSem)
diff --git a/libgo/go/sync/rwmutex_test.go b/libgo/go/sync/rwmutex_test.go
index 39d5d6540d..f625bc3a58 100644
--- a/libgo/go/sync/rwmutex_test.go
+++ b/libgo/go/sync/rwmutex_test.go
@@ -155,69 +155,86 @@ func TestRLocker(t *testing.T) {
}
}
+func TestUnlockPanic(t *testing.T) {
+ defer func() {
+ if recover() == nil {
+ t.Fatalf("unlock of unlocked RWMutex did not panic")
+ }
+ }()
+ var mu RWMutex
+ mu.Unlock()
+}
+
+func TestUnlockPanic2(t *testing.T) {
+ defer func() {
+ if recover() == nil {
+ t.Fatalf("unlock of unlocked RWMutex did not panic")
+ }
+ }()
+ var mu RWMutex
+ mu.RLock()
+ mu.Unlock()
+}
+
+func TestRUnlockPanic(t *testing.T) {
+ defer func() {
+ if recover() == nil {
+ t.Fatalf("read unlock of unlocked RWMutex did not panic")
+ }
+ }()
+ var mu RWMutex
+ mu.RUnlock()
+}
+
+func TestRUnlockPanic2(t *testing.T) {
+ defer func() {
+ if recover() == nil {
+ t.Fatalf("read unlock of unlocked RWMutex did not panic")
+ }
+ }()
+ var mu RWMutex
+ mu.Lock()
+ mu.RUnlock()
+}
+
func BenchmarkRWMutexUncontended(b *testing.B) {
type PaddedRWMutex struct {
RWMutex
pad [32]uint32
}
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
- for p := 0; p < procs; p++ {
- go func() {
- var rwm PaddedRWMutex
- for atomic.AddInt32(&N, -1) >= 0 {
- runtime.Gosched()
- for g := 0; g < CallsPerSched; g++ {
- rwm.RLock()
- rwm.RLock()
- rwm.RUnlock()
- rwm.RUnlock()
- rwm.Lock()
- rwm.Unlock()
- }
- }
- c <- true
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ b.RunParallel(func(pb *testing.PB) {
+ var rwm PaddedRWMutex
+ for pb.Next() {
+ rwm.RLock()
+ rwm.RLock()
+ rwm.RUnlock()
+ rwm.RUnlock()
+ rwm.Lock()
+ rwm.Unlock()
+ }
+ })
}
func benchmarkRWMutex(b *testing.B, localWork, writeRatio int) {
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
var rwm RWMutex
- for p := 0; p < procs; p++ {
- go func() {
- foo := 0
- for atomic.AddInt32(&N, -1) >= 0 {
- runtime.Gosched()
- for g := 0; g < CallsPerSched; g++ {
- foo++
- if foo%writeRatio == 0 {
- rwm.Lock()
- rwm.Unlock()
- } else {
- rwm.RLock()
- for i := 0; i != localWork; i += 1 {
- foo *= 2
- foo /= 2
- }
- rwm.RUnlock()
- }
+ b.RunParallel(func(pb *testing.PB) {
+ foo := 0
+ for pb.Next() {
+ foo++
+ if foo%writeRatio == 0 {
+ rwm.Lock()
+ rwm.Unlock()
+ } else {
+ rwm.RLock()
+ for i := 0; i != localWork; i += 1 {
+ foo *= 2
+ foo /= 2
}
+ rwm.RUnlock()
}
- c <- foo == 42
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ }
+ _ = foo
+ })
}
func BenchmarkRWMutexWrite100(b *testing.B) {
diff --git a/libgo/go/sync/waitgroup.go b/libgo/go/sync/waitgroup.go
index 22681115cb..92cc57d2cc 100644
--- a/libgo/go/sync/waitgroup.go
+++ b/libgo/go/sync/waitgroup.go
@@ -37,10 +37,13 @@ type WaitGroup struct {
// If the counter becomes zero, all goroutines blocked on Wait are released.
// If the counter goes negative, Add panics.
//
-// Note that calls with positive delta must happen before the call to Wait,
-// or else Wait may wait for too small a group. Typically this means the calls
-// to Add should execute before the statement creating the goroutine or
-// other event to be waited for. See the WaitGroup example.
+// Note that calls with a positive delta that occur when the counter is zero
+// must happen before a Wait. Calls with a negative delta, or calls with a
+// positive delta that start when the counter is greater than zero, may happen
+// at any time.
+// Typically this means the calls to Add should execute before the statement
+// creating the goroutine or other event to be waited for.
+// See the WaitGroup example.
func (wg *WaitGroup) Add(delta int) {
if raceenabled {
_ = wg.m.state // trigger nil deref early
@@ -67,11 +70,13 @@ func (wg *WaitGroup) Add(delta int) {
return
}
wg.m.Lock()
- for i := int32(0); i < wg.waiters; i++ {
- runtime_Semrelease(wg.sema)
+ if atomic.LoadInt32(&wg.counter) == 0 {
+ for i := int32(0); i < wg.waiters; i++ {
+ runtime_Semrelease(wg.sema)
+ }
+ wg.waiters = 0
+ wg.sema = nil
}
- wg.waiters = 0
- wg.sema = nil
wg.m.Unlock()
}
diff --git a/libgo/go/sync/waitgroup_test.go b/libgo/go/sync/waitgroup_test.go
index 84c4cfc37a..4c0a043c01 100644
--- a/libgo/go/sync/waitgroup_test.go
+++ b/libgo/go/sync/waitgroup_test.go
@@ -5,7 +5,6 @@
package sync_test
import (
- "runtime"
. "sync"
"sync/atomic"
"testing"
@@ -61,60 +60,60 @@ func TestWaitGroupMisuse(t *testing.T) {
t.Fatal("Should panic")
}
+func TestWaitGroupRace(t *testing.T) {
+ // Run this test for about 1ms.
+ for i := 0; i < 1000; i++ {
+ wg := &WaitGroup{}
+ n := new(int32)
+ // spawn goroutine 1
+ wg.Add(1)
+ go func() {
+ atomic.AddInt32(n, 1)
+ wg.Done()
+ }()
+ // spawn goroutine 2
+ wg.Add(1)
+ go func() {
+ atomic.AddInt32(n, 1)
+ wg.Done()
+ }()
+ // Wait for goroutine 1 and 2
+ wg.Wait()
+ if atomic.LoadInt32(n) != 2 {
+ t.Fatal("Spurious wakeup from Wait")
+ }
+ }
+}
+
func BenchmarkWaitGroupUncontended(b *testing.B) {
type PaddedWaitGroup struct {
WaitGroup
pad [128]uint8
}
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
- for p := 0; p < procs; p++ {
- go func() {
- var wg PaddedWaitGroup
- for atomic.AddInt32(&N, -1) >= 0 {
- runtime.Gosched()
- for g := 0; g < CallsPerSched; g++ {
- wg.Add(1)
- wg.Done()
- wg.Wait()
- }
- }
- c <- true
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ b.RunParallel(func(pb *testing.PB) {
+ var wg PaddedWaitGroup
+ for pb.Next() {
+ wg.Add(1)
+ wg.Done()
+ wg.Wait()
+ }
+ })
}
func benchmarkWaitGroupAddDone(b *testing.B, localWork int) {
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
var wg WaitGroup
- for p := 0; p < procs; p++ {
- go func() {
- foo := 0
- for atomic.AddInt32(&N, -1) >= 0 {
- runtime.Gosched()
- for g := 0; g < CallsPerSched; g++ {
- wg.Add(1)
- for i := 0; i < localWork; i++ {
- foo *= 2
- foo /= 2
- }
- wg.Done()
- }
+ b.RunParallel(func(pb *testing.PB) {
+ foo := 0
+ for pb.Next() {
+ wg.Add(1)
+ for i := 0; i < localWork; i++ {
+ foo *= 2
+ foo /= 2
}
- c <- foo == 42
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ wg.Done()
+ }
+ _ = foo
+ })
}
func BenchmarkWaitGroupAddDone(b *testing.B) {
@@ -126,34 +125,18 @@ func BenchmarkWaitGroupAddDoneWork(b *testing.B) {
}
func benchmarkWaitGroupWait(b *testing.B, localWork int) {
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
var wg WaitGroup
- wg.Add(procs)
- for p := 0; p < procs; p++ {
- go wg.Done()
- }
- for p := 0; p < procs; p++ {
- go func() {
- foo := 0
- for atomic.AddInt32(&N, -1) >= 0 {
- runtime.Gosched()
- for g := 0; g < CallsPerSched; g++ {
- wg.Wait()
- for i := 0; i < localWork; i++ {
- foo *= 2
- foo /= 2
- }
- }
+ b.RunParallel(func(pb *testing.PB) {
+ foo := 0
+ for pb.Next() {
+ wg.Wait()
+ for i := 0; i < localWork; i++ {
+ foo *= 2
+ foo /= 2
}
- c <- foo == 42
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ }
+ _ = foo
+ })
}
func BenchmarkWaitGroupWait(b *testing.B) {
diff --git a/libgo/go/syscall/consistency_unix_test.go b/libgo/go/syscall/consistency_unix_test.go
deleted file mode 100644
index 73630bc614..0000000000
--- a/libgo/go/syscall/consistency_unix_test.go
+++ /dev/null
@@ -1,34 +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 freebsd dragonfly darwin linux netbsd openbsd
-
-// This file tests that some basic syscalls are consistent across
-// all Unixes.
-
-package syscall_test
-
-import "syscall"
-
-// {Set,Get}priority and needed constants for them
-func _() {
- var (
- _ func(int, int, int) error = syscall.Setpriority
- _ func(int, int) (int, error) = syscall.Getpriority
- )
- const (
- _ int = syscall.PRIO_USER
- _ int = syscall.PRIO_PROCESS
- _ int = syscall.PRIO_PGRP
- )
-}
-
-// termios functions and constants
-func _() {
- const (
- _ int = syscall.TCIFLUSH
- _ int = syscall.TCIOFLUSH
- _ int = syscall.TCOFLUSH
- )
-}
diff --git a/libgo/go/syscall/dir_plan9.go b/libgo/go/syscall/dir_plan9.go
index b7ab4cd108..697bf5499c 100644
--- a/libgo/go/syscall/dir_plan9.go
+++ b/libgo/go/syscall/dir_plan9.go
@@ -11,6 +11,7 @@ import "errors"
var (
ErrShortStat = errors.New("stat buffer too short")
ErrBadStat = errors.New("malformed stat buffer")
+ ErrBadName = errors.New("bad character in file name")
)
// A Qid represents a 9P server's unique identification for a file.
@@ -53,7 +54,7 @@ var nullDir = Dir{
}
// Null assigns special "don't touch" values to members of d to
-// avoid modifiying them during syscall.Wstat.
+// avoid modifying them during syscall.Wstat.
func (d *Dir) Null() { *d = nullDir }
// Marshal encodes a 9P stat message corresponding to d into b
@@ -65,6 +66,12 @@ func (d *Dir) Marshal(b []byte) (n int, err error) {
return n, ErrShortStat
}
+ for _, c := range d.Name {
+ if c == '/' {
+ return n, ErrBadName
+ }
+ }
+
b = pbit16(b, uint16(n)-2)
b = pbit16(b, d.Type)
b = pbit32(b, d.Dev)
diff --git a/libgo/go/syscall/env_plan9.go b/libgo/go/syscall/env_plan9.go
index 9587ab5af9..9ea36c886a 100644
--- a/libgo/go/syscall/env_plan9.go
+++ b/libgo/go/syscall/env_plan9.go
@@ -8,22 +8,9 @@ package syscall
import (
"errors"
- "sync"
)
var (
- // envOnce guards copyenv, which populates env.
- envOnce sync.Once
-
- // envLock guards env and envs.
- envLock sync.RWMutex
-
- // env maps from an environment variable to its value.
- env = make(map[string]string)
-
- // envs contains elements of env in the form "key=value".
- envs []string
-
errZeroLengthKey = errors.New("zero length key")
errShortWrite = errors.New("i/o count too small")
)
@@ -64,46 +51,14 @@ func writeenv(key, value string) error {
return nil
}
-func copyenv() {
- fd, err := Open("/env", O_RDONLY)
- if err != nil {
- return
- }
- defer Close(fd)
- files, err := readdirnames(fd)
- if err != nil {
- return
- }
- envs = make([]string, len(files))
- i := 0
- for _, key := range files {
- v, err := readenv(key)
- if err != nil {
- continue
- }
- env[key] = v
- envs[i] = key + "=" + v
- i++
- }
-}
-
func Getenv(key string) (value string, found bool) {
if len(key) == 0 {
return "", false
}
-
- envLock.RLock()
- defer envLock.RUnlock()
-
- if v, ok := env[key]; ok {
- return v, true
- }
v, err := readenv(key)
if err != nil {
return "", false
}
- env[key] = v
- envs = append(envs, key+"="+v)
return v, true
}
@@ -111,32 +66,43 @@ func Setenv(key, value string) error {
if len(key) == 0 {
return errZeroLengthKey
}
-
- envLock.Lock()
- defer envLock.Unlock()
-
err := writeenv(key, value)
if err != nil {
return err
}
- env[key] = value
- envs = append(envs, key+"="+value)
return nil
}
func Clearenv() {
- envLock.Lock()
- defer envLock.Unlock()
-
- env = make(map[string]string)
- envs = []string{}
RawSyscall(SYS_RFORK, RFCENVG, 0, 0)
}
+func Unsetenv(key string) error {
+ if len(key) == 0 {
+ return errZeroLengthKey
+ }
+ Remove("/env/" + key)
+ return nil
+}
+
func Environ() []string {
- envLock.RLock()
- defer envLock.RUnlock()
+ fd, err := Open("/env", O_RDONLY)
+ if err != nil {
+ return nil
+ }
+ defer Close(fd)
+ files, err := readdirnames(fd)
+ if err != nil {
+ return nil
+ }
+ ret := make([]string, 0, len(files))
- envOnce.Do(copyenv)
- return append([]string(nil), envs...)
+ for _, key := range files {
+ v, err := readenv(key)
+ if err != nil {
+ continue
+ }
+ ret = append(ret, key+"="+v)
+ }
+ return ret
}
diff --git a/libgo/go/syscall/env_unix.go b/libgo/go/syscall/env_unix.go
index f64202ed11..b5ded9c763 100644
--- a/libgo/go/syscall/env_unix.go
+++ b/libgo/go/syscall/env_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 netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
// Unix environment variables.
@@ -20,23 +20,33 @@ var (
// env maps from an environment variable to its first occurrence in envs.
env map[string]int
- // envs is provided by the runtime. elements are expected to be
- // of the form "key=value".
- Envs []string
+ // envs is provided by the runtime. elements are expected to
+ // be of the form "key=value". An empty string means deleted
+ // (or a duplicate to be ignored).
+ envs []string = runtime_envs()
)
-// setenv_c is provided by the runtime, but is a no-op if cgo isn't
-// loaded.
+func runtime_envs() []string // in package runtime
+
+// setenv_c and unsetenv_c are provided by the runtime but are no-ops
+// if cgo isn't loaded.
func setenv_c(k, v string)
+func unsetenv_c(k string)
func copyenv() {
env = make(map[string]int)
- for i, s := range Envs {
+ for i, s := range envs {
for j := 0; j < len(s); j++ {
if s[j] == '=' {
key := s[:j]
if _, ok := env[key]; !ok {
- env[key] = i
+ env[key] = i // first mention of key
+ } else {
+ // Clear duplicate keys. This permits Unsetenv to
+ // safely delete only the first item without
+ // worrying about unshadowing a later one,
+ // which might be a security problem.
+ envs[i] = ""
}
break
}
@@ -44,6 +54,20 @@ func copyenv() {
}
}
+func Unsetenv(key string) error {
+ envOnce.Do(copyenv)
+
+ envLock.Lock()
+ defer envLock.Unlock()
+
+ if i, ok := env[key]; ok {
+ envs[i] = ""
+ delete(env, key)
+ }
+ unsetenv_c(key)
+ return nil
+}
+
func Getenv(key string) (value string, found bool) {
envOnce.Do(copyenv)
if len(key) == 0 {
@@ -57,7 +81,7 @@ func Getenv(key string) (value string, found bool) {
if !ok {
return "", false
}
- s := Envs[i]
+ s := envs[i]
for i := 0; i < len(s); i++ {
if s[i] == '=' {
return s[i+1:], true
@@ -88,10 +112,10 @@ func Setenv(key, value string) error {
i, ok := env[key]
kv := key + "=" + value
if ok {
- Envs[i] = kv
+ envs[i] = kv
} else {
- i = len(Envs)
- Envs = append(Envs, kv)
+ i = len(envs)
+ envs = append(envs, kv)
}
env[key] = i
setenv_c(key, value)
@@ -104,16 +128,22 @@ func Clearenv() {
envLock.Lock()
defer envLock.Unlock()
+ for k := range env {
+ unsetenv_c(k)
+ }
env = make(map[string]int)
- Envs = []string{}
- // TODO(bradfitz): pass through to C
+ envs = []string{}
}
func Environ() []string {
envOnce.Do(copyenv)
envLock.RLock()
defer envLock.RUnlock()
- a := make([]string, len(Envs))
- copy(a, Envs)
+ a := make([]string, 0, len(envs))
+ for _, env := range envs {
+ if env != "" {
+ a = append(a, env)
+ }
+ }
return a
}
diff --git a/libgo/go/syscall/env_windows.go b/libgo/go/syscall/env_windows.go
index 420b387246..bc21690d9f 100644
--- a/libgo/go/syscall/env_windows.go
+++ b/libgo/go/syscall/env_windows.go
@@ -47,6 +47,14 @@ func Setenv(key, value string) error {
return nil
}
+func Unsetenv(key string) error {
+ keyp, err := UTF16PtrFromString(key)
+ if err != nil {
+ return err
+ }
+ return SetEnvironmentVariable(keyp, nil)
+}
+
func Clearenv() {
for _, s := range Environ() {
// Environment variables can begin with =
diff --git a/libgo/go/syscall/exec_linux.go b/libgo/go/syscall/exec_linux.go
index 6a92163206..97bde0c4f5 100644
--- a/libgo/go/syscall/exec_linux.go
+++ b/libgo/go/syscall/exec_linux.go
@@ -7,23 +7,34 @@
package syscall
import (
+ "runtime"
"unsafe"
)
//sysnb raw_prctl(option int, arg2 int, arg3 int, arg4 int, arg5 int) (ret int, err Errno)
//prctl(option _C_int, arg2 _C_long, arg3 _C_long, arg4 _C_long, arg5 _C_long) _C_int
+// SysProcIDMap holds Container ID to Host ID mappings used for User Namespaces in Linux.
+// See user_namespaces(7).
+type SysProcIDMap struct {
+ ContainerID int // Container ID.
+ HostID int // Host ID.
+ Size int // Size.
+}
+
type SysProcAttr struct {
- Chroot string // Chroot.
- Credential *Credential // Credential.
- Ptrace bool // Enable tracing.
- Setsid bool // Create session.
- Setpgid bool // Set process group ID to new pid (SYSV setpgrp)
- Setctty bool // Set controlling terminal to fd Ctty (only meaningful if Setsid is set)
- Noctty bool // Detach fd 0 from controlling terminal
- Ctty int // Controlling TTY fd (Linux only)
- Pdeathsig Signal // Signal that the process will get when its parent dies (Linux only)
- Cloneflags uintptr // Flags for clone calls (Linux only)
+ Chroot string // Chroot.
+ Credential *Credential // Credential.
+ Ptrace bool // Enable tracing.
+ Setsid bool // Create session.
+ Setpgid bool // Set process group ID to new pid (SYSV setpgrp)
+ Setctty bool // Set controlling terminal to fd Ctty (only meaningful if Setsid is set)
+ Noctty bool // Detach fd 0 from controlling terminal
+ Ctty int // Controlling TTY fd (Linux only)
+ Pdeathsig Signal // Signal that the process will get when its parent dies (Linux only)
+ Cloneflags uintptr // Flags for clone calls (Linux only)
+ UidMappings []SysProcIDMap // User ID mappings for user namespaces.
+ GidMappings []SysProcIDMap // Group ID mappings for user namespaces.
}
// Implemented in runtime package.
@@ -45,8 +56,10 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
var (
r1 uintptr
err1 Errno
+ err2 Errno
nextfd int
i int
+ p [2]int
)
// Guard against side effects of shuffling fds below.
@@ -62,10 +75,22 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
}
nextfd++
+ // Allocate another pipe for parent to child communication for
+ // synchronizing writing of User ID/Group ID mappings.
+ if sys.UidMappings != nil || sys.GidMappings != nil {
+ if err := forkExecPipe(p[:]); err != nil {
+ return 0, err.(Errno)
+ }
+ }
+
// About to call fork.
// No more allocation or calls of non-assembly functions.
runtime_BeforeFork()
- r1, _, err1 = RawSyscall6(SYS_CLONE, uintptr(SIGCHLD)|sys.Cloneflags, 0, 0, 0, 0, 0)
+ if runtime.GOARCH == "s390x" || runtime.GOARCH == "s390" {
+ r1, _, err1 = RawSyscall6(SYS_CLONE, 0, uintptr(SIGCHLD)|sys.Cloneflags, 0, 0, 0, 0)
+ } else {
+ r1, _, err1 = RawSyscall6(SYS_CLONE, uintptr(SIGCHLD)|sys.Cloneflags, 0, 0, 0, 0, 0)
+ }
if err1 != 0 {
runtime_AfterFork()
return 0, err1
@@ -74,11 +99,42 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
if r1 != 0 {
// parent; return PID
runtime_AfterFork()
- return int(r1), 0
+ pid = int(r1)
+
+ if sys.UidMappings != nil || sys.GidMappings != nil {
+ Close(p[0])
+ err := writeUidGidMappings(pid, sys)
+ if err != nil {
+ err2 = err.(Errno)
+ }
+ RawSyscall(SYS_WRITE, uintptr(p[1]), uintptr(unsafe.Pointer(&err2)), unsafe.Sizeof(err2))
+ Close(p[1])
+ }
+
+ return pid, 0
}
// Fork succeeded, now in child.
+ // Wait for User ID/Group ID mappings to be written.
+ if sys.UidMappings != nil || sys.GidMappings != nil {
+ if _, _, err1 = RawSyscall(SYS_CLOSE, uintptr(p[1]), 0, 0); err1 != 0 {
+ goto childerror
+ }
+ r1, _, err1 = RawSyscall(SYS_READ, uintptr(p[0]), uintptr(unsafe.Pointer(&err2)), unsafe.Sizeof(err2))
+ if err1 != 0 {
+ goto childerror
+ }
+ if r1 != unsafe.Sizeof(err2) {
+ err1 = EINVAL
+ goto childerror
+ }
+ if err2 != 0 {
+ err1 = err2
+ goto childerror
+ }
+ }
+
// Parent death signal
if sys.Pdeathsig != 0 {
_, err1 = raw_prctl(PR_SET_PDEATHSIG, int(sys.Pdeathsig), 0, 0, 0)
@@ -277,3 +333,53 @@ func forkExecPipe(p []int) (err error) {
}
return
}
+
+// writeIDMappings writes the user namespace User ID or Group ID mappings to the specified path.
+func writeIDMappings(path string, idMap []SysProcIDMap) error {
+ fd, err := Open(path, O_RDWR, 0)
+ if err != nil {
+ return err
+ }
+
+ data := ""
+ for _, im := range idMap {
+ data = data + itoa(im.ContainerID) + " " + itoa(im.HostID) + " " + itoa(im.Size) + "\n"
+ }
+
+ bytes, err := ByteSliceFromString(data)
+ if err != nil {
+ Close(fd)
+ return err
+ }
+
+ if _, err := Write(fd, bytes); err != nil {
+ Close(fd)
+ return err
+ }
+
+ if err := Close(fd); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// writeUidGidMappings writes User ID and Group ID mappings for user namespaces
+// for a process and it is called from the parent process.
+func writeUidGidMappings(pid int, sys *SysProcAttr) error {
+ if sys.UidMappings != nil {
+ uidf := "/proc/" + itoa(pid) + "/uid_map"
+ if err := writeIDMappings(uidf, sys.UidMappings); err != nil {
+ return err
+ }
+ }
+
+ if sys.GidMappings != nil {
+ gidf := "/proc/" + itoa(pid) + "/gid_map"
+ if err := writeIDMappings(gidf, sys.GidMappings); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
diff --git a/libgo/go/syscall/exec_unix.go b/libgo/go/syscall/exec_unix.go
index 0cfedb71cf..a49d95bc94 100644
--- a/libgo/go/syscall/exec_unix.go
+++ b/libgo/go/syscall/exec_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 netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
// Fork, exec, wait, etc.
@@ -194,7 +194,7 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error)
return 0, err
}
- if runtime.GOOS == "freebsd" && len(argv[0]) > len(argv0) {
+ if (runtime.GOOS == "freebsd" || runtime.GOOS == "dragonfly") && len(argv[0]) > len(argv0) {
argvp[0] = argv0p
}
@@ -226,6 +226,7 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error)
// Kick off child.
pid, err1 = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, sys, p[1])
if err1 != 0 {
+ err = Errno(err1)
goto error
}
ForkLock.Unlock()
diff --git a/libgo/go/syscall/exec_windows.go b/libgo/go/syscall/exec_windows.go
index 82abc0715e..936aeb577b 100644
--- a/libgo/go/syscall/exec_windows.go
+++ b/libgo/go/syscall/exec_windows.go
@@ -129,9 +129,8 @@ func SetNonblock(fd Handle, nonblocking bool) (err error) {
return nil
}
-// getFullPath retrieves the full path of the specified file.
-// Just a wrapper for Windows GetFullPathName api.
-func getFullPath(name string) (path string, err error) {
+// FullPath retrieves the full path of the specified file.
+func FullPath(name string) (path string, err error) {
p, err := UTF16PtrFromString(name)
if err != nil {
return "", err
@@ -160,7 +159,7 @@ func isSlash(c uint8) bool {
}
func normalizeDir(dir string) (name string, err error) {
- ndir, err := getFullPath(dir)
+ ndir, err := FullPath(dir)
if err != nil {
return "", err
}
@@ -199,9 +198,9 @@ func joinExeDirAndFName(dir, p string) (name string, err error) {
return "", err
}
if volToUpper(int(p[0])) == volToUpper(int(d[0])) {
- return getFullPath(d + "\\" + p[2:])
+ return FullPath(d + "\\" + p[2:])
} else {
- return getFullPath(p)
+ return FullPath(p)
}
}
} else {
@@ -211,9 +210,9 @@ func joinExeDirAndFName(dir, p string) (name string, err error) {
return "", err
}
if isSlash(p[0]) {
- return getFullPath(d[:2] + p)
+ return FullPath(d[:2] + p)
} else {
- return getFullPath(d + "\\" + p)
+ return FullPath(d + "\\" + p)
}
}
// we shouldn't be here
diff --git a/libgo/go/syscall/export_test.go b/libgo/go/syscall/export_test.go
new file mode 100644
index 0000000000..c9774622c8
--- /dev/null
+++ b/libgo/go/syscall/export_test.go
@@ -0,0 +1,7 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+var Itoa = itoa
diff --git a/libgo/go/syscall/libcall_linux_s390.go b/libgo/go/syscall/libcall_linux_s390.go
new file mode 100644
index 0000000000..c5f3b30ffd
--- /dev/null
+++ b/libgo/go/syscall/libcall_linux_s390.go
@@ -0,0 +1,7 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// GNU/Linux library calls s390 specific.
+
+package syscall
diff --git a/libgo/go/syscall/libcall_linux_s390x.go b/libgo/go/syscall/libcall_linux_s390x.go
new file mode 100644
index 0000000000..c5f3b30ffd
--- /dev/null
+++ b/libgo/go/syscall/libcall_linux_s390x.go
@@ -0,0 +1,7 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// GNU/Linux library calls s390 specific.
+
+package syscall
diff --git a/libgo/go/syscall/libcall_posix.go b/libgo/go/syscall/libcall_posix.go
index 8f5b020758..d3580a1bc0 100644
--- a/libgo/go/syscall/libcall_posix.go
+++ b/libgo/go/syscall/libcall_posix.go
@@ -138,7 +138,7 @@ func (w WaitStatus) TrapCause() int
//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error)
//select(nfd _C_int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) _C_int
-const nfdbits = int(unsafe.Sizeof(fds_bits_type) * 8)
+const nfdbits = int(unsafe.Sizeof(fds_bits_type(0)) * 8)
type FdSet struct {
Bits [(FD_SETSIZE + nfdbits - 1) / nfdbits]fds_bits_type
@@ -208,6 +208,9 @@ func FDZero(set *FdSet) {
//sys fcntl(fd int, cmd int, arg int) (val int, err error)
//__go_fcntl(fd _C_int, cmd _C_int, arg _C_int) _C_int
+//sys FcntlFlock(fd uintptr, cmd int, lk *Flock_t) (err error)
+//__go_fcntl_flock(fd _C_int, cmd _C_int, arg *Flock_t) _C_int
+
//sys Fdatasync(fd int) (err error)
//fdatasync(fd _C_int) _C_int
@@ -241,9 +244,6 @@ func FDZero(set *FdSet) {
//sys Getpriority(which int, who int) (prio int, err error)
//getpriority(which _C_int, who _C_int) _C_int
-//sysnb Getrlimit(resource int, rlim *Rlimit) (err error)
-//getrlimit(resource _C_int, rlim *Rlimit) _C_int
-
//sysnb Getrusage(who int, rusage *Rusage) (err error)
//getrusage(who _C_int, rusage *Rusage) _C_int
@@ -316,9 +316,6 @@ func Gettimeofday(tv *Timeval) (err error) {
//sysnb Setreuid(ruid int, euid int) (err error)
//setreuid(ruid Uid_t, euid Uid_t) _C_int
-//sysnb Setrlimit(resource int, rlim *Rlimit) (err error)
-//setrlimit(resource int, rlim *Rlimit) _C_int
-
//sysnb Setsid() (pid int, err error)
//setsid() Pid_t
diff --git a/libgo/go/syscall/libcall_posix_largefile.go b/libgo/go/syscall/libcall_posix_largefile.go
index fced6e57dd..c05d3d2a5e 100644
--- a/libgo/go/syscall/libcall_posix_largefile.go
+++ b/libgo/go/syscall/libcall_posix_largefile.go
@@ -12,6 +12,9 @@ package syscall
//sys Ftruncate(fd int, length int64) (err error)
//ftruncate64(fd _C_int, length Offset_t) _C_int
+//sysnb Getrlimit(resource int, rlim *Rlimit) (err error)
+//getrlimit64(resource _C_int, rlim *Rlimit) _C_int
+
//sys Lstat(path string, stat *Stat_t) (err error)
//lstat64(path *byte, stat *Stat_t) _C_int
@@ -30,6 +33,9 @@ package syscall
//sys Seek(fd int, offset int64, whence int) (off int64, err error)
//lseek64(fd _C_int, offset Offset_t, whence _C_int) Offset_t
+//sysnb Setrlimit(resource int, rlim *Rlimit) (err error)
+//setrlimit64(resource int, rlim *Rlimit) _C_int
+
//sys Stat(path string, stat *Stat_t) (err error)
//stat64(path *byte, stat *Stat_t) _C_int
diff --git a/libgo/go/syscall/libcall_posix_regfile.go b/libgo/go/syscall/libcall_posix_regfile.go
index 6c98e29873..7de5800939 100644
--- a/libgo/go/syscall/libcall_posix_regfile.go
+++ b/libgo/go/syscall/libcall_posix_regfile.go
@@ -13,6 +13,9 @@ package syscall
//sys Ftruncate(fd int, length int64) (err error)
//ftruncate(fd _C_int, length Offset_t) _C_int
+//sysnb Getrlimit(resource int, rlim *Rlimit) (err error)
+//getrlimit(resource _C_int, rlim *Rlimit) _C_int
+
//sys Lstat(path string, stat *Stat_t) (err error)
//lstat(path *byte, stat *Stat_t) _C_int
@@ -31,6 +34,9 @@ package syscall
//sys Seek(fd int, offset int64, whence int) (off int64, err error)
//lseek(fd _C_int, offset Offset_t, whence _C_int) Offset_t
+//sysnb Setrlimit(resource int, rlim *Rlimit) (err error)
+//setrlimit(resource int, rlim *Rlimit) _C_int
+
//sys Stat(path string, stat *Stat_t) (err error)
//stat(path *byte, stat *Stat_t) _C_int
diff --git a/libgo/go/syscall/lsf_linux.go b/libgo/go/syscall/lsf_linux.go
index 5296cec9c6..48ba191c6d 100644
--- a/libgo/go/syscall/lsf_linux.go
+++ b/libgo/go/syscall/lsf_linux.go
@@ -69,10 +69,10 @@ func AttachLsf(fd int, i []SockFilter) error {
var p SockFprog
p.Len = uint16(len(i))
p.Filter = (*SockFilter)(unsafe.Pointer(&i[0]))
- return setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, (*byte)(unsafe.Pointer(&p)), Socklen_t(unsafe.Sizeof(p)))
+ return setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, unsafe.Pointer(&p), Socklen_t(unsafe.Sizeof(p)))
}
func DetachLsf(fd int) error {
var dummy int
- return setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, (*byte)(unsafe.Pointer(&dummy)), Socklen_t(unsafe.Sizeof(dummy)))
+ return setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, unsafe.Pointer(&dummy), Socklen_t(unsafe.Sizeof(dummy)))
}
diff --git a/libgo/go/syscall/mksyscall.awk b/libgo/go/syscall/mksyscall.awk
index daf6554a6c..6fbd2ac8ef 100644
--- a/libgo/go/syscall/mksyscall.awk
+++ b/libgo/go/syscall/mksyscall.awk
@@ -96,8 +96,11 @@ BEGIN {
cfnresult = line
printf("// Automatically generated wrapper for %s/%s\n", gofnname, cfnname)
- printf("//extern %s\n", cfnname)
- printf("func c_%s(%s) %s\n", cfnname, cfnparams, cfnresult)
+ if (!(cfnname in cfns)) {
+ cfns[cfnname] = 1
+ printf("//extern %s\n", cfnname)
+ printf("func c_%s(%s) %s\n", cfnname, cfnparams, cfnresult)
+ }
printf("func %s(%s) %s%s%s%s{\n",
gofnname, gofnparams, gofnresults == "" ? "" : "(", gofnresults,
gofnresults == "" ? "" : ")", gofnresults == "" ? "" : " ")
@@ -196,6 +199,8 @@ BEGIN {
args = sprintf("%s_p%d, %s(len(%s))", args, goarg, cparam[2], goname)
} else if (gotype == "uintptr" && ctype ~ /^\*/) {
args = sprintf("%s(%s)(unsafe.Pointer(%s))", args, ctype, goname)
+ } else if (gotype == "unsafe.Pointer" && ctype ~ /^\*/) {
+ args = sprintf("%s(%s)(%s)", args, ctype, goname)
} else {
args = sprintf("%s%s(%s)", args, ctype, goname)
}
diff --git a/libgo/go/syscall/mmap_unix_test.go b/libgo/go/syscall/mmap_unix_test.go
new file mode 100644
index 0000000000..01f7783022
--- /dev/null
+++ b/libgo/go/syscall/mmap_unix_test.go
@@ -0,0 +1,22 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd
+
+package syscall_test
+
+import (
+ "syscall"
+ "testing"
+)
+
+func TestMmap(t *testing.T) {
+ b, err := syscall.Mmap(-1, 0, syscall.Getpagesize(), syscall.PROT_NONE, syscall.MAP_ANON|syscall.MAP_PRIVATE)
+ if err != nil {
+ t.Fatalf("Mmap: %v", err)
+ }
+ if err := syscall.Munmap(b); err != nil {
+ t.Fatalf("Munmap: %v", err)
+ }
+}
diff --git a/libgo/go/syscall/netlink_linux.go b/libgo/go/syscall/netlink_linux.go
index 49550ea2f0..1b73dce827 100644
--- a/libgo/go/syscall/netlink_linux.go
+++ b/libgo/go/syscall/netlink_linux.go
@@ -64,9 +64,10 @@ func NetlinkRIB(proto, family int) ([]byte, error) {
return nil, err
}
var tab []byte
+ rbNew := make([]byte, Getpagesize())
done:
for {
- rb := make([]byte, Getpagesize())
+ rb := rbNew
nr, _, err := Recvfrom(s, rb, 0)
if err != nil {
return nil, err
diff --git a/libgo/go/syscall/rlimit_linux_test.go b/libgo/go/syscall/rlimit_linux_test.go
deleted file mode 100644
index 4ec720e936..0000000000
--- a/libgo/go/syscall/rlimit_linux_test.go
+++ /dev/null
@@ -1,41 +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 syscall_test
-
-import (
- "syscall"
- "testing"
-)
-
-func TestRlimit(t *testing.T) {
- var rlimit, zero syscall.Rlimit
- err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit)
- if err != nil {
- t.Fatalf("Getrlimit: save failed: %v", err)
- }
- if zero == rlimit {
- t.Fatalf("Getrlimit: save failed: got zero value %#v", rlimit)
- }
- set := rlimit
- set.Cur = set.Max - 1
- err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &set)
- if err != nil {
- t.Fatalf("Setrlimit: set failed: %#v %v", set, err)
- }
- var get syscall.Rlimit
- err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &get)
- if err != nil {
- t.Fatalf("Getrlimit: get failed: %v", err)
- }
- set = rlimit
- set.Cur = set.Max - 1
- if set != get {
- t.Fatalf("Rlimit: change failed: wanted %#v got %#v", set, get)
- }
- err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rlimit)
- if err != nil {
- t.Fatalf("Setrlimit: restore failed: %#v %v", rlimit, err)
- }
-}
diff --git a/libgo/go/syscall/route_bsd.go b/libgo/go/syscall/route_bsd.go
index 638073592d..1dabe42531 100644
--- a/libgo/go/syscall/route_bsd.go
+++ b/libgo/go/syscall/route_bsd.go
@@ -153,7 +153,7 @@ func (m *InterfaceAddrMessage) sockaddr() (sas []Sockaddr) {
// RTAX_NETMASK socket address on the FreeBSD kernel.
preferredFamily := uint8(AF_UNSPEC)
for i := uint(0); i < RTAX_MAX; i++ {
- if m.Header.Addrs&rtaIfaMask&(1<<i) == 0 {
+ if m.Header.Addrs&(1<<i) == 0 {
continue
}
rsa := (*RawSockaddr)(unsafe.Pointer(&b[0]))
@@ -199,14 +199,21 @@ func (m *InterfaceAddrMessage) sockaddr() (sas []Sockaddr) {
// ParseRoutingMessage parses b as routing messages and returns the
// slice containing the RoutingMessage interfaces.
func ParseRoutingMessage(b []byte) (msgs []RoutingMessage, err error) {
+ msgCount := 0
for len(b) >= anyMessageLen {
+ msgCount++
any := (*anyMessage)(unsafe.Pointer(&b[0]))
if any.Version != RTM_VERSION {
- return nil, EINVAL
+ b = b[any.Msglen:]
+ continue
}
msgs = append(msgs, any.toRoutingMessage(b))
b = b[any.Msglen:]
}
+ // We failed to parse any of the messages - version mismatch?
+ if msgCount > 0 && len(msgs) == 0 {
+ return nil, EINVAL
+ }
return msgs, nil
}
diff --git a/libgo/go/syscall/route_dragonfly.go b/libgo/go/syscall/route_dragonfly.go
index acad7a2be8..79190d2b01 100644
--- a/libgo/go/syscall/route_dragonfly.go
+++ b/libgo/go/syscall/route_dragonfly.go
@@ -30,7 +30,7 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
}
// InterfaceAnnounceMessage represents a routing message containing
-// network interface arrival and depature information.
+// network interface arrival and departure information.
type InterfaceAnnounceMessage struct {
Header IfAnnounceMsghdr
}
diff --git a/libgo/go/syscall/route_freebsd.go b/libgo/go/syscall/route_freebsd.go
index d8f80316b8..15897b1aca 100644
--- a/libgo/go/syscall/route_freebsd.go
+++ b/libgo/go/syscall/route_freebsd.go
@@ -8,14 +8,20 @@ package syscall
import "unsafe"
+// See http://www.freebsd.org/doc/en/books/porters-handbook/freebsd-versions.html.
+var freebsdVersion uint32
+
+func init() {
+ freebsdVersion, _ = SysctlUint32("kern.osreldate")
+}
+
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]}
case RTM_IFINFO:
- p := (*InterfaceMessage)(unsafe.Pointer(any))
- return &InterfaceMessage{Header: p.Header, Data: b[SizeofIfMsghdr:any.Msglen]}
+ return any.parseInterfaceMessage(b)
case RTM_IFANNOUNCE:
p := (*InterfaceAnnounceMessage)(unsafe.Pointer(any))
return &InterfaceAnnounceMessage{Header: p.Header}
@@ -30,7 +36,7 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
}
// InterfaceAnnounceMessage represents a routing message containing
-// network interface arrival and depature information.
+// network interface arrival and departure information.
type InterfaceAnnounceMessage struct {
Header IfAnnounceMsghdr
}
diff --git a/libgo/go/syscall/route_freebsd_32bit.go b/libgo/go/syscall/route_freebsd_32bit.go
new file mode 100644
index 0000000000..93efdddb3b
--- /dev/null
+++ b/libgo/go/syscall/route_freebsd_32bit.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 freebsd,386 freebsd,arm
+
+package syscall
+
+import "unsafe"
+
+func (any *anyMessage) parseInterfaceMessage(b []byte) *InterfaceMessage {
+ p := (*InterfaceMessage)(unsafe.Pointer(any))
+ // FreeBSD 10 and beyond have a restructured mbuf
+ // packet header view.
+ // See http://svnweb.freebsd.org/base?view=revision&revision=254804.
+ if freebsdVersion >= 1000000 {
+ m := (*ifMsghdr)(unsafe.Pointer(any))
+ p.Header.Data.Hwassist = uint32(m.Data.Hwassist)
+ p.Header.Data.Epoch = m.Data.Epoch
+ p.Header.Data.Lastchange = m.Data.Lastchange
+ return &InterfaceMessage{Header: p.Header, Data: b[sizeofIfMsghdr:any.Msglen]}
+ }
+ return &InterfaceMessage{Header: p.Header, Data: b[SizeofIfMsghdr:any.Msglen]}
+}
diff --git a/libgo/go/syscall/route_freebsd_64bit.go b/libgo/go/syscall/route_freebsd_64bit.go
new file mode 100644
index 0000000000..9377f2fedc
--- /dev/null
+++ b/libgo/go/syscall/route_freebsd_64bit.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 freebsd,amd64
+
+package syscall
+
+import "unsafe"
+
+func (any *anyMessage) parseInterfaceMessage(b []byte) *InterfaceMessage {
+ p := (*InterfaceMessage)(unsafe.Pointer(any))
+ return &InterfaceMessage{Header: p.Header, Data: b[SizeofIfMsghdr:any.Msglen]}
+}
diff --git a/libgo/go/syscall/route_netbsd.go b/libgo/go/syscall/route_netbsd.go
index a6baa02f80..9883aebaf5 100644
--- a/libgo/go/syscall/route_netbsd.go
+++ b/libgo/go/syscall/route_netbsd.go
@@ -27,7 +27,7 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
}
// InterfaceAnnounceMessage represents a routing message containing
-// network interface arrival and depature information.
+// network interface arrival and departure information.
type InterfaceAnnounceMessage struct {
Header IfAnnounceMsghdr
}
diff --git a/libgo/go/syscall/route_openbsd.go b/libgo/go/syscall/route_openbsd.go
index 223c157791..e5086400c5 100644
--- a/libgo/go/syscall/route_openbsd.go
+++ b/libgo/go/syscall/route_openbsd.go
@@ -12,22 +12,22 @@ 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 &RouteMessage{Header: p.Header, Data: b[p.Header.Hdrlen:any.Msglen]}
case RTM_IFINFO:
p := (*InterfaceMessage)(unsafe.Pointer(any))
- return &InterfaceMessage{Header: p.Header, Data: b[SizeofIfMsghdr:any.Msglen]}
+ return &InterfaceMessage{Header: p.Header, Data: b[p.Header.Hdrlen:any.Msglen]}
case RTM_IFANNOUNCE:
p := (*InterfaceAnnounceMessage)(unsafe.Pointer(any))
return &InterfaceAnnounceMessage{Header: p.Header}
case RTM_NEWADDR, RTM_DELADDR:
p := (*InterfaceAddrMessage)(unsafe.Pointer(any))
- return &InterfaceAddrMessage{Header: p.Header, Data: b[SizeofIfaMsghdr:any.Msglen]}
+ return &InterfaceAddrMessage{Header: p.Header, Data: b[p.Header.Hdrlen:any.Msglen]}
}
return nil
}
// InterfaceAnnounceMessage represents a routing message containing
-// network interface arrival and depature information.
+// network interface arrival and departure information.
type InterfaceAnnounceMessage struct {
Header IfAnnounceMsghdr
}
diff --git a/libgo/go/syscall/sockcmsg_unix.go b/libgo/go/syscall/sockcmsg_unix.go
index 5bc4c2acfb..34c707d932 100644
--- a/libgo/go/syscall/sockcmsg_unix.go
+++ b/libgo/go/syscall/sockcmsg_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 netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
// Socket control messages
@@ -16,9 +16,9 @@ import (
// Round the length of a raw sockaddr up to align it properly.
func cmsgAlignOf(salen int) int {
salign := int(sizeofPtr)
- // NOTE: It seems like 64-bit Darwin kernel still requires 32-bit
- // aligned access to BSD subsystem.
- if darwin64Bit {
+ // NOTE: It seems like 64-bit Darwin and DragonFly BSD kernels
+ // still require 32-bit aligned access to network subsystem.
+ if darwin64Bit || dragonfly64Bit {
salign = 4
}
// NOTE: Solaris always uses 32-bit alignment,
diff --git a/libgo/go/syscall/socket.go b/libgo/go/syscall/socket.go
index f4dba36908..d96a717303 100644
--- a/libgo/go/syscall/socket.go
+++ b/libgo/go/syscall/socket.go
@@ -213,67 +213,67 @@ func Socketpair(domain, typ, proto int) (fd [2]int, err error) {
func GetsockoptByte(fd, level, opt int) (value byte, err error) {
var n byte
vallen := Socklen_t(1)
- err = getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&n)), &vallen)
+ err = getsockopt(fd, level, opt, unsafe.Pointer(&n), &vallen)
return n, err
}
func GetsockoptInt(fd, level, opt int) (value int, err error) {
var n int32
vallen := Socklen_t(4)
- err = getsockopt(fd, level, opt, (uintptr)(unsafe.Pointer(&n)), &vallen)
+ err = getsockopt(fd, level, opt, unsafe.Pointer(&n), &vallen)
return int(n), err
}
func GetsockoptInet4Addr(fd, level, opt int) (value [4]byte, err error) {
vallen := Socklen_t(4)
- err = getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value[0])), &vallen)
+ err = getsockopt(fd, level, opt, unsafe.Pointer(&value[0]), &vallen)
return value, err
}
func GetsockoptIPMreq(fd, level, opt int) (*IPMreq, error) {
var value IPMreq
vallen := Socklen_t(SizeofIPMreq)
- err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
return &value, err
}
func GetsockoptIPMreqn(fd, level, opt int) (*IPMreqn, error) {
var value IPMreqn
vallen := Socklen_t(SizeofIPMreqn)
- err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
return &value, err
}
func GetsockoptIPv6Mreq(fd, level, opt int) (*IPv6Mreq, error) {
var value IPv6Mreq
vallen := Socklen_t(SizeofIPv6Mreq)
- err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
return &value, err
}
-//sys setsockopt(s int, level int, name int, val *byte, vallen Socklen_t) (err error)
+//sys setsockopt(s int, level int, name int, val unsafe.Pointer, vallen Socklen_t) (err error)
//setsockopt(s _C_int, level _C_int, optname _C_int, val *byte, vallen Socklen_t) _C_int
func SetsockoptByte(fd, level, opt int, value byte) (err error) {
var n = byte(value)
- return setsockopt(fd, level, opt, (*byte)(unsafe.Pointer(&n)), 1)
+ return setsockopt(fd, level, opt, unsafe.Pointer(&n), 1)
}
func SetsockoptInt(fd, level, opt int, value int) (err error) {
var n = int32(value)
- return setsockopt(fd, level, opt, (*byte)(unsafe.Pointer(&n)), 4)
+ return setsockopt(fd, level, opt, unsafe.Pointer(&n), 4)
}
func SetsockoptInet4Addr(fd, level, opt int, value [4]byte) (err error) {
- return setsockopt(fd, level, opt, (*byte)(unsafe.Pointer(&value[0])), 4)
+ return setsockopt(fd, level, opt, unsafe.Pointer(&value[0]), 4)
}
func SetsockoptTimeval(fd, level, opt int, tv *Timeval) (err error) {
- return setsockopt(fd, level, opt, (*byte)(unsafe.Pointer(tv)), Socklen_t(unsafe.Sizeof(*tv)))
+ return setsockopt(fd, level, opt, unsafe.Pointer(tv), Socklen_t(unsafe.Sizeof(*tv)))
}
func SetsockoptICMPv6Filter(fd, level, opt int, filter *ICMPv6Filter) error {
- return setsockopt(fd, level, opt, (*byte)(unsafe.Pointer(filter)), SizeofICMPv6Filter)
+ return setsockopt(fd, level, opt, unsafe.Pointer(filter), SizeofICMPv6Filter)
}
type Linger struct {
@@ -282,23 +282,23 @@ type Linger struct {
}
func SetsockoptLinger(fd, level, opt int, l *Linger) (err error) {
- return setsockopt(fd, level, opt, (*byte)(unsafe.Pointer(l)), Socklen_t(unsafe.Sizeof(*l)))
+ return setsockopt(fd, level, opt, unsafe.Pointer(l), Socklen_t(unsafe.Sizeof(*l)))
}
func SetsockoptIPMreq(fd, level, opt int, mreq *IPMreq) (err error) {
- return setsockopt(fd, level, opt, (*byte)(unsafe.Pointer(mreq)), Socklen_t(unsafe.Sizeof(*mreq)))
+ return setsockopt(fd, level, opt, unsafe.Pointer(mreq), Socklen_t(unsafe.Sizeof(*mreq)))
}
func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) {
- return setsockopt(fd, level, opt, (*byte)(unsafe.Pointer(mreq)), Socklen_t(unsafe.Sizeof(*mreq)))
+ return setsockopt(fd, level, opt, unsafe.Pointer(mreq), Socklen_t(unsafe.Sizeof(*mreq)))
}
func SetsockoptIPv6Mreq(fd, level, opt int, mreq *IPv6Mreq) (err error) {
- return setsockopt(fd, level, opt, (*byte)(unsafe.Pointer(mreq)), Socklen_t(unsafe.Sizeof(*mreq)))
+ return setsockopt(fd, level, opt, unsafe.Pointer(mreq), Socklen_t(unsafe.Sizeof(*mreq)))
}
func SetsockoptString(fd, level, opt int, s string) (err error) {
- return setsockopt(fd, level, opt, (*byte)(unsafe.Pointer(&[]byte(s)[0])), Socklen_t(len(s)))
+ return setsockopt(fd, level, opt, unsafe.Pointer(&[]byte(s)[0]), Socklen_t(len(s)))
}
//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *Socklen_t) (n int, err error)
@@ -359,13 +359,18 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from
}
func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
+ _, err = SendmsgN(fd, p, oob, to, flags)
+ return
+}
+
+func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
var ptr *RawSockaddrAny
var salen Socklen_t
if to != nil {
var err error
ptr, salen, err = to.sockaddr()
if err != nil {
- return err
+ return 0, err
}
}
var msg Msghdr
@@ -388,10 +393,13 @@ func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
}
msg.Iov = &iov
msg.Iovlen = 1
- if err = sendmsg(fd, &msg, flags); err != nil {
- return
+ if n, err = sendmsg(fd, &msg, flags); err != nil {
+ return 0, err
}
- return
+ if len(oob) > 0 && len(p) == 0 {
+ n = 0
+ }
+ return n, nil
}
//sys Listen(fd int, n int) (err error)
diff --git a/libgo/go/syscall/socket_posix.go b/libgo/go/syscall/socket_posix.go
index 06d7dab464..fda7dc65e4 100644
--- a/libgo/go/syscall/socket_posix.go
+++ b/libgo/go/syscall/socket_posix.go
@@ -18,7 +18,7 @@ package syscall
//sysnb socketpair(domain int, typ int, proto int, fd *[2]_C_int) (err error)
//socketpair(domain _C_int, typ _C_int, protocol _C_int, fd *[2]_C_int) _C_int
-//sys getsockopt(s int, level int, name int, val uintptr, vallen *Socklen_t) (err error)
+//sys getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *Socklen_t) (err error)
//getsockopt(s _C_int, level _C_int, name _C_int, val *byte, vallen *Socklen_t) _C_int
//sys sendto(s int, buf []byte, flags int, to *RawSockaddrAny, tolen Socklen_t) (err error)
@@ -27,5 +27,5 @@ package syscall
//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error)
//recvmsg(s _C_int, msg *Msghdr, flags _C_int) Ssize_t
-//sys sendmsg(s int, msg *Msghdr, flags int) (err error)
+//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
//sendmsg(s _C_int, msg *Msghdr, flags _C_int) Ssize_t
diff --git a/libgo/go/syscall/socket_xnet.go b/libgo/go/syscall/socket_xnet.go
index 8f86c622b9..3c5b6b4180 100644
--- a/libgo/go/syscall/socket_xnet.go
+++ b/libgo/go/syscall/socket_xnet.go
@@ -19,7 +19,7 @@ package syscall
//sysnb socketpair(domain int, typ int, proto int, fd *[2]_C_int) (err error)
//__xnet_socketpair(domain _C_int, typ _C_int, protocol _C_int, fd *[2]_C_int) _C_int
-//sys getsockopt(s int, level int, name int, val uintptr, vallen *Socklen_t) (err error)
+//sys getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *Socklen_t) (err error)
//__xnet_getsockopt(s _C_int, level _C_int, name _C_int, val *byte, vallen *Socklen_t) _C_int
//sys sendto(s int, buf []byte, flags int, to *RawSockaddrAny, tolen Socklen_t) (err error)
@@ -28,5 +28,5 @@ package syscall
//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error)
//__xnet_recvmsg(s _C_int, msg *Msghdr, flags _C_int) Ssize_t
-//sys sendmsg(s int, msg *Msghdr, flags int) (err error)
+//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
//__xnet_sendmsg(s _C_int, msg *Msghdr, flags _C_int) Ssize_t
diff --git a/libgo/go/syscall/str.go b/libgo/go/syscall/str.go
index 0fce842e8c..2ddf04b227 100644
--- a/libgo/go/syscall/str.go
+++ b/libgo/go/syscall/str.go
@@ -6,8 +6,12 @@ package syscall
func itoa(val int) string { // do it here rather than with fmt to avoid dependency
if val < 0 {
- return "-" + itoa(-val)
+ return "-" + uitoa(uint(-val))
}
+ return uitoa(uint(val))
+}
+
+func uitoa(val uint) string {
var buf [32]byte // big enough for int64
i := len(buf) - 1
for val >= 10 {
diff --git a/libgo/go/syscall/syscall.go b/libgo/go/syscall/syscall.go
index c4f2125140..ef9d7d6597 100644
--- a/libgo/go/syscall/syscall.go
+++ b/libgo/go/syscall/syscall.go
@@ -17,6 +17,13 @@
// These calls return err == nil to indicate success; otherwise
// err is an operating system error describing the failure.
// On most systems, that error has type syscall.Errno.
+//
+// NOTE: This package is locked down. Code outside the standard
+// Go repository should be migrated to use the corresponding
+// package in the go.sys subrepository. That is also where updates
+// required by new systems or versions should be applied.
+// See https://golang.org/s/go1.4-syscall for more information.
+//
package syscall
import "unsafe"
@@ -85,3 +92,8 @@ func (ts *Timespec) Nano() int64 {
func (tv *Timeval) Nano() int64 {
return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000
}
+
+// use is a no-op, but the compiler cannot see that it is.
+// Calling use(p) ensures that p is kept live until that point.
+//go:noescape
+func use(p unsafe.Pointer)
diff --git a/libgo/go/syscall/syscall_errno.go b/libgo/go/syscall/syscall_errno.go
index 810572f58a..01618d173a 100644
--- a/libgo/go/syscall/syscall_errno.go
+++ b/libgo/go/syscall/syscall_errno.go
@@ -18,7 +18,7 @@ func (e Errno) Error() string {
}
func (e Errno) Temporary() bool {
- return e == EINTR || e == EMFILE || e.Timeout()
+ return e == EINTR || e == EMFILE || e == ECONNRESET || e == ECONNABORTED || e.Timeout()
}
func (e Errno) Timeout() bool {
diff --git a/libgo/go/syscall/syscall_linux_386.go b/libgo/go/syscall/syscall_linux_386.go
index 08422def37..591d3e1a33 100644
--- a/libgo/go/syscall/syscall_linux_386.go
+++ b/libgo/go/syscall/syscall_linux_386.go
@@ -4,6 +4,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
+// so that go vet can check that they are correct.
+
package syscall
import "unsafe"
diff --git a/libgo/go/syscall/syscall_linux_s390.go b/libgo/go/syscall/syscall_linux_s390.go
new file mode 100644
index 0000000000..a744f6b784
--- /dev/null
+++ b/libgo/go/syscall/syscall_linux_s390.go
@@ -0,0 +1,21 @@
+// syscall_linux_s390.go -- GNU/Linux s390 specific support
+
+// 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 "unsafe"
+
+func (r *PtraceRegs) PC() uint64 { return uint64(r.Psw.Addr) }
+
+func (r *PtraceRegs) SetPC(pc uint64) { r.Psw.Addr = uint32(pc) }
+
+func PtraceGetRegs(pid int, regsout *PtraceRegs) (err error) {
+ return ptrace(PTRACE_GETREGS, pid, 0, uintptr(unsafe.Pointer(regsout)))
+}
+
+func PtraceSetRegs(pid int, regs *PtraceRegs) (err error) {
+ return ptrace(PTRACE_SETREGS, pid, 0, uintptr(unsafe.Pointer(regs)))
+}
diff --git a/libgo/go/syscall/syscall_linux_s390x.go b/libgo/go/syscall/syscall_linux_s390x.go
new file mode 100644
index 0000000000..44d567983c
--- /dev/null
+++ b/libgo/go/syscall/syscall_linux_s390x.go
@@ -0,0 +1,21 @@
+// syscall_linux_s390x.go -- GNU/Linux s390x specific support
+
+// 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 "unsafe"
+
+func (r *PtraceRegs) PC() uint64 { return r.Psw.Addr }
+
+func (r *PtraceRegs) SetPC(pc uint64) { r.Psw.Addr = pc }
+
+func PtraceGetRegs(pid int, regsout *PtraceRegs) (err error) {
+ return ptrace(PTRACE_GETREGS, pid, 0, uintptr(unsafe.Pointer(regsout)))
+}
+
+func PtraceSetRegs(pid int, regs *PtraceRegs) (err error) {
+ return ptrace(PTRACE_SETREGS, pid, 0, uintptr(unsafe.Pointer(regs)))
+}
diff --git a/libgo/go/syscall/syscall_test.go b/libgo/go/syscall/syscall_test.go
index 2a39b54f1b..846c4873d2 100644
--- a/libgo/go/syscall/syscall_test.go
+++ b/libgo/go/syscall/syscall_test.go
@@ -5,6 +5,7 @@
package syscall_test
import (
+ "fmt"
"syscall"
"testing"
)
@@ -28,3 +29,19 @@ func TestEnv(t *testing.T) {
// make sure TESTENV gets set to "", not deleted
testSetGetenv(t, "TESTENV", "")
}
+
+func TestItoa(t *testing.T) {
+ // Make most negative integer: 0x8000...
+ i := 1
+ for i<<1 != 0 {
+ i <<= 1
+ }
+ if i >= 0 {
+ t.Fatal("bad math")
+ }
+ s := syscall.Itoa(i)
+ f := fmt.Sprint(i)
+ if s != f {
+ t.Fatalf("itoa(%d) = %s, want %s", i, s, f)
+ }
+}
diff --git a/libgo/go/syscall/syscall_unix.go b/libgo/go/syscall/syscall_unix.go
index 966090a076..74f10c29da 100644
--- a/libgo/go/syscall/syscall_unix.go
+++ b/libgo/go/syscall/syscall_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 netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package syscall
@@ -25,8 +25,9 @@ func c_syscall32(trap int32, a1, a2, a3, a4, a5, a6 int32) int32
func c_syscall64(trap int64, a1, a2, a3, a4, a5, a6 int64) int64
const (
- darwin64Bit = runtime.GOOS == "darwin" && sizeofPtr == 8
- netbsd32Bit = runtime.GOOS == "netbsd" && sizeofPtr == 4
+ darwin64Bit = runtime.GOOS == "darwin" && sizeofPtr == 8
+ dragonfly64Bit = runtime.GOOS == "dragonfly" && sizeofPtr == 8
+ netbsd32Bit = runtime.GOOS == "netbsd" && sizeofPtr == 4
)
// Do a system call. We look at the size of uintptr to see how to pass
@@ -153,7 +154,7 @@ func (m *mmapper) Munmap(data []byte) (err error) {
if errno := m.munmap(uintptr(unsafe.Pointer(&b[0])), uintptr(len(b))); errno != nil {
return errno
}
- m.active[p] = nil, false
+ delete(m.active, p)
return nil
}
diff --git a/libgo/go/syscall/passfd_test.go b/libgo/go/syscall/syscall_unix_test.go
index e8ac32d3f5..897ad18a97 100644
--- a/libgo/go/syscall/passfd_test.go
+++ b/libgo/go/syscall/syscall_unix_test.go
@@ -1,8 +1,8 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// 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 dragonfly darwin freebsd netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package syscall_test
@@ -13,12 +13,70 @@ import (
"net"
"os"
"os/exec"
+ "path/filepath"
"runtime"
"syscall"
"testing"
"time"
)
+// Tests that below functions, structures and constants are consistent
+// on all Unix-like systems.
+func _() {
+ // program scheduling priority functions and constants
+ var (
+ _ func(int, int, int) error = syscall.Setpriority
+ _ func(int, int) (int, error) = syscall.Getpriority
+ )
+ const (
+ _ int = syscall.PRIO_USER
+ _ int = syscall.PRIO_PROCESS
+ _ int = syscall.PRIO_PGRP
+ )
+
+ // termios constants
+ const (
+ _ int = syscall.TCIFLUSH
+ _ int = syscall.TCIOFLUSH
+ _ int = syscall.TCOFLUSH
+ )
+
+ // fcntl file locking structure and constants
+ var (
+ _ = syscall.Flock_t{
+ Type: int16(0),
+ Whence: int16(0),
+ Start: int64(0),
+ Len: int64(0),
+ Pid: int32(0),
+ }
+ )
+ const (
+ _ = syscall.F_GETLK
+ _ = syscall.F_SETLK
+ _ = syscall.F_SETLKW
+ )
+}
+
+// TestFcntlFlock tests whether the file locking structure matches
+// the calling convention of each kernel.
+func TestFcntlFlock(t *testing.T) {
+ name := filepath.Join(os.TempDir(), "TestFcntlFlock")
+ fd, err := syscall.Open(name, syscall.O_CREAT|syscall.O_RDWR|syscall.O_CLOEXEC, 0)
+ if err != nil {
+ t.Fatalf("Open failed: %v", err)
+ }
+ defer syscall.Unlink(name)
+ defer syscall.Close(fd)
+ flock := syscall.Flock_t{
+ Type: syscall.F_RDLCK,
+ Start: 0, Len: 0, Whence: 1,
+ }
+ if err := syscall.FcntlFlock(uintptr(fd), syscall.F_GETLK, &flock); err != nil {
+ t.Fatalf("FcntlFlock failed: %v", err)
+ }
+}
+
// TestPassFD tests passing a file descriptor over a Unix socket.
//
// This test involved both a parent and child process. The parent
@@ -27,9 +85,13 @@ import (
// "-test.run=^TestPassFD$" and an environment variable used to signal
// that the test should become the child process instead.
func TestPassFD(t *testing.T) {
- if runtime.GOOS == "dragonfly" {
+ switch runtime.GOOS {
+ case "dragonfly":
// TODO(jsing): Figure out why sendmsg is returning EINVAL.
- t.Skip("Skipping test on dragonfly")
+ t.Skip("skipping test on dragonfly")
+ case "solaris":
+ // TODO(aram): Figure out why ReadMsgUnix is returning empty message.
+ t.Skip("skipping test on solaris, see issue 7402")
}
if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
passFDChild()
@@ -204,3 +266,53 @@ func TestUnixRightsRoundtrip(t *testing.T) {
}
}
}
+
+func TestRlimit(t *testing.T) {
+ var rlimit, zero syscall.Rlimit
+ err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit)
+ if err != nil {
+ t.Fatalf("Getrlimit: save failed: %v", err)
+ }
+ if zero == rlimit {
+ t.Fatalf("Getrlimit: save failed: got zero value %#v", rlimit)
+ }
+ set := rlimit
+ set.Cur = set.Max - 1
+ err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &set)
+ if err != nil {
+ t.Fatalf("Setrlimit: set failed: %#v %v", set, err)
+ }
+ var get syscall.Rlimit
+ err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &get)
+ if err != nil {
+ t.Fatalf("Getrlimit: get failed: %v", err)
+ }
+ set = rlimit
+ set.Cur = set.Max - 1
+ if set != get {
+ // Seems like Darwin requires some privilege to
+ // increase the soft limit of rlimit sandbox, though
+ // Setrlimit never reports an error.
+ switch runtime.GOOS {
+ case "darwin":
+ default:
+ t.Fatalf("Rlimit: change failed: wanted %#v got %#v", set, get)
+ }
+ }
+ err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rlimit)
+ if err != nil {
+ t.Fatalf("Setrlimit: restore failed: %#v %v", rlimit, err)
+ }
+}
+
+func TestSeekFailure(t *testing.T) {
+ _, err := syscall.Seek(-1, 0, 0)
+ if err == nil {
+ t.Fatalf("Seek(-1, 0, 0) did not fail")
+ }
+ str := err.Error() // used to crash on Linux
+ t.Logf("Seek: %v", str)
+ if str == "" {
+ t.Fatalf("Seek(-1, 0, 0) return error with empty message")
+ }
+}
diff --git a/libgo/go/testing/allocs_test.go b/libgo/go/testing/allocs_test.go
new file mode 100644
index 0000000000..ec17daa2b1
--- /dev/null
+++ b/libgo/go/testing/allocs_test.go
@@ -0,0 +1,29 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package testing_test
+
+import "testing"
+
+var global interface{}
+
+var allocsPerRunTests = []struct {
+ name string
+ fn func()
+ allocs float64
+}{
+ {"alloc *byte", func() { global = new(*byte) }, 1},
+ {"alloc complex128", func() { global = new(complex128) }, 1},
+ {"alloc float64", func() { global = new(float64) }, 1},
+ {"alloc int32", func() { global = new(int32) }, 1},
+ {"alloc byte", func() { global = new(byte) }, 1},
+}
+
+func TestAllocsPerRun(t *testing.T) {
+ for _, tt := range allocsPerRunTests {
+ if allocs := testing.AllocsPerRun(100, tt.fn); allocs != tt.allocs {
+ t.Errorf("AllocsPerRun(100, %s) = %v, want %v", tt.name, allocs, tt.allocs)
+ }
+ }
+}
diff --git a/libgo/go/testing/benchmark.go b/libgo/go/testing/benchmark.go
index 3473c5b2cb..ffd5376844 100644
--- a/libgo/go/testing/benchmark.go
+++ b/libgo/go/testing/benchmark.go
@@ -10,6 +10,7 @@ import (
"os"
"runtime"
"sync"
+ "sync/atomic"
"time"
)
@@ -34,12 +35,15 @@ type InternalBenchmark struct {
// timing and to specify the number of iterations to run.
type B struct {
common
- N int
- benchmark InternalBenchmark
- bytes int64
- timerOn bool
- showAllocResult bool
- result BenchmarkResult
+ N int
+ previousN int // number of iterations in the previous run
+ previousDuration time.Duration // total duration of the previous run
+ benchmark InternalBenchmark
+ bytes int64
+ timerOn bool
+ showAllocResult bool
+ result BenchmarkResult
+ parallelism int // RunParallel creates parallelism*GOMAXPROCS goroutines
// The initial states of memStats.Mallocs and memStats.TotalAlloc.
startAllocs uint64
startBytes uint64
@@ -74,7 +78,7 @@ func (b *B) StopTimer() {
}
}
-// ResetTimer sets the elapsed benchmark time to zero.
+// ResetTimer zeros the elapsed benchmark time and memory allocation counters.
// It does not affect whether the timer is running.
func (b *B) ResetTimer() {
if b.timerOn {
@@ -114,10 +118,13 @@ func (b *B) runN(n int) {
// by clearing garbage from previous runs.
runtime.GC()
b.N = n
+ b.parallelism = 1
b.ResetTimer()
b.StartTimer()
b.benchmark.F(b)
b.StopTimer()
+ b.previousN = n
+ b.previousDuration = b.duration
}
func min(x, y int) int {
@@ -150,7 +157,7 @@ func roundDown10(n int) int {
return result
}
-// roundUp rounds x up to a number of the form [1eX, 2eX, 5eX].
+// roundUp rounds x up to a number of the form [1eX, 2eX, 3eX, 5eX].
func roundUp(n int) int {
base := roundDown10(n)
switch {
@@ -158,6 +165,8 @@ func roundUp(n int) int {
return base
case n <= (2 * base):
return 2 * base
+ case n <= (3 * base):
+ return 3 * base
case n <= (5 * base):
return 5 * base
default:
@@ -173,10 +182,10 @@ func (b *B) run() BenchmarkResult {
}
// launch launches the benchmark function. It gradually increases the number
-// of benchmark iterations until the benchmark runs for a second in order
-// to get a reasonable measurement. It prints timing information in this form
+// of benchmark iterations until the benchmark runs for the requested benchtime.
+// It prints timing information in this form
// testing.BenchmarkHello 100000 19 ns/op
-// launch is run by the fun function as a separate goroutine.
+// launch is run by the run function as a separate goroutine.
func (b *B) launch() {
// Run the benchmark for a single iteration in case it's expensive.
n := 1
@@ -192,16 +201,16 @@ func (b *B) launch() {
d := *benchTime
for !b.failed && b.duration < d && n < 1e9 {
last := n
- // Predict iterations/sec.
+ // Predict required iterations.
if b.nsPerOp() == 0 {
n = 1e9
} else {
n = int(d.Nanoseconds() / b.nsPerOp())
}
- // Run more iterations than we think we'll need for a second (1.5x).
+ // Run more iterations than we think we'll need (1.2x).
// Don't grow too fast in case we had timing errors previously.
// Be sure to run at least one more than last time.
- n = max(min(n+n/2, 100*last), last+1)
+ n = max(min(n+n/5, 100*last), last+1)
// Round up to something easy to read.
n = roundUp(n)
b.runN(n)
@@ -343,6 +352,87 @@ func (b *B) trimOutput() {
}
}
+// A PB is used by RunParallel for running parallel benchmarks.
+type PB struct {
+ globalN *uint64 // shared between all worker goroutines iteration counter
+ grain uint64 // acquire that many iterations from globalN at once
+ cache uint64 // local cache of acquired iterations
+ bN uint64 // total number of iterations to execute (b.N)
+}
+
+// Next reports whether there are more iterations to execute.
+func (pb *PB) Next() bool {
+ if pb.cache == 0 {
+ n := atomic.AddUint64(pb.globalN, pb.grain)
+ if n <= pb.bN {
+ pb.cache = pb.grain
+ } else if n < pb.bN+pb.grain {
+ pb.cache = pb.bN + pb.grain - n
+ } else {
+ return false
+ }
+ }
+ pb.cache--
+ return true
+}
+
+// RunParallel runs a benchmark in parallel.
+// It creates multiple goroutines and distributes b.N iterations among them.
+// The number of goroutines defaults to GOMAXPROCS. To increase parallelism for
+// non-CPU-bound benchmarks, call SetParallelism before RunParallel.
+// RunParallel is usually used with the go test -cpu flag.
+//
+// The body function will be run in each goroutine. It should set up any
+// goroutine-local state and then iterate until pb.Next returns false.
+// It should not use the StartTimer, StopTimer, or ResetTimer functions,
+// because they have global effect.
+func (b *B) RunParallel(body func(*PB)) {
+ // Calculate grain size as number of iterations that take ~100µs.
+ // 100µs is enough to amortize the overhead and provide sufficient
+ // dynamic load balancing.
+ grain := uint64(0)
+ if b.previousN > 0 && b.previousDuration > 0 {
+ grain = 1e5 * uint64(b.previousN) / uint64(b.previousDuration)
+ }
+ if grain < 1 {
+ grain = 1
+ }
+ // We expect the inner loop and function call to take at least 10ns,
+ // so do not do more than 100µs/10ns=1e4 iterations.
+ if grain > 1e4 {
+ grain = 1e4
+ }
+
+ n := uint64(0)
+ numProcs := b.parallelism * runtime.GOMAXPROCS(0)
+ var wg sync.WaitGroup
+ wg.Add(numProcs)
+ for p := 0; p < numProcs; p++ {
+ go func() {
+ defer wg.Done()
+ pb := &PB{
+ globalN: &n,
+ grain: grain,
+ bN: uint64(b.N),
+ }
+ body(pb)
+ }()
+ }
+ wg.Wait()
+ if n <= uint64(b.N) && !b.Failed() {
+ b.Fatal("RunParallel: body exited without pb.Next() == false")
+ }
+}
+
+// SetParallelism sets the number of goroutines used by RunParallel to p*GOMAXPROCS.
+// There is usually no need to call SetParallelism for CPU-bound benchmarks.
+// If p is less than 1, this call will have no effect.
+func (b *B) SetParallelism(p int) {
+ if p >= 1 {
+ b.parallelism = p
+ }
+}
+
// Benchmark benchmarks a single function. Useful for creating
// custom benchmarks that do not use the "go test" command.
func Benchmark(f func(b *B)) BenchmarkResult {
diff --git a/libgo/go/testing/benchmark_test.go b/libgo/go/testing/benchmark_test.go
index 94e994dfae..431bb537bd 100644
--- a/libgo/go/testing/benchmark_test.go
+++ b/libgo/go/testing/benchmark_test.go
@@ -5,7 +5,11 @@
package testing_test
import (
+ "bytes"
+ "runtime"
+ "sync/atomic"
"testing"
+ "text/template"
)
var roundDownTests = []struct {
@@ -37,12 +41,14 @@ var roundUpTests = []struct {
{0, 1},
{1, 1},
{2, 2},
+ {3, 3},
{5, 5},
{9, 10},
{999, 1000},
{1000, 1000},
{1400, 2000},
{1700, 2000},
+ {2700, 3000},
{4999, 5000},
{5000, 5000},
{5001, 10000},
@@ -56,3 +62,52 @@ func TestRoundUp(t *testing.T) {
}
}
}
+
+func TestRunParallel(t *testing.T) {
+ testing.Benchmark(func(b *testing.B) {
+ procs := uint32(0)
+ iters := uint64(0)
+ b.SetParallelism(3)
+ b.RunParallel(func(pb *testing.PB) {
+ atomic.AddUint32(&procs, 1)
+ for pb.Next() {
+ atomic.AddUint64(&iters, 1)
+ }
+ })
+ if want := uint32(3 * runtime.GOMAXPROCS(0)); procs != want {
+ t.Errorf("got %v procs, want %v", procs, want)
+ }
+ if iters != uint64(b.N) {
+ t.Errorf("got %v iters, want %v", iters, b.N)
+ }
+ })
+}
+
+func TestRunParallelFail(t *testing.T) {
+ testing.Benchmark(func(b *testing.B) {
+ b.RunParallel(func(pb *testing.PB) {
+ // The function must be able to log/abort
+ // w/o crashing/deadlocking the whole benchmark.
+ b.Log("log")
+ b.Error("error")
+ })
+ })
+}
+
+func ExampleB_RunParallel() {
+ // Parallel benchmark for text/template.Template.Execute on a single object.
+ testing.Benchmark(func(b *testing.B) {
+ templ := template.Must(template.New("test").Parse("Hello, {{.}}!"))
+ // RunParallel will create GOMAXPROCS goroutines
+ // and distribute work among them.
+ b.RunParallel(func(pb *testing.PB) {
+ // Each goroutine has its own bytes.Buffer.
+ var buf bytes.Buffer
+ for pb.Next() {
+ // The loop body is executed b.N times total across all goroutines.
+ buf.Reset()
+ templ.Execute(&buf, "World")
+ }
+ })
+ })
+}
diff --git a/libgo/go/testing/cover.go b/libgo/go/testing/cover.go
index dd29364d87..a4ce37f7c2 100644
--- a/libgo/go/testing/cover.go
+++ b/libgo/go/testing/cover.go
@@ -9,6 +9,7 @@ package testing
import (
"fmt"
"os"
+ "sync/atomic"
)
// CoverBlock records the coverage data for a single basic block.
@@ -34,6 +35,29 @@ type Cover struct {
CoveredPackages string
}
+// Coverage reports the current code coverage as a fraction in the range [0, 1].
+// If coverage is not enabled, Coverage returns 0.
+//
+// When running a large set of sequential test cases, checking Coverage after each one
+// can be useful for identifying which test cases exercise new code paths.
+// It is not a replacement for the reports generated by 'go test -cover' and
+// 'go tool cover'.
+func Coverage() float64 {
+ var n, d int64
+ for _, counters := range cover.Counters {
+ for i := range counters {
+ if atomic.LoadUint32(&counters[i]) > 0 {
+ n++
+ }
+ d++
+ }
+ }
+ if d == 0 {
+ return 0
+ }
+ return float64(n) / float64(d)
+}
+
// RegisterCover records the coverage data accumulators for the tests.
// NOTE: This function is internal to the testing infrastructure and may change.
// It is not covered (yet) by the Go 1 compatibility guidelines.
@@ -61,11 +85,13 @@ func coverReport() {
}
var active, total int64
+ var count uint32
for name, counts := range cover.Counters {
blocks := cover.Blocks[name]
- for i, count := range counts {
+ for i := range counts {
stmts := int64(blocks[i].Stmts)
total += stmts
+ count = atomic.LoadUint32(&counts[i]) // For -mode=atomic.
if count > 0 {
active += stmts
}
diff --git a/libgo/go/testing/example.go b/libgo/go/testing/example.go
index 828c2d3eda..f5762e4db4 100644
--- a/libgo/go/testing/example.go
+++ b/libgo/go/testing/example.go
@@ -71,7 +71,7 @@ func runExample(eg InternalExample) (ok bool) {
// Clean up in a deferred call so we can recover if the example panics.
defer func() {
- d := time.Now().Sub(start)
+ dstr := fmtDuration(time.Now().Sub(start))
// Close pipe, restore stdout, get output.
w.Close()
@@ -84,10 +84,10 @@ func runExample(eg InternalExample) (ok bool) {
fail = fmt.Sprintf("got:\n%s\nwant:\n%s\n", g, e)
}
if fail != "" || err != nil {
- fmt.Printf("--- FAIL: %s (%v)\n%s", eg.Name, d, fail)
+ fmt.Printf("--- FAIL: %s (%s)\n%s", eg.Name, dstr, fail)
ok = false
} else if *chatty {
- fmt.Printf("--- PASS: %s (%v)\n", eg.Name, d)
+ fmt.Printf("--- PASS: %s (%s)\n", eg.Name, dstr)
}
if err != nil {
panic(err)
diff --git a/libgo/go/testing/quick/quick.go b/libgo/go/testing/quick/quick.go
index bc79cc3292..909c65f788 100644
--- a/libgo/go/testing/quick/quick.go
+++ b/libgo/go/testing/quick/quick.go
@@ -225,12 +225,12 @@ func (s *CheckEqualError) Error() string {
// t.Error(err)
// }
// }
-func Check(function interface{}, config *Config) (err error) {
+func Check(f interface{}, config *Config) (err error) {
if config == nil {
config = &defaultConfig
}
- f, fType, ok := functionAndType(function)
+ fVal, fType, ok := functionAndType(f)
if !ok {
err = SetupError("argument is not a function")
return
@@ -255,7 +255,7 @@ func Check(function interface{}, config *Config) (err error) {
return
}
- if !f.Call(arguments)[0].Bool() {
+ if !fVal.Call(arguments)[0].Bool() {
err = &CheckError{i + 1, toInterfaces(arguments)}
return
}
diff --git a/libgo/go/testing/quick/quick_test.go b/libgo/go/testing/quick/quick_test.go
index 36745ae2ab..e925ba6750 100644
--- a/libgo/go/testing/quick/quick_test.go
+++ b/libgo/go/testing/quick/quick_test.go
@@ -7,7 +7,6 @@ package quick
import (
"math/rand"
"reflect"
- "runtime"
"testing"
)
@@ -158,12 +157,10 @@ func TestCheckEqual(t *testing.T) {
reportError("fFloat32Alias", CheckEqual(fFloat32Alias, fFloat32Alias, nil), t)
reportError("fFloat64", CheckEqual(fFloat64, fFloat64, nil), t)
reportError("fFloat64Alias", CheckEqual(fFloat64Alias, fFloat64Alias, nil), t)
- if runtime.GOARCH != "alpha" {
- reportError("fComplex64", CheckEqual(fComplex64, fComplex64, nil), t)
- reportError("fComplex64Alias", CheckEqual(fComplex64Alias, fComplex64Alias, nil), t)
- reportError("fComplex128", CheckEqual(fComplex128, fComplex128, nil), t)
- reportError("fComplex128Alias", CheckEqual(fComplex128Alias, fComplex128Alias, nil), t)
- }
+ reportError("fComplex64", CheckEqual(fComplex64, fComplex64, nil), t)
+ reportError("fComplex64Alias", CheckEqual(fComplex64Alias, fComplex64Alias, nil), t)
+ reportError("fComplex128", CheckEqual(fComplex128, fComplex128, nil), t)
+ reportError("fComplex128Alias", CheckEqual(fComplex128Alias, fComplex128Alias, nil), t)
reportError("fInt16", CheckEqual(fInt16, fInt16, nil), t)
reportError("fInt16Alias", CheckEqual(fInt16Alias, fInt16Alias, nil), t)
reportError("fInt32", CheckEqual(fInt32, fInt32, nil), t)
diff --git a/libgo/go/testing/testing.go b/libgo/go/testing/testing.go
index 52dc166dd9..e54a3b8ce4 100644
--- a/libgo/go/testing/testing.go
+++ b/libgo/go/testing/testing.go
@@ -8,9 +8,17 @@
// func TestXxx(*testing.T)
// where Xxx can be any alphanumeric string (but the first letter must not be in
// [a-z]) and serves to identify the test routine.
-// These TestXxx routines should be declared within the package they are testing.
//
-// Tests and benchmarks may be skipped if not applicable like this:
+// Within these functions, use the Error, Fail or related methods to signal failure.
+//
+// To write a new test suite, create a file whose name ends _test.go that
+// contains the TestXxx functions as described here. Put the file in the same
+// package as the one being tested. The file will be excluded from regular
+// package builds but will be included when the ``go test'' command is run.
+// For more detail, run ``go help test'' and ``go help testflag''.
+//
+// Tests and benchmarks may be skipped if not applicable with a call to
+// the Skip method of *T and *B:
// func TestTimeConsuming(t *testing.T) {
// if testing.Short() {
// t.Skip("skipping test in short mode.")
@@ -36,13 +44,14 @@
// }
//
// The benchmark function must run the target code b.N times.
-// The benchmark package will vary b.N until the benchmark function lasts
+// During benchark execution, b.N is adjusted until the benchmark function lasts
// long enough to be timed reliably. The output
// BenchmarkHello 10000000 282 ns/op
// means that the loop ran 10000000 times at a speed of 282 ns per loop.
//
// If a benchmark needs some expensive setup before running, the timer
// may be reset:
+//
// func BenchmarkBigLen(b *testing.B) {
// big := NewBig()
// b.ResetTimer()
@@ -51,6 +60,21 @@
// }
// }
//
+// If a benchmark needs to test performance in a parallel setting, it may use
+// the RunParallel helper function; such benchmarks are intended to be used with
+// the go test -cpu flag:
+//
+// func BenchmarkTemplateParallel(b *testing.B) {
+// templ := template.Must(template.New("test").Parse("Hello, {{.}}!"))
+// b.RunParallel(func(pb *testing.PB) {
+// var buf bytes.Buffer
+// for pb.Next() {
+// buf.Reset()
+// templ.Execute(&buf, "World")
+// }
+// })
+// }
+//
// Examples
//
// The package also runs and verifies example code. Example functions may
@@ -93,6 +117,26 @@
// The entire test file is presented as the example when it contains a single
// example function, at least one other function, type, variable, or constant
// declaration, and no test or benchmark functions.
+//
+// Main
+//
+// It is sometimes necessary for a test program to do extra setup or teardown
+// before or after testing. It is also sometimes necessary for a test to control
+// which code runs on the main thread. To support these and other cases,
+// if a test file contains a function:
+//
+// func TestMain(m *testing.M)
+//
+// then the generated test will call TestMain(m) instead of running the tests
+// directly. TestMain runs in the main goroutine and can do whatever setup
+// and teardown is necessary around a call to m.Run. It should then call
+// os.Exit with the result of m.Run.
+//
+// The minimal implementation of TestMain is:
+//
+// func TestMain(m *testing.M) { os.Exit(m.Run()) }
+//
+// In effect, that is the implementation used when no TestMain is explicitly defined.
package testing
import (
@@ -143,10 +187,11 @@ var (
// common holds the elements common between T and B and
// captures common methods such as Errorf.
type common struct {
- mu sync.RWMutex // guards output and failed
- output []byte // Output generated by test or benchmark.
- failed bool // Test or benchmark has failed.
- skipped bool // Test of benchmark has been skipped.
+ mu sync.RWMutex // guards output and failed
+ output []byte // Output generated by test or benchmark.
+ failed bool // Test or benchmark has failed.
+ skipped bool // Test of benchmark has been skipped.
+ finished bool
start time.Time // Time test or benchmark started
duration time.Duration
@@ -198,6 +243,11 @@ func decorate(s string) string {
return buf.String()
}
+// fmtDuration returns a string representing d in the form "87.00s".
+func fmtDuration(d time.Duration) string {
+ return fmt.Sprintf("%.2fs", d.Seconds())
+}
+
// TB is the interface common to T and B.
type TB interface {
Error(args ...interface{})
@@ -275,6 +325,7 @@ func (c *common) FailNow() {
// it would run on a test failure. Because we send on c.signal during
// a top-of-stack deferred function now, we know that the send
// only happens after any other stacked defers have completed.
+ c.finished = true
runtime.Goexit()
}
@@ -338,6 +389,7 @@ func (c *common) Skipf(format string, args ...interface{}) {
// those other goroutines.
func (c *common) SkipNow() {
c.skip()
+ c.finished = true
runtime.Goexit()
}
@@ -379,7 +431,11 @@ func tRunner(t *T, test *InternalTest) {
defer func() {
t.duration = time.Now().Sub(t.start)
// If the test panicked, print any test output before dying.
- if err := recover(); err != nil {
+ err := recover()
+ if !t.finished && err == nil {
+ err = fmt.Errorf("test executed panic(nil) or runtime.Goexit")
+ }
+ if err != nil {
t.Fail()
t.report()
panic(err)
@@ -389,39 +445,67 @@ func tRunner(t *T, test *InternalTest) {
t.start = time.Now()
test.F(t)
+ t.finished = true
}
// An internal function but exported because it is cross-package; part of the implementation
// of the "go test" command.
func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) {
+ os.Exit(MainStart(matchString, tests, benchmarks, examples).Run())
+}
+
+// M is a type passed to a TestMain function to run the actual tests.
+type M struct {
+ matchString func(pat, str string) (bool, error)
+ tests []InternalTest
+ benchmarks []InternalBenchmark
+ examples []InternalExample
+}
+
+// MainStart is meant for use by tests generated by 'go test'.
+// It is not meant to be called directly and is not subject to the Go 1 compatibility document.
+// It may change signature from release to release.
+func MainStart(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) *M {
+ return &M{
+ matchString: matchString,
+ tests: tests,
+ benchmarks: benchmarks,
+ examples: examples,
+ }
+}
+
+// Run runs the tests. It returns an exit code to pass to os.Exit.
+func (m *M) Run() int {
flag.Parse()
parseCpuList()
before()
startAlarm()
- haveExamples = len(examples) > 0
- testOk := RunTests(matchString, tests)
- exampleOk := RunExamples(matchString, examples)
+ haveExamples = len(m.examples) > 0
+ testOk := RunTests(m.matchString, m.tests)
+ exampleOk := RunExamples(m.matchString, m.examples)
stopAlarm()
if !testOk || !exampleOk {
fmt.Println("FAIL")
- os.Exit(1)
+ after()
+ return 1
}
fmt.Println("PASS")
- RunBenchmarks(matchString, benchmarks)
+ RunBenchmarks(m.matchString, m.benchmarks)
after()
+ return 0
}
func (t *T) report() {
- tstr := fmt.Sprintf("(%.2f seconds)", t.duration.Seconds())
- format := "--- %s: %s %s\n%s"
+ dstr := fmtDuration(t.duration)
+ format := "--- %s: %s (%s)\n%s"
if t.Failed() {
- fmt.Printf(format, "FAIL", t.name, tstr, t.output)
+ fmt.Printf(format, "FAIL", t.name, dstr, t.output)
} else if *chatty {
if t.Skipped() {
- fmt.Printf(format, "SKIP", t.name, tstr, t.output)
+ fmt.Printf(format, "SKIP", t.name, dstr, t.output)
} else {
- fmt.Printf(format, "PASS", t.name, tstr, t.output)
+ fmt.Printf(format, "PASS", t.name, dstr, t.output)
}
}
}
@@ -536,6 +620,7 @@ func after() {
fmt.Fprintf(os.Stderr, "testing: %s\n", err)
os.Exit(2)
}
+ runtime.GC() // materialize all statistics
if err = pprof.WriteHeapProfile(f); err != nil {
fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *memProfile, err)
os.Exit(2)
diff --git a/libgo/go/testing/testing_test.go b/libgo/go/testing/testing_test.go
new file mode 100644
index 0000000000..87a5c16d6e
--- /dev/null
+++ b/libgo/go/testing/testing_test.go
@@ -0,0 +1,18 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package testing_test
+
+import (
+ "os"
+ "testing"
+)
+
+// This is exactly what a test would do without a TestMain.
+// It's here only so that there is at least one package in the
+// standard library with a TestMain, so that code is executed.
+
+func TestMain(m *testing.M) {
+ os.Exit(m.Run())
+}
diff --git a/libgo/go/text/scanner/scanner.go b/libgo/go/text/scanner/scanner.go
index e0d86e343d..5199ee4fc7 100644
--- a/libgo/go/text/scanner/scanner.go
+++ b/libgo/go/text/scanner/scanner.go
@@ -11,7 +11,7 @@
// By default, a Scanner skips white space and Go comments and recognizes all
// literals as defined by the Go language specification. It may be
// customized to recognize only a subset of those literals and to recognize
-// different white space characters.
+// different identifier and white space characters.
//
// Basic usage pattern:
//
@@ -34,8 +34,6 @@ import (
"unicode/utf8"
)
-// TODO(gri): Consider changing this to use the new (token) Position package.
-
// A source position is represented by a Position value.
// A position is valid if Line > 0.
type Position struct {
@@ -68,6 +66,12 @@ func (pos Position) String() string {
//
// ScanIdents | ScanInts | SkipComments
//
+// With the exceptions of comments, which are skipped if SkipComments is
+// set, unrecognized tokens are not ignored. Instead, the scanner simply
+// returns the respective individual characters (or possibly sub-tokens).
+// For instance, if the mode is ScanIdents (not ScanStrings), the string
+// "foo" is scanned as the token sequence '"' Ident '"'.
+//
const (
ScanIdents = 1 << -Ident
ScanInts = 1 << -Int
@@ -164,6 +168,13 @@ type Scanner struct {
// for values ch > ' '). The field may be changed at any time.
Whitespace uint64
+ // IsIdentRune is a predicate controlling the characters accepted
+ // as the ith rune in an identifier. The set of valid characters
+ // must not intersect with the set of white space characters.
+ // If no IsIdentRune function is set, regular Go identifiers are
+ // accepted instead. The field may be changed at any time.
+ IsIdentRune func(ch rune, i int) bool
+
// Start position of most recently scanned token; set by Scan.
// Calling Init or Next invalidates the position (Line == 0).
// The Filename field is always left untouched by the Scanner.
@@ -240,6 +251,9 @@ func (s *Scanner) next() rune {
s.srcEnd = i + n
s.srcBuf[s.srcEnd] = utf8.RuneSelf // sentinel
if err != nil {
+ if err != io.EOF {
+ s.error(err.Error())
+ }
if s.srcEnd == 0 {
if s.lastCharLen > 0 {
// previous character was not EOF
@@ -248,9 +262,6 @@ func (s *Scanner) next() rune {
s.lastCharLen = 0
return EOF
}
- if err != io.EOF {
- s.error(err.Error())
- }
// If err == EOF, we won't be getting more
// bytes; break to avoid infinite loop. If
// err is something else, we don't know if
@@ -334,9 +345,17 @@ func (s *Scanner) error(msg string) {
fmt.Fprintf(os.Stderr, "%s: %s\n", pos, msg)
}
+func (s *Scanner) isIdentRune(ch rune, i int) bool {
+ if s.IsIdentRune != nil {
+ return s.IsIdentRune(ch, i)
+ }
+ return ch == '_' || unicode.IsLetter(ch) || unicode.IsDigit(ch) && i > 0
+}
+
func (s *Scanner) scanIdentifier() rune {
- ch := s.next() // read character after first '_' or letter
- for ch == '_' || unicode.IsLetter(ch) || unicode.IsDigit(ch) {
+ // we know the zero'th rune is OK; start scanning at the next one
+ ch := s.next()
+ for i := 1; s.isIdentRune(ch, i); i++ {
ch = s.next()
}
return ch
@@ -563,7 +582,7 @@ redo:
// determine token value
tok := ch
switch {
- case unicode.IsLetter(ch) || ch == '_':
+ case s.isIdentRune(ch, 0):
if s.Mode&ScanIdents != 0 {
tok = Ident
ch = s.scanIdentifier()
diff --git a/libgo/go/text/scanner/scanner_test.go b/libgo/go/text/scanner/scanner_test.go
index 496eed4a31..702fac2b1a 100644
--- a/libgo/go/text/scanner/scanner_test.go
+++ b/libgo/go/text/scanner/scanner_test.go
@@ -357,10 +357,32 @@ func TestScanSelectedMask(t *testing.T) {
testScanSelectedMode(t, ScanComments, Comment)
}
+func TestScanCustomIdent(t *testing.T) {
+ const src = "faab12345 a12b123 a12 3b"
+ s := new(Scanner).Init(strings.NewReader(src))
+ // ident = ( 'a' | 'b' ) { digit } .
+ // digit = '0' .. '3' .
+ // with a maximum length of 4
+ s.IsIdentRune = func(ch rune, i int) bool {
+ return i == 0 && (ch == 'a' || ch == 'b') || 0 < i && i < 4 && '0' <= ch && ch <= '3'
+ }
+ checkTok(t, s, 1, s.Scan(), 'f', "f")
+ checkTok(t, s, 1, s.Scan(), Ident, "a")
+ checkTok(t, s, 1, s.Scan(), Ident, "a")
+ checkTok(t, s, 1, s.Scan(), Ident, "b123")
+ checkTok(t, s, 1, s.Scan(), Int, "45")
+ checkTok(t, s, 1, s.Scan(), Ident, "a12")
+ checkTok(t, s, 1, s.Scan(), Ident, "b123")
+ checkTok(t, s, 1, s.Scan(), Ident, "a12")
+ checkTok(t, s, 1, s.Scan(), Int, "3")
+ checkTok(t, s, 1, s.Scan(), Ident, "b")
+ checkTok(t, s, 1, s.Scan(), EOF, "")
+}
+
func TestScanNext(t *testing.T) {
const BOM = '\uFEFF'
BOMs := string(BOM)
- s := new(Scanner).Init(bytes.NewBufferString(BOMs + "if a == bcd /* com" + BOMs + "ment */ {\n\ta += c\n}" + BOMs + "// line comment ending in eof"))
+ s := new(Scanner).Init(strings.NewReader(BOMs + "if a == bcd /* com" + BOMs + "ment */ {\n\ta += c\n}" + BOMs + "// line comment ending in eof"))
checkTok(t, s, 1, s.Scan(), Ident, "if") // the first BOM is ignored
checkTok(t, s, 1, s.Scan(), Ident, "a")
checkTok(t, s, 1, s.Scan(), '=', "=")
@@ -402,7 +424,7 @@ func TestScanWhitespace(t *testing.T) {
}
func testError(t *testing.T, src, pos, msg string, tok rune) {
- s := new(Scanner).Init(bytes.NewBufferString(src))
+ s := new(Scanner).Init(strings.NewReader(src))
errorCalled := false
s.Error = func(s *Scanner, m string) {
if !errorCalled {
@@ -462,6 +484,33 @@ func TestError(t *testing.T) {
testError(t, `/*/`, "1:4", "comment not terminated", EOF)
}
+// An errReader returns (0, err) where err is not io.EOF.
+type errReader struct{}
+
+func (errReader) Read(b []byte) (int, error) {
+ return 0, io.ErrNoProgress // some error that is not io.EOF
+}
+
+func TestIOError(t *testing.T) {
+ s := new(Scanner).Init(errReader{})
+ errorCalled := false
+ s.Error = func(s *Scanner, msg string) {
+ if !errorCalled {
+ if want := io.ErrNoProgress.Error(); msg != want {
+ t.Errorf("msg = %q, want %q", msg, want)
+ }
+ errorCalled = true
+ }
+ }
+ tok := s.Scan()
+ if tok != EOF {
+ t.Errorf("tok = %s, want EOF", TokenString(tok))
+ }
+ if !errorCalled {
+ t.Errorf("error handler not called")
+ }
+}
+
func checkPos(t *testing.T, got, want Position) {
if got.Offset != want.Offset || got.Line != want.Line || got.Column != want.Column {
t.Errorf("got offset, line, column = %d, %d, %d; want %d, %d, %d",
@@ -491,13 +540,13 @@ func checkScanPos(t *testing.T, s *Scanner, offset, line, column int, char rune)
func TestPos(t *testing.T) {
// corner case: empty source
- s := new(Scanner).Init(bytes.NewBufferString(""))
+ s := new(Scanner).Init(strings.NewReader(""))
checkPos(t, s.Pos(), Position{Offset: 0, Line: 1, Column: 1})
s.Peek() // peek doesn't affect the position
checkPos(t, s.Pos(), Position{Offset: 0, Line: 1, Column: 1})
// corner case: source with only a newline
- s = new(Scanner).Init(bytes.NewBufferString("\n"))
+ s = new(Scanner).Init(strings.NewReader("\n"))
checkPos(t, s.Pos(), Position{Offset: 0, Line: 1, Column: 1})
checkNextPos(t, s, 1, 2, 1, '\n')
// after EOF position doesn't change
@@ -509,7 +558,7 @@ func TestPos(t *testing.T) {
}
// corner case: source with only a single character
- s = new(Scanner).Init(bytes.NewBufferString("本"))
+ s = new(Scanner).Init(strings.NewReader("本"))
checkPos(t, s.Pos(), Position{Offset: 0, Line: 1, Column: 1})
checkNextPos(t, s, 3, 1, 2, '本')
// after EOF position doesn't change
@@ -521,7 +570,7 @@ func TestPos(t *testing.T) {
}
// positions after calling Next
- s = new(Scanner).Init(bytes.NewBufferString(" foo६४ \n\n本語\n"))
+ s = new(Scanner).Init(strings.NewReader(" foo६४ \n\n本語\n"))
checkNextPos(t, s, 1, 1, 2, ' ')
s.Peek() // peek doesn't affect the position
checkNextPos(t, s, 2, 1, 3, ' ')
@@ -546,7 +595,7 @@ func TestPos(t *testing.T) {
}
// positions after calling Scan
- s = new(Scanner).Init(bytes.NewBufferString("abc\n本語\n\nx"))
+ s = new(Scanner).Init(strings.NewReader("abc\n本語\n\nx"))
s.Mode = 0
s.Whitespace = 0
checkScanPos(t, s, 0, 1, 1, 'a')
diff --git a/libgo/go/text/tabwriter/tabwriter.go b/libgo/go/text/tabwriter/tabwriter.go
index 722ac8d877..c0c32d5dec 100644
--- a/libgo/go/text/tabwriter/tabwriter.go
+++ b/libgo/go/text/tabwriter/tabwriter.go
@@ -434,9 +434,13 @@ func (b *Writer) terminateCell(htab bool) int {
return len(*line)
}
-func handlePanic(err *error) {
+func handlePanic(err *error, op string) {
if e := recover(); e != nil {
- *err = e.(osError).err // re-panics if it's not a local osError
+ if nerr, ok := e.(osError); ok {
+ *err = nerr.err
+ return
+ }
+ panic("tabwriter: panic during " + op)
}
}
@@ -447,7 +451,7 @@ func handlePanic(err *error) {
//
func (b *Writer) Flush() (err error) {
defer b.reset() // even in the presence of errors
- defer handlePanic(&err)
+ defer handlePanic(&err, "Flush")
// add current cell if not empty
if b.cell.size > 0 {
@@ -471,7 +475,7 @@ var hbar = []byte("---\n")
// while writing to the underlying output stream.
//
func (b *Writer) Write(buf []byte) (n int, err error) {
- defer handlePanic(&err)
+ defer handlePanic(&err, "Write")
// split text into cells
n = 0
diff --git a/libgo/go/text/tabwriter/tabwriter_test.go b/libgo/go/text/tabwriter/tabwriter_test.go
index ace5356473..9d3111e2c2 100644
--- a/libgo/go/text/tabwriter/tabwriter_test.go
+++ b/libgo/go/text/tabwriter/tabwriter_test.go
@@ -14,7 +14,7 @@ type buffer struct {
a []byte
}
-func (b *buffer) init(n int) { b.a = make([]byte, n)[0:0] }
+func (b *buffer) init(n int) { b.a = make([]byte, 0, n) }
func (b *buffer) clear() { b.a = b.a[0:0] }
@@ -613,3 +613,40 @@ func Test(t *testing.T) {
check(t, e.testname, e.minwidth, e.tabwidth, e.padding, e.padchar, e.flags, e.src, e.expected)
}
}
+
+type panicWriter struct{}
+
+func (panicWriter) Write([]byte) (int, error) {
+ panic("cannot write")
+}
+
+func wantPanicString(t *testing.T, want string) {
+ if e := recover(); e != nil {
+ got, ok := e.(string)
+ switch {
+ case !ok:
+ t.Errorf("got %v (%T), want panic string", e, e)
+ case got != want:
+ t.Errorf("wrong panic message: got %q, want %q", got, want)
+ }
+ }
+}
+
+func TestPanicDuringFlush(t *testing.T) {
+ defer wantPanicString(t, "tabwriter: panic during Flush")
+ var p panicWriter
+ w := new(Writer)
+ w.Init(p, 0, 0, 5, ' ', 0)
+ io.WriteString(w, "a")
+ w.Flush()
+ t.Errorf("failed to panic during Flush")
+}
+
+func TestPanicDuringWrite(t *testing.T) {
+ defer wantPanicString(t, "tabwriter: panic during Write")
+ var p panicWriter
+ w := new(Writer)
+ w.Init(p, 0, 0, 5, ' ', 0)
+ io.WriteString(w, "a\n\n") // the second \n triggers a call to w.Write and thus a panic
+ t.Errorf("failed to panic during Write")
+}
diff --git a/libgo/go/text/template/doc.go b/libgo/go/text/template/doc.go
index f622ac7dce..223c595c25 100644
--- a/libgo/go/text/template/doc.go
+++ b/libgo/go/text/template/doc.go
@@ -20,7 +20,7 @@ The input text for a template is UTF-8-encoded text in any format.
"{{" and "}}"; all text outside actions is copied to the output unchanged.
Actions may not span newlines, although comments can.
-Once constructed, a template may be executed safely in parallel.
+Once parsed, a template may be executed safely in parallel.
Here is a trivial example that prints "17 items are made of wool".
@@ -338,10 +338,11 @@ arguments will be evaluated.)
The comparison functions work on basic types only (or named basic
types, such as "type Celsius float32"). They implement the Go rules
for comparison of values, except that size and exact type are
-ignored, so any integer value may be compared with any other integer
-value, any unsigned integer value may be compared with any other
-unsigned integer value, and so on. However, as usual, one may not
-compare an int with a float32 and so on.
+ignored, so any integer value, signed or unsigned, may be compared
+with any other integer value. (The arithmetic value is compared,
+not the bit pattern, so all negative integers are less than all
+unsigned integers.) However, as usual, one may not compare an int
+with a float32 and so on.
Associated templates
diff --git a/libgo/go/text/template/exec.go b/libgo/go/text/template/exec.go
index 43b0b266ec..b00e10c7e4 100644
--- a/libgo/go/text/template/exec.go
+++ b/libgo/go/text/template/exec.go
@@ -108,6 +108,10 @@ func errRecover(errp *error) {
// ExecuteTemplate applies the template associated with t that has the given name
// to the specified data object and writes the output to wr.
+// If an error occurs executing the template or writing its output,
+// execution stops, but partial results may already have been written to
+// 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]
if tmpl == nil {
@@ -118,6 +122,10 @@ func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{})
// Execute applies a parsed template to the specified data object,
// and writes the output to wr.
+// If an error occurs executing the template or writing its output,
+// execution stops, but partial results may already have been written to
+// the output writer.
+// A template may be executed safely in parallel.
func (t *Template) Execute(wr io.Writer, data interface{}) (err error) {
defer errRecover(&err)
value := reflect.ValueOf(data)
@@ -385,7 +393,7 @@ func (s *state) idealConstant(constant *parse.NumberNode) reflect.Value {
switch {
case constant.IsComplex:
return reflect.ValueOf(constant.Complex128) // incontrovertible.
- case constant.IsFloat && strings.IndexAny(constant.Text, ".eE") >= 0:
+ case constant.IsFloat && !isHexConstant(constant.Text) && strings.IndexAny(constant.Text, ".eE") >= 0:
return reflect.ValueOf(constant.Float64)
case constant.IsInt:
n := int(constant.Int64)
@@ -399,6 +407,10 @@ func (s *state) idealConstant(constant *parse.NumberNode) reflect.Value {
return zero
}
+func isHexConstant(s string) bool {
+ return len(s) > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')
+}
+
func (s *state) evalFieldNode(dot reflect.Value, field *parse.FieldNode, args []parse.Node, final reflect.Value) reflect.Value {
s.at(field)
return s.evalFieldChain(dot, dot, field, field.Ident, args, final)
@@ -534,7 +546,7 @@ func (s *state) evalCall(dot, fun reflect.Value, node parse.Node, name string, a
argv := make([]reflect.Value, numIn)
// Args must be evaluated. Fixed args first.
i := 0
- for ; i < numFixed; i++ {
+ for ; i < numFixed && i < len(args); i++ {
argv[i] = s.evalArg(dot, typ.In(i), args[i])
}
// Now the ... args.
@@ -594,6 +606,9 @@ func (s *state) validateType(value reflect.Value, typ reflect.Type) reflect.Valu
switch {
case value.Kind() == reflect.Ptr && value.Type().Elem().AssignableTo(typ):
value = value.Elem()
+ if !value.IsValid() {
+ s.errorf("dereference of nil pointer of type %s", typ)
+ }
case reflect.PtrTo(value.Type()).AssignableTo(typ) && value.CanAddr():
value = value.Addr()
default:
@@ -621,6 +636,8 @@ func (s *state) evalArg(dot reflect.Value, typ reflect.Type, n parse.Node) refle
return s.validateType(s.evalPipeline(dot, arg), typ)
case *parse.IdentifierNode:
return s.evalFunction(dot, arg, arg, nil, zero)
+ case *parse.ChainNode:
+ return s.validateType(s.evalChainNode(dot, arg, nil, zero), typ)
}
switch typ.Kind() {
case reflect.Bool:
diff --git a/libgo/go/text/template/exec_test.go b/libgo/go/text/template/exec_test.go
index f60702de8f..69c213ed24 100644
--- a/libgo/go/text/template/exec_test.go
+++ b/libgo/go/text/template/exec_test.go
@@ -176,6 +176,12 @@ func (t *T) Method3(v interface{}) string {
return fmt.Sprintf("Method3: %v", v)
}
+func (t *T) Copy() *T {
+ n := new(T)
+ *n = *t
+ return n
+}
+
func (t *T) MAdd(a int, b []int) []int {
v := make([]int, len(b))
for i, x := range b {
@@ -512,6 +518,15 @@ var execTests = []execTest{
{"bug9", "{{.cause}}", "neglect", map[string]string{"cause": "neglect"}, true},
// Field chain starting with function did not work.
{"bug10", "{{mapOfThree.three}}-{{(mapOfThree).three}}", "3-3", 0, true},
+ // Dereferencing nil pointer while evaluating function arguments should not panic. Issue 7333.
+ {"bug11", "{{valueString .PS}}", "", T{}, false},
+ // 0xef gave constant type float64. Issue 8622.
+ {"bug12xe", "{{printf `%T` 0xef}}", "int", T{}, true},
+ {"bug12xE", "{{printf `%T` 0xEE}}", "int", T{}, true},
+ {"bug12Xe", "{{printf `%T` 0Xef}}", "int", T{}, true},
+ {"bug12XE", "{{printf `%T` 0XEE}}", "int", T{}, true},
+ // Chained nodes did not work as arguments. Issue 8473.
+ {"bug13", "{{print (.Copy).I}}", "17", tVal, true},
}
func zeroArgs() string {
@@ -546,6 +561,11 @@ func vfunc(V, *V) string {
return "vfunc"
}
+// valueString takes a string, not a pointer.
+func valueString(v string) string {
+ return "value is ignored"
+}
+
func add(args ...int) int {
sum := 0
for _, x := range args {
@@ -580,17 +600,18 @@ func mapOfThree() interface{} {
func testExecute(execTests []execTest, template *Template, t *testing.T) {
b := new(bytes.Buffer)
funcs := FuncMap{
- "add": add,
- "count": count,
- "dddArg": dddArg,
- "echo": echo,
- "makemap": makemap,
- "mapOfThree": mapOfThree,
- "oneArg": oneArg,
- "stringer": stringer,
- "typeOf": typeOf,
- "vfunc": vfunc,
- "zeroArgs": zeroArgs,
+ "add": add,
+ "count": count,
+ "dddArg": dddArg,
+ "echo": echo,
+ "makemap": makemap,
+ "mapOfThree": mapOfThree,
+ "oneArg": oneArg,
+ "stringer": stringer,
+ "typeOf": typeOf,
+ "valueString": valueString,
+ "vfunc": vfunc,
+ "zeroArgs": zeroArgs,
}
for _, test := range execTests {
var tmpl *Template
@@ -872,6 +893,18 @@ func TestMessageForExecuteEmpty(t *testing.T) {
}
}
+func TestFinalForPrintf(t *testing.T) {
+ tmpl, err := New("").Parse(`{{"x" | printf}}`)
+ if err != nil {
+ t.Fatal(err)
+ }
+ var b bytes.Buffer
+ err = tmpl.Execute(&b, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
type cmpTest struct {
expr string
truth string
@@ -889,8 +922,8 @@ var cmpTests = []cmpTest{
{"eq 1 2", "false", true},
{"eq `xy` `xy`", "true", true},
{"eq `xy` `xyz`", "false", true},
- {"eq .Xuint .Xuint", "true", true},
- {"eq .Xuint .Yuint", "false", true},
+ {"eq .Uthree .Uthree", "true", true},
+ {"eq .Uthree .Ufour", "false", true},
{"eq 3 4 5 6 3", "true", true},
{"eq 3 4 5 6 7", "false", true},
{"ne true true", "false", true},
@@ -903,16 +936,16 @@ var cmpTests = []cmpTest{
{"ne 1 2", "true", true},
{"ne `xy` `xy`", "false", true},
{"ne `xy` `xyz`", "true", true},
- {"ne .Xuint .Xuint", "false", true},
- {"ne .Xuint .Yuint", "true", true},
+ {"ne .Uthree .Uthree", "false", true},
+ {"ne .Uthree .Ufour", "true", true},
{"lt 1.5 1.5", "false", true},
{"lt 1.5 2.5", "true", true},
{"lt 1 1", "false", true},
{"lt 1 2", "true", true},
{"lt `xy` `xy`", "false", true},
{"lt `xy` `xyz`", "true", true},
- {"lt .Xuint .Xuint", "false", true},
- {"lt .Xuint .Yuint", "true", true},
+ {"lt .Uthree .Uthree", "false", true},
+ {"lt .Uthree .Ufour", "true", true},
{"le 1.5 1.5", "true", true},
{"le 1.5 2.5", "true", true},
{"le 2.5 1.5", "false", true},
@@ -922,9 +955,9 @@ var cmpTests = []cmpTest{
{"le `xy` `xy`", "true", true},
{"le `xy` `xyz`", "true", true},
{"le `xyz` `xy`", "false", true},
- {"le .Xuint .Xuint", "true", true},
- {"le .Xuint .Yuint", "true", true},
- {"le .Yuint .Xuint", "false", true},
+ {"le .Uthree .Uthree", "true", true},
+ {"le .Uthree .Ufour", "true", true},
+ {"le .Ufour .Uthree", "false", true},
{"gt 1.5 1.5", "false", true},
{"gt 1.5 2.5", "false", true},
{"gt 1 1", "false", true},
@@ -932,9 +965,9 @@ var cmpTests = []cmpTest{
{"gt 1 2", "false", true},
{"gt `xy` `xy`", "false", true},
{"gt `xy` `xyz`", "false", true},
- {"gt .Xuint .Xuint", "false", true},
- {"gt .Xuint .Yuint", "false", true},
- {"gt .Yuint .Xuint", "true", true},
+ {"gt .Uthree .Uthree", "false", true},
+ {"gt .Uthree .Ufour", "false", true},
+ {"gt .Ufour .Uthree", "true", true},
{"ge 1.5 1.5", "true", true},
{"ge 1.5 2.5", "false", true},
{"ge 2.5 1.5", "true", true},
@@ -944,11 +977,40 @@ var cmpTests = []cmpTest{
{"ge `xy` `xy`", "true", true},
{"ge `xy` `xyz`", "false", true},
{"ge `xyz` `xy`", "true", true},
- {"ge .Xuint .Xuint", "true", true},
- {"ge .Xuint .Yuint", "false", true},
- {"ge .Yuint .Xuint", "true", true},
+ {"ge .Uthree .Uthree", "true", true},
+ {"ge .Uthree .Ufour", "false", true},
+ {"ge .Ufour .Uthree", "true", true},
+ // Mixing signed and unsigned integers.
+ {"eq .Uthree .Three", "true", true},
+ {"eq .Three .Uthree", "true", true},
+ {"le .Uthree .Three", "true", true},
+ {"le .Three .Uthree", "true", true},
+ {"ge .Uthree .Three", "true", true},
+ {"ge .Three .Uthree", "true", true},
+ {"lt .Uthree .Three", "false", true},
+ {"lt .Three .Uthree", "false", true},
+ {"gt .Uthree .Three", "false", true},
+ {"gt .Three .Uthree", "false", true},
+ {"eq .Ufour .Three", "false", true},
+ {"lt .Ufour .Three", "false", true},
+ {"gt .Ufour .Three", "true", true},
+ {"eq .NegOne .Uthree", "false", true},
+ {"eq .Uthree .NegOne", "false", true},
+ {"ne .NegOne .Uthree", "true", true},
+ {"ne .Uthree .NegOne", "true", true},
+ {"lt .NegOne .Uthree", "true", true},
+ {"lt .Uthree .NegOne", "false", true},
+ {"le .NegOne .Uthree", "true", true},
+ {"le .Uthree .NegOne", "false", true},
+ {"gt .NegOne .Uthree", "false", true},
+ {"gt .Uthree .NegOne", "true", true},
+ {"ge .NegOne .Uthree", "false", true},
+ {"ge .Uthree .NegOne", "true", true},
+ {"eq (index `x` 0) 'x'", "true", true}, // The example that triggered this rule.
+ {"eq (index `x` 0) 'y'", "false", true},
// Errors
{"eq `xy` 1", "", false}, // Different types.
+ {"eq 2 2.0", "", false}, // Different types.
{"lt true true", "", false}, // Unordered types.
{"lt 1+0i 1+0i", "", false}, // Unordered types.
}
@@ -956,13 +1018,14 @@ var cmpTests = []cmpTest{
func TestComparison(t *testing.T) {
b := new(bytes.Buffer)
var cmpStruct = struct {
- Xuint, Yuint uint
- }{3, 4}
+ Uthree, Ufour uint
+ NegOne, Three int
+ }{3, 4, -1, 3}
for _, test := range cmpTests {
text := fmt.Sprintf("{{if %s}}true{{else}}false{{end}}", test.expr)
tmpl, err := New("empty").Parse(text)
if err != nil {
- t.Fatal(err)
+ t.Fatalf("%q: %s", test.expr, err)
}
b.Reset()
err = tmpl.Execute(b, &cmpStruct)
diff --git a/libgo/go/text/template/funcs.go b/libgo/go/text/template/funcs.go
index e854122624..39ee5ed68f 100644
--- a/libgo/go/text/template/funcs.go
+++ b/libgo/go/text/template/funcs.go
@@ -314,25 +314,34 @@ func eq(arg1 interface{}, arg2 ...interface{}) (bool, error) {
if err != nil {
return false, err
}
- if k1 != k2 {
- return false, errBadComparison
- }
truth := false
- switch k1 {
- case boolKind:
- truth = v1.Bool() == v2.Bool()
- case complexKind:
- truth = v1.Complex() == v2.Complex()
- case floatKind:
- truth = v1.Float() == v2.Float()
- case intKind:
- truth = v1.Int() == v2.Int()
- case stringKind:
- truth = v1.String() == v2.String()
- case uintKind:
- truth = v1.Uint() == v2.Uint()
- default:
- panic("invalid kind")
+ if k1 != k2 {
+ // Special case: Can compare integer values regardless of type's sign.
+ switch {
+ case k1 == intKind && k2 == uintKind:
+ truth = v1.Int() >= 0 && uint64(v1.Int()) == v2.Uint()
+ case k1 == uintKind && k2 == intKind:
+ truth = v2.Int() >= 0 && v1.Uint() == uint64(v2.Int())
+ default:
+ return false, errBadComparison
+ }
+ } else {
+ switch k1 {
+ case boolKind:
+ truth = v1.Bool() == v2.Bool()
+ case complexKind:
+ truth = v1.Complex() == v2.Complex()
+ case floatKind:
+ truth = v1.Float() == v2.Float()
+ case intKind:
+ truth = v1.Int() == v2.Int()
+ case stringKind:
+ truth = v1.String() == v2.String()
+ case uintKind:
+ truth = v1.Uint() == v2.Uint()
+ default:
+ panic("invalid kind")
+ }
}
if truth {
return true, nil
@@ -360,23 +369,32 @@ func lt(arg1, arg2 interface{}) (bool, error) {
if err != nil {
return false, err
}
- if k1 != k2 {
- return false, errBadComparison
- }
truth := false
- switch k1 {
- case boolKind, complexKind:
- return false, errBadComparisonType
- case floatKind:
- truth = v1.Float() < v2.Float()
- case intKind:
- truth = v1.Int() < v2.Int()
- case stringKind:
- truth = v1.String() < v2.String()
- case uintKind:
- truth = v1.Uint() < v2.Uint()
- default:
- panic("invalid kind")
+ if k1 != k2 {
+ // Special case: Can compare integer values regardless of type's sign.
+ switch {
+ case k1 == intKind && k2 == uintKind:
+ truth = v1.Int() < 0 || uint64(v1.Int()) < v2.Uint()
+ case k1 == uintKind && k2 == intKind:
+ truth = v2.Int() >= 0 && v1.Uint() < uint64(v2.Int())
+ default:
+ return false, errBadComparison
+ }
+ } else {
+ switch k1 {
+ case boolKind, complexKind:
+ return false, errBadComparisonType
+ case floatKind:
+ truth = v1.Float() < v2.Float()
+ case intKind:
+ truth = v1.Int() < v2.Int()
+ case stringKind:
+ truth = v1.String() < v2.String()
+ case uintKind:
+ truth = v1.Uint() < v2.Uint()
+ default:
+ panic("invalid kind")
+ }
}
return truth, nil
}
diff --git a/libgo/go/text/template/multi_test.go b/libgo/go/text/template/multi_test.go
index 1f6ed5d8e2..e4e804880a 100644
--- a/libgo/go/text/template/multi_test.go
+++ b/libgo/go/text/template/multi_test.go
@@ -259,6 +259,18 @@ func TestAddParseTree(t *testing.T) {
}
}
+// Issue 7032
+func TestAddParseTreeToUnparsedTemplate(t *testing.T) {
+ master := "{{define \"master\"}}{{end}}"
+ tmpl := New("master")
+ tree, err := parse.Parse("master", master, "", "", nil)
+ if err != nil {
+ t.Fatalf("unexpected parse err: %v", err)
+ }
+ masterTree := tree["master"]
+ tmpl.AddParseTree("master", masterTree) // used to panic
+}
+
func TestRedefinition(t *testing.T) {
var tmpl *Template
var err error
diff --git a/libgo/go/text/template/parse/node.go b/libgo/go/text/template/parse/node.go
index dc6a3bb929..55c37f6dba 100644
--- a/libgo/go/text/template/parse/node.go
+++ b/libgo/go/text/template/parse/node.go
@@ -26,8 +26,9 @@ type Node interface {
// CopyXxx methods that return *XxxNode.
Copy() Node
Position() Pos // byte position of start of node in full original input string
- // Make sure only functions in this package can create Nodes.
- unexported()
+ // tree returns the containing *Tree.
+ // It is unexported so all implementations of Node are in this package.
+ tree() *Tree
}
// NodeType identifies the type of a parse tree node.
@@ -41,11 +42,6 @@ func (p Pos) Position() Pos {
return p
}
-// unexported keeps Node implementations local to the package.
-// All implementations embed Pos, so this takes care of it.
-func (Pos) unexported() {
-}
-
// Type returns itself and provides an easy default implementation
// for embedding in a Node. Embedded in all non-trivial Nodes.
func (t NodeType) Type() NodeType {
@@ -81,17 +77,22 @@ const (
type ListNode struct {
NodeType
Pos
+ tr *Tree
Nodes []Node // The element nodes in lexical order.
}
-func newList(pos Pos) *ListNode {
- return &ListNode{NodeType: NodeList, Pos: pos}
+func (t *Tree) newList(pos Pos) *ListNode {
+ return &ListNode{tr: t, NodeType: NodeList, Pos: pos}
}
func (l *ListNode) append(n Node) {
l.Nodes = append(l.Nodes, n)
}
+func (l *ListNode) tree() *Tree {
+ return l.tr
+}
+
func (l *ListNode) String() string {
b := new(bytes.Buffer)
for _, n := range l.Nodes {
@@ -104,7 +105,7 @@ func (l *ListNode) CopyList() *ListNode {
if l == nil {
return l
}
- n := newList(l.Pos)
+ n := l.tr.newList(l.Pos)
for _, elem := range l.Nodes {
n.append(elem.Copy())
}
@@ -119,32 +120,38 @@ func (l *ListNode) Copy() Node {
type TextNode struct {
NodeType
Pos
+ tr *Tree
Text []byte // The text; may span newlines.
}
-func newText(pos Pos, text string) *TextNode {
- return &TextNode{NodeType: NodeText, Pos: pos, Text: []byte(text)}
+func (t *Tree) newText(pos Pos, text string) *TextNode {
+ return &TextNode{tr: t, NodeType: NodeText, Pos: pos, Text: []byte(text)}
}
func (t *TextNode) String() string {
return fmt.Sprintf(textFormat, t.Text)
}
+func (t *TextNode) tree() *Tree {
+ return t.tr
+}
+
func (t *TextNode) Copy() Node {
- return &TextNode{NodeType: NodeText, Text: append([]byte{}, t.Text...)}
+ return &TextNode{tr: t.tr, NodeType: NodeText, Pos: t.Pos, Text: append([]byte{}, t.Text...)}
}
// PipeNode holds a pipeline with optional declaration
type PipeNode struct {
NodeType
Pos
+ tr *Tree
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.
}
-func newPipeline(pos Pos, line int, decl []*VariableNode) *PipeNode {
- return &PipeNode{NodeType: NodePipe, Pos: pos, Line: line, Decl: decl}
+func (t *Tree) newPipeline(pos Pos, line int, decl []*VariableNode) *PipeNode {
+ return &PipeNode{tr: t, NodeType: NodePipe, Pos: pos, Line: line, Decl: decl}
}
func (p *PipeNode) append(command *CommandNode) {
@@ -171,6 +178,10 @@ func (p *PipeNode) String() string {
return s
}
+func (p *PipeNode) tree() *Tree {
+ return p.tr
+}
+
func (p *PipeNode) CopyPipe() *PipeNode {
if p == nil {
return p
@@ -179,7 +190,7 @@ func (p *PipeNode) CopyPipe() *PipeNode {
for _, d := range p.Decl {
decl = append(decl, d.Copy().(*VariableNode))
}
- n := newPipeline(p.Pos, p.Line, decl)
+ n := p.tr.newPipeline(p.Pos, p.Line, decl)
for _, c := range p.Cmds {
n.append(c.Copy().(*CommandNode))
}
@@ -196,12 +207,13 @@ func (p *PipeNode) Copy() Node {
type ActionNode struct {
NodeType
Pos
+ tr *Tree
Line int // The line number in the input (deprecated; kept for compatibility)
Pipe *PipeNode // The pipeline in the action.
}
-func newAction(pos Pos, line int, pipe *PipeNode) *ActionNode {
- return &ActionNode{NodeType: NodeAction, Pos: pos, Line: line, Pipe: pipe}
+func (t *Tree) newAction(pos Pos, line int, pipe *PipeNode) *ActionNode {
+ return &ActionNode{tr: t, NodeType: NodeAction, Pos: pos, Line: line, Pipe: pipe}
}
func (a *ActionNode) String() string {
@@ -209,8 +221,12 @@ func (a *ActionNode) String() string {
}
+func (a *ActionNode) tree() *Tree {
+ return a.tr
+}
+
func (a *ActionNode) Copy() Node {
- return newAction(a.Pos, a.Line, a.Pipe.CopyPipe())
+ return a.tr.newAction(a.Pos, a.Line, a.Pipe.CopyPipe())
}
@@ -218,11 +234,12 @@ func (a *ActionNode) Copy() Node {
type CommandNode struct {
NodeType
Pos
+ tr *Tree
Args []Node // Arguments in lexical order: Identifier, field, or constant.
}
-func newCommand(pos Pos) *CommandNode {
- return &CommandNode{NodeType: NodeCommand, Pos: pos}
+func (t *Tree) newCommand(pos Pos) *CommandNode {
+ return &CommandNode{tr: t, NodeType: NodeCommand, Pos: pos}
}
func (c *CommandNode) append(arg Node) {
@@ -244,11 +261,15 @@ func (c *CommandNode) String() string {
return s
}
+func (c *CommandNode) tree() *Tree {
+ return c.tr
+}
+
func (c *CommandNode) Copy() Node {
if c == nil {
return c
}
- n := newCommand(c.Pos)
+ n := c.tr.newCommand(c.Pos)
for _, c := range c.Args {
n.append(c.Copy())
}
@@ -259,6 +280,7 @@ func (c *CommandNode) Copy() Node {
type IdentifierNode struct {
NodeType
Pos
+ tr *Tree
Ident string // The identifier's name.
}
@@ -275,12 +297,24 @@ func (i *IdentifierNode) SetPos(pos Pos) *IdentifierNode {
return i
}
+// SetTree sets the parent tree for the node. NewIdentifier is a public method so we can't modify its signature.
+// Chained for convenience.
+// TODO: fix one day?
+func (i *IdentifierNode) SetTree(t *Tree) *IdentifierNode {
+ i.tr = t
+ return i
+}
+
func (i *IdentifierNode) String() string {
return i.Ident
}
+func (i *IdentifierNode) tree() *Tree {
+ return i.tr
+}
+
func (i *IdentifierNode) Copy() Node {
- return NewIdentifier(i.Ident).SetPos(i.Pos)
+ return NewIdentifier(i.Ident).SetTree(i.tr).SetPos(i.Pos)
}
// VariableNode holds a list of variable names, possibly with chained field
@@ -288,11 +322,12 @@ func (i *IdentifierNode) Copy() Node {
type VariableNode struct {
NodeType
Pos
+ tr *Tree
Ident []string // Variable name and fields in lexical order.
}
-func newVariable(pos Pos, ident string) *VariableNode {
- return &VariableNode{NodeType: NodeVariable, Pos: pos, Ident: strings.Split(ident, ".")}
+func (t *Tree) newVariable(pos Pos, ident string) *VariableNode {
+ return &VariableNode{tr: t, NodeType: NodeVariable, Pos: pos, Ident: strings.Split(ident, ".")}
}
func (v *VariableNode) String() string {
@@ -306,20 +341,29 @@ func (v *VariableNode) String() string {
return s
}
+func (v *VariableNode) tree() *Tree {
+ return v.tr
+}
+
func (v *VariableNode) Copy() Node {
- return &VariableNode{NodeType: NodeVariable, Pos: v.Pos, Ident: append([]string{}, v.Ident...)}
+ return &VariableNode{tr: v.tr, NodeType: NodeVariable, Pos: v.Pos, Ident: append([]string{}, v.Ident...)}
}
// DotNode holds the special identifier '.'.
type DotNode struct {
+ NodeType
Pos
+ tr *Tree
}
-func newDot(pos Pos) *DotNode {
- return &DotNode{Pos: pos}
+func (t *Tree) newDot(pos Pos) *DotNode {
+ return &DotNode{tr: t, NodeType: NodeDot, Pos: pos}
}
func (d *DotNode) Type() NodeType {
+ // Override method on embedded NodeType for API compatibility.
+ // TODO: Not really a problem; could change API without effect but
+ // api tool complains.
return NodeDot
}
@@ -327,20 +371,29 @@ func (d *DotNode) String() string {
return "."
}
+func (d *DotNode) tree() *Tree {
+ return d.tr
+}
+
func (d *DotNode) Copy() Node {
- return newDot(d.Pos)
+ return d.tr.newDot(d.Pos)
}
// NilNode holds the special identifier 'nil' representing an untyped nil constant.
type NilNode struct {
+ NodeType
Pos
+ tr *Tree
}
-func newNil(pos Pos) *NilNode {
- return &NilNode{Pos: pos}
+func (t *Tree) newNil(pos Pos) *NilNode {
+ return &NilNode{tr: t, NodeType: NodeNil, Pos: pos}
}
func (n *NilNode) Type() NodeType {
+ // Override method on embedded NodeType for API compatibility.
+ // TODO: Not really a problem; could change API without effect but
+ // api tool complains.
return NodeNil
}
@@ -348,8 +401,12 @@ func (n *NilNode) String() string {
return "nil"
}
+func (n *NilNode) tree() *Tree {
+ return n.tr
+}
+
func (n *NilNode) Copy() Node {
- return newNil(n.Pos)
+ return n.tr.newNil(n.Pos)
}
// FieldNode holds a field (identifier starting with '.').
@@ -358,11 +415,12 @@ func (n *NilNode) Copy() Node {
type FieldNode struct {
NodeType
Pos
+ tr *Tree
Ident []string // The identifiers in lexical order.
}
-func newField(pos Pos, ident string) *FieldNode {
- return &FieldNode{NodeType: NodeField, Pos: pos, Ident: strings.Split(ident[1:], ".")} // [1:] to drop leading period
+func (t *Tree) newField(pos Pos, ident string) *FieldNode {
+ return &FieldNode{tr: t, NodeType: NodeField, Pos: pos, Ident: strings.Split(ident[1:], ".")} // [1:] to drop leading period
}
func (f *FieldNode) String() string {
@@ -373,8 +431,12 @@ func (f *FieldNode) String() string {
return s
}
+func (f *FieldNode) tree() *Tree {
+ return f.tr
+}
+
func (f *FieldNode) Copy() Node {
- return &FieldNode{NodeType: NodeField, Pos: f.Pos, Ident: append([]string{}, f.Ident...)}
+ return &FieldNode{tr: f.tr, NodeType: NodeField, Pos: f.Pos, Ident: append([]string{}, f.Ident...)}
}
// ChainNode holds a term followed by a chain of field accesses (identifier starting with '.').
@@ -383,12 +445,13 @@ func (f *FieldNode) Copy() Node {
type ChainNode struct {
NodeType
Pos
+ tr *Tree
Node Node
Field []string // The identifiers in lexical order.
}
-func newChain(pos Pos, node Node) *ChainNode {
- return &ChainNode{NodeType: NodeChain, Pos: pos, Node: node}
+func (t *Tree) newChain(pos Pos, node Node) *ChainNode {
+ return &ChainNode{tr: t, NodeType: NodeChain, Pos: pos, Node: node}
}
// Add adds the named field (which should start with a period) to the end of the chain.
@@ -414,19 +477,24 @@ func (c *ChainNode) String() string {
return s
}
+func (c *ChainNode) tree() *Tree {
+ return c.tr
+}
+
func (c *ChainNode) Copy() Node {
- return &ChainNode{NodeType: NodeChain, Pos: c.Pos, Node: c.Node, Field: append([]string{}, c.Field...)}
+ return &ChainNode{tr: c.tr, NodeType: NodeChain, Pos: c.Pos, Node: c.Node, Field: append([]string{}, c.Field...)}
}
// BoolNode holds a boolean constant.
type BoolNode struct {
NodeType
Pos
+ tr *Tree
True bool // The value of the boolean constant.
}
-func newBool(pos Pos, true bool) *BoolNode {
- return &BoolNode{NodeType: NodeBool, Pos: pos, True: true}
+func (t *Tree) newBool(pos Pos, true bool) *BoolNode {
+ return &BoolNode{tr: t, NodeType: NodeBool, Pos: pos, True: true}
}
func (b *BoolNode) String() string {
@@ -436,8 +504,12 @@ func (b *BoolNode) String() string {
return "false"
}
+func (b *BoolNode) tree() *Tree {
+ return b.tr
+}
+
func (b *BoolNode) Copy() Node {
- return newBool(b.Pos, b.True)
+ return b.tr.newBool(b.Pos, b.True)
}
// NumberNode holds a number: signed or unsigned integer, float, or complex.
@@ -446,6 +518,7 @@ func (b *BoolNode) Copy() Node {
type NumberNode struct {
NodeType
Pos
+ tr *Tree
IsInt bool // Number has an integral value.
IsUint bool // Number has an unsigned integral value.
IsFloat bool // Number has a floating-point value.
@@ -457,8 +530,8 @@ type NumberNode struct {
Text string // The original textual representation from the input.
}
-func newNumber(pos Pos, text string, typ itemType) (*NumberNode, error) {
- n := &NumberNode{NodeType: NodeNumber, Pos: pos, Text: text}
+func (t *Tree) newNumber(pos Pos, text string, typ itemType) (*NumberNode, error) {
+ n := &NumberNode{tr: t, NodeType: NodeNumber, Pos: pos, Text: text}
switch typ {
case itemCharConstant:
rune, _, tail, err := strconv.UnquoteChar(text[1:], text[0])
@@ -559,6 +632,10 @@ func (n *NumberNode) String() string {
return n.Text
}
+func (n *NumberNode) tree() *Tree {
+ return n.tr
+}
+
func (n *NumberNode) Copy() Node {
nn := new(NumberNode)
*nn = *n // Easy, fast, correct.
@@ -569,53 +646,61 @@ func (n *NumberNode) Copy() Node {
type StringNode struct {
NodeType
Pos
+ tr *Tree
Quoted string // The original text of the string, with quotes.
Text string // The string, after quote processing.
}
-func newString(pos Pos, orig, text string) *StringNode {
- return &StringNode{NodeType: NodeString, Pos: pos, Quoted: orig, Text: text}
+func (t *Tree) newString(pos Pos, orig, text string) *StringNode {
+ return &StringNode{tr: t, NodeType: NodeString, Pos: pos, Quoted: orig, Text: text}
}
func (s *StringNode) String() string {
return s.Quoted
}
+func (s *StringNode) tree() *Tree {
+ return s.tr
+}
+
func (s *StringNode) Copy() Node {
- return newString(s.Pos, s.Quoted, s.Text)
+ return s.tr.newString(s.Pos, s.Quoted, s.Text)
}
// endNode represents an {{end}} action.
// It does not appear in the final parse tree.
type endNode struct {
+ NodeType
Pos
+ tr *Tree
}
-func newEnd(pos Pos) *endNode {
- return &endNode{Pos: pos}
-}
-
-func (e *endNode) Type() NodeType {
- return nodeEnd
+func (t *Tree) newEnd(pos Pos) *endNode {
+ return &endNode{tr: t, NodeType: nodeEnd, Pos: pos}
}
func (e *endNode) String() string {
return "{{end}}"
}
+func (e *endNode) tree() *Tree {
+ return e.tr
+}
+
func (e *endNode) Copy() Node {
- return newEnd(e.Pos)
+ return e.tr.newEnd(e.Pos)
}
// elseNode represents an {{else}} action. Does not appear in the final tree.
type elseNode struct {
NodeType
Pos
+ tr *Tree
Line int // The line number in the input (deprecated; kept for compatibility)
}
-func newElse(pos Pos, line int) *elseNode {
- return &elseNode{NodeType: nodeElse, Pos: pos, Line: line}
+func (t *Tree) newElse(pos Pos, line int) *elseNode {
+ return &elseNode{tr: t, NodeType: nodeElse, Pos: pos, Line: line}
}
func (e *elseNode) Type() NodeType {
@@ -626,14 +711,19 @@ func (e *elseNode) String() string {
return "{{else}}"
}
+func (e *elseNode) tree() *Tree {
+ return e.tr
+}
+
func (e *elseNode) Copy() Node {
- return newElse(e.Pos, e.Line)
+ return e.tr.newElse(e.Pos, e.Line)
}
// BranchNode is the common representation of if, range, and with.
type BranchNode struct {
NodeType
Pos
+ tr *Tree
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.
@@ -658,17 +748,34 @@ func (b *BranchNode) String() string {
return fmt.Sprintf("{{%s %s}}%s{{end}}", name, b.Pipe, b.List)
}
+func (b *BranchNode) tree() *Tree {
+ return b.tr
+}
+
+func (b *BranchNode) Copy() Node {
+ switch b.NodeType {
+ case NodeIf:
+ return b.tr.newIf(b.Pos, b.Line, b.Pipe, b.List, b.ElseList)
+ case NodeRange:
+ return b.tr.newRange(b.Pos, b.Line, b.Pipe, b.List, b.ElseList)
+ case NodeWith:
+ return b.tr.newWith(b.Pos, b.Line, b.Pipe, b.List, b.ElseList)
+ default:
+ panic("unknown branch type")
+ }
+}
+
// IfNode represents an {{if}} action and its commands.
type IfNode struct {
BranchNode
}
-func newIf(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *IfNode {
- return &IfNode{BranchNode{NodeType: NodeIf, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
+func (t *Tree) newIf(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *IfNode {
+ return &IfNode{BranchNode{tr: t, NodeType: NodeIf, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
}
func (i *IfNode) Copy() Node {
- return newIf(i.Pos, i.Line, i.Pipe.CopyPipe(), i.List.CopyList(), i.ElseList.CopyList())
+ return i.tr.newIf(i.Pos, i.Line, i.Pipe.CopyPipe(), i.List.CopyList(), i.ElseList.CopyList())
}
// RangeNode represents a {{range}} action and its commands.
@@ -676,12 +783,12 @@ type RangeNode struct {
BranchNode
}
-func newRange(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *RangeNode {
- return &RangeNode{BranchNode{NodeType: NodeRange, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
+func (t *Tree) newRange(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *RangeNode {
+ return &RangeNode{BranchNode{tr: t, NodeType: NodeRange, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
}
func (r *RangeNode) Copy() Node {
- return newRange(r.Pos, r.Line, r.Pipe.CopyPipe(), r.List.CopyList(), r.ElseList.CopyList())
+ return r.tr.newRange(r.Pos, r.Line, r.Pipe.CopyPipe(), r.List.CopyList(), r.ElseList.CopyList())
}
// WithNode represents a {{with}} action and its commands.
@@ -689,25 +796,26 @@ type WithNode struct {
BranchNode
}
-func newWith(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *WithNode {
- return &WithNode{BranchNode{NodeType: NodeWith, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
+func (t *Tree) newWith(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *WithNode {
+ return &WithNode{BranchNode{tr: t, NodeType: NodeWith, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
}
func (w *WithNode) Copy() Node {
- return newWith(w.Pos, w.Line, w.Pipe.CopyPipe(), w.List.CopyList(), w.ElseList.CopyList())
+ return w.tr.newWith(w.Pos, w.Line, w.Pipe.CopyPipe(), w.List.CopyList(), w.ElseList.CopyList())
}
// TemplateNode represents a {{template}} action.
type TemplateNode struct {
NodeType
Pos
+ tr *Tree
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.
}
-func newTemplate(pos Pos, line int, name string, pipe *PipeNode) *TemplateNode {
- return &TemplateNode{NodeType: NodeTemplate, Line: line, Pos: pos, Name: name, Pipe: pipe}
+func (t *Tree) newTemplate(pos Pos, line int, name string, pipe *PipeNode) *TemplateNode {
+ return &TemplateNode{tr: t, NodeType: NodeTemplate, Pos: pos, Line: line, Name: name, Pipe: pipe}
}
func (t *TemplateNode) String() string {
@@ -717,6 +825,10 @@ func (t *TemplateNode) String() string {
return fmt.Sprintf("{{template %q %s}}", t.Name, t.Pipe)
}
+func (t *TemplateNode) tree() *Tree {
+ return t.tr
+}
+
func (t *TemplateNode) Copy() Node {
- return newTemplate(t.Pos, t.Line, t.Name, t.Pipe.CopyPipe())
+ return t.tr.newTemplate(t.Pos, t.Line, t.Name, t.Pipe.CopyPipe())
}
diff --git a/libgo/go/text/template/parse/parse.go b/libgo/go/text/template/parse/parse.go
index 34112fb7b3..af33880c15 100644
--- a/libgo/go/text/template/parse/parse.go
+++ b/libgo/go/text/template/parse/parse.go
@@ -129,9 +129,15 @@ func New(name string, funcs ...map[string]interface{}) *Tree {
}
// ErrorContext returns a textual representation of the location of the node in the input text.
+// The receiver is only used when the node does not have a pointer to the tree inside,
+// which can occur in old code.
func (t *Tree) ErrorContext(n Node) (location, context string) {
pos := int(n.Position())
- text := t.text[:pos]
+ tree := n.tree()
+ if tree == nil {
+ tree = t
+ }
+ text := tree.text[:pos]
byteNum := strings.LastIndex(text, "\n")
if byteNum == -1 {
byteNum = pos // On first line.
@@ -144,7 +150,7 @@ func (t *Tree) ErrorContext(n Node) (location, context string) {
if len(context) > 20 {
context = fmt.Sprintf("%.20s...", context)
}
- return fmt.Sprintf("%s:%d:%d", t.ParseName, lineNum, byteNum), context
+ return fmt.Sprintf("%s:%d:%d", tree.ParseName, lineNum, byteNum), context
}
// errorf formats the error and terminates processing.
@@ -268,7 +274,7 @@ func IsEmptyTree(n Node) bool {
// as itemList except it also parses {{define}} actions.
// It runs to EOF.
func (t *Tree) parse(treeSet map[string]*Tree) (next Node) {
- t.Root = newList(t.peek().pos)
+ t.Root = t.newList(t.peek().pos)
for t.peek().typ != itemEOF {
if t.peek().typ == itemLeftDelim {
delim := t.next()
@@ -316,7 +322,7 @@ func (t *Tree) parseDefinition(treeSet map[string]*Tree) {
// textOrAction*
// Terminates at {{end}} or {{else}}, returned separately.
func (t *Tree) itemList() (list *ListNode, next Node) {
- list = newList(t.peekNonSpace().pos)
+ list = t.newList(t.peekNonSpace().pos)
for t.peekNonSpace().typ != itemEOF {
n := t.textOrAction()
switch n.Type() {
@@ -334,7 +340,7 @@ func (t *Tree) itemList() (list *ListNode, next Node) {
func (t *Tree) textOrAction() Node {
switch token := t.nextNonSpace(); token.typ {
case itemText:
- return newText(token.pos, token.val)
+ return t.newText(token.pos, token.val)
case itemLeftDelim:
return t.action()
default:
@@ -365,7 +371,7 @@ func (t *Tree) action() (n Node) {
}
t.backup()
// Do not pop variables; they persist until "end".
- return newAction(t.peek().pos, t.lex.lineNumber(), t.pipeline("command"))
+ return t.newAction(t.peek().pos, t.lex.lineNumber(), t.pipeline("command"))
}
// Pipeline:
@@ -384,7 +390,7 @@ func (t *Tree) pipeline(context string) (pipe *PipeNode) {
tokenAfterVariable := t.peek()
if next := t.peekNonSpace(); next.typ == itemColonEquals || (next.typ == itemChar && next.val == ",") {
t.nextNonSpace()
- variable := newVariable(v.pos, v.val)
+ variable := t.newVariable(v.pos, v.val)
decl = append(decl, variable)
t.vars = append(t.vars, v.val)
if next.typ == itemChar && next.val == "," {
@@ -401,7 +407,7 @@ func (t *Tree) pipeline(context string) (pipe *PipeNode) {
}
break
}
- pipe = newPipeline(pos, t.lex.lineNumber(), decl)
+ pipe = t.newPipeline(pos, t.lex.lineNumber(), decl)
for {
switch token := t.nextNonSpace(); token.typ {
case itemRightDelim, itemRightParen:
@@ -442,7 +448,7 @@ func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int
// TODO: Should we allow else-if in with and range?
if t.peek().typ == itemIf {
t.next() // Consume the "if" token.
- elseList = newList(next.Position())
+ elseList = t.newList(next.Position())
elseList.append(t.ifControl())
// Do not consume the next item - only one {{end}} required.
break
@@ -461,7 +467,7 @@ func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int
// {{if pipeline}} itemList {{else}} itemList {{end}}
// If keyword is past.
func (t *Tree) ifControl() Node {
- return newIf(t.parseControl(true, "if"))
+ return t.newIf(t.parseControl(true, "if"))
}
// Range:
@@ -469,7 +475,7 @@ func (t *Tree) ifControl() Node {
// {{range pipeline}} itemList {{else}} itemList {{end}}
// Range keyword is past.
func (t *Tree) rangeControl() Node {
- return newRange(t.parseControl(false, "range"))
+ return t.newRange(t.parseControl(false, "range"))
}
// With:
@@ -477,14 +483,14 @@ func (t *Tree) rangeControl() Node {
// {{with pipeline}} itemList {{else}} itemList {{end}}
// If keyword is past.
func (t *Tree) withControl() Node {
- return newWith(t.parseControl(false, "with"))
+ return t.newWith(t.parseControl(false, "with"))
}
// End:
// {{end}}
// End keyword is past.
func (t *Tree) endControl() Node {
- return newEnd(t.expect(itemRightDelim, "end").pos)
+ return t.newEnd(t.expect(itemRightDelim, "end").pos)
}
// Else:
@@ -495,9 +501,9 @@ func (t *Tree) elseControl() Node {
peek := t.peekNonSpace()
if peek.typ == itemIf {
// We see "{{else if ... " but in effect rewrite it to {{else}}{{if ... ".
- return newElse(peek.pos, t.lex.lineNumber())
+ return t.newElse(peek.pos, t.lex.lineNumber())
}
- return newElse(t.expect(itemRightDelim, "else").pos, t.lex.lineNumber())
+ return t.newElse(t.expect(itemRightDelim, "else").pos, t.lex.lineNumber())
}
// Template:
@@ -523,7 +529,7 @@ func (t *Tree) templateControl() Node {
// Do not pop variables; they persist until "end".
pipe = t.pipeline("template")
}
- return newTemplate(token.pos, t.lex.lineNumber(), name, pipe)
+ return t.newTemplate(token.pos, t.lex.lineNumber(), name, pipe)
}
// command:
@@ -531,7 +537,7 @@ func (t *Tree) templateControl() Node {
// space-separated arguments up to a pipeline character or right delimiter.
// we consume the pipe character but leave the right delim to terminate the action.
func (t *Tree) command() *CommandNode {
- cmd := newCommand(t.peekNonSpace().pos)
+ cmd := t.newCommand(t.peekNonSpace().pos)
for {
t.peekNonSpace() // skip leading spaces.
operand := t.operand()
@@ -568,7 +574,7 @@ func (t *Tree) operand() Node {
return nil
}
if t.peek().typ == itemField {
- chain := newChain(t.peek().pos, node)
+ chain := t.newChain(t.peek().pos, node)
for t.peek().typ == itemField {
chain.Add(t.next().val)
}
@@ -578,9 +584,9 @@ func (t *Tree) operand() Node {
// TODO: Switch to Chains always when we can.
switch node.Type() {
case NodeField:
- node = newField(chain.Position(), chain.String())
+ node = t.newField(chain.Position(), chain.String())
case NodeVariable:
- node = newVariable(chain.Position(), chain.String())
+ node = t.newVariable(chain.Position(), chain.String())
default:
node = chain
}
@@ -605,19 +611,19 @@ func (t *Tree) term() Node {
if !t.hasFunction(token.val) {
t.errorf("function %q not defined", token.val)
}
- return NewIdentifier(token.val).SetPos(token.pos)
+ return NewIdentifier(token.val).SetTree(t).SetPos(token.pos)
case itemDot:
- return newDot(token.pos)
+ return t.newDot(token.pos)
case itemNil:
- return newNil(token.pos)
+ return t.newNil(token.pos)
case itemVariable:
return t.useVar(token.pos, token.val)
case itemField:
- return newField(token.pos, token.val)
+ return t.newField(token.pos, token.val)
case itemBool:
- return newBool(token.pos, token.val == "true")
+ return t.newBool(token.pos, token.val == "true")
case itemCharConstant, itemComplex, itemNumber:
- number, err := newNumber(token.pos, token.val, token.typ)
+ number, err := t.newNumber(token.pos, token.val, token.typ)
if err != nil {
t.error(err)
}
@@ -633,7 +639,7 @@ func (t *Tree) term() Node {
if err != nil {
t.error(err)
}
- return newString(token.pos, token.val, s)
+ return t.newString(token.pos, token.val, s)
}
t.backup()
return nil
@@ -660,7 +666,7 @@ func (t *Tree) popVars(n int) {
// useVar returns a node for a variable reference. It errors if the
// variable is not defined.
func (t *Tree) useVar(pos Pos, name string) Node {
- v := newVariable(pos, name)
+ v := t.newVariable(pos, name)
for _, varName := range t.vars {
if varName == v.Ident[0] {
return v
diff --git a/libgo/go/text/template/parse/parse_test.go b/libgo/go/text/template/parse/parse_test.go
index ba1a18ec54..4a504fa7c8 100644
--- a/libgo/go/text/template/parse/parse_test.go
+++ b/libgo/go/text/template/parse/parse_test.go
@@ -69,6 +69,8 @@ var numberTests = []numberTest{
{text: "1+2."},
{text: "'x"},
{text: "'xx'"},
+ // Issue 8622 - 0xe parsed as floating point. Very embarrassing.
+ {"0xef", true, true, true, false, 0xef, 0xef, 0xef, 0},
}
func TestNumberParse(t *testing.T) {
@@ -77,6 +79,7 @@ func TestNumberParse(t *testing.T) {
// because imaginary comes out as a number.
var c complex128
typ := itemNumber
+ var tree *Tree
if test.text[0] == '\'' {
typ = itemCharConstant
} else {
@@ -85,7 +88,7 @@ func TestNumberParse(t *testing.T) {
typ = itemComplex
}
}
- n, err := newNumber(0, test.text, typ)
+ n, err := tree.newNumber(0, test.text, typ)
ok := test.isInt || test.isUint || test.isFloat || test.isComplex
if ok && err != nil {
t.Errorf("unexpected error for %q: %s", test.text, err)
diff --git a/libgo/go/text/template/template.go b/libgo/go/text/template/template.go
index a2b9062ad1..249d0cbfb9 100644
--- a/libgo/go/text/template/template.go
+++ b/libgo/go/text/template/template.go
@@ -105,7 +105,7 @@ func (t *Template) copy(c *common) *Template {
// AddParseTree creates a new template with the name and parse tree
// and associates it with t.
func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) {
- if t.tmpl[name] != nil {
+ if t.common != nil && t.tmpl[name] != nil {
return nil, fmt.Errorf("template: redefinition of template %q", name)
}
nt := t.New(name)
diff --git a/libgo/go/time/example_test.go b/libgo/go/time/example_test.go
index cfa5b38c5f..a37e8b86dd 100644
--- a/libgo/go/time/example_test.go
+++ b/libgo/go/time/example_test.go
@@ -122,7 +122,7 @@ func ExampleTime_Round() {
}
// Output:
// t.Round( 1ns) = 12:15:30.918273645
- // t.Round( 1us) = 12:15:30.918274
+ // t.Round( 1µs) = 12:15:30.918274
// t.Round( 1ms) = 12:15:30.918
// t.Round( 1s) = 12:15:31
// t.Round( 2s) = 12:15:30
@@ -150,7 +150,7 @@ func ExampleTime_Truncate() {
// Output:
// t.Truncate( 1ns) = 12:15:30.918273645
- // t.Truncate( 1us) = 12:15:30.918273
+ // t.Truncate( 1µs) = 12:15:30.918273
// t.Truncate( 1ms) = 12:15:30.918
// t.Truncate( 1s) = 12:15:30
// t.Truncate( 2s) = 12:15:30
diff --git a/libgo/go/time/format.go b/libgo/go/time/format.go
index 6f92c12626..04e79f32dc 100644
--- a/libgo/go/time/format.go
+++ b/libgo/go/time/format.go
@@ -7,7 +7,7 @@ package time
import "errors"
// These are predefined layouts for use in Time.Format and Time.Parse.
-// The reference time used in the layouts is:
+// The reference time used in the layouts is the specific time:
// Mon Jan 2 15:04:05 MST 2006
// which is Unix time 1136239445. Since MST is GMT-0700,
// the reference time can be thought of as
@@ -102,7 +102,7 @@ const (
// std0x records the std values for "01", "02", ..., "06".
var std0x = [...]int{stdZeroMonth, stdZeroDay, stdZeroHour12, stdZeroMinute, stdZeroSecond, stdYear}
-// startsWithLowerCase reports whether the the string has a lower-case letter at the beginning.
+// startsWithLowerCase reports whether the string has a lower-case letter at the beginning.
// Its purpose is to prevent matching strings like "Month" when looking for "Mon".
func startsWithLowerCase(str string) bool {
if len(str) == 0 {
@@ -402,7 +402,7 @@ func (t Time) String() string {
// Format returns a textual representation of the time value formatted
// according to layout, which defines the format by showing how the reference
-// time,
+// time, defined to be
// Mon Jan 2 15:04:05 -0700 MST 2006
// 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
@@ -556,7 +556,7 @@ func (t Time) Format(layout string) string {
b = append(b, '+')
}
b = appendUint(b, uint(zone/60), '0')
- if std == stdISO8601ColonTZ || std == stdNumColonTZ {
+ if std == stdISO8601ColonTZ || std == stdNumColonTZ || std == stdISO8601ColonSecondsTZ || std == stdNumColonSecondsTZ {
b = append(b, ':')
}
b = appendUint(b, uint(zone%60), '0')
@@ -676,6 +676,7 @@ func skip(value, prefix string) (string, error) {
// Parse parses a formatted string and returns the time value it represents.
// The layout defines the format by showing how the reference time,
+// defined to be
// Mon Jan 2 15:04:05 -0700 MST 2006
// 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
@@ -704,7 +705,7 @@ func skip(value, prefix string) (string, error) {
// The zone abbreviation "UTC" is recognized as UTC regardless of location.
// If the zone abbreviation is unknown, Parse records the time as being
// in a fabricated location with the given zone abbreviation and a zero offset.
-// This choice means that such a time can be parse and reformatted with the
+// This choice means that such a time can be parsed and reformatted with the
// same layout losslessly, but the exact instant used in the representation will
// differ by the actual zone offset. To avoid such problems, prefer time layouts
// that use a numeric zone offset, or use ParseInLocation.
@@ -1037,8 +1038,8 @@ func parseTimeZone(value string) (length int, ok bool) {
if len(value) < 3 {
return 0, false
}
- // Special case 1: This is the only zone with a lower-case letter.
- if len(value) >= 4 && value[:4] == "ChST" {
+ // Special case 1: ChST and MeST are the only zones with a lower-case letter.
+ if len(value) >= 4 && (value[:4] == "ChST" || value[:4] == "MeST") {
return 4, true
}
// Special case 2: GMT may have an hour offset; treat it specially.
@@ -1240,5 +1241,8 @@ func ParseDuration(s string) (Duration, error) {
if neg {
f = -f
}
+ if f < float64(-1<<63) || f > float64(1<<63-1) {
+ return 0, errors.New("time: overflow parsing duration")
+ }
return Duration(f), nil
}
diff --git a/libgo/go/time/format_test.go b/libgo/go/time/format_test.go
new file mode 100644
index 0000000000..75a08c7453
--- /dev/null
+++ b/libgo/go/time/format_test.go
@@ -0,0 +1,520 @@
+// 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 time_test
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "testing"
+ "testing/quick"
+ . "time"
+)
+
+type TimeFormatTest struct {
+ time Time
+ formattedValue string
+}
+
+var rfc3339Formats = []TimeFormatTest{
+ {Date(2008, 9, 17, 20, 4, 26, 0, UTC), "2008-09-17T20:04:26Z"},
+ {Date(1994, 9, 17, 20, 4, 26, 0, FixedZone("EST", -18000)), "1994-09-17T20:04:26-05:00"},
+ {Date(2000, 12, 26, 1, 15, 6, 0, FixedZone("OTO", 15600)), "2000-12-26T01:15:06+04:20"},
+}
+
+func TestRFC3339Conversion(t *testing.T) {
+ for _, f := range rfc3339Formats {
+ if f.time.Format(RFC3339) != f.formattedValue {
+ t.Error("RFC3339:")
+ t.Errorf(" want=%+v", f.formattedValue)
+ t.Errorf(" have=%+v", f.time.Format(RFC3339))
+ }
+ }
+}
+
+type FormatTest struct {
+ name string
+ format string
+ result string
+}
+
+var formatTests = []FormatTest{
+ {"ANSIC", ANSIC, "Wed Feb 4 21:00:57 2009"},
+ {"UnixDate", UnixDate, "Wed Feb 4 21:00:57 PST 2009"},
+ {"RubyDate", RubyDate, "Wed Feb 04 21:00:57 -0800 2009"},
+ {"RFC822", RFC822, "04 Feb 09 21:00 PST"},
+ {"RFC850", RFC850, "Wednesday, 04-Feb-09 21:00:57 PST"},
+ {"RFC1123", RFC1123, "Wed, 04 Feb 2009 21:00:57 PST"},
+ {"RFC1123Z", RFC1123Z, "Wed, 04 Feb 2009 21:00:57 -0800"},
+ {"RFC3339", RFC3339, "2009-02-04T21:00:57-08:00"},
+ {"RFC3339Nano", RFC3339Nano, "2009-02-04T21:00:57.0123456-08:00"},
+ {"Kitchen", Kitchen, "9:00PM"},
+ {"am/pm", "3pm", "9pm"},
+ {"AM/PM", "3PM", "9PM"},
+ {"two-digit year", "06 01 02", "09 02 04"},
+ // Three-letter months and days must not be followed by lower-case letter.
+ {"Janet", "Hi Janet, the Month is January", "Hi Janet, the Month is February"},
+ // Time stamps, Fractional seconds.
+ {"Stamp", Stamp, "Feb 4 21:00:57"},
+ {"StampMilli", StampMilli, "Feb 4 21:00:57.012"},
+ {"StampMicro", StampMicro, "Feb 4 21:00:57.012345"},
+ {"StampNano", StampNano, "Feb 4 21:00:57.012345600"},
+}
+
+func TestFormat(t *testing.T) {
+ // The numeric time represents Thu Feb 4 21:00:57.012345600 PST 2010
+ time := Unix(0, 1233810057012345600)
+ for _, test := range formatTests {
+ result := time.Format(test.format)
+ if result != test.result {
+ t.Errorf("%s expected %q got %q", test.name, test.result, result)
+ }
+ }
+}
+
+func TestFormatShortYear(t *testing.T) {
+ years := []int{
+ -100001, -100000, -99999,
+ -10001, -10000, -9999,
+ -1001, -1000, -999,
+ -101, -100, -99,
+ -11, -10, -9,
+ -1, 0, 1,
+ 9, 10, 11,
+ 99, 100, 101,
+ 999, 1000, 1001,
+ 9999, 10000, 10001,
+ 99999, 100000, 100001,
+ }
+
+ for _, y := range years {
+ time := Date(y, January, 1, 0, 0, 0, 0, UTC)
+ result := time.Format("2006.01.02")
+ var want string
+ if y < 0 {
+ // The 4 in %04d counts the - sign, so print -y instead
+ // and introduce our own - sign.
+ want = fmt.Sprintf("-%04d.%02d.%02d", -y, 1, 1)
+ } else {
+ want = fmt.Sprintf("%04d.%02d.%02d", y, 1, 1)
+ }
+ if result != want {
+ t.Errorf("(jan 1 %d).Format(\"2006.01.02\") = %q, want %q", y, result, want)
+ }
+ }
+}
+
+type ParseTest struct {
+ name string
+ format string
+ value string
+ hasTZ bool // contains a time zone
+ hasWD bool // contains a weekday
+ yearSign int // sign of year, -1 indicates the year is not present in the format
+ fracDigits int // number of digits of fractional second
+}
+
+var parseTests = []ParseTest{
+ {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0},
+ {"UnixDate", UnixDate, "Thu Feb 4 21:00:57 PST 2010", true, true, 1, 0},
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1, 0},
+ {"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57 PST", true, true, 1, 0},
+ {"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57 PST", true, true, 1, 0},
+ {"RFC1123", RFC1123, "Thu, 04 Feb 2010 22:00:57 PDT", true, true, 1, 0},
+ {"RFC1123Z", RFC1123Z, "Thu, 04 Feb 2010 21:00:57 -0800", true, true, 1, 0},
+ {"RFC3339", RFC3339, "2010-02-04T21:00:57-08:00", true, false, 1, 0},
+ {"custom: \"2006-01-02 15:04:05-07\"", "2006-01-02 15:04:05-07", "2010-02-04 21:00:57-08", true, false, 1, 0},
+ // Optional fractional seconds.
+ {"ANSIC", ANSIC, "Thu Feb 4 21:00:57.0 2010", false, true, 1, 1},
+ {"UnixDate", UnixDate, "Thu Feb 4 21:00:57.01 PST 2010", true, true, 1, 2},
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57.012 -0800 2010", true, true, 1, 3},
+ {"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57.0123 PST", true, true, 1, 4},
+ {"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57.01234 PST", true, true, 1, 5},
+ {"RFC1123Z", RFC1123Z, "Thu, 04 Feb 2010 21:00:57.01234 -0800", true, true, 1, 5},
+ {"RFC3339", RFC3339, "2010-02-04T21:00:57.012345678-08:00", true, false, 1, 9},
+ {"custom: \"2006-01-02 15:04:05\"", "2006-01-02 15:04:05", "2010-02-04 21:00:57.0", false, false, 1, 0},
+ // Amount of white space should not matter.
+ {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0},
+ {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0},
+ // Case should not matter
+ {"ANSIC", ANSIC, "THU FEB 4 21:00:57 2010", false, true, 1, 0},
+ {"ANSIC", ANSIC, "thu feb 4 21:00:57 2010", false, true, 1, 0},
+ // Fractional seconds.
+ {"millisecond", "Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 21:00:57.012 2010", false, true, 1, 3},
+ {"microsecond", "Mon Jan _2 15:04:05.000000 2006", "Thu Feb 4 21:00:57.012345 2010", false, true, 1, 6},
+ {"nanosecond", "Mon Jan _2 15:04:05.000000000 2006", "Thu Feb 4 21:00:57.012345678 2010", false, true, 1, 9},
+ // Leading zeros in other places should not be taken as fractional seconds.
+ {"zero1", "2006.01.02.15.04.05.0", "2010.02.04.21.00.57.0", false, false, 1, 1},
+ {"zero2", "2006.01.02.15.04.05.00", "2010.02.04.21.00.57.01", false, false, 1, 2},
+ // Month and day names only match when not followed by a lower-case letter.
+ {"Janet", "Hi Janet, the Month is January: Jan _2 15:04:05 2006", "Hi Janet, the Month is February: Feb 4 21:00:57 2010", false, true, 1, 0},
+
+ // GMT with offset.
+ {"GMT-8", UnixDate, "Fri Feb 5 05:00:57 GMT-8 2010", true, true, 1, 0},
+
+ // Accept any number of fractional second digits (including none) for .999...
+ // In Go 1, .999... was completely ignored in the format, meaning the first two
+ // cases would succeed, but the next four would not. Go 1.1 accepts all six.
+ {"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0},
+ {"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0},
+ {"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4},
+ {"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4},
+ {"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9},
+ {"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9},
+
+ // issue 4502.
+ {"", StampNano, "Feb 4 21:00:57.012345678", false, false, -1, 9},
+ {"", "Jan _2 15:04:05.999", "Feb 4 21:00:57.012300000", false, false, -1, 4},
+ {"", "Jan _2 15:04:05.999", "Feb 4 21:00:57.012345678", false, false, -1, 9},
+ {"", "Jan _2 15:04:05.999999999", "Feb 4 21:00:57.0123", false, false, -1, 4},
+ {"", "Jan _2 15:04:05.999999999", "Feb 4 21:00:57.012345678", false, false, -1, 9},
+}
+
+func TestParse(t *testing.T) {
+ for _, test := range parseTests {
+ time, err := Parse(test.format, test.value)
+ if err != nil {
+ t.Errorf("%s error: %v", test.name, err)
+ } else {
+ checkTime(time, &test, t)
+ }
+ }
+}
+
+func TestParseInLocation(t *testing.T) {
+ // Check that Parse (and ParseInLocation) understand that
+ // Feb 01 AST (Arabia Standard Time) and Feb 01 AST (Atlantic Standard Time)
+ // are in different time zones even though both are called AST
+
+ baghdad, err := LoadLocation("Asia/Baghdad")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ t1, err := ParseInLocation("Jan 02 2006 MST", "Feb 01 2013 AST", baghdad)
+ if err != nil {
+ t.Fatal(err)
+ }
+ t2 := Date(2013, February, 1, 00, 00, 00, 0, baghdad)
+ if t1 != t2 {
+ t.Fatalf("ParseInLocation(Feb 01 2013 AST, Baghdad) = %v, want %v", t1, t2)
+ }
+ _, offset := t1.Zone()
+ if offset != 3*60*60 {
+ t.Fatalf("ParseInLocation(Feb 01 2013 AST, Baghdad).Zone = _, %d, want _, %d", offset, 3*60*60)
+ }
+
+ blancSablon, err := LoadLocation("America/Blanc-Sablon")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ t1, err = ParseInLocation("Jan 02 2006 MST", "Feb 01 2013 AST", blancSablon)
+ if err != nil {
+ t.Fatal(err)
+ }
+ t2 = Date(2013, February, 1, 00, 00, 00, 0, blancSablon)
+ if t1 != t2 {
+ t.Fatalf("ParseInLocation(Feb 01 2013 AST, Blanc-Sablon) = %v, want %v", t1, t2)
+ }
+ _, offset = t1.Zone()
+ if offset != -4*60*60 {
+ t.Fatalf("ParseInLocation(Feb 01 2013 AST, Blanc-Sablon).Zone = _, %d, want _, %d", offset, -4*60*60)
+ }
+}
+
+func TestLoadLocationZipFile(t *testing.T) {
+ t.Skip("gccgo does not use the zip file")
+
+ ForceZipFileForTesting(true)
+ defer ForceZipFileForTesting(false)
+
+ _, err := LoadLocation("Australia/Sydney")
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+var rubyTests = []ParseTest{
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1, 0},
+ // Ignore the time zone in the test. If it parses, it'll be OK.
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0000 2010", false, true, 1, 0},
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +0000 2010", false, true, 1, 0},
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +1130 2010", false, true, 1, 0},
+}
+
+// Problematic time zone format needs special tests.
+func TestRubyParse(t *testing.T) {
+ for _, test := range rubyTests {
+ time, err := Parse(test.format, test.value)
+ if err != nil {
+ t.Errorf("%s error: %v", test.name, err)
+ } else {
+ checkTime(time, &test, t)
+ }
+ }
+}
+
+func checkTime(time Time, test *ParseTest, t *testing.T) {
+ // The time should be Thu Feb 4 21:00:57 PST 2010
+ if test.yearSign >= 0 && test.yearSign*time.Year() != 2010 {
+ t.Errorf("%s: bad year: %d not %d", test.name, time.Year(), 2010)
+ }
+ if time.Month() != February {
+ t.Errorf("%s: bad month: %s not %s", test.name, time.Month(), February)
+ }
+ if time.Day() != 4 {
+ t.Errorf("%s: bad day: %d not %d", test.name, time.Day(), 4)
+ }
+ if time.Hour() != 21 {
+ t.Errorf("%s: bad hour: %d not %d", test.name, time.Hour(), 21)
+ }
+ if time.Minute() != 0 {
+ t.Errorf("%s: bad minute: %d not %d", test.name, time.Minute(), 0)
+ }
+ if time.Second() != 57 {
+ t.Errorf("%s: bad second: %d not %d", test.name, time.Second(), 57)
+ }
+ // Nanoseconds must be checked against the precision of the input.
+ nanosec, err := strconv.ParseUint("012345678"[:test.fracDigits]+"000000000"[:9-test.fracDigits], 10, 0)
+ if err != nil {
+ panic(err)
+ }
+ if time.Nanosecond() != int(nanosec) {
+ t.Errorf("%s: bad nanosecond: %d not %d", test.name, time.Nanosecond(), nanosec)
+ }
+ name, offset := time.Zone()
+ if test.hasTZ && offset != -28800 {
+ t.Errorf("%s: bad tz offset: %s %d not %d", test.name, name, offset, -28800)
+ }
+ if test.hasWD && time.Weekday() != Thursday {
+ t.Errorf("%s: bad weekday: %s not %s", test.name, time.Weekday(), Thursday)
+ }
+}
+
+func TestFormatAndParse(t *testing.T) {
+ const fmt = "Mon MST " + RFC3339 // all fields
+ f := func(sec int64) bool {
+ t1 := Unix(sec, 0)
+ if t1.Year() < 1000 || t1.Year() > 9999 {
+ // not required to work
+ return true
+ }
+ t2, err := Parse(fmt, t1.Format(fmt))
+ if err != nil {
+ t.Errorf("error: %s", err)
+ return false
+ }
+ if t1.Unix() != t2.Unix() || t1.Nanosecond() != t2.Nanosecond() {
+ t.Errorf("FormatAndParse %d: %q(%d) %q(%d)", sec, t1, t1.Unix(), t2, t2.Unix())
+ return false
+ }
+ return true
+ }
+ f32 := func(sec int32) bool { return f(int64(sec)) }
+ cfg := &quick.Config{MaxCount: 10000}
+
+ // Try a reasonable date first, then the huge ones.
+ if err := quick.Check(f32, cfg); err != nil {
+ t.Fatal(err)
+ }
+ if err := quick.Check(f, cfg); err != nil {
+ t.Fatal(err)
+ }
+}
+
+type ParseTimeZoneTest struct {
+ value string
+ length int
+ ok bool
+}
+
+var parseTimeZoneTests = []ParseTimeZoneTest{
+ {"gmt hi there", 0, false},
+ {"GMT hi there", 3, true},
+ {"GMT+12 hi there", 6, true},
+ {"GMT+00 hi there", 3, true}, // 0 or 00 is not a legal offset.
+ {"GMT-5 hi there", 5, true},
+ {"GMT-51 hi there", 3, true},
+ {"ChST hi there", 4, true},
+ {"MeST hi there", 4, true},
+ {"MSDx", 3, true},
+ {"MSDY", 0, false}, // four letters must end in T.
+ {"ESAST hi", 5, true},
+ {"ESASTT hi", 0, false}, // run of upper-case letters too long.
+ {"ESATY hi", 0, false}, // five letters must end in T.
+}
+
+func TestParseTimeZone(t *testing.T) {
+ for _, test := range parseTimeZoneTests {
+ length, ok := ParseTimeZone(test.value)
+ if ok != test.ok {
+ t.Errorf("expected %t for %q got %t", test.ok, test.value, ok)
+ } else if length != test.length {
+ t.Errorf("expected %d for %q got %d", test.length, test.value, length)
+ }
+ }
+}
+
+type ParseErrorTest struct {
+ format string
+ value string
+ expect string // must appear within the error
+}
+
+var parseErrorTests = []ParseErrorTest{
+ {ANSIC, "Feb 4 21:00:60 2010", "cannot parse"}, // cannot parse Feb as Mon
+ {ANSIC, "Thu Feb 4 21:00:57 @2010", "cannot parse"},
+ {ANSIC, "Thu Feb 4 21:00:60 2010", "second out of range"},
+ {ANSIC, "Thu Feb 4 21:61:57 2010", "minute out of range"},
+ {ANSIC, "Thu Feb 4 24:00:60 2010", "hour out of range"},
+ {"Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 23:00:59x01 2010", "cannot parse"},
+ {"Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 23:00:59.xxx 2010", "cannot parse"},
+ {"Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 23:00:59.-123 2010", "fractional second out of range"},
+ // issue 4502. StampNano requires exactly 9 digits of precision.
+ {StampNano, "Dec 7 11:22:01.000000", `cannot parse ".000000" as ".000000000"`},
+ {StampNano, "Dec 7 11:22:01.0000000000", "extra text: 0"},
+ // issue 4493. Helpful errors.
+ {RFC3339, "2006-01-02T15:04:05Z07:00", `parsing time "2006-01-02T15:04:05Z07:00": extra text: 07:00`},
+ {RFC3339, "2006-01-02T15:04_abc", `parsing time "2006-01-02T15:04_abc" as "2006-01-02T15:04:05Z07:00": cannot parse "_abc" as ":"`},
+ {RFC3339, "2006-01-02T15:04:05_abc", `parsing time "2006-01-02T15:04:05_abc" as "2006-01-02T15:04:05Z07:00": cannot parse "_abc" as "Z07:00"`},
+ {RFC3339, "2006-01-02T15:04:05Z_abc", `parsing time "2006-01-02T15:04:05Z_abc": extra text: _abc`},
+}
+
+func TestParseErrors(t *testing.T) {
+ for _, test := range parseErrorTests {
+ _, err := Parse(test.format, test.value)
+ if err == nil {
+ t.Errorf("expected error for %q %q", test.format, test.value)
+ } else if strings.Index(err.Error(), test.expect) < 0 {
+ t.Errorf("expected error with %q for %q %q; got %s", test.expect, test.format, test.value, err)
+ }
+ }
+}
+
+func TestNoonIs12PM(t *testing.T) {
+ noon := Date(0, January, 1, 12, 0, 0, 0, UTC)
+ const expect = "12:00PM"
+ got := noon.Format("3:04PM")
+ if got != expect {
+ t.Errorf("got %q; expect %q", got, expect)
+ }
+ got = noon.Format("03:04PM")
+ if got != expect {
+ t.Errorf("got %q; expect %q", got, expect)
+ }
+}
+
+func TestMidnightIs12AM(t *testing.T) {
+ midnight := Date(0, January, 1, 0, 0, 0, 0, UTC)
+ expect := "12:00AM"
+ got := midnight.Format("3:04PM")
+ if got != expect {
+ t.Errorf("got %q; expect %q", got, expect)
+ }
+ got = midnight.Format("03:04PM")
+ if got != expect {
+ t.Errorf("got %q; expect %q", got, expect)
+ }
+}
+
+func Test12PMIsNoon(t *testing.T) {
+ noon, err := Parse("3:04PM", "12:00PM")
+ if err != nil {
+ t.Fatal("error parsing date:", err)
+ }
+ if noon.Hour() != 12 {
+ t.Errorf("got %d; expect 12", noon.Hour())
+ }
+ noon, err = Parse("03:04PM", "12:00PM")
+ if err != nil {
+ t.Fatal("error parsing date:", err)
+ }
+ if noon.Hour() != 12 {
+ t.Errorf("got %d; expect 12", noon.Hour())
+ }
+}
+
+func Test12AMIsMidnight(t *testing.T) {
+ midnight, err := Parse("3:04PM", "12:00AM")
+ if err != nil {
+ t.Fatal("error parsing date:", err)
+ }
+ if midnight.Hour() != 0 {
+ t.Errorf("got %d; expect 0", midnight.Hour())
+ }
+ midnight, err = Parse("03:04PM", "12:00AM")
+ if err != nil {
+ t.Fatal("error parsing date:", err)
+ }
+ if midnight.Hour() != 0 {
+ t.Errorf("got %d; expect 0", midnight.Hour())
+ }
+}
+
+// Check that a time without a Zone still produces a (numeric) time zone
+// when formatted with MST as a requested zone.
+func TestMissingZone(t *testing.T) {
+ time, err := Parse(RubyDate, "Thu Feb 02 16:10:03 -0500 2006")
+ if err != nil {
+ t.Fatal("error parsing date:", err)
+ }
+ expect := "Thu Feb 2 16:10:03 -0500 2006" // -0500 not EST
+ str := time.Format(UnixDate) // uses MST as its time zone
+ if str != expect {
+ t.Errorf("got %s; expect %s", str, expect)
+ }
+}
+
+func TestMinutesInTimeZone(t *testing.T) {
+ time, err := Parse(RubyDate, "Mon Jan 02 15:04:05 +0123 2006")
+ if err != nil {
+ t.Fatal("error parsing date:", err)
+ }
+ expected := (1*60 + 23) * 60
+ _, offset := time.Zone()
+ if offset != expected {
+ t.Errorf("ZoneOffset = %d, want %d", offset, expected)
+ }
+}
+
+type SecondsTimeZoneOffsetTest struct {
+ format string
+ value string
+ expectedoffset int
+}
+
+var secondsTimeZoneOffsetTests = []SecondsTimeZoneOffsetTest{
+ {"2006-01-02T15:04:05-070000", "1871-01-01T05:33:02-003408", -(34*60 + 8)},
+ {"2006-01-02T15:04:05-07:00:00", "1871-01-01T05:33:02-00:34:08", -(34*60 + 8)},
+ {"2006-01-02T15:04:05-070000", "1871-01-01T05:33:02+003408", 34*60 + 8},
+ {"2006-01-02T15:04:05-07:00:00", "1871-01-01T05:33:02+00:34:08", 34*60 + 8},
+ {"2006-01-02T15:04:05Z070000", "1871-01-01T05:33:02-003408", -(34*60 + 8)},
+ {"2006-01-02T15:04:05Z07:00:00", "1871-01-01T05:33:02+00:34:08", 34*60 + 8},
+}
+
+func TestParseSecondsInTimeZone(t *testing.T) {
+ // should accept timezone offsets with seconds like: Zone America/New_York -4:56:02 - LMT 1883 Nov 18 12:03:58
+ for _, test := range secondsTimeZoneOffsetTests {
+ time, err := Parse(test.format, test.value)
+ if err != nil {
+ t.Fatal("error parsing date:", err)
+ }
+ _, offset := time.Zone()
+ if offset != test.expectedoffset {
+ t.Errorf("ZoneOffset = %d, want %d", offset, test.expectedoffset)
+ }
+ }
+}
+
+func TestFormatSecondsInTimeZone(t *testing.T) {
+ for _, test := range secondsTimeZoneOffsetTests {
+ d := Date(1871, 1, 1, 5, 33, 2, 0, FixedZone("LMT", test.expectedoffset))
+ timestr := d.Format(test.format)
+ if timestr != test.value {
+ t.Errorf("Format = %s, want %s", timestr, test.value)
+ }
+ }
+}
diff --git a/libgo/go/time/genzabbrs.go b/libgo/go/time/genzabbrs.go
index 7c637cb43a..9eb0728a42 100644
--- a/libgo/go/time/genzabbrs.go
+++ b/libgo/go/time/genzabbrs.go
@@ -7,22 +7,26 @@
//
// usage:
//
-// go run genzabbrs.go | gofmt > $GOROOT/src/pkg/time/zoneinfo_abbrs_windows.go
+// go run genzabbrs.go -output zoneinfo_abbrs_windows.go
//
package main
import (
+ "bytes"
"encoding/xml"
+ "flag"
+ "go/format"
"io/ioutil"
"log"
"net/http"
- "os"
"sort"
"text/template"
"time"
)
+var filename = flag.String("output", "zoneinfo_abbrs_windows.go", "output file name")
+
// getAbbrs finds timezone abbreviations (standard and daylight saving time)
// for location l.
func getAbbrs(l *time.Location) (st, dt string) {
@@ -105,6 +109,7 @@ func readWindowsZones() (zones, error) {
}
func main() {
+ flag.Parse()
zs, err := readWindowsZones()
if err != nil {
log.Fatal(err)
@@ -117,7 +122,16 @@ func main() {
wzURL,
zs,
}
- err = template.Must(template.New("prog").Parse(prog)).Execute(os.Stdout, v)
+ var buf bytes.Buffer
+ err = template.Must(template.New("prog").Parse(prog)).Execute(&buf, v)
+ if err != nil {
+ log.Fatal(err)
+ }
+ data, err := format.Source(buf.Bytes())
+ if err != nil {
+ log.Fatal(err)
+ }
+ err = ioutil.WriteFile(*filename, data, 0644)
if err != nil {
log.Fatal(err)
}
diff --git a/libgo/go/time/internal_test.go b/libgo/go/time/internal_test.go
index 87fdd3216f..edd523bc80 100644
--- a/libgo/go/time/internal_test.go
+++ b/libgo/go/time/internal_test.go
@@ -4,11 +4,6 @@
package time
-import (
- "errors"
- "runtime"
-)
-
func init() {
// force US/Pacific for time zone tests
ForceUSPacificForTesting()
@@ -17,31 +12,25 @@ func init() {
var Interrupt = interrupt
var DaysIn = daysIn
-func empty(now int64, arg interface{}) {}
+func empty(arg interface{}, seq uintptr) {}
// Test that a runtimeTimer with a duration so large it overflows
// does not cause other timers to hang.
//
// This test has to be in internal_test.go since it fiddles with
// unexported data structures.
-func CheckRuntimeTimerOverflow() error {
+func CheckRuntimeTimerOverflow() {
// We manually create a runtimeTimer to bypass the overflow
// detection logic in NewTimer: we're testing the underlying
// runtime.addtimer function.
r := &runtimeTimer{
- when: nano() + (1<<63 - 1),
+ when: runtimeNano() + (1<<63 - 1),
f: empty,
arg: nil,
}
startTimer(r)
- timeout := 100 * Millisecond
- if runtime.GOOS == "windows" {
- // Allow more time for gobuilder to succeed.
- timeout = Second
- }
-
- // Start a goroutine that should send on t.C before the timeout.
+ // Start a goroutine that should send on t.C right away.
t := NewTimer(1)
defer func() {
@@ -60,21 +49,11 @@ func CheckRuntimeTimerOverflow() error {
startTimer(r)
}()
- // Try to receive from t.C before the timeout. It will succeed
- // iff the previous sleep was able to finish. We're forced to
- // spin and yield after trying to receive since we can't start
- // any more timers (they might hang due to the same bug we're
- // now testing).
- stop := Now().Add(timeout)
- for {
- select {
- case <-t.C:
- return nil // It worked!
- default:
- if Now().After(stop) {
- return errors.New("runtime timer stuck: overflow in addtimer")
- }
- runtime.Gosched()
- }
- }
+ // If the test fails, we will hang here until the timeout in the testing package
+ // fires, which is 10 minutes. It would be nice to catch the problem sooner,
+ // but there is no reliable way to guarantee that timerproc schedules without
+ // doing something involving timerproc itself. Previous failed attempts have
+ // tried calling runtime.Gosched and runtime.GC, but neither is reliable.
+ // So we fall back to hope: We hope we don't hang here.
+ <-t.C
}
diff --git a/libgo/go/time/sleep.go b/libgo/go/time/sleep.go
index 4f55bebe62..e7a2ee2059 100644
--- a/libgo/go/time/sleep.go
+++ b/libgo/go/time/sleep.go
@@ -8,19 +8,18 @@ package time
// A negative or zero duration causes Sleep to return immediately.
func Sleep(d Duration)
-func nano() int64 {
- sec, nsec := now()
- return sec*1e9 + int64(nsec)
-}
+// runtimeNano returns the current value of the runtime clock in nanoseconds.
+func runtimeNano() int64
// Interface to timers implemented in package runtime.
// Must be in sync with ../runtime/runtime.h:/^struct.Timer$
type runtimeTimer struct {
- i int32
+ i int
when int64
period int64
- f func(int64, interface{}) // NOTE: must not be closure
+ f func(interface{}, uintptr) // NOTE: must not be closure
arg interface{}
+ seq uintptr
}
// when is a helper function for setting the 'when' field of a runtimeTimer.
@@ -29,9 +28,9 @@ type runtimeTimer struct {
// zero because of an overflow, MaxInt64 is returned.
func when(d Duration) int64 {
if d <= 0 {
- return nano()
+ return runtimeNano()
}
- t := nano() + int64(d)
+ t := runtimeNano() + int64(d)
if t < 0 {
t = 1<<63 - 1 // math.MaxInt64
}
@@ -44,6 +43,7 @@ func stopTimer(*runtimeTimer) bool
// The Timer type represents a single event.
// When the Timer expires, the current time will be sent on C,
// unless the Timer was created by AfterFunc.
+// A Timer must be created with NewTimer or AfterFunc.
type Timer struct {
C <-chan Time
r runtimeTimer
@@ -55,6 +55,9 @@ type Timer struct {
// Stop does not close the channel, to prevent a read from the channel succeeding
// incorrectly.
func (t *Timer) Stop() bool {
+ if t.r.f == nil {
+ panic("time: Stop called on uninitialized Timer")
+ }
return stopTimer(&t.r)
}
@@ -78,6 +81,9 @@ func NewTimer(d Duration) *Timer {
// It returns true if the timer had been active, false if the timer had
// expired or been stopped.
func (t *Timer) Reset(d Duration) bool {
+ if t.r.f == nil {
+ panic("time: Reset called on uninitialized Timer")
+ }
w := when(d)
active := stopTimer(&t.r)
t.r.when = w
@@ -85,14 +91,14 @@ func (t *Timer) Reset(d Duration) bool {
return active
}
-func sendTime(now int64, c interface{}) {
+func sendTime(c interface{}, seq uintptr) {
// Non-blocking send of time on c.
// Used in NewTimer, it cannot block anyway (buffer).
// Used in NewTicker, dropping sends on the floor is
// the desired behavior when the reader gets behind,
// because the sends are periodic.
select {
- case c.(chan Time) <- Unix(0, now):
+ case c.(chan Time) <- Now():
default:
}
}
@@ -119,6 +125,6 @@ func AfterFunc(d Duration, f func()) *Timer {
return t
}
-func goFunc(now int64, arg interface{}) {
+func goFunc(arg interface{}, seq uintptr) {
go arg.(func())()
}
diff --git a/libgo/go/time/sleep_test.go b/libgo/go/time/sleep_test.go
index cb09a84469..c21eb997dc 100644
--- a/libgo/go/time/sleep_test.go
+++ b/libgo/go/time/sleep_test.go
@@ -9,12 +9,21 @@ import (
"fmt"
"runtime"
"sort"
+ "strings"
"sync"
"sync/atomic"
"testing"
. "time"
)
+// Go runtime uses different Windows timers for time.Now and sleeping.
+// These can tick at different frequencies and can arrive out of sync.
+// The effect can be seen, for example, as time.Sleep(100ms) is actually
+// shorter then 100ms when measured as difference between time.Now before and
+// after time.Sleep call. This was observed on Windows XP SP3 (windows/386).
+// windowsInaccuracy is to ignore such errors.
+const windowsInaccuracy = 17 * Millisecond
+
func TestSleep(t *testing.T) {
const delay = 100 * Millisecond
go func() {
@@ -23,8 +32,12 @@ func TestSleep(t *testing.T) {
}()
start := Now()
Sleep(delay)
+ delayadj := delay
+ if runtime.GOOS == "windows" {
+ delayadj -= windowsInaccuracy
+ }
duration := Now().Sub(start)
- if duration < delay {
+ if duration < delayadj {
t.Fatalf("Sleep(%s) slept for only %s", delay, duration)
}
}
@@ -74,26 +87,13 @@ func benchmark(b *testing.B, bench func(n int)) {
for i := 0; i < len(garbage); i++ {
garbage[i] = AfterFunc(Hour, nil)
}
-
- const batch = 1000
- P := runtime.GOMAXPROCS(-1)
- N := int32(b.N / batch)
-
b.ResetTimer()
- var wg sync.WaitGroup
- wg.Add(P)
-
- for p := 0; p < P; p++ {
- go func() {
- for atomic.AddInt32(&N, -1) >= 0 {
- bench(batch)
- }
- wg.Done()
- }()
- }
-
- wg.Wait()
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ bench(1000)
+ }
+ })
b.StopTimer()
for i := 0; i < len(garbage); i++ {
@@ -163,10 +163,14 @@ func TestAfter(t *testing.T) {
const delay = 100 * Millisecond
start := Now()
end := <-After(delay)
- if duration := Now().Sub(start); duration < delay {
+ delayadj := delay
+ if runtime.GOOS == "windows" {
+ delayadj -= windowsInaccuracy
+ }
+ if duration := Now().Sub(start); duration < delayadj {
t.Fatalf("After(%s) slept for only %d ns", delay, duration)
}
- if min := start.Add(delay); end.Before(min) {
+ if min := start.Add(delayadj); end.Before(min) {
t.Fatalf("After(%s) expect >= %s, got %s", delay, min, end)
}
}
@@ -361,19 +365,18 @@ func TestReset(t *testing.T) {
// Test that sleeping for an interval so large it overflows does not
// result in a short sleep duration.
func TestOverflowSleep(t *testing.T) {
- const timeout = 25 * Millisecond
const big = Duration(int64(1<<63 - 1))
select {
case <-After(big):
t.Fatalf("big timeout fired")
- case <-After(timeout):
+ case <-After(25 * Millisecond):
// OK
}
const neg = Duration(-1 << 63)
select {
case <-After(neg):
// OK
- case <-After(timeout):
+ case <-After(1 * Second):
t.Fatalf("negative timeout didn't fire")
}
}
@@ -399,7 +402,30 @@ func TestIssue5745(t *testing.T) {
}
func TestOverflowRuntimeTimer(t *testing.T) {
- if err := CheckRuntimeTimerOverflow(); err != nil {
- t.Fatalf(err.Error())
+ if testing.Short() {
+ t.Skip("skipping in short mode, see issue 6874")
+ }
+ // This may hang forever if timers are broken. See comment near
+ // the end of CheckRuntimeTimerOverflow in internal_test.go.
+ CheckRuntimeTimerOverflow()
+}
+
+func checkZeroPanicString(t *testing.T) {
+ e := recover()
+ s, _ := e.(string)
+ if want := "called on uninitialized Timer"; !strings.Contains(s, want) {
+ t.Errorf("panic = %v; want substring %q", e, want)
}
}
+
+func TestZeroTimerResetPanics(t *testing.T) {
+ defer checkZeroPanicString(t)
+ var tr Timer
+ tr.Reset(1)
+}
+
+func TestZeroTimerStopPanics(t *testing.T) {
+ defer checkZeroPanicString(t)
+ var tr Timer
+ tr.Stop()
+}
diff --git a/libgo/go/time/sys_unix.go b/libgo/go/time/sys_unix.go
index 60a3ce08f9..379e13d6a5 100644
--- a/libgo/go/time/sys_unix.go
+++ b/libgo/go/time/sys_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 netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package time
diff --git a/libgo/go/time/tick.go b/libgo/go/time/tick.go
index b92c339c02..19007841e1 100644
--- a/libgo/go/time/tick.go
+++ b/libgo/go/time/tick.go
@@ -17,6 +17,7 @@ type Ticker struct {
// time with a period specified by the duration argument.
// It adjusts the intervals or drops ticks to make up for slow receivers.
// The duration d must be greater than zero; if not, NewTicker will panic.
+// Stop the ticker to release associated resources.
func NewTicker(d Duration) *Ticker {
if d <= 0 {
panic(errors.New("non-positive interval for NewTicker"))
@@ -28,7 +29,7 @@ func NewTicker(d Duration) *Ticker {
t := &Ticker{
C: c,
r: runtimeTimer{
- when: nano() + int64(d),
+ when: when(d),
period: int64(d),
f: sendTime,
arg: c,
diff --git a/libgo/go/time/tick_test.go b/libgo/go/time/tick_test.go
index d8a086ceb2..32f4740ad9 100644
--- a/libgo/go/time/tick_test.go
+++ b/libgo/go/time/tick_test.go
@@ -48,6 +48,24 @@ func TestTeardown(t *testing.T) {
}
}
+// Test the Tick convenience wrapper.
+func TestTick(t *testing.T) {
+ // Test that giving a negative duration returns nil.
+ if got := Tick(-1); got != nil {
+ t.Errorf("Tick(-1) = %v; want nil", got)
+ }
+}
+
+// Test that NewTicker panics when given a duration less than zero.
+func TestNewTickerLtZeroDuration(t *testing.T) {
+ defer func() {
+ if err := recover(); err == nil {
+ t.Errorf("NewTicker(-1) should have panicked")
+ }
+ }()
+ NewTicker(-1)
+}
+
func BenchmarkTicker(b *testing.B) {
ticker := NewTicker(1)
b.ResetTimer()
diff --git a/libgo/go/time/time.go b/libgo/go/time/time.go
index c504df7401..0300e846a4 100644
--- a/libgo/go/time/time.go
+++ b/libgo/go/time/time.go
@@ -31,6 +31,11 @@ import "errors"
// change the instant in time being denoted and therefore does not affect the
// computations described in earlier paragraphs.
//
+// Note that the Go == operator compares not just the time instant but also the
+// Location. Therefore, Time values should not be used as map or database keys
+// without first guaranteeing that the identical Location has been set for all
+// values, which can be achieved through use of the UTC or Local method.
+//
type Time struct {
// sec gives the number of seconds elapsed since
// January 1, year 1 00:00:00 UTC.
@@ -39,14 +44,7 @@ type Time struct {
// nsec specifies a non-negative nanosecond
// offset within the second named by Seconds.
// It must be in the range [0, 999999999].
- //
- // It is declared as uintptr instead of int32 or uint32
- // to avoid garbage collector aliasing in the case where
- // on a 64-bit system the int32 or uint32 field is written
- // over the low half of a pointer, creating another pointer.
- // TODO(rsc): When the garbage collector is completely
- // precise, change back to int32.
- nsec uintptr
+ nsec int32
// loc specifies the Location that should be used to
// determine the minute, hour, month, day, and year
@@ -475,29 +473,28 @@ func (d Duration) String() string {
if u < uint64(Second) {
// Special case: if duration is smaller than a second,
// use smaller units, like 1.2ms
- var (
- prec int
- unit byte
- )
+ var prec int
+ w--
+ buf[w] = 's'
+ w--
switch {
case u == 0:
return "0"
case u < uint64(Microsecond):
// print nanoseconds
prec = 0
- unit = 'n'
+ buf[w] = 'n'
case u < uint64(Millisecond):
// print microseconds
prec = 3
- unit = 'u'
+ // U+00B5 'µ' micro sign == 0xC2 0xB5
+ w-- // Need room for two bytes.
+ copy(buf[w:], "µ")
default:
// print milliseconds
prec = 6
- unit = 'm'
+ buf[w] = 'm'
}
- w -= 2
- buf[w] = unit
- buf[w+1] = 's'
w, u = fmtFrac(buf[:w], u, prec)
w = fmtInt(buf[:w], u)
} else {
@@ -620,7 +617,7 @@ func (t Time) Add(d Duration) Time {
t.sec--
nsec += 1e9
}
- t.nsec = uintptr(nsec)
+ t.nsec = nsec
return t
}
@@ -783,7 +780,7 @@ func now() (sec int64, nsec int32)
// Now returns the current local time.
func Now() Time {
sec, nsec := now()
- return Time{sec + unixToInternal, uintptr(nsec), Local}
+ return Time{sec + unixToInternal, nsec, Local}
}
// UTC returns t with the location set to UTC.
@@ -900,7 +897,7 @@ func (t *Time) UnmarshalBinary(data []byte) error {
int64(buf[3])<<32 | int64(buf[2])<<40 | int64(buf[1])<<48 | int64(buf[0])<<56
buf = buf[8:]
- t.nsec = uintptr(int32(buf[3]) | int32(buf[2])<<8 | int32(buf[1])<<16 | int32(buf[0])<<24)
+ t.nsec = int32(buf[3]) | int32(buf[2])<<8 | int32(buf[1])<<16 | int32(buf[0])<<24
buf = buf[4:]
offset := int(int16(buf[1])|int16(buf[0])<<8) * 60
@@ -934,6 +931,8 @@ func (t *Time) GobDecode(data []byte) error {
// The time is a quoted string in RFC 3339 format, with sub-second precision added if present.
func (t Time) MarshalJSON() ([]byte, error) {
if y := t.Year(); y < 0 || y >= 10000 {
+ // RFC 3339 is clear that years are 4 digits exactly.
+ // See golang.org/issue/4556#c15 for more discussion.
return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]")
}
return []byte(t.Format(`"` + RFC3339Nano + `"`)), nil
@@ -977,7 +976,7 @@ func Unix(sec int64, nsec int64) Time {
sec--
}
}
- return Time{sec + unixToInternal, uintptr(nsec), Local}
+ return Time{sec + unixToInternal, int32(nsec), Local}
}
func isLeap(year int) bool {
@@ -1086,7 +1085,7 @@ func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) T
unix -= int64(offset)
}
- return Time{unix + unixToInternal, uintptr(nsec), loc}
+ return Time{unix + unixToInternal, int32(nsec), loc}
}
// Truncate returns the result of rounding t down to a multiple of d (since the zero time).
diff --git a/libgo/go/time/time_test.go b/libgo/go/time/time_test.go
index 53ae97ea0a..7e31dd78a9 100644
--- a/libgo/go/time/time_test.go
+++ b/libgo/go/time/time_test.go
@@ -12,8 +12,6 @@ import (
"math/big"
"math/rand"
"runtime"
- "strconv"
- "strings"
"testing"
"testing/quick"
. "time"
@@ -372,504 +370,6 @@ func TestTruncateRound(t *testing.T) {
quick.Check(f4, cfg)
}
-type TimeFormatTest struct {
- time Time
- formattedValue string
-}
-
-var rfc3339Formats = []TimeFormatTest{
- {Date(2008, 9, 17, 20, 4, 26, 0, UTC), "2008-09-17T20:04:26Z"},
- {Date(1994, 9, 17, 20, 4, 26, 0, FixedZone("EST", -18000)), "1994-09-17T20:04:26-05:00"},
- {Date(2000, 12, 26, 1, 15, 6, 0, FixedZone("OTO", 15600)), "2000-12-26T01:15:06+04:20"},
-}
-
-func TestRFC3339Conversion(t *testing.T) {
- for _, f := range rfc3339Formats {
- if f.time.Format(RFC3339) != f.formattedValue {
- t.Error("RFC3339:")
- t.Errorf(" want=%+v", f.formattedValue)
- t.Errorf(" have=%+v", f.time.Format(RFC3339))
- }
- }
-}
-
-type FormatTest struct {
- name string
- format string
- result string
-}
-
-var formatTests = []FormatTest{
- {"ANSIC", ANSIC, "Wed Feb 4 21:00:57 2009"},
- {"UnixDate", UnixDate, "Wed Feb 4 21:00:57 PST 2009"},
- {"RubyDate", RubyDate, "Wed Feb 04 21:00:57 -0800 2009"},
- {"RFC822", RFC822, "04 Feb 09 21:00 PST"},
- {"RFC850", RFC850, "Wednesday, 04-Feb-09 21:00:57 PST"},
- {"RFC1123", RFC1123, "Wed, 04 Feb 2009 21:00:57 PST"},
- {"RFC1123Z", RFC1123Z, "Wed, 04 Feb 2009 21:00:57 -0800"},
- {"RFC3339", RFC3339, "2009-02-04T21:00:57-08:00"},
- {"RFC3339Nano", RFC3339Nano, "2009-02-04T21:00:57.0123456-08:00"},
- {"Kitchen", Kitchen, "9:00PM"},
- {"am/pm", "3pm", "9pm"},
- {"AM/PM", "3PM", "9PM"},
- {"two-digit year", "06 01 02", "09 02 04"},
- // Three-letter months and days must not be followed by lower-case letter.
- {"Janet", "Hi Janet, the Month is January", "Hi Janet, the Month is February"},
- // Time stamps, Fractional seconds.
- {"Stamp", Stamp, "Feb 4 21:00:57"},
- {"StampMilli", StampMilli, "Feb 4 21:00:57.012"},
- {"StampMicro", StampMicro, "Feb 4 21:00:57.012345"},
- {"StampNano", StampNano, "Feb 4 21:00:57.012345600"},
-}
-
-func TestFormat(t *testing.T) {
- // The numeric time represents Thu Feb 4 21:00:57.012345600 PST 2010
- time := Unix(0, 1233810057012345600)
- for _, test := range formatTests {
- result := time.Format(test.format)
- if result != test.result {
- t.Errorf("%s expected %q got %q", test.name, test.result, result)
- }
- }
-}
-
-func TestFormatShortYear(t *testing.T) {
- years := []int{
- -100001, -100000, -99999,
- -10001, -10000, -9999,
- -1001, -1000, -999,
- -101, -100, -99,
- -11, -10, -9,
- -1, 0, 1,
- 9, 10, 11,
- 99, 100, 101,
- 999, 1000, 1001,
- 9999, 10000, 10001,
- 99999, 100000, 100001,
- }
-
- for _, y := range years {
- time := Date(y, January, 1, 0, 0, 0, 0, UTC)
- result := time.Format("2006.01.02")
- var want string
- if y < 0 {
- // The 4 in %04d counts the - sign, so print -y instead
- // and introduce our own - sign.
- want = fmt.Sprintf("-%04d.%02d.%02d", -y, 1, 1)
- } else {
- want = fmt.Sprintf("%04d.%02d.%02d", y, 1, 1)
- }
- if result != want {
- t.Errorf("(jan 1 %d).Format(\"2006.01.02\") = %q, want %q", y, result, want)
- }
- }
-}
-
-type ParseTest struct {
- name string
- format string
- value string
- hasTZ bool // contains a time zone
- hasWD bool // contains a weekday
- yearSign int // sign of year, -1 indicates the year is not present in the format
- fracDigits int // number of digits of fractional second
-}
-
-var parseTests = []ParseTest{
- {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0},
- {"UnixDate", UnixDate, "Thu Feb 4 21:00:57 PST 2010", true, true, 1, 0},
- {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1, 0},
- {"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57 PST", true, true, 1, 0},
- {"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57 PST", true, true, 1, 0},
- {"RFC1123", RFC1123, "Thu, 04 Feb 2010 22:00:57 PDT", true, true, 1, 0},
- {"RFC1123Z", RFC1123Z, "Thu, 04 Feb 2010 21:00:57 -0800", true, true, 1, 0},
- {"RFC3339", RFC3339, "2010-02-04T21:00:57-08:00", true, false, 1, 0},
- {"custom: \"2006-01-02 15:04:05-07\"", "2006-01-02 15:04:05-07", "2010-02-04 21:00:57-08", true, false, 1, 0},
- // Optional fractional seconds.
- {"ANSIC", ANSIC, "Thu Feb 4 21:00:57.0 2010", false, true, 1, 1},
- {"UnixDate", UnixDate, "Thu Feb 4 21:00:57.01 PST 2010", true, true, 1, 2},
- {"RubyDate", RubyDate, "Thu Feb 04 21:00:57.012 -0800 2010", true, true, 1, 3},
- {"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57.0123 PST", true, true, 1, 4},
- {"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57.01234 PST", true, true, 1, 5},
- {"RFC1123Z", RFC1123Z, "Thu, 04 Feb 2010 21:00:57.01234 -0800", true, true, 1, 5},
- {"RFC3339", RFC3339, "2010-02-04T21:00:57.012345678-08:00", true, false, 1, 9},
- {"custom: \"2006-01-02 15:04:05\"", "2006-01-02 15:04:05", "2010-02-04 21:00:57.0", false, false, 1, 0},
- // Amount of white space should not matter.
- {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0},
- {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0},
- // Case should not matter
- {"ANSIC", ANSIC, "THU FEB 4 21:00:57 2010", false, true, 1, 0},
- {"ANSIC", ANSIC, "thu feb 4 21:00:57 2010", false, true, 1, 0},
- // Fractional seconds.
- {"millisecond", "Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 21:00:57.012 2010", false, true, 1, 3},
- {"microsecond", "Mon Jan _2 15:04:05.000000 2006", "Thu Feb 4 21:00:57.012345 2010", false, true, 1, 6},
- {"nanosecond", "Mon Jan _2 15:04:05.000000000 2006", "Thu Feb 4 21:00:57.012345678 2010", false, true, 1, 9},
- // Leading zeros in other places should not be taken as fractional seconds.
- {"zero1", "2006.01.02.15.04.05.0", "2010.02.04.21.00.57.0", false, false, 1, 1},
- {"zero2", "2006.01.02.15.04.05.00", "2010.02.04.21.00.57.01", false, false, 1, 2},
- // Month and day names only match when not followed by a lower-case letter.
- {"Janet", "Hi Janet, the Month is January: Jan _2 15:04:05 2006", "Hi Janet, the Month is February: Feb 4 21:00:57 2010", false, true, 1, 0},
-
- // GMT with offset.
- {"GMT-8", UnixDate, "Fri Feb 5 05:00:57 GMT-8 2010", true, true, 1, 0},
-
- // Accept any number of fractional second digits (including none) for .999...
- // In Go 1, .999... was completely ignored in the format, meaning the first two
- // cases would succeed, but the next four would not. Go 1.1 accepts all six.
- {"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0},
- {"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0},
- {"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4},
- {"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4},
- {"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9},
- {"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9},
-
- // issue 4502.
- {"", StampNano, "Feb 4 21:00:57.012345678", false, false, -1, 9},
- {"", "Jan _2 15:04:05.999", "Feb 4 21:00:57.012300000", false, false, -1, 4},
- {"", "Jan _2 15:04:05.999", "Feb 4 21:00:57.012345678", false, false, -1, 9},
- {"", "Jan _2 15:04:05.999999999", "Feb 4 21:00:57.0123", false, false, -1, 4},
- {"", "Jan _2 15:04:05.999999999", "Feb 4 21:00:57.012345678", false, false, -1, 9},
-}
-
-func TestParse(t *testing.T) {
- for _, test := range parseTests {
- time, err := Parse(test.format, test.value)
- if err != nil {
- t.Errorf("%s error: %v", test.name, err)
- } else {
- checkTime(time, &test, t)
- }
- }
-}
-
-func TestParseInSydney(t *testing.T) {
- loc, err := LoadLocation("Australia/Sydney")
- if err != nil {
- t.Fatal(err)
- }
-
- // Check that Parse (and ParseInLocation) understand
- // that Feb EST and Aug EST are different time zones in Sydney
- // even though both are called EST.
- t1, err := ParseInLocation("Jan 02 2006 MST", "Feb 01 2013 EST", loc)
- if err != nil {
- t.Fatal(err)
- }
- t2 := Date(2013, February, 1, 00, 00, 00, 0, loc)
- if t1 != t2 {
- t.Fatalf("ParseInLocation(Feb 01 2013 EST, Sydney) = %v, want %v", t1, t2)
- }
- _, offset := t1.Zone()
- if offset != 11*60*60 {
- t.Fatalf("ParseInLocation(Feb 01 2013 EST, Sydney).Zone = _, %d, want _, %d", offset, 11*60*60)
- }
-
- t1, err = ParseInLocation("Jan 02 2006 MST", "Aug 01 2013 EST", loc)
- if err != nil {
- t.Fatal(err)
- }
- t2 = Date(2013, August, 1, 00, 00, 00, 0, loc)
- if t1 != t2 {
- t.Fatalf("ParseInLocation(Aug 01 2013 EST, Sydney) = %v, want %v", t1, t2)
- }
- _, offset = t1.Zone()
- if offset != 10*60*60 {
- t.Fatalf("ParseInLocation(Aug 01 2013 EST, Sydney).Zone = _, %d, want _, %d", offset, 10*60*60)
- }
-}
-
-func TestLoadLocationZipFile(t *testing.T) {
- t.Skip("gccgo does not use the zip file")
-
- ForceZipFileForTesting(true)
- defer ForceZipFileForTesting(false)
-
- _, err := LoadLocation("Australia/Sydney")
- if err != nil {
- t.Fatal(err)
- }
-}
-
-var rubyTests = []ParseTest{
- {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1, 0},
- // Ignore the time zone in the test. If it parses, it'll be OK.
- {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0000 2010", false, true, 1, 0},
- {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +0000 2010", false, true, 1, 0},
- {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +1130 2010", false, true, 1, 0},
-}
-
-// Problematic time zone format needs special tests.
-func TestRubyParse(t *testing.T) {
- for _, test := range rubyTests {
- time, err := Parse(test.format, test.value)
- if err != nil {
- t.Errorf("%s error: %v", test.name, err)
- } else {
- checkTime(time, &test, t)
- }
- }
-}
-
-func checkTime(time Time, test *ParseTest, t *testing.T) {
- // The time should be Thu Feb 4 21:00:57 PST 2010
- if test.yearSign >= 0 && test.yearSign*time.Year() != 2010 {
- t.Errorf("%s: bad year: %d not %d", test.name, time.Year(), 2010)
- }
- if time.Month() != February {
- t.Errorf("%s: bad month: %s not %s", test.name, time.Month(), February)
- }
- if time.Day() != 4 {
- t.Errorf("%s: bad day: %d not %d", test.name, time.Day(), 4)
- }
- if time.Hour() != 21 {
- t.Errorf("%s: bad hour: %d not %d", test.name, time.Hour(), 21)
- }
- if time.Minute() != 0 {
- t.Errorf("%s: bad minute: %d not %d", test.name, time.Minute(), 0)
- }
- if time.Second() != 57 {
- t.Errorf("%s: bad second: %d not %d", test.name, time.Second(), 57)
- }
- // Nanoseconds must be checked against the precision of the input.
- nanosec, err := strconv.ParseUint("012345678"[:test.fracDigits]+"000000000"[:9-test.fracDigits], 10, 0)
- if err != nil {
- panic(err)
- }
- if time.Nanosecond() != int(nanosec) {
- t.Errorf("%s: bad nanosecond: %d not %d", test.name, time.Nanosecond(), nanosec)
- }
- name, offset := time.Zone()
- if test.hasTZ && offset != -28800 {
- t.Errorf("%s: bad tz offset: %s %d not %d", test.name, name, offset, -28800)
- }
- if test.hasWD && time.Weekday() != Thursday {
- t.Errorf("%s: bad weekday: %s not %s", test.name, time.Weekday(), Thursday)
- }
-}
-
-func TestFormatAndParse(t *testing.T) {
- const fmt = "Mon MST " + RFC3339 // all fields
- f := func(sec int64) bool {
- t1 := Unix(sec, 0)
- if t1.Year() < 1000 || t1.Year() > 9999 {
- // not required to work
- return true
- }
- t2, err := Parse(fmt, t1.Format(fmt))
- if err != nil {
- t.Errorf("error: %s", err)
- return false
- }
- if t1.Unix() != t2.Unix() || t1.Nanosecond() != t2.Nanosecond() {
- t.Errorf("FormatAndParse %d: %q(%d) %q(%d)", sec, t1, t1.Unix(), t2, t2.Unix())
- return false
- }
- return true
- }
- f32 := func(sec int32) bool { return f(int64(sec)) }
- cfg := &quick.Config{MaxCount: 10000}
-
- // Try a reasonable date first, then the huge ones.
- if err := quick.Check(f32, cfg); err != nil {
- t.Fatal(err)
- }
- if err := quick.Check(f, cfg); err != nil {
- t.Fatal(err)
- }
-}
-
-type ParseTimeZoneTest struct {
- value string
- length int
- ok bool
-}
-
-var parseTimeZoneTests = []ParseTimeZoneTest{
- {"gmt hi there", 0, false},
- {"GMT hi there", 3, true},
- {"GMT+12 hi there", 6, true},
- {"GMT+00 hi there", 3, true}, // 0 or 00 is not a legal offset.
- {"GMT-5 hi there", 5, true},
- {"GMT-51 hi there", 3, true},
- {"ChST hi there", 4, true},
- {"MSDx", 3, true},
- {"MSDY", 0, false}, // four letters must end in T.
- {"ESAST hi", 5, true},
- {"ESASTT hi", 0, false}, // run of upper-case letters too long.
- {"ESATY hi", 0, false}, // five letters must end in T.
-}
-
-func TestParseTimeZone(t *testing.T) {
- for _, test := range parseTimeZoneTests {
- length, ok := ParseTimeZone(test.value)
- if ok != test.ok {
- t.Errorf("expected %t for %q got %t", test.ok, test.value, ok)
- } else if length != test.length {
- t.Errorf("expected %d for %q got %d", test.length, test.value, length)
- }
- }
-}
-
-type ParseErrorTest struct {
- format string
- value string
- expect string // must appear within the error
-}
-
-var parseErrorTests = []ParseErrorTest{
- {ANSIC, "Feb 4 21:00:60 2010", "cannot parse"}, // cannot parse Feb as Mon
- {ANSIC, "Thu Feb 4 21:00:57 @2010", "cannot parse"},
- {ANSIC, "Thu Feb 4 21:00:60 2010", "second out of range"},
- {ANSIC, "Thu Feb 4 21:61:57 2010", "minute out of range"},
- {ANSIC, "Thu Feb 4 24:00:60 2010", "hour out of range"},
- {"Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 23:00:59x01 2010", "cannot parse"},
- {"Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 23:00:59.xxx 2010", "cannot parse"},
- {"Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 23:00:59.-123 2010", "fractional second out of range"},
- // issue 4502. StampNano requires exactly 9 digits of precision.
- {StampNano, "Dec 7 11:22:01.000000", `cannot parse ".000000" as ".000000000"`},
- {StampNano, "Dec 7 11:22:01.0000000000", "extra text: 0"},
- // issue 4493. Helpful errors.
- {RFC3339, "2006-01-02T15:04:05Z07:00", `parsing time "2006-01-02T15:04:05Z07:00": extra text: 07:00`},
- {RFC3339, "2006-01-02T15:04_abc", `parsing time "2006-01-02T15:04_abc" as "2006-01-02T15:04:05Z07:00": cannot parse "_abc" as ":"`},
- {RFC3339, "2006-01-02T15:04:05_abc", `parsing time "2006-01-02T15:04:05_abc" as "2006-01-02T15:04:05Z07:00": cannot parse "_abc" as "Z07:00"`},
- {RFC3339, "2006-01-02T15:04:05Z_abc", `parsing time "2006-01-02T15:04:05Z_abc": extra text: _abc`},
-}
-
-func TestParseErrors(t *testing.T) {
- for _, test := range parseErrorTests {
- _, err := Parse(test.format, test.value)
- if err == nil {
- t.Errorf("expected error for %q %q", test.format, test.value)
- } else if strings.Index(err.Error(), test.expect) < 0 {
- t.Errorf("expected error with %q for %q %q; got %s", test.expect, test.format, test.value, err)
- }
- }
-}
-
-func TestNoonIs12PM(t *testing.T) {
- noon := Date(0, January, 1, 12, 0, 0, 0, UTC)
- const expect = "12:00PM"
- got := noon.Format("3:04PM")
- if got != expect {
- t.Errorf("got %q; expect %q", got, expect)
- }
- got = noon.Format("03:04PM")
- if got != expect {
- t.Errorf("got %q; expect %q", got, expect)
- }
-}
-
-func TestMidnightIs12AM(t *testing.T) {
- midnight := Date(0, January, 1, 0, 0, 0, 0, UTC)
- expect := "12:00AM"
- got := midnight.Format("3:04PM")
- if got != expect {
- t.Errorf("got %q; expect %q", got, expect)
- }
- got = midnight.Format("03:04PM")
- if got != expect {
- t.Errorf("got %q; expect %q", got, expect)
- }
-}
-
-func Test12PMIsNoon(t *testing.T) {
- noon, err := Parse("3:04PM", "12:00PM")
- if err != nil {
- t.Fatal("error parsing date:", err)
- }
- if noon.Hour() != 12 {
- t.Errorf("got %d; expect 12", noon.Hour())
- }
- noon, err = Parse("03:04PM", "12:00PM")
- if err != nil {
- t.Fatal("error parsing date:", err)
- }
- if noon.Hour() != 12 {
- t.Errorf("got %d; expect 12", noon.Hour())
- }
-}
-
-func Test12AMIsMidnight(t *testing.T) {
- midnight, err := Parse("3:04PM", "12:00AM")
- if err != nil {
- t.Fatal("error parsing date:", err)
- }
- if midnight.Hour() != 0 {
- t.Errorf("got %d; expect 0", midnight.Hour())
- }
- midnight, err = Parse("03:04PM", "12:00AM")
- if err != nil {
- t.Fatal("error parsing date:", err)
- }
- if midnight.Hour() != 0 {
- t.Errorf("got %d; expect 0", midnight.Hour())
- }
-}
-
-// Check that a time without a Zone still produces a (numeric) time zone
-// when formatted with MST as a requested zone.
-func TestMissingZone(t *testing.T) {
- time, err := Parse(RubyDate, "Thu Feb 02 16:10:03 -0500 2006")
- if err != nil {
- t.Fatal("error parsing date:", err)
- }
- expect := "Thu Feb 2 16:10:03 -0500 2006" // -0500 not EST
- str := time.Format(UnixDate) // uses MST as its time zone
- if str != expect {
- t.Errorf("got %s; expect %s", str, expect)
- }
-}
-
-func TestMinutesInTimeZone(t *testing.T) {
- time, err := Parse(RubyDate, "Mon Jan 02 15:04:05 +0123 2006")
- if err != nil {
- t.Fatal("error parsing date:", err)
- }
- expected := (1*60 + 23) * 60
- _, offset := time.Zone()
- if offset != expected {
- t.Errorf("ZoneOffset = %d, want %d", offset, expected)
- }
-}
-
-type SecondsTimeZoneOffsetTest struct {
- format string
- value string
- expectedoffset int
-}
-
-var secondsTimeZoneOffsetTests = []SecondsTimeZoneOffsetTest{
- {"2006-01-02T15:04:05-070000", "1871-01-01T05:33:02-003408", -(34*60 + 8)},
- {"2006-01-02T15:04:05-07:00:00", "1871-01-01T05:33:02-00:34:08", -(34*60 + 8)},
- {"2006-01-02T15:04:05-070000", "1871-01-01T05:33:02+003408", 34*60 + 8},
- {"2006-01-02T15:04:05-07:00:00", "1871-01-01T05:33:02+00:34:08", 34*60 + 8},
- {"2006-01-02T15:04:05Z070000", "1871-01-01T05:33:02-003408", -(34*60 + 8)},
- {"2006-01-02T15:04:05Z07:00:00", "1871-01-01T05:33:02+00:34:08", 34*60 + 8},
-}
-
-func TestParseSecondsInTimeZone(t *testing.T) {
- // should accept timezone offsets with seconds like: Zone America/New_York -4:56:02 - LMT 1883 Nov 18 12:03:58
- for _, test := range secondsTimeZoneOffsetTests {
- time, err := Parse(test.format, test.value)
- if err != nil {
- t.Fatal("error parsing date:", err)
- }
- _, offset := time.Zone()
- if offset != test.expectedoffset {
- t.Errorf("ZoneOffset = %d, want %d", offset, test.expectedoffset)
- }
- }
-}
-
-func TestFormatSecondsInTimeZone(t *testing.T) {
- d := Date(1871, 9, 17, 20, 4, 26, 0, FixedZone("LMT", -(34*60+8)))
- timestr := d.Format("2006-01-02T15:04:05Z070000")
- expected := "1871-09-17T20:04:26-003408"
- if timestr != expected {
- t.Errorf("Got %s, want %s", timestr, expected)
- }
-}
-
type ISOWeekTest struct {
year int // year
month, day int // month and day
@@ -1035,7 +535,7 @@ var durationTests = []struct {
}{
{"0", 0},
{"1ns", 1 * Nanosecond},
- {"1.1us", 1100 * Nanosecond},
+ {"1.1µs", 1100 * Nanosecond},
{"2.2ms", 2200 * Microsecond},
{"3.3s", 3300 * Millisecond},
{"4m5s", 4*Minute + 5*Second},
@@ -1342,6 +842,7 @@ var parseDurationTests = []struct {
{"-.", false, 0},
{".s", false, 0},
{"+.s", false, 0},
+ {"3000000h", false, 0}, // overflow
}
func TestParseDuration(t *testing.T) {
@@ -1463,6 +964,60 @@ func TestSub(t *testing.T) {
}
}
+var nsDurationTests = []struct {
+ d Duration
+ want int64
+}{
+ {Duration(-1000), -1000},
+ {Duration(-1), -1},
+ {Duration(1), 1},
+ {Duration(1000), 1000},
+}
+
+func TestDurationNanoseconds(t *testing.T) {
+ for _, tt := range nsDurationTests {
+ if got := tt.d.Nanoseconds(); got != tt.want {
+ t.Errorf("d.Nanoseconds() = %d; want: %d", got, tt.want)
+ }
+ }
+}
+
+var minDurationTests = []struct {
+ d Duration
+ want float64
+}{
+ {Duration(-60000000000), -1},
+ {Duration(-1), -1 / 60e9},
+ {Duration(1), 1 / 60e9},
+ {Duration(60000000000), 1},
+}
+
+func TestDurationMinutes(t *testing.T) {
+ for _, tt := range minDurationTests {
+ if got := tt.d.Minutes(); got != tt.want {
+ t.Errorf("d.Minutes() = %g; want: %g", got, tt.want)
+ }
+ }
+}
+
+var hourDurationTests = []struct {
+ d Duration
+ want float64
+}{
+ {Duration(-3600000000000), -1},
+ {Duration(-1), -1 / 3600e9},
+ {Duration(1), 1 / 3600e9},
+ {Duration(3600000000000), 1},
+}
+
+func TestDurationHours(t *testing.T) {
+ for _, tt := range hourDurationTests {
+ if got := tt.d.Hours(); got != tt.want {
+ t.Errorf("d.Hours() = %g; want: %g", got, tt.want)
+ }
+ }
+}
+
func BenchmarkNow(b *testing.B) {
for i := 0; i < b.N; i++ {
t = Now()
diff --git a/libgo/go/time/zoneinfo.go b/libgo/go/time/zoneinfo.go
index 1c6186258f..c8e53a27cf 100644
--- a/libgo/go/time/zoneinfo.go
+++ b/libgo/go/time/zoneinfo.go
@@ -45,6 +45,13 @@ type zoneTrans struct {
isstd, isutc bool // ignored - no idea what these mean
}
+// alpha and omega are the beginning and end of time for zone
+// transitions.
+const (
+ alpha = -1 << 63 // math.MinInt64
+ omega = 1<<63 - 1 // math.MaxInt64
+)
+
// UTC represents Universal Coordinated Time (UTC).
var UTC *Location = &utcLoc
@@ -83,9 +90,9 @@ func FixedZone(name string, offset int) *Location {
l := &Location{
name: name,
zone: []zone{{name, offset, false}},
- tx: []zoneTrans{{-1 << 63, 0, false, false}},
- cacheStart: -1 << 63,
- cacheEnd: 1<<63 - 1,
+ tx: []zoneTrans{{alpha, 0, false, false}},
+ cacheStart: alpha,
+ cacheEnd: omega,
}
l.cacheZone = &l.zone[0]
return l
@@ -101,12 +108,12 @@ func FixedZone(name string, offset int) *Location {
func (l *Location) lookup(sec int64) (name string, offset int, isDST bool, start, end int64) {
l = l.get()
- if len(l.tx) == 0 {
+ if len(l.zone) == 0 {
name = "UTC"
offset = 0
isDST = false
- start = -1 << 63
- end = 1<<63 - 1
+ start = alpha
+ end = omega
return
}
@@ -119,10 +126,24 @@ func (l *Location) lookup(sec int64) (name string, offset int, isDST bool, start
return
}
+ if len(l.tx) == 0 || sec < l.tx[0].when {
+ zone := &l.zone[l.lookupFirstZone()]
+ name = zone.name
+ offset = zone.offset
+ isDST = zone.isDST
+ start = alpha
+ if len(l.tx) > 0 {
+ end = l.tx[0].when
+ } else {
+ end = omega
+ }
+ return
+ }
+
// Binary search for entry with largest time <= sec.
// Not using sort.Search to avoid dependencies.
tx := l.tx
- end = 1<<63 - 1
+ end = omega
lo := 0
hi := len(tx)
for hi-lo > 1 {
@@ -144,6 +165,58 @@ func (l *Location) lookup(sec int64) (name string, offset int, isDST bool, start
return
}
+// lookupFirstZone returns the index of the time zone to use for times
+// before the first transition time, or when there are no transition
+// times.
+//
+// The reference implementation in localtime.c from
+// http://www.iana.org/time-zones/repository/releases/tzcode2013g.tar.gz
+// implements the following algorithm for these cases:
+// 1) If the first zone is unused by the transitions, use it.
+// 2) Otherwise, if there are transition times, and the first
+// transition is to a zone in daylight time, find the first
+// non-daylight-time zone before and closest to the first transition
+// zone.
+// 3) Otherwise, use the first zone that is not daylight time, if
+// there is one.
+// 4) Otherwise, use the first zone.
+func (l *Location) lookupFirstZone() int {
+ // Case 1.
+ if !l.firstZoneUsed() {
+ return 0
+ }
+
+ // Case 2.
+ if len(l.tx) > 0 && l.zone[l.tx[0].index].isDST {
+ for zi := int(l.tx[0].index) - 1; zi >= 0; zi-- {
+ if !l.zone[zi].isDST {
+ return zi
+ }
+ }
+ }
+
+ // Case 3.
+ for zi := range l.zone {
+ if !l.zone[zi].isDST {
+ return zi
+ }
+ }
+
+ // Case 4.
+ return 0
+}
+
+// firstZoneUsed returns whether the first zone is used by some
+// transition.
+func (l *Location) firstZoneUsed() bool {
+ for _, tx := range l.tx {
+ if tx.index == 0 {
+ return true
+ }
+ }
+ return false
+}
+
// lookupName returns information about the time zone with
// the given name (such as "EST") at the given pseudo-Unix time
// (what the given time of day would be in UTC).
diff --git a/libgo/go/time/zoneinfo_abbrs_windows.go b/libgo/go/time/zoneinfo_abbrs_windows.go
index 80334371fe..51a1a2f66d 100644
--- a/libgo/go/time/zoneinfo_abbrs_windows.go
+++ b/libgo/go/time/zoneinfo_abbrs_windows.go
@@ -18,6 +18,7 @@ var abbrs = map[string]abbr{
"South Africa Standard Time": {"SAST", "SAST"}, // Africa/Johannesburg
"W. Central Africa Standard Time": {"WAT", "WAT"}, // Africa/Lagos
"E. Africa Standard Time": {"EAT", "EAT"}, // Africa/Nairobi
+ "Libya Standard Time": {"EET", "EET"}, // Africa/Tripoli
"Namibia Standard Time": {"WAT", "WAST"}, // Africa/Windhoek
"Alaskan Standard Time": {"AKST", "AKDT"}, // America/Anchorage
"Paraguay Standard Time": {"PYT", "PYST"}, // America/Asuncion
@@ -63,7 +64,6 @@ var abbrs = map[string]abbr{
"Nepal Standard Time": {"NPT", "NPT"}, // Asia/Katmandu
"North Asia Standard Time": {"KRAT", "KRAT"}, // Asia/Krasnoyarsk
"Magadan Standard Time": {"MAGT", "MAGT"}, // Asia/Magadan
- "E. Europe Standard Time": {"EET", "EEST"}, // Asia/Nicosia
"N. Central Asia Standard Time": {"NOVT", "NOVT"}, // Asia/Novosibirsk
"Myanmar Standard Time": {"MMT", "MMT"}, // Asia/Rangoon
"Arab Standard Time": {"AST", "AST"}, // Asia/Riyadh
@@ -110,6 +110,7 @@ var abbrs = map[string]abbr{
"Fiji Standard Time": {"FJT", "FJT"}, // Pacific/Fiji
"Central Pacific Standard Time": {"SBT", "SBT"}, // Pacific/Guadalcanal
"Hawaiian Standard Time": {"HST", "HST"}, // Pacific/Honolulu
+ "Line Islands Standard Time": {"LINT", "LINT"}, // Pacific/Kiritimati
"West Pacific Standard Time": {"PGT", "PGT"}, // Pacific/Port_Moresby
"Tonga Standard Time": {"TOT", "TOT"}, // Pacific/Tongatapu
}
diff --git a/libgo/go/time/zoneinfo_plan9.go b/libgo/go/time/zoneinfo_plan9.go
index 0e8f3811be..4bb0cb3909 100644
--- a/libgo/go/time/zoneinfo_plan9.go
+++ b/libgo/go/time/zoneinfo_plan9.go
@@ -100,7 +100,7 @@ func loadZoneDataPlan9(s string) (l *Location, err error) {
for i := range tx {
if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) {
l.cacheStart = tx[i].when
- l.cacheEnd = 1<<63 - 1
+ l.cacheEnd = omega
if i+1 < len(tx) {
l.cacheEnd = tx[i+1].when
}
diff --git a/libgo/go/time/zoneinfo_read.go b/libgo/go/time/zoneinfo_read.go
index 7714aa9f58..de9ebb41c8 100644
--- a/libgo/go/time/zoneinfo_read.go
+++ b/libgo/go/time/zoneinfo_read.go
@@ -68,7 +68,7 @@ func loadZoneData(bytes []byte) (l *Location, err error) {
// 1-byte version, then 15 bytes of padding
var p []byte
- if p = d.read(16); len(p) != 16 || p[0] != 0 && p[0] != '2' {
+ if p = d.read(16); len(p) != 16 || p[0] != 0 && p[0] != '2' && p[0] != '3' {
return nil, badData
}
@@ -123,7 +123,7 @@ func loadZoneData(bytes []byte) (l *Location, err error) {
return nil, badData
}
- // If version == 2, the entire file repeats, this time using
+ // If version == 2 or 3, the entire file repeats, this time using
// 8-byte ints for txtimes and leap seconds.
// We won't need those until 2106.
@@ -173,7 +173,7 @@ func loadZoneData(bytes []byte) (l *Location, err error) {
if len(tx) == 0 {
// Build fake transition to cover all time.
// This happens in fixed locations like "Etc/GMT0".
- tx = append(tx, zoneTrans{when: -1 << 63, index: 0})
+ tx = append(tx, zoneTrans{when: alpha, index: 0})
}
// Committed to succeed.
@@ -185,7 +185,7 @@ func loadZoneData(bytes []byte) (l *Location, err error) {
for i := range tx {
if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) {
l.cacheStart = tx[i].when
- l.cacheEnd = 1<<63 - 1
+ l.cacheEnd = omega
if i+1 < len(tx) {
l.cacheEnd = tx[i+1].when
}
diff --git a/libgo/go/time/zoneinfo_test.go b/libgo/go/time/zoneinfo_test.go
new file mode 100644
index 0000000000..ede5330f5c
--- /dev/null
+++ b/libgo/go/time/zoneinfo_test.go
@@ -0,0 +1,66 @@
+// 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 time_test
+
+import (
+ "testing"
+ "time"
+)
+
+func TestVersion3(t *testing.T) {
+ t.Skip("gccgo does not use the zip file")
+ time.ForceZipFileForTesting(true)
+ defer time.ForceZipFileForTesting(false)
+ _, err := time.LoadLocation("Asia/Jerusalem")
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+// Test that we get the correct results for times before the first
+// transition time. To do this we explicitly check early dates in a
+// couple of specific timezones.
+func TestFirstZone(t *testing.T) {
+ t.Skip("gccgo does not use the zip file")
+
+ time.ForceZipFileForTesting(true)
+ defer time.ForceZipFileForTesting(false)
+
+ const format = "Mon, 02 Jan 2006 15:04:05 -0700 (MST)"
+ var tests = []struct {
+ zone string
+ unix int64
+ want1 string
+ want2 string
+ }{
+ {
+ "PST8PDT",
+ -1633269601,
+ "Sun, 31 Mar 1918 01:59:59 -0800 (PST)",
+ "Sun, 31 Mar 1918 03:00:00 -0700 (PDT)",
+ },
+ {
+ "Pacific/Fakaofo",
+ 1325242799,
+ "Thu, 29 Dec 2011 23:59:59 -1100 (TKT)",
+ "Sat, 31 Dec 2011 00:00:00 +1300 (TKT)",
+ },
+ }
+
+ for _, test := range tests {
+ z, err := time.LoadLocation(test.zone)
+ if err != nil {
+ t.Fatal(err)
+ }
+ s := time.Unix(test.unix, 0).In(z).Format(format)
+ if s != test.want1 {
+ t.Errorf("for %s %d got %q want %q", test.zone, test.unix, s, test.want1)
+ }
+ s = time.Unix(test.unix+1, 0).In(z).Format(format)
+ if s != test.want2 {
+ t.Errorf("for %s %d got %q want %q", test.zone, test.unix, s, test.want2)
+ }
+ }
+}
diff --git a/libgo/go/time/zoneinfo_unix.go b/libgo/go/time/zoneinfo_unix.go
index 1a4d115b93..3fe8e55795 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 netbsd openbsd
+// +build darwin 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.
diff --git a/libgo/go/time/zoneinfo_windows.go b/libgo/go/time/zoneinfo_windows.go
index be4e5c13ff..02d8e0edcc 100644
--- a/libgo/go/time/zoneinfo_windows.go
+++ b/libgo/go/time/zoneinfo_windows.go
@@ -11,6 +11,8 @@ import (
"unsafe"
)
+//go:generate go run genzabbrs.go -output zoneinfo_abbrs_windows.go
+
// TODO(rsc): Fall back to copy of zoneinfo files.
// BUG(brainman,rsc): On Windows, the operating system does not provide complete
@@ -54,7 +56,7 @@ func matchZoneKey(zones syscall.Handle, kname string, stdname, dstname string) (
if err != nil {
return false, err
}
- if s != dstname {
+ if s != dstname && dstname != stdname {
return false, nil
}
return true, nil
@@ -90,7 +92,7 @@ func toEnglishName(stdname, dstname string) (string, error) {
return "", errors.New(`English name for time zone "` + stdname + `" not found in registry`)
}
-// extractCAPS exracts capital letters from description desc.
+// extractCAPS extracts capital letters from description desc.
func extractCAPS(desc string) string {
var short []rune
for _, c := range desc {
@@ -165,8 +167,8 @@ func initLocalFromTZI(i *syscall.Timezoneinformation) {
if nzone == 1 {
// No daylight savings.
std.offset = -int(i.Bias) * 60
- l.cacheStart = -1 << 63
- l.cacheEnd = 1<<63 - 1
+ l.cacheStart = alpha
+ l.cacheEnd = omega
l.cacheZone = std
l.tx = make([]zoneTrans, 1)
l.tx[0].when = l.cacheStart
diff --git a/libgo/go/unicode/letter.go b/libgo/go/unicode/letter.go
index fadaa57d8b..7fe4241edd 100644
--- a/libgo/go/unicode/letter.go
+++ b/libgo/go/unicode/letter.go
@@ -6,6 +6,9 @@
// Unicode code points.
package unicode
+// Tables are regenerated each time we update the Unicode version.
+//go:generate go run maketables.go -tables=all -output tables.go
+
const (
MaxRune = '\U0010FFFF' // Maximum valid Unicode code point.
ReplacementChar = '\uFFFD' // Represents invalid code points.
@@ -74,7 +77,7 @@ const (
type d [MaxCase]rune // to make the CaseRanges text shorter
-// If the Delta field of a CaseRange is UpperLower or LowerUpper, it means
+// If the Delta field of a CaseRange is UpperLower, it means
// this CaseRange represents a sequence of the form (say)
// Upper Lower Upper Lower.
const (
@@ -316,7 +319,7 @@ type foldPair struct {
// SimpleFold iterates over Unicode code points equivalent under
// the Unicode-defined simple case folding. Among the code points
// equivalent to rune (including rune itself), SimpleFold returns the
-// smallest rune >= r if one exists, or else the smallest rune >= 0.
+// smallest rune > r if one exists, or else the smallest rune >= 0.
//
// For example:
// SimpleFold('A') = 'a'
diff --git a/libgo/go/unicode/letter_test.go b/libgo/go/unicode/letter_test.go
index e4d5572a0f..4ee11fb364 100644
--- a/libgo/go/unicode/letter_test.go
+++ b/libgo/go/unicode/letter_test.go
@@ -387,32 +387,20 @@ func TestTurkishCase(t *testing.T) {
}
var simpleFoldTests = []string{
- // SimpleFold could order its returned slices in any order it wants,
- // but we know it orders them in increasing order starting at in
- // and looping around from MaxRune to 0.
+ // SimpleFold(x) returns the next equivalent rune > x or wraps
+ // around to smaller values.
// Easy cases.
"Aa",
- "aA",
"δΔ",
- "Δδ",
// ASCII special cases.
"KkK",
- "kKK",
- "KKk",
"Ssſ",
- "sſS",
- "ſSs",
// Non-ASCII special cases.
"ρϱΡ",
- "ϱΡρ",
- "Ρρϱ",
"ͅΙιι",
- "Ιιιͅ",
- "ιιͅΙ",
- "ιͅΙι",
// Extra special cases: has lower/upper but no case fold.
"İ",
diff --git a/libgo/go/unicode/script_test.go b/libgo/go/unicode/script_test.go
index 395cc71a0b..795cb4e171 100644
--- a/libgo/go/unicode/script_test.go
+++ b/libgo/go/unicode/script_test.go
@@ -14,14 +14,15 @@ type T struct {
script string
}
-// Hand-chosen tests from Unicode 5.1.0, 6.0.0 and 6.2.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 and 7.0.0 mostly to
+// discover when new scripts and categories arise.
var inTest = []T{
{0x06e2, "Arabic"},
{0x0567, "Armenian"},
{0x10b20, "Avestan"},
{0x1b37, "Balinese"},
{0xa6af, "Bamum"},
+ {0x16ada, "Bassa_Vah"},
{0x1be1, "Batak"},
{0x09c2, "Bengali"},
{0x3115, "Bopomofo"},
@@ -31,6 +32,7 @@ var inTest = []T{
{0x11011, "Brahmi"},
{0x156d, "Canadian_Aboriginal"},
{0x102a9, "Carian"},
+ {0x10563, "Caucasian_Albanian"},
{0x11111, "Chakma"},
{0xaa4d, "Cham"},
{0x13c2, "Cherokee"},
@@ -42,11 +44,14 @@ var inTest = []T{
{0xa663, "Cyrillic"},
{0x10430, "Deseret"},
{0x094a, "Devanagari"},
+ {0x1BC00, "Duployan"},
{0x13001, "Egyptian_Hieroglyphs"},
+ {0x10500, "Elbasan"},
{0x1271, "Ethiopic"},
{0x10fc, "Georgian"},
{0x2c40, "Glagolitic"},
{0x10347, "Gothic"},
+ {0x11303, "Grantha"},
{0x03ae, "Greek"},
{0x0abf, "Gujarati"},
{0x0a24, "Gurmukhi"},
@@ -66,40 +71,56 @@ var inTest = []T{
{0xa928, "Kayah_Li"},
{0x10a11, "Kharoshthi"},
{0x17c6, "Khmer"},
+ {0x11211, "Khojki"},
+ {0x112df, "Khudawadi"},
{0x0eaa, "Lao"},
{0x1d79, "Latin"},
{0x1c10, "Lepcha"},
{0x1930, "Limbu"},
+ {0x10755, "Linear_A"},
{0x1003c, "Linear_B"},
{0xa4e1, "Lisu"},
{0x10290, "Lycian"},
{0x10930, "Lydian"},
+ {0x11173, "Mahajani"},
{0x0d42, "Malayalam"},
{0x0843, "Mandaic"},
+ {0x10ac8, "Manichaean"},
{0xabd0, "Meetei_Mayek"},
+ {0x1e800, "Mende_Kikakui"},
{0x1099f, "Meroitic_Hieroglyphs"},
{0x109a0, "Meroitic_Cursive"},
{0x16f00, "Miao"},
+ {0x11611, "Modi"},
{0x1822, "Mongolian"},
+ {0x16a60, "Mro"},
{0x104c, "Myanmar"},
+ {0x10880, "Nabataean"},
{0x19c3, "New_Tai_Lue"},
{0x07f8, "Nko"},
{0x169b, "Ogham"},
{0x1c6a, "Ol_Chiki"},
{0x10310, "Old_Italic"},
+ {0x10a80, "Old_North_Arabian"},
+ {0x10350, "Old_Permic"},
{0x103c9, "Old_Persian"},
{0x10a6f, "Old_South_Arabian"},
{0x10c20, "Old_Turkic"},
{0x0b3e, "Oriya"},
{0x10491, "Osmanya"},
+ {0x16b2b, "Pahawh_Hmong"},
+ {0x10876, "Palmyrene"},
+ {0x11ACE, "Pau_Cin_Hau"},
{0xa860, "Phags_Pa"},
{0x10918, "Phoenician"},
+ {0x10baf, "Psalter_Pahlavi"},
{0xa949, "Rejang"},
{0x16c0, "Runic"},
{0x081d, "Samaritan"},
{0xa892, "Saurashtra"},
{0x111a0, "Sharada"},
{0x10463, "Shavian"},
+ {0x115c1, "Siddham"},
{0x0dbd, "Sinhala"},
{0x110d0, "Sora_Sompeng"},
{0x1ba3, "Sundanese"},
@@ -117,8 +138,10 @@ var inTest = []T{
{0x0e46, "Thai"},
{0x0f36, "Tibetan"},
{0x2d55, "Tifinagh"},
+ {0x114d9, "Tirhuta"},
{0x10388, "Ugaritic"},
{0xa60e, "Vai"},
+ {0x118ff, "Warang_Citi"},
{0xa216, "Yi"},
}
@@ -182,7 +205,7 @@ var inPropTest = []T{
{0x0EC4, "Logical_Order_Exception"},
{0x2FFFF, "Noncharacter_Code_Point"},
{0x065E, "Other_Alphabetic"},
- {0x2069, "Other_Default_Ignorable_Code_Point"},
+ {0x2065, "Other_Default_Ignorable_Code_Point"},
{0x0BD7, "Other_Grapheme_Extend"},
{0x0387, "Other_ID_Continue"},
{0x212E, "Other_ID_Start"},
diff --git a/libgo/go/unicode/tables.go b/libgo/go/unicode/tables.go
index 939c41dc51..8b77dd6036 100644
--- a/libgo/go/unicode/tables.go
+++ b/libgo/go/unicode/tables.go
@@ -1,11 +1,15 @@
+// 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.
+
// Generated by running
-// maketables --tables=all --data=http://www.unicode.org/Public/6.2.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/6.2.0/ucd/CaseFolding.txt
+// 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
// DO NOT EDIT
package unicode
// Version is the Unicode edition from which the tables are derived.
-const Version = "6.2.0"
+const Version = "7.0.0"
// Categories is the set of Unicode category tables.
var Categories = map[string]*RangeTable{
@@ -52,19 +56,21 @@ var _C = &RangeTable{
{0x0001, 0x001f, 1},
{0x007f, 0x009f, 1},
{0x00ad, 0x0600, 1363},
- {0x0601, 0x0604, 1},
- {0x06dd, 0x070f, 50},
+ {0x0601, 0x0605, 1},
+ {0x061c, 0x06dd, 193},
+ {0x070f, 0x180e, 4351},
{0x200b, 0x200f, 1},
{0x202a, 0x202e, 1},
{0x2060, 0x2064, 1},
- {0x206a, 0x206f, 1},
+ {0x2066, 0x206f, 1},
{0xd800, 0xf8ff, 1},
{0xfeff, 0xfff9, 250},
{0xfffa, 0xfffb, 1},
},
R32: []Range32{
- {0x110bd, 0x1d173, 49334},
- {0x1d174, 0x1d17a, 1},
+ {0x110bd, 0x1bca0, 44003},
+ {0x1bca1, 0x1bca3, 1},
+ {0x1d173, 0x1d17a, 1},
{0xe0001, 0xe0020, 31},
{0xe0021, 0xe007f, 1},
{0xf0000, 0xffffd, 1},
@@ -84,18 +90,20 @@ var _Cc = &RangeTable{
var _Cf = &RangeTable{
R16: []Range16{
{0x00ad, 0x0600, 1363},
- {0x0601, 0x0604, 1},
- {0x06dd, 0x070f, 50},
+ {0x0601, 0x0605, 1},
+ {0x061c, 0x06dd, 193},
+ {0x070f, 0x180e, 4351},
{0x200b, 0x200f, 1},
{0x202a, 0x202e, 1},
{0x2060, 0x2064, 1},
- {0x206a, 0x206f, 1},
+ {0x2066, 0x206f, 1},
{0xfeff, 0xfff9, 250},
{0xfffa, 0xfffb, 1},
},
R32: []Range32{
- {0x110bd, 0x1d173, 49334},
- {0x1d174, 0x1d17a, 1},
+ {0x110bd, 0x1bca0, 44003},
+ {0x1bca1, 0x1bca3, 1},
+ {0x1d173, 0x1d17a, 1},
{0xe0001, 0xe0020, 31},
{0xe0021, 0xe007f, 1},
},
@@ -132,13 +140,13 @@ var _L = &RangeTable{
{0x0370, 0x0374, 1},
{0x0376, 0x0377, 1},
{0x037a, 0x037d, 1},
- {0x0386, 0x0388, 2},
- {0x0389, 0x038a, 1},
+ {0x037f, 0x0386, 7},
+ {0x0388, 0x038a, 1},
{0x038c, 0x038e, 2},
{0x038f, 0x03a1, 1},
{0x03a3, 0x03f5, 1},
{0x03f7, 0x0481, 1},
- {0x048a, 0x0527, 1},
+ {0x048a, 0x052f, 1},
{0x0531, 0x0556, 1},
{0x0559, 0x0561, 8},
{0x0562, 0x0587, 1},
@@ -162,13 +170,11 @@ var _L = &RangeTable{
{0x081a, 0x0824, 10},
{0x0828, 0x0840, 24},
{0x0841, 0x0858, 1},
- {0x08a0, 0x08a2, 2},
- {0x08a3, 0x08ac, 1},
+ {0x08a0, 0x08b2, 1},
{0x0904, 0x0939, 1},
{0x093d, 0x0950, 19},
{0x0958, 0x0961, 1},
- {0x0971, 0x0977, 1},
- {0x0979, 0x097f, 1},
+ {0x0971, 0x0980, 1},
{0x0985, 0x098c, 1},
{0x098f, 0x0990, 1},
{0x0993, 0x09a8, 1},
@@ -220,8 +226,7 @@ var _L = &RangeTable{
{0x0c06, 0x0c0c, 1},
{0x0c0e, 0x0c10, 1},
{0x0c12, 0x0c28, 1},
- {0x0c2a, 0x0c33, 1},
- {0x0c35, 0x0c39, 1},
+ {0x0c2a, 0x0c39, 1},
{0x0c3d, 0x0c58, 27},
{0x0c59, 0x0c60, 7},
{0x0c61, 0x0c85, 36},
@@ -300,6 +305,7 @@ var _L = &RangeTable{
{0x166f, 0x167f, 1},
{0x1681, 0x169a, 1},
{0x16a0, 0x16ea, 1},
+ {0x16f1, 0x16f8, 1},
{0x1700, 0x170c, 1},
{0x170e, 0x1711, 1},
{0x1720, 0x1731, 1},
@@ -312,7 +318,7 @@ var _L = &RangeTable{
{0x1880, 0x18a8, 1},
{0x18aa, 0x18b0, 6},
{0x18b1, 0x18f5, 1},
- {0x1900, 0x191c, 1},
+ {0x1900, 0x191e, 1},
{0x1950, 0x196d, 1},
{0x1970, 0x1974, 1},
{0x1980, 0x19ab, 1},
@@ -400,14 +406,14 @@ var _L = &RangeTable{
{0xa610, 0xa61f, 1},
{0xa62a, 0xa62b, 1},
{0xa640, 0xa66e, 1},
- {0xa67f, 0xa697, 1},
+ {0xa67f, 0xa69d, 1},
{0xa6a0, 0xa6e5, 1},
{0xa717, 0xa71f, 1},
{0xa722, 0xa788, 1},
{0xa78b, 0xa78e, 1},
- {0xa790, 0xa793, 1},
- {0xa7a0, 0xa7aa, 1},
- {0xa7f8, 0xa801, 1},
+ {0xa790, 0xa7ad, 1},
+ {0xa7b0, 0xa7b1, 1},
+ {0xa7f7, 0xa801, 1},
{0xa803, 0xa805, 1},
{0xa807, 0xa80a, 1},
{0xa80c, 0xa822, 1},
@@ -419,13 +425,16 @@ var _L = &RangeTable{
{0xa930, 0xa946, 1},
{0xa960, 0xa97c, 1},
{0xa984, 0xa9b2, 1},
- {0xa9cf, 0xaa00, 49},
- {0xaa01, 0xaa28, 1},
+ {0xa9cf, 0xa9e0, 17},
+ {0xa9e1, 0xa9e4, 1},
+ {0xa9e6, 0xa9ef, 1},
+ {0xa9fa, 0xa9fe, 1},
+ {0xaa00, 0xaa28, 1},
{0xaa40, 0xaa42, 1},
{0xaa44, 0xaa4b, 1},
{0xaa60, 0xaa76, 1},
- {0xaa7a, 0xaa80, 6},
- {0xaa81, 0xaaaf, 1},
+ {0xaa7a, 0xaa7e, 4},
+ {0xaa7f, 0xaaaf, 1},
{0xaab1, 0xaab5, 4},
{0xaab6, 0xaab9, 3},
{0xaaba, 0xaabd, 1},
@@ -438,6 +447,9 @@ var _L = &RangeTable{
{0xab11, 0xab16, 1},
{0xab20, 0xab26, 1},
{0xab28, 0xab2e, 1},
+ {0xab30, 0xab5a, 1},
+ {0xab5c, 0xab5f, 1},
+ {0xab64, 0xab65, 1},
{0xabc0, 0xabe2, 1},
{0xac00, 0xd7a3, 1},
{0xd7b0, 0xd7c6, 1},
@@ -478,19 +490,27 @@ var _L = &RangeTable{
{0x10080, 0x100fa, 1},
{0x10280, 0x1029c, 1},
{0x102a0, 0x102d0, 1},
- {0x10300, 0x1031e, 1},
+ {0x10300, 0x1031f, 1},
{0x10330, 0x10340, 1},
{0x10342, 0x10349, 1},
+ {0x10350, 0x10375, 1},
{0x10380, 0x1039d, 1},
{0x103a0, 0x103c3, 1},
{0x103c8, 0x103cf, 1},
{0x10400, 0x1049d, 1},
+ {0x10500, 0x10527, 1},
+ {0x10530, 0x10563, 1},
+ {0x10600, 0x10736, 1},
+ {0x10740, 0x10755, 1},
+ {0x10760, 0x10767, 1},
{0x10800, 0x10805, 1},
{0x10808, 0x1080a, 2},
{0x1080b, 0x10835, 1},
{0x10837, 0x10838, 1},
{0x1083c, 0x1083f, 3},
{0x10840, 0x10855, 1},
+ {0x10860, 0x10876, 1},
+ {0x10880, 0x1089e, 1},
{0x10900, 0x10915, 1},
{0x10920, 0x10939, 1},
{0x10980, 0x109b7, 1},
@@ -500,24 +520,61 @@ var _L = &RangeTable{
{0x10a15, 0x10a17, 1},
{0x10a19, 0x10a33, 1},
{0x10a60, 0x10a7c, 1},
+ {0x10a80, 0x10a9c, 1},
+ {0x10ac0, 0x10ac7, 1},
+ {0x10ac9, 0x10ae4, 1},
{0x10b00, 0x10b35, 1},
{0x10b40, 0x10b55, 1},
{0x10b60, 0x10b72, 1},
+ {0x10b80, 0x10b91, 1},
{0x10c00, 0x10c48, 1},
{0x11003, 0x11037, 1},
{0x11083, 0x110af, 1},
{0x110d0, 0x110e8, 1},
{0x11103, 0x11126, 1},
- {0x11183, 0x111b2, 1},
+ {0x11150, 0x11172, 1},
+ {0x11176, 0x11183, 13},
+ {0x11184, 0x111b2, 1},
{0x111c1, 0x111c4, 1},
- {0x11680, 0x116aa, 1},
- {0x12000, 0x1236e, 1},
+ {0x111da, 0x11200, 38},
+ {0x11201, 0x11211, 1},
+ {0x11213, 0x1122b, 1},
+ {0x112b0, 0x112de, 1},
+ {0x11305, 0x1130c, 1},
+ {0x1130f, 0x11310, 1},
+ {0x11313, 0x11328, 1},
+ {0x1132a, 0x11330, 1},
+ {0x11332, 0x11333, 1},
+ {0x11335, 0x11339, 1},
+ {0x1133d, 0x1135d, 32},
+ {0x1135e, 0x11361, 1},
+ {0x11480, 0x114af, 1},
+ {0x114c4, 0x114c5, 1},
+ {0x114c7, 0x11580, 185},
+ {0x11581, 0x115ae, 1},
+ {0x11600, 0x1162f, 1},
+ {0x11644, 0x11680, 60},
+ {0x11681, 0x116aa, 1},
+ {0x118a0, 0x118df, 1},
+ {0x118ff, 0x11ac0, 449},
+ {0x11ac1, 0x11af8, 1},
+ {0x12000, 0x12398, 1},
{0x13000, 0x1342e, 1},
{0x16800, 0x16a38, 1},
+ {0x16a40, 0x16a5e, 1},
+ {0x16ad0, 0x16aed, 1},
+ {0x16b00, 0x16b2f, 1},
+ {0x16b40, 0x16b43, 1},
+ {0x16b63, 0x16b77, 1},
+ {0x16b7d, 0x16b8f, 1},
{0x16f00, 0x16f44, 1},
{0x16f50, 0x16f93, 67},
{0x16f94, 0x16f9f, 1},
{0x1b000, 0x1b001, 1},
+ {0x1bc00, 0x1bc6a, 1},
+ {0x1bc70, 0x1bc7c, 1},
+ {0x1bc80, 0x1bc88, 1},
+ {0x1bc90, 0x1bc99, 1},
{0x1d400, 0x1d454, 1},
{0x1d456, 0x1d49c, 1},
{0x1d49e, 0x1d49f, 1},
@@ -548,6 +605,7 @@ var _L = &RangeTable{
{0x1d78a, 0x1d7a8, 1},
{0x1d7aa, 0x1d7c2, 1},
{0x1d7c4, 0x1d7cb, 1},
+ {0x1e800, 0x1e8c4, 1},
{0x1ee00, 0x1ee03, 1},
{0x1ee05, 0x1ee1f, 1},
{0x1ee21, 0x1ee22, 1},
@@ -631,7 +689,7 @@ var _Ll = &RangeTable{
{0x0461, 0x0481, 2},
{0x048b, 0x04bf, 2},
{0x04c2, 0x04ce, 2},
- {0x04cf, 0x0527, 2},
+ {0x04cf, 0x052f, 2},
{0x0561, 0x0587, 1},
{0x1d00, 0x1d2b, 1},
{0x1d6b, 0x1d77, 1},
@@ -678,7 +736,7 @@ var _Ll = &RangeTable{
{0x2d00, 0x2d25, 1},
{0x2d27, 0x2d2d, 6},
{0xa641, 0xa66d, 2},
- {0xa681, 0xa697, 2},
+ {0xa681, 0xa69b, 2},
{0xa723, 0xa72f, 2},
{0xa730, 0xa731, 1},
{0xa733, 0xa771, 2},
@@ -687,14 +745,18 @@ var _Ll = &RangeTable{
{0xa77f, 0xa787, 2},
{0xa78c, 0xa78e, 2},
{0xa791, 0xa793, 2},
- {0xa7a1, 0xa7a9, 2},
- {0xa7fa, 0xfb00, 21254},
- {0xfb01, 0xfb06, 1},
+ {0xa794, 0xa795, 1},
+ {0xa797, 0xa7a9, 2},
+ {0xa7fa, 0xab30, 822},
+ {0xab31, 0xab5a, 1},
+ {0xab64, 0xab65, 1},
+ {0xfb00, 0xfb06, 1},
{0xfb13, 0xfb17, 1},
{0xff41, 0xff5a, 1},
},
R32: []Range32{
{0x10428, 0x1044f, 1},
+ {0x118c0, 0x118df, 1},
{0x1d41a, 0x1d433, 1},
{0x1d44e, 0x1d454, 1},
{0x1d456, 0x1d467, 1},
@@ -759,15 +821,20 @@ var _Lm = &RangeTable{
{0xa015, 0xa4f8, 1251},
{0xa4f9, 0xa4fd, 1},
{0xa60c, 0xa67f, 115},
+ {0xa69c, 0xa69d, 1},
{0xa717, 0xa71f, 1},
{0xa770, 0xa788, 24},
{0xa7f8, 0xa7f9, 1},
- {0xa9cf, 0xaa70, 161},
- {0xaadd, 0xaaf3, 22},
- {0xaaf4, 0xff70, 21628},
- {0xff9e, 0xff9f, 1},
+ {0xa9cf, 0xa9e6, 23},
+ {0xaa70, 0xaadd, 109},
+ {0xaaf3, 0xaaf4, 1},
+ {0xab5c, 0xab5f, 1},
+ {0xff70, 0xff9e, 46},
+ {0xff9f, 0xff9f, 1},
},
R32: []Range32{
+ {0x16b40, 0x16b40, 1},
+ {0x16b41, 0x16b43, 1},
{0x16f93, 0x16f9f, 1},
},
}
@@ -794,13 +861,11 @@ var _Lo = &RangeTable{
{0x07cb, 0x07ea, 1},
{0x0800, 0x0815, 1},
{0x0840, 0x0858, 1},
- {0x08a0, 0x08a2, 2},
- {0x08a3, 0x08ac, 1},
+ {0x08a0, 0x08b2, 1},
{0x0904, 0x0939, 1},
{0x093d, 0x0950, 19},
{0x0958, 0x0961, 1},
- {0x0972, 0x0977, 1},
- {0x0979, 0x097f, 1},
+ {0x0972, 0x0980, 1},
{0x0985, 0x098c, 1},
{0x098f, 0x0990, 1},
{0x0993, 0x09a8, 1},
@@ -852,8 +917,7 @@ var _Lo = &RangeTable{
{0x0c06, 0x0c0c, 1},
{0x0c0e, 0x0c10, 1},
{0x0c12, 0x0c28, 1},
- {0x0c2a, 0x0c33, 1},
- {0x0c35, 0x0c39, 1},
+ {0x0c2a, 0x0c39, 1},
{0x0c3d, 0x0c58, 27},
{0x0c59, 0x0c60, 7},
{0x0c61, 0x0c85, 36},
@@ -929,6 +993,7 @@ var _Lo = &RangeTable{
{0x166f, 0x167f, 1},
{0x1681, 0x169a, 1},
{0x16a0, 0x16ea, 1},
+ {0x16f1, 0x16f8, 1},
{0x1700, 0x170c, 1},
{0x170e, 0x1711, 1},
{0x1720, 0x1731, 1},
@@ -942,7 +1007,7 @@ var _Lo = &RangeTable{
{0x1880, 0x18a8, 1},
{0x18aa, 0x18b0, 6},
{0x18b1, 0x18f5, 1},
- {0x1900, 0x191c, 1},
+ {0x1900, 0x191e, 1},
{0x1950, 0x196d, 1},
{0x1970, 0x1974, 1},
{0x1980, 0x19ab, 1},
@@ -990,7 +1055,8 @@ var _Lo = &RangeTable{
{0xa62a, 0xa62b, 1},
{0xa66e, 0xa6a0, 50},
{0xa6a1, 0xa6e5, 1},
- {0xa7fb, 0xa801, 1},
+ {0xa7f7, 0xa7fb, 4},
+ {0xa7fc, 0xa801, 1},
{0xa803, 0xa805, 1},
{0xa807, 0xa80a, 1},
{0xa80c, 0xa822, 1},
@@ -1002,13 +1068,16 @@ var _Lo = &RangeTable{
{0xa930, 0xa946, 1},
{0xa960, 0xa97c, 1},
{0xa984, 0xa9b2, 1},
+ {0xa9e0, 0xa9e4, 1},
+ {0xa9e7, 0xa9ef, 1},
+ {0xa9fa, 0xa9fe, 1},
{0xaa00, 0xaa28, 1},
{0xaa40, 0xaa42, 1},
{0xaa44, 0xaa4b, 1},
{0xaa60, 0xaa6f, 1},
{0xaa71, 0xaa76, 1},
- {0xaa7a, 0xaa80, 6},
- {0xaa81, 0xaaaf, 1},
+ {0xaa7a, 0xaa7e, 4},
+ {0xaa7f, 0xaaaf, 1},
{0xaab1, 0xaab5, 4},
{0xaab6, 0xaab9, 3},
{0xaaba, 0xaabd, 1},
@@ -1059,19 +1128,27 @@ var _Lo = &RangeTable{
{0x10080, 0x100fa, 1},
{0x10280, 0x1029c, 1},
{0x102a0, 0x102d0, 1},
- {0x10300, 0x1031e, 1},
+ {0x10300, 0x1031f, 1},
{0x10330, 0x10340, 1},
{0x10342, 0x10349, 1},
+ {0x10350, 0x10375, 1},
{0x10380, 0x1039d, 1},
{0x103a0, 0x103c3, 1},
{0x103c8, 0x103cf, 1},
{0x10450, 0x1049d, 1},
+ {0x10500, 0x10527, 1},
+ {0x10530, 0x10563, 1},
+ {0x10600, 0x10736, 1},
+ {0x10740, 0x10755, 1},
+ {0x10760, 0x10767, 1},
{0x10800, 0x10805, 1},
{0x10808, 0x1080a, 2},
{0x1080b, 0x10835, 1},
{0x10837, 0x10838, 1},
{0x1083c, 0x1083f, 3},
{0x10840, 0x10855, 1},
+ {0x10860, 0x10876, 1},
+ {0x10880, 0x1089e, 1},
{0x10900, 0x10915, 1},
{0x10920, 0x10939, 1},
{0x10980, 0x109b7, 1},
@@ -1081,24 +1158,60 @@ var _Lo = &RangeTable{
{0x10a15, 0x10a17, 1},
{0x10a19, 0x10a33, 1},
{0x10a60, 0x10a7c, 1},
+ {0x10a80, 0x10a9c, 1},
+ {0x10ac0, 0x10ac7, 1},
+ {0x10ac9, 0x10ae4, 1},
{0x10b00, 0x10b35, 1},
{0x10b40, 0x10b55, 1},
{0x10b60, 0x10b72, 1},
+ {0x10b80, 0x10b91, 1},
{0x10c00, 0x10c48, 1},
{0x11003, 0x11037, 1},
{0x11083, 0x110af, 1},
{0x110d0, 0x110e8, 1},
{0x11103, 0x11126, 1},
- {0x11183, 0x111b2, 1},
+ {0x11150, 0x11172, 1},
+ {0x11176, 0x11183, 13},
+ {0x11184, 0x111b2, 1},
{0x111c1, 0x111c4, 1},
- {0x11680, 0x116aa, 1},
- {0x12000, 0x1236e, 1},
+ {0x111da, 0x11200, 38},
+ {0x11201, 0x11211, 1},
+ {0x11213, 0x1122b, 1},
+ {0x112b0, 0x112de, 1},
+ {0x11305, 0x1130c, 1},
+ {0x1130f, 0x11310, 1},
+ {0x11313, 0x11328, 1},
+ {0x1132a, 0x11330, 1},
+ {0x11332, 0x11333, 1},
+ {0x11335, 0x11339, 1},
+ {0x1133d, 0x1135d, 32},
+ {0x1135e, 0x11361, 1},
+ {0x11480, 0x114af, 1},
+ {0x114c4, 0x114c5, 1},
+ {0x114c7, 0x11580, 185},
+ {0x11581, 0x115ae, 1},
+ {0x11600, 0x1162f, 1},
+ {0x11644, 0x11680, 60},
+ {0x11681, 0x116aa, 1},
+ {0x118ff, 0x11ac0, 449},
+ {0x11ac1, 0x11af8, 1},
+ {0x12000, 0x12398, 1},
{0x13000, 0x1342e, 1},
{0x16800, 0x16a38, 1},
+ {0x16a40, 0x16a5e, 1},
+ {0x16ad0, 0x16aed, 1},
+ {0x16b00, 0x16b2f, 1},
+ {0x16b63, 0x16b77, 1},
+ {0x16b7d, 0x16b8f, 1},
{0x16f00, 0x16f44, 1},
{0x16f50, 0x1b000, 16560},
- {0x1b001, 0x1ee00, 15871},
- {0x1ee01, 0x1ee03, 1},
+ {0x1b001, 0x1bc00, 3071},
+ {0x1bc01, 0x1bc6a, 1},
+ {0x1bc70, 0x1bc7c, 1},
+ {0x1bc80, 0x1bc88, 1},
+ {0x1bc90, 0x1bc99, 1},
+ {0x1e800, 0x1e8c4, 1},
+ {0x1ee00, 0x1ee03, 1},
{0x1ee05, 0x1ee1f, 1},
{0x1ee21, 0x1ee22, 1},
{0x1ee24, 0x1ee27, 3},
@@ -1179,8 +1292,9 @@ var _Lu = &RangeTable{
{0x0244, 0x0246, 1},
{0x0248, 0x024e, 2},
{0x0370, 0x0372, 2},
- {0x0376, 0x0386, 16},
- {0x0388, 0x038a, 1},
+ {0x0376, 0x037f, 9},
+ {0x0386, 0x0388, 2},
+ {0x0389, 0x038a, 1},
{0x038c, 0x038e, 2},
{0x038f, 0x0391, 2},
{0x0392, 0x03a1, 1},
@@ -1194,7 +1308,7 @@ var _Lu = &RangeTable{
{0x0460, 0x0480, 2},
{0x048a, 0x04c0, 2},
{0x04c1, 0x04cd, 2},
- {0x04d0, 0x0526, 2},
+ {0x04d0, 0x052e, 2},
{0x0531, 0x0556, 1},
{0x10a0, 0x10c5, 1},
{0x10c7, 0x10cd, 6},
@@ -1233,18 +1347,21 @@ var _Lu = &RangeTable{
{0x2ceb, 0x2ced, 2},
{0x2cf2, 0xa640, 31054},
{0xa642, 0xa66c, 2},
- {0xa680, 0xa696, 2},
+ {0xa680, 0xa69a, 2},
{0xa722, 0xa72e, 2},
{0xa732, 0xa76e, 2},
{0xa779, 0xa77d, 2},
{0xa77e, 0xa786, 2},
{0xa78b, 0xa78d, 2},
{0xa790, 0xa792, 2},
- {0xa7a0, 0xa7aa, 2},
+ {0xa796, 0xa7aa, 2},
+ {0xa7ab, 0xa7ad, 1},
+ {0xa7b0, 0xa7b1, 1},
{0xff21, 0xff3a, 1},
},
R32: []Range32{
{0x10400, 0x10427, 1},
+ {0x118a0, 0x118bf, 1},
{0x1d400, 0x1d419, 1},
{0x1d434, 0x1d44d, 1},
{0x1d468, 0x1d481, 1},
@@ -1303,8 +1420,7 @@ var _M = &RangeTable{
{0x0825, 0x0827, 1},
{0x0829, 0x082d, 1},
{0x0859, 0x085b, 1},
- {0x08e4, 0x08fe, 1},
- {0x0900, 0x0903, 1},
+ {0x08e4, 0x0903, 1},
{0x093a, 0x093c, 1},
{0x093e, 0x094f, 1},
{0x0951, 0x0957, 1},
@@ -1340,21 +1456,21 @@ var _M = &RangeTable{
{0x0bbf, 0x0bc2, 1},
{0x0bc6, 0x0bc8, 1},
{0x0bca, 0x0bcd, 1},
- {0x0bd7, 0x0c01, 42},
- {0x0c02, 0x0c03, 1},
+ {0x0bd7, 0x0c00, 41},
+ {0x0c01, 0x0c03, 1},
{0x0c3e, 0x0c44, 1},
{0x0c46, 0x0c48, 1},
{0x0c4a, 0x0c4d, 1},
{0x0c55, 0x0c56, 1},
{0x0c62, 0x0c63, 1},
- {0x0c82, 0x0c83, 1},
+ {0x0c81, 0x0c83, 1},
{0x0cbc, 0x0cbe, 2},
{0x0cbf, 0x0cc4, 1},
{0x0cc6, 0x0cc8, 1},
{0x0cca, 0x0ccd, 1},
{0x0cd5, 0x0cd6, 1},
{0x0ce2, 0x0ce3, 1},
- {0x0d02, 0x0d03, 1},
+ {0x0d01, 0x0d03, 1},
{0x0d3e, 0x0d44, 1},
{0x0d46, 0x0d48, 1},
{0x0d4a, 0x0d4d, 1},
@@ -1405,8 +1521,9 @@ var _M = &RangeTable{
{0x1a17, 0x1a1b, 1},
{0x1a55, 0x1a5e, 1},
{0x1a60, 0x1a7c, 1},
- {0x1a7f, 0x1b00, 129},
- {0x1b01, 0x1b04, 1},
+ {0x1a7f, 0x1ab0, 49},
+ {0x1ab1, 0x1abe, 1},
+ {0x1b00, 0x1b04, 1},
{0x1b34, 0x1b44, 1},
{0x1b6b, 0x1b73, 1},
{0x1b80, 0x1b82, 1},
@@ -1417,7 +1534,8 @@ var _M = &RangeTable{
{0x1cd4, 0x1ce8, 1},
{0x1ced, 0x1cf2, 5},
{0x1cf3, 0x1cf4, 1},
- {0x1dc0, 0x1de6, 1},
+ {0x1cf8, 0x1cf9, 1},
+ {0x1dc0, 0x1df5, 1},
{0x1dfc, 0x1dff, 1},
{0x20d0, 0x20f0, 1},
{0x2cef, 0x2cf1, 1},
@@ -1438,9 +1556,11 @@ var _M = &RangeTable{
{0xa947, 0xa953, 1},
{0xa980, 0xa983, 1},
{0xa9b3, 0xa9c0, 1},
- {0xaa29, 0xaa36, 1},
+ {0xa9e5, 0xaa29, 68},
+ {0xaa2a, 0xaa36, 1},
{0xaa43, 0xaa4c, 9},
{0xaa4d, 0xaa7b, 46},
+ {0xaa7c, 0xaa7d, 1},
{0xaab0, 0xaab2, 2},
{0xaab3, 0xaab4, 1},
{0xaab7, 0xaab8, 1},
@@ -1452,32 +1572,54 @@ var _M = &RangeTable{
{0xabec, 0xabed, 1},
{0xfb1e, 0xfe00, 738},
{0xfe01, 0xfe0f, 1},
- {0xfe20, 0xfe26, 1},
+ {0xfe20, 0xfe2d, 1},
},
R32: []Range32{
- {0x101fd, 0x10a01, 2052},
- {0x10a02, 0x10a03, 1},
+ {0x101fd, 0x102e0, 227},
+ {0x10376, 0x1037a, 1},
+ {0x10a01, 0x10a03, 1},
{0x10a05, 0x10a06, 1},
{0x10a0c, 0x10a0f, 1},
{0x10a38, 0x10a3a, 1},
- {0x10a3f, 0x11000, 1473},
+ {0x10a3f, 0x10ae5, 166},
+ {0x10ae6, 0x11000, 1306},
{0x11001, 0x11002, 1},
{0x11038, 0x11046, 1},
- {0x11080, 0x11082, 1},
+ {0x1107f, 0x11082, 1},
{0x110b0, 0x110ba, 1},
{0x11100, 0x11102, 1},
{0x11127, 0x11134, 1},
- {0x11180, 0x11182, 1},
+ {0x11173, 0x11180, 13},
+ {0x11181, 0x11182, 1},
{0x111b3, 0x111c0, 1},
+ {0x1122c, 0x11237, 1},
+ {0x112df, 0x112ea, 1},
+ {0x11301, 0x11303, 1},
+ {0x1133c, 0x1133e, 2},
+ {0x1133f, 0x11344, 1},
+ {0x11347, 0x11348, 1},
+ {0x1134b, 0x1134d, 1},
+ {0x11357, 0x11362, 11},
+ {0x11363, 0x11366, 3},
+ {0x11367, 0x1136c, 1},
+ {0x11370, 0x11374, 1},
+ {0x114b0, 0x114c3, 1},
+ {0x115af, 0x115b5, 1},
+ {0x115b8, 0x115c0, 1},
+ {0x11630, 0x11640, 1},
{0x116ab, 0x116b7, 1},
+ {0x16af0, 0x16af4, 1},
+ {0x16b30, 0x16b36, 1},
{0x16f51, 0x16f7e, 1},
{0x16f8f, 0x16f92, 1},
+ {0x1bc9d, 0x1bc9e, 1},
{0x1d165, 0x1d169, 1},
{0x1d16d, 0x1d172, 1},
{0x1d17b, 0x1d182, 1},
{0x1d185, 0x1d18b, 1},
{0x1d1aa, 0x1d1ad, 1},
{0x1d242, 0x1d244, 1},
+ {0x1e8d0, 0x1e8d6, 1},
{0xe0100, 0xe01ef, 1},
},
}
@@ -1545,7 +1687,7 @@ var _Mc = &RangeTable{
{0x1933, 0x1938, 1},
{0x19b0, 0x19c0, 1},
{0x19c8, 0x19c9, 1},
- {0x1a19, 0x1a1b, 1},
+ {0x1a19, 0x1a1a, 1},
{0x1a55, 0x1a57, 2},
{0x1a61, 0x1a63, 2},
{0x1a64, 0x1a6d, 9},
@@ -1556,8 +1698,7 @@ var _Mc = &RangeTable{
{0x1b43, 0x1b44, 1},
{0x1b82, 0x1ba1, 31},
{0x1ba6, 0x1ba7, 1},
- {0x1baa, 0x1bac, 2},
- {0x1bad, 0x1be7, 58},
+ {0x1baa, 0x1be7, 61},
{0x1bea, 0x1bec, 1},
{0x1bee, 0x1bf2, 4},
{0x1bf3, 0x1c24, 49},
@@ -1577,24 +1718,45 @@ var _Mc = &RangeTable{
{0xaa2f, 0xaa30, 1},
{0xaa33, 0xaa34, 1},
{0xaa4d, 0xaa7b, 46},
- {0xaaeb, 0xaaee, 3},
- {0xaaef, 0xaaf5, 6},
- {0xabe3, 0xabe4, 1},
- {0xabe6, 0xabe7, 1},
- {0xabe9, 0xabea, 1},
- {0xabec, 0xabec, 1},
+ {0xaa7d, 0xaaeb, 110},
+ {0xaaee, 0xaaef, 1},
+ {0xaaf5, 0xabe3, 238},
+ {0xabe4, 0xabe6, 2},
+ {0xabe7, 0xabe9, 2},
+ {0xabea, 0xabec, 2},
},
R32: []Range32{
- {0x11000, 0x11000, 1},
- {0x11002, 0x11082, 128},
- {0x110b0, 0x110b2, 1},
+ {0x11000, 0x11002, 2},
+ {0x11082, 0x110b0, 46},
+ {0x110b1, 0x110b2, 1},
{0x110b7, 0x110b8, 1},
{0x1112c, 0x11182, 86},
{0x111b3, 0x111b5, 1},
{0x111bf, 0x111c0, 1},
- {0x116ac, 0x116ae, 2},
- {0x116af, 0x116b6, 7},
- {0x16f51, 0x16f7e, 1},
+ {0x1122c, 0x1122e, 1},
+ {0x11232, 0x11233, 1},
+ {0x11235, 0x112e0, 171},
+ {0x112e1, 0x112e2, 1},
+ {0x11302, 0x11303, 1},
+ {0x1133e, 0x1133f, 1},
+ {0x11341, 0x11344, 1},
+ {0x11347, 0x11348, 1},
+ {0x1134b, 0x1134d, 1},
+ {0x11357, 0x11362, 11},
+ {0x11363, 0x114b0, 333},
+ {0x114b1, 0x114b2, 1},
+ {0x114b9, 0x114bb, 2},
+ {0x114bc, 0x114be, 1},
+ {0x114c1, 0x115af, 238},
+ {0x115b0, 0x115b1, 1},
+ {0x115b8, 0x115bb, 1},
+ {0x115be, 0x11630, 114},
+ {0x11631, 0x11632, 1},
+ {0x1163b, 0x1163c, 1},
+ {0x1163e, 0x116ac, 110},
+ {0x116ae, 0x116af, 1},
+ {0x116b6, 0x16f51, 22683},
+ {0x16f52, 0x16f7e, 1},
{0x1d165, 0x1d166, 1},
{0x1d16d, 0x1d172, 1},
},
@@ -1603,7 +1765,8 @@ var _Mc = &RangeTable{
var _Me = &RangeTable{
R16: []Range16{
{0x0488, 0x0489, 1},
- {0x20dd, 0x20e0, 1},
+ {0x1abe, 0x20dd, 1567},
+ {0x20de, 0x20e0, 1},
{0x20e2, 0x20e4, 1},
{0xa670, 0xa672, 1},
},
@@ -1633,8 +1796,7 @@ var _Mn = &RangeTable{
{0x0825, 0x0827, 1},
{0x0829, 0x082d, 1},
{0x0859, 0x085b, 1},
- {0x08e4, 0x08fe, 1},
- {0x0900, 0x0902, 1},
+ {0x08e4, 0x0902, 1},
{0x093a, 0x093c, 2},
{0x0941, 0x0948, 1},
{0x094d, 0x0951, 4},
@@ -1661,16 +1823,17 @@ var _Mn = &RangeTable{
{0x0b4d, 0x0b56, 9},
{0x0b62, 0x0b63, 1},
{0x0b82, 0x0bc0, 62},
- {0x0bcd, 0x0c3e, 113},
- {0x0c3f, 0x0c40, 1},
+ {0x0bcd, 0x0c00, 51},
+ {0x0c3e, 0x0c40, 1},
{0x0c46, 0x0c48, 1},
{0x0c4a, 0x0c4d, 1},
{0x0c55, 0x0c56, 1},
{0x0c62, 0x0c63, 1},
- {0x0cbc, 0x0cbf, 3},
- {0x0cc6, 0x0ccc, 6},
- {0x0ccd, 0x0ce2, 21},
- {0x0ce3, 0x0d41, 94},
+ {0x0c81, 0x0cbc, 59},
+ {0x0cbf, 0x0cc6, 7},
+ {0x0ccc, 0x0ccd, 1},
+ {0x0ce2, 0x0ce3, 1},
+ {0x0d01, 0x0d41, 64},
{0x0d42, 0x0d44, 1},
{0x0d4d, 0x0d62, 21},
{0x0d63, 0x0dca, 103},
@@ -1717,13 +1880,14 @@ var _Mn = &RangeTable{
{0x1932, 0x1939, 7},
{0x193a, 0x193b, 1},
{0x1a17, 0x1a18, 1},
- {0x1a56, 0x1a58, 2},
- {0x1a59, 0x1a5e, 1},
+ {0x1a1b, 0x1a56, 59},
+ {0x1a58, 0x1a5e, 1},
{0x1a60, 0x1a62, 2},
{0x1a65, 0x1a6c, 1},
{0x1a73, 0x1a7c, 1},
- {0x1a7f, 0x1b00, 129},
- {0x1b01, 0x1b03, 1},
+ {0x1a7f, 0x1ab0, 49},
+ {0x1ab1, 0x1abd, 1},
+ {0x1b00, 0x1b03, 1},
{0x1b34, 0x1b36, 2},
{0x1b37, 0x1b3a, 1},
{0x1b3c, 0x1b42, 6},
@@ -1731,17 +1895,18 @@ var _Mn = &RangeTable{
{0x1b80, 0x1b81, 1},
{0x1ba2, 0x1ba5, 1},
{0x1ba8, 0x1ba9, 1},
- {0x1bab, 0x1be6, 59},
- {0x1be8, 0x1be9, 1},
- {0x1bed, 0x1bef, 2},
- {0x1bf0, 0x1bf1, 1},
+ {0x1bab, 0x1bad, 1},
+ {0x1be6, 0x1be8, 2},
+ {0x1be9, 0x1bed, 4},
+ {0x1bef, 0x1bf1, 1},
{0x1c2c, 0x1c33, 1},
{0x1c36, 0x1c37, 1},
{0x1cd0, 0x1cd2, 1},
{0x1cd4, 0x1ce0, 1},
{0x1ce2, 0x1ce8, 1},
{0x1ced, 0x1cf4, 7},
- {0x1dc0, 0x1de6, 1},
+ {0x1cf8, 0x1cf9, 1},
+ {0x1dc0, 0x1df5, 1},
{0x1dfc, 0x1dff, 1},
{0x20d0, 0x20dc, 1},
{0x20e1, 0x20e5, 4},
@@ -1764,13 +1929,13 @@ var _Mn = &RangeTable{
{0xa980, 0xa982, 1},
{0xa9b3, 0xa9b6, 3},
{0xa9b7, 0xa9b9, 1},
- {0xa9bc, 0xaa29, 109},
- {0xaa2a, 0xaa2e, 1},
+ {0xa9bc, 0xa9e5, 41},
+ {0xaa29, 0xaa2e, 1},
{0xaa31, 0xaa32, 1},
{0xaa35, 0xaa36, 1},
{0xaa43, 0xaa4c, 9},
- {0xaab0, 0xaab2, 2},
- {0xaab3, 0xaab4, 1},
+ {0xaa7c, 0xaab0, 52},
+ {0xaab2, 0xaab4, 1},
{0xaab7, 0xaab8, 1},
{0xaabe, 0xaabf, 1},
{0xaac1, 0xaaec, 43},
@@ -1778,33 +1943,58 @@ var _Mn = &RangeTable{
{0xabe5, 0xabe8, 3},
{0xabed, 0xfb1e, 20273},
{0xfe00, 0xfe0f, 1},
- {0xfe20, 0xfe26, 1},
+ {0xfe20, 0xfe2d, 1},
},
R32: []Range32{
- {0x101fd, 0x10a01, 2052},
- {0x10a02, 0x10a03, 1},
+ {0x101fd, 0x102e0, 227},
+ {0x10376, 0x1037a, 1},
+ {0x10a01, 0x10a03, 1},
{0x10a05, 0x10a06, 1},
{0x10a0c, 0x10a0f, 1},
{0x10a38, 0x10a3a, 1},
- {0x10a3f, 0x11001, 1474},
+ {0x10a3f, 0x10ae5, 166},
+ {0x10ae6, 0x11001, 1307},
{0x11038, 0x11046, 1},
- {0x11080, 0x11081, 1},
+ {0x1107f, 0x11081, 1},
{0x110b3, 0x110b6, 1},
{0x110b9, 0x110ba, 1},
{0x11100, 0x11102, 1},
{0x11127, 0x1112b, 1},
{0x1112d, 0x11134, 1},
- {0x11180, 0x11181, 1},
- {0x111b6, 0x111be, 1},
- {0x116ab, 0x116ad, 2},
- {0x116b0, 0x116b5, 1},
- {0x116b7, 0x16f8f, 22744},
- {0x16f90, 0x16f92, 1},
+ {0x11173, 0x11180, 13},
+ {0x11181, 0x111b6, 53},
+ {0x111b7, 0x111be, 1},
+ {0x1122f, 0x11231, 1},
+ {0x11234, 0x11236, 2},
+ {0x11237, 0x112df, 168},
+ {0x112e3, 0x112ea, 1},
+ {0x11301, 0x1133c, 59},
+ {0x11340, 0x11366, 38},
+ {0x11367, 0x1136c, 1},
+ {0x11370, 0x11374, 1},
+ {0x114b3, 0x114b8, 1},
+ {0x114ba, 0x114bf, 5},
+ {0x114c0, 0x114c2, 2},
+ {0x114c3, 0x115b2, 239},
+ {0x115b3, 0x115b5, 1},
+ {0x115bc, 0x115bd, 1},
+ {0x115bf, 0x115c0, 1},
+ {0x11633, 0x1163a, 1},
+ {0x1163d, 0x1163f, 2},
+ {0x11640, 0x116ab, 107},
+ {0x116ad, 0x116b0, 3},
+ {0x116b1, 0x116b5, 1},
+ {0x116b7, 0x16af0, 21561},
+ {0x16af1, 0x16af4, 1},
+ {0x16b30, 0x16b36, 1},
+ {0x16f8f, 0x16f92, 1},
+ {0x1bc9d, 0x1bc9e, 1},
{0x1d167, 0x1d169, 1},
{0x1d17b, 0x1d182, 1},
{0x1d185, 0x1d18b, 1},
{0x1d1aa, 0x1d1ad, 1},
{0x1d242, 0x1d244, 1},
+ {0x1e8d0, 0x1e8d6, 1},
{0xe0100, 0xe01ef, 1},
},
}
@@ -1830,6 +2020,7 @@ var _N = &RangeTable{
{0x0c78, 0x0c7e, 1},
{0x0ce6, 0x0cef, 1},
{0x0d66, 0x0d75, 1},
+ {0x0de6, 0x0def, 1},
{0x0e50, 0x0e59, 1},
{0x0ed0, 0x0ed9, 1},
{0x0f20, 0x0f33, 1},
@@ -1871,6 +2062,7 @@ var _N = &RangeTable{
{0xa8d0, 0xa8d9, 1},
{0xa900, 0xa909, 1},
{0xa9d0, 0xa9d9, 1},
+ {0xa9f0, 0xa9f9, 1},
{0xaa50, 0xaa59, 1},
{0xabf0, 0xabf9, 1},
{0xff10, 0xff19, 1},
@@ -1878,27 +2070,42 @@ var _N = &RangeTable{
R32: []Range32{
{0x10107, 0x10133, 1},
{0x10140, 0x10178, 1},
- {0x1018a, 0x10320, 406},
- {0x10321, 0x10323, 1},
+ {0x1018a, 0x1018b, 1},
+ {0x102e1, 0x102fb, 1},
+ {0x10320, 0x10323, 1},
{0x10341, 0x1034a, 9},
{0x103d1, 0x103d5, 1},
{0x104a0, 0x104a9, 1},
{0x10858, 0x1085f, 1},
+ {0x10879, 0x1087f, 1},
+ {0x108a7, 0x108af, 1},
{0x10916, 0x1091b, 1},
{0x10a40, 0x10a47, 1},
{0x10a7d, 0x10a7e, 1},
+ {0x10a9d, 0x10a9f, 1},
+ {0x10aeb, 0x10aef, 1},
{0x10b58, 0x10b5f, 1},
{0x10b78, 0x10b7f, 1},
+ {0x10ba9, 0x10baf, 1},
{0x10e60, 0x10e7e, 1},
{0x11052, 0x1106f, 1},
{0x110f0, 0x110f9, 1},
{0x11136, 0x1113f, 1},
{0x111d0, 0x111d9, 1},
+ {0x111e1, 0x111f4, 1},
+ {0x112f0, 0x112f9, 1},
+ {0x114d0, 0x114d9, 1},
+ {0x11650, 0x11659, 1},
{0x116c0, 0x116c9, 1},
- {0x12400, 0x12462, 1},
+ {0x118e0, 0x118f2, 1},
+ {0x12400, 0x1246e, 1},
+ {0x16a60, 0x16a69, 1},
+ {0x16b50, 0x16b59, 1},
+ {0x16b5b, 0x16b61, 1},
{0x1d360, 0x1d371, 1},
{0x1d7ce, 0x1d7ff, 1},
- {0x1f100, 0x1f10a, 1},
+ {0x1e8c7, 0x1e8cf, 1},
+ {0x1f100, 0x1f10c, 1},
},
LatinOffset: 4,
}
@@ -1918,6 +2125,7 @@ var _Nd = &RangeTable{
{0x0c66, 0x0c6f, 1},
{0x0ce6, 0x0cef, 1},
{0x0d66, 0x0d6f, 1},
+ {0x0de6, 0x0def, 1},
{0x0e50, 0x0e59, 1},
{0x0ed0, 0x0ed9, 1},
{0x0f20, 0x0f29, 1},
@@ -1937,6 +2145,7 @@ var _Nd = &RangeTable{
{0xa8d0, 0xa8d9, 1},
{0xa900, 0xa909, 1},
{0xa9d0, 0xa9d9, 1},
+ {0xa9f0, 0xa9f9, 1},
{0xaa50, 0xaa59, 1},
{0xabf0, 0xabf9, 1},
{0xff10, 0xff19, 1},
@@ -1947,7 +2156,13 @@ var _Nd = &RangeTable{
{0x110f0, 0x110f9, 1},
{0x11136, 0x1113f, 1},
{0x111d0, 0x111d9, 1},
+ {0x112f0, 0x112f9, 1},
+ {0x114d0, 0x114d9, 1},
+ {0x11650, 0x11659, 1},
{0x116c0, 0x116c9, 1},
+ {0x118e0, 0x118e9, 1},
+ {0x16a60, 0x16a69, 1},
+ {0x16b50, 0x16b59, 1},
{0x1d7ce, 0x1d7ff, 1},
},
LatinOffset: 1,
@@ -1967,7 +2182,7 @@ var _Nl = &RangeTable{
{0x10140, 0x10174, 1},
{0x10341, 0x1034a, 9},
{0x103d1, 0x103d5, 1},
- {0x12400, 0x12462, 1},
+ {0x12400, 0x1246e, 1},
},
}
@@ -2004,18 +2219,28 @@ var _No = &RangeTable{
R32: []Range32{
{0x10107, 0x10133, 1},
{0x10175, 0x10178, 1},
- {0x1018a, 0x10320, 406},
- {0x10321, 0x10323, 1},
+ {0x1018a, 0x1018b, 1},
+ {0x102e1, 0x102fb, 1},
+ {0x10320, 0x10323, 1},
{0x10858, 0x1085f, 1},
+ {0x10879, 0x1087f, 1},
+ {0x108a7, 0x108af, 1},
{0x10916, 0x1091b, 1},
{0x10a40, 0x10a47, 1},
{0x10a7d, 0x10a7e, 1},
+ {0x10a9d, 0x10a9f, 1},
+ {0x10aeb, 0x10aef, 1},
{0x10b58, 0x10b5f, 1},
{0x10b78, 0x10b7f, 1},
+ {0x10ba9, 0x10baf, 1},
{0x10e60, 0x10e7e, 1},
{0x11052, 0x11065, 1},
+ {0x111e1, 0x111f4, 1},
+ {0x118ea, 0x118f2, 1},
+ {0x16b5b, 0x16b61, 1},
{0x1d360, 0x1d371, 1},
- {0x1f100, 0x1f10a, 1},
+ {0x1e8c7, 0x1e8cf, 1},
+ {0x1f100, 0x1f10c, 1},
},
LatinOffset: 3,
}
@@ -2086,6 +2311,7 @@ var _P = &RangeTable{
{0x2053, 0x205e, 1},
{0x207d, 0x207e, 1},
{0x208d, 0x208e, 1},
+ {0x2308, 0x230b, 1},
{0x2329, 0x232a, 1},
{0x2768, 0x2775, 1},
{0x27c5, 0x27c6, 1},
@@ -2097,7 +2323,7 @@ var _P = &RangeTable{
{0x2cfe, 0x2cff, 1},
{0x2d70, 0x2e00, 144},
{0x2e01, 0x2e2e, 1},
- {0x2e30, 0x2e3b, 1},
+ {0x2e30, 0x2e42, 1},
{0x3001, 0x3003, 1},
{0x3008, 0x3011, 1},
{0x3014, 0x301f, 1},
@@ -2137,17 +2363,29 @@ var _P = &RangeTable{
R32: []Range32{
{0x10100, 0x10102, 1},
{0x1039f, 0x103d0, 49},
- {0x10857, 0x1091f, 200},
- {0x1093f, 0x10a50, 273},
- {0x10a51, 0x10a58, 1},
- {0x10a7f, 0x10b39, 186},
- {0x10b3a, 0x10b3f, 1},
+ {0x1056f, 0x10857, 744},
+ {0x1091f, 0x1093f, 32},
+ {0x10a50, 0x10a58, 1},
+ {0x10a7f, 0x10af0, 113},
+ {0x10af1, 0x10af6, 1},
+ {0x10b39, 0x10b3f, 1},
+ {0x10b99, 0x10b9c, 1},
{0x11047, 0x1104d, 1},
{0x110bb, 0x110bc, 1},
{0x110be, 0x110c1, 1},
{0x11140, 0x11143, 1},
+ {0x11174, 0x11175, 1},
{0x111c5, 0x111c8, 1},
- {0x12470, 0x12473, 1},
+ {0x111cd, 0x11238, 107},
+ {0x11239, 0x1123d, 1},
+ {0x114c6, 0x115c1, 251},
+ {0x115c2, 0x115c9, 1},
+ {0x11641, 0x11643, 1},
+ {0x12470, 0x12474, 1},
+ {0x16a6e, 0x16a6f, 1},
+ {0x16af5, 0x16b37, 66},
+ {0x16b38, 0x16b3b, 1},
+ {0x16b44, 0x1bc9f, 20827},
},
LatinOffset: 11,
}
@@ -2170,10 +2408,11 @@ var _Pd = &RangeTable{
{0x2011, 0x2015, 1},
{0x2e17, 0x2e1a, 3},
{0x2e3a, 0x2e3b, 1},
- {0x301c, 0x3030, 20},
- {0x30a0, 0xfe31, 52625},
- {0xfe32, 0xfe58, 38},
- {0xfe63, 0xff0d, 170},
+ {0x2e40, 0x301c, 476},
+ {0x3030, 0x30a0, 112},
+ {0xfe31, 0xfe32, 1},
+ {0xfe58, 0xfe63, 11},
+ {0xff0d, 0xff0d, 1},
},
}
@@ -2183,7 +2422,8 @@ var _Pe = &RangeTable{
{0x007d, 0x0f3b, 3774},
{0x0f3d, 0x169c, 1887},
{0x2046, 0x207e, 56},
- {0x208e, 0x232a, 668},
+ {0x208e, 0x2309, 635},
+ {0x230b, 0x232a, 31},
{0x2769, 0x2775, 2},
{0x27c6, 0x27e7, 33},
{0x27e9, 0x27ef, 2},
@@ -2194,7 +2434,7 @@ var _Pe = &RangeTable{
{0x3009, 0x3011, 2},
{0x3015, 0x301b, 2},
{0x301e, 0x301f, 1},
- {0xfd3f, 0xfe18, 217},
+ {0xfd3e, 0xfe18, 218},
{0xfe36, 0xfe44, 2},
{0xfe48, 0xfe5a, 18},
{0xfe5c, 0xfe5e, 2},
@@ -2299,7 +2539,9 @@ var _Po = &RangeTable{
{0x2e1f, 0x2e2a, 11},
{0x2e2b, 0x2e2e, 1},
{0x2e30, 0x2e39, 1},
- {0x3001, 0x3003, 1},
+ {0x2e3c, 0x2e3f, 1},
+ {0x2e41, 0x3001, 448},
+ {0x3002, 0x3003, 1},
{0x303d, 0x30fb, 190},
{0xa4fe, 0xa4ff, 1},
{0xa60d, 0xa60f, 1},
@@ -2338,17 +2580,29 @@ var _Po = &RangeTable{
{0x10100, 0x10100, 1},
{0x10101, 0x10102, 1},
{0x1039f, 0x103d0, 49},
- {0x10857, 0x1091f, 200},
- {0x1093f, 0x10a50, 273},
- {0x10a51, 0x10a58, 1},
- {0x10a7f, 0x10b39, 186},
- {0x10b3a, 0x10b3f, 1},
+ {0x1056f, 0x10857, 744},
+ {0x1091f, 0x1093f, 32},
+ {0x10a50, 0x10a58, 1},
+ {0x10a7f, 0x10af0, 113},
+ {0x10af1, 0x10af6, 1},
+ {0x10b39, 0x10b3f, 1},
+ {0x10b99, 0x10b9c, 1},
{0x11047, 0x1104d, 1},
{0x110bb, 0x110bc, 1},
{0x110be, 0x110c1, 1},
{0x11140, 0x11143, 1},
+ {0x11174, 0x11175, 1},
{0x111c5, 0x111c8, 1},
- {0x12470, 0x12473, 1},
+ {0x111cd, 0x11238, 107},
+ {0x11239, 0x1123d, 1},
+ {0x114c6, 0x115c1, 251},
+ {0x115c2, 0x115c9, 1},
+ {0x11641, 0x11643, 1},
+ {0x12470, 0x12474, 1},
+ {0x16a6e, 0x16a6f, 1},
+ {0x16af5, 0x16b37, 66},
+ {0x16b38, 0x16b3b, 1},
+ {0x16b44, 0x1bc9f, 20827},
},
LatinOffset: 8,
}
@@ -2360,7 +2614,8 @@ var _Ps = &RangeTable{
{0x0f3c, 0x169b, 1887},
{0x201a, 0x201e, 4},
{0x2045, 0x207d, 56},
- {0x208d, 0x2329, 668},
+ {0x208d, 0x2308, 635},
+ {0x230a, 0x2329, 31},
{0x2768, 0x2774, 2},
{0x27c5, 0x27e6, 33},
{0x27e8, 0x27ee, 2},
@@ -2368,9 +2623,10 @@ var _Ps = &RangeTable{
{0x29d8, 0x29da, 2},
{0x29fc, 0x2e22, 1062},
{0x2e24, 0x2e28, 2},
- {0x3008, 0x3010, 2},
+ {0x2e42, 0x3008, 454},
+ {0x300a, 0x3010, 2},
{0x3014, 0x301a, 2},
- {0x301d, 0xfd3e, 52513},
+ {0x301d, 0xfd3f, 52514},
{0xfe17, 0xfe35, 30},
{0xfe37, 0xfe43, 2},
{0xfe47, 0xfe59, 18},
@@ -2401,7 +2657,8 @@ var _S = &RangeTable{
{0x02f0, 0x02ff, 1},
{0x0375, 0x0384, 15},
{0x0385, 0x03f6, 113},
- {0x0482, 0x058f, 269},
+ {0x0482, 0x058d, 267},
+ {0x058e, 0x058f, 1},
{0x0606, 0x0608, 1},
{0x060b, 0x060e, 3},
{0x060f, 0x06de, 207},
@@ -2437,7 +2694,7 @@ var _S = &RangeTable{
{0x2044, 0x2052, 14},
{0x207a, 0x207c, 1},
{0x208a, 0x208c, 1},
- {0x20a0, 0x20ba, 1},
+ {0x20a0, 0x20bd, 1},
{0x2100, 0x2101, 1},
{0x2103, 0x2106, 1},
{0x2108, 0x2109, 1},
@@ -2450,20 +2707,23 @@ var _S = &RangeTable{
{0x2141, 0x2144, 1},
{0x214a, 0x214d, 1},
{0x214f, 0x2190, 65},
- {0x2191, 0x2328, 1},
- {0x232b, 0x23f3, 1},
+ {0x2191, 0x2307, 1},
+ {0x230c, 0x2328, 1},
+ {0x232b, 0x23fa, 1},
{0x2400, 0x2426, 1},
{0x2440, 0x244a, 1},
{0x249c, 0x24e9, 1},
- {0x2500, 0x26ff, 1},
- {0x2701, 0x2767, 1},
+ {0x2500, 0x2767, 1},
{0x2794, 0x27c4, 1},
{0x27c7, 0x27e5, 1},
{0x27f0, 0x2982, 1},
{0x2999, 0x29d7, 1},
{0x29dc, 0x29fb, 1},
- {0x29fe, 0x2b4c, 1},
- {0x2b50, 0x2b59, 1},
+ {0x29fe, 0x2b73, 1},
+ {0x2b76, 0x2b95, 1},
+ {0x2b98, 0x2bb9, 1},
+ {0x2bbd, 0x2bc8, 1},
+ {0x2bca, 0x2bd1, 1},
{0x2ce5, 0x2cea, 1},
{0x2e80, 0x2e99, 1},
{0x2e9b, 0x2ef3, 1},
@@ -2492,8 +2752,8 @@ var _S = &RangeTable{
{0xa828, 0xa82b, 1},
{0xa836, 0xa839, 1},
{0xaa77, 0xaa79, 1},
- {0xfb29, 0xfbb2, 137},
- {0xfbb3, 0xfbc1, 1},
+ {0xab5b, 0xfb29, 20430},
+ {0xfbb2, 0xfbc1, 1},
{0xfdfc, 0xfdfd, 1},
{0xfe62, 0xfe64, 2},
{0xfe65, 0xfe66, 1},
@@ -2509,8 +2769,14 @@ var _S = &RangeTable{
R32: []Range32{
{0x10137, 0x1013f, 1},
{0x10179, 0x10189, 1},
- {0x10190, 0x1019b, 1},
- {0x101d0, 0x101fc, 1},
+ {0x1018c, 0x10190, 4},
+ {0x10191, 0x1019b, 1},
+ {0x101a0, 0x101d0, 48},
+ {0x101d1, 0x101fc, 1},
+ {0x10877, 0x10878, 1},
+ {0x10ac8, 0x16b3c, 24692},
+ {0x16b3d, 0x16b3f, 1},
+ {0x16b45, 0x1bc9c, 20823},
{0x1d000, 0x1d0f5, 1},
{0x1d100, 0x1d126, 1},
{0x1d129, 0x1d164, 1},
@@ -2530,9 +2796,9 @@ var _S = &RangeTable{
{0x1f000, 0x1f02b, 1},
{0x1f030, 0x1f093, 1},
{0x1f0a0, 0x1f0ae, 1},
- {0x1f0b1, 0x1f0be, 1},
+ {0x1f0b1, 0x1f0bf, 1},
{0x1f0c1, 0x1f0cf, 1},
- {0x1f0d1, 0x1f0df, 1},
+ {0x1f0d1, 0x1f0f5, 1},
{0x1f110, 0x1f12e, 1},
{0x1f130, 0x1f16b, 1},
{0x1f170, 0x1f19a, 1},
@@ -2540,24 +2806,25 @@ var _S = &RangeTable{
{0x1f210, 0x1f23a, 1},
{0x1f240, 0x1f248, 1},
{0x1f250, 0x1f251, 1},
- {0x1f300, 0x1f320, 1},
- {0x1f330, 0x1f335, 1},
- {0x1f337, 0x1f37c, 1},
- {0x1f380, 0x1f393, 1},
- {0x1f3a0, 0x1f3c4, 1},
- {0x1f3c6, 0x1f3ca, 1},
- {0x1f3e0, 0x1f3f0, 1},
- {0x1f400, 0x1f43e, 1},
- {0x1f440, 0x1f442, 2},
- {0x1f443, 0x1f4f7, 1},
- {0x1f4f9, 0x1f4fc, 1},
- {0x1f500, 0x1f53d, 1},
- {0x1f540, 0x1f543, 1},
- {0x1f550, 0x1f567, 1},
- {0x1f5fb, 0x1f640, 1},
- {0x1f645, 0x1f64f, 1},
- {0x1f680, 0x1f6c5, 1},
+ {0x1f300, 0x1f32c, 1},
+ {0x1f330, 0x1f37d, 1},
+ {0x1f380, 0x1f3ce, 1},
+ {0x1f3d4, 0x1f3f7, 1},
+ {0x1f400, 0x1f4fe, 1},
+ {0x1f500, 0x1f54a, 1},
+ {0x1f550, 0x1f579, 1},
+ {0x1f57b, 0x1f5a3, 1},
+ {0x1f5a5, 0x1f642, 1},
+ {0x1f645, 0x1f6cf, 1},
+ {0x1f6e0, 0x1f6ec, 1},
+ {0x1f6f0, 0x1f6f3, 1},
{0x1f700, 0x1f773, 1},
+ {0x1f780, 0x1f7d4, 1},
+ {0x1f800, 0x1f80b, 1},
+ {0x1f810, 0x1f847, 1},
+ {0x1f850, 0x1f859, 1},
+ {0x1f860, 0x1f887, 1},
+ {0x1f890, 0x1f8ad, 1},
},
LatinOffset: 10,
}
@@ -2571,7 +2838,7 @@ var _Sc = &RangeTable{
{0x09fb, 0x0af1, 246},
{0x0bf9, 0x0e3f, 582},
{0x17db, 0x20a0, 2245},
- {0x20a1, 0x20ba, 1},
+ {0x20a1, 0x20bd, 1},
{0xa838, 0xfdfc, 21956},
{0xfe69, 0xff04, 155},
{0xffe0, 0xffe1, 1},
@@ -2601,7 +2868,8 @@ var _Sk = &RangeTable{
{0xa700, 0xa716, 1},
{0xa720, 0xa721, 1},
{0xa789, 0xa78a, 1},
- {0xfbb2, 0xfbc1, 1},
+ {0xab5b, 0xfbb2, 20567},
+ {0xfbb3, 0xfbc1, 1},
{0xff3e, 0xff40, 2},
{0xffe3, 0xffe3, 1},
},
@@ -2630,7 +2898,6 @@ var _Sm = &RangeTable{
{0x21cf, 0x21d2, 3},
{0x21d4, 0x21f4, 32},
{0x21f5, 0x22ff, 1},
- {0x2308, 0x230b, 1},
{0x2320, 0x2321, 1},
{0x237c, 0x239b, 31},
{0x239c, 0x23b3, 1},
@@ -2670,7 +2937,8 @@ var _So = &RangeTable{
R16: []Range16{
{0x00a6, 0x00a9, 3},
{0x00ae, 0x00b0, 2},
- {0x0482, 0x060e, 396},
+ {0x0482, 0x058d, 267},
+ {0x058e, 0x060e, 128},
{0x060f, 0x06de, 207},
{0x06e9, 0x06fd, 20},
{0x06fe, 0x07f6, 248},
@@ -2719,7 +2987,7 @@ var _So = &RangeTable{
{0x232b, 0x237b, 1},
{0x237d, 0x239a, 1},
{0x23b4, 0x23db, 1},
- {0x23e2, 0x23f3, 1},
+ {0x23e2, 0x23fa, 1},
{0x2400, 0x2426, 1},
{0x2440, 0x244a, 1},
{0x249c, 0x24e9, 1},
@@ -2727,13 +2995,16 @@ var _So = &RangeTable{
{0x25b8, 0x25c0, 1},
{0x25c2, 0x25f7, 1},
{0x2600, 0x266e, 1},
- {0x2670, 0x26ff, 1},
- {0x2701, 0x2767, 1},
+ {0x2670, 0x2767, 1},
{0x2794, 0x27bf, 1},
{0x2800, 0x28ff, 1},
{0x2b00, 0x2b2f, 1},
{0x2b45, 0x2b46, 1},
- {0x2b50, 0x2b59, 1},
+ {0x2b4d, 0x2b73, 1},
+ {0x2b76, 0x2b95, 1},
+ {0x2b98, 0x2bb9, 1},
+ {0x2bbd, 0x2bc8, 1},
+ {0x2bca, 0x2bd1, 1},
{0x2ce5, 0x2cea, 1},
{0x2e80, 0x2e99, 1},
{0x2e9b, 0x2ef3, 1},
@@ -2768,8 +3039,14 @@ var _So = &RangeTable{
{0x10137, 0x10137, 1},
{0x10138, 0x1013f, 1},
{0x10179, 0x10189, 1},
- {0x10190, 0x1019b, 1},
- {0x101d0, 0x101fc, 1},
+ {0x1018c, 0x10190, 4},
+ {0x10191, 0x1019b, 1},
+ {0x101a0, 0x101d0, 48},
+ {0x101d1, 0x101fc, 1},
+ {0x10877, 0x10878, 1},
+ {0x10ac8, 0x16b3c, 24692},
+ {0x16b3d, 0x16b3f, 1},
+ {0x16b45, 0x1bc9c, 20823},
{0x1d000, 0x1d0f5, 1},
{0x1d100, 0x1d126, 1},
{0x1d129, 0x1d164, 1},
@@ -2783,9 +3060,9 @@ var _So = &RangeTable{
{0x1f000, 0x1f02b, 1},
{0x1f030, 0x1f093, 1},
{0x1f0a0, 0x1f0ae, 1},
- {0x1f0b1, 0x1f0be, 1},
+ {0x1f0b1, 0x1f0bf, 1},
{0x1f0c1, 0x1f0cf, 1},
- {0x1f0d1, 0x1f0df, 1},
+ {0x1f0d1, 0x1f0f5, 1},
{0x1f110, 0x1f12e, 1},
{0x1f130, 0x1f16b, 1},
{0x1f170, 0x1f19a, 1},
@@ -2793,24 +3070,25 @@ var _So = &RangeTable{
{0x1f210, 0x1f23a, 1},
{0x1f240, 0x1f248, 1},
{0x1f250, 0x1f251, 1},
- {0x1f300, 0x1f320, 1},
- {0x1f330, 0x1f335, 1},
- {0x1f337, 0x1f37c, 1},
- {0x1f380, 0x1f393, 1},
- {0x1f3a0, 0x1f3c4, 1},
- {0x1f3c6, 0x1f3ca, 1},
- {0x1f3e0, 0x1f3f0, 1},
- {0x1f400, 0x1f43e, 1},
- {0x1f440, 0x1f442, 2},
- {0x1f443, 0x1f4f7, 1},
- {0x1f4f9, 0x1f4fc, 1},
- {0x1f500, 0x1f53d, 1},
- {0x1f540, 0x1f543, 1},
- {0x1f550, 0x1f567, 1},
- {0x1f5fb, 0x1f640, 1},
- {0x1f645, 0x1f64f, 1},
- {0x1f680, 0x1f6c5, 1},
+ {0x1f300, 0x1f32c, 1},
+ {0x1f330, 0x1f37d, 1},
+ {0x1f380, 0x1f3ce, 1},
+ {0x1f3d4, 0x1f3f7, 1},
+ {0x1f400, 0x1f4fe, 1},
+ {0x1f500, 0x1f54a, 1},
+ {0x1f550, 0x1f579, 1},
+ {0x1f57b, 0x1f5a3, 1},
+ {0x1f5a5, 0x1f642, 1},
+ {0x1f645, 0x1f6cf, 1},
+ {0x1f6e0, 0x1f6ec, 1},
+ {0x1f6f0, 0x1f6f3, 1},
{0x1f700, 0x1f773, 1},
+ {0x1f780, 0x1f7d4, 1},
+ {0x1f800, 0x1f80b, 1},
+ {0x1f810, 0x1f847, 1},
+ {0x1f850, 0x1f859, 1},
+ {0x1f860, 0x1f887, 1},
+ {0x1f890, 0x1f8ad, 1},
},
LatinOffset: 2,
}
@@ -2818,8 +3096,8 @@ var _So = &RangeTable{
var _Z = &RangeTable{
R16: []Range16{
{0x0020, 0x00a0, 128},
- {0x1680, 0x180e, 398},
- {0x2000, 0x200a, 1},
+ {0x1680, 0x2000, 2432},
+ {0x2001, 0x200a, 1},
{0x2028, 0x2029, 1},
{0x202f, 0x205f, 48},
{0x3000, 0x3000, 1},
@@ -2842,8 +3120,8 @@ var _Zp = &RangeTable{
var _Zs = &RangeTable{
R16: []Range16{
{0x0020, 0x00a0, 128},
- {0x1680, 0x180e, 398},
- {0x2000, 0x200a, 1},
+ {0x1680, 0x2000, 2432},
+ {0x2001, 0x200a, 1},
{0x202f, 0x205f, 48},
{0x3000, 0x3000, 1},
},
@@ -2902,7 +3180,7 @@ var (
)
// Generated by running
-// maketables --scripts=all --url=http://www.unicode.org/Public/6.2.0/ucd/
+// maketables --scripts=all --url=http://www.unicode.org/Public/7.0.0/ucd/
// DO NOT EDIT
// Scripts is the set of Unicode script tables.
@@ -2912,6 +3190,7 @@ var Scripts = map[string]*RangeTable{
"Avestan": Avestan,
"Balinese": Balinese,
"Bamum": Bamum,
+ "Bassa_Vah": Bassa_Vah,
"Batak": Batak,
"Bengali": Bengali,
"Bopomofo": Bopomofo,
@@ -2921,6 +3200,7 @@ var Scripts = map[string]*RangeTable{
"Buhid": Buhid,
"Canadian_Aboriginal": Canadian_Aboriginal,
"Carian": Carian,
+ "Caucasian_Albanian": Caucasian_Albanian,
"Chakma": Chakma,
"Cham": Cham,
"Cherokee": Cherokee,
@@ -2931,11 +3211,14 @@ var Scripts = map[string]*RangeTable{
"Cyrillic": Cyrillic,
"Deseret": Deseret,
"Devanagari": Devanagari,
+ "Duployan": Duployan,
"Egyptian_Hieroglyphs": Egyptian_Hieroglyphs,
+ "Elbasan": Elbasan,
"Ethiopic": Ethiopic,
"Georgian": Georgian,
"Glagolitic": Glagolitic,
"Gothic": Gothic,
+ "Grantha": Grantha,
"Greek": Greek,
"Gujarati": Gujarati,
"Gurmukhi": Gurmukhi,
@@ -2955,40 +3238,56 @@ var Scripts = map[string]*RangeTable{
"Kayah_Li": Kayah_Li,
"Kharoshthi": Kharoshthi,
"Khmer": Khmer,
+ "Khojki": Khojki,
+ "Khudawadi": Khudawadi,
"Lao": Lao,
"Latin": Latin,
"Lepcha": Lepcha,
"Limbu": Limbu,
+ "Linear_A": Linear_A,
"Linear_B": Linear_B,
"Lisu": Lisu,
"Lycian": Lycian,
"Lydian": Lydian,
+ "Mahajani": Mahajani,
"Malayalam": Malayalam,
"Mandaic": Mandaic,
+ "Manichaean": Manichaean,
"Meetei_Mayek": Meetei_Mayek,
+ "Mende_Kikakui": Mende_Kikakui,
"Meroitic_Cursive": Meroitic_Cursive,
"Meroitic_Hieroglyphs": Meroitic_Hieroglyphs,
"Miao": Miao,
+ "Modi": Modi,
"Mongolian": Mongolian,
+ "Mro": Mro,
"Myanmar": Myanmar,
+ "Nabataean": Nabataean,
"New_Tai_Lue": New_Tai_Lue,
"Nko": Nko,
"Ogham": Ogham,
"Ol_Chiki": Ol_Chiki,
"Old_Italic": Old_Italic,
+ "Old_North_Arabian": Old_North_Arabian,
+ "Old_Permic": Old_Permic,
"Old_Persian": Old_Persian,
"Old_South_Arabian": Old_South_Arabian,
"Old_Turkic": Old_Turkic,
"Oriya": Oriya,
"Osmanya": Osmanya,
+ "Pahawh_Hmong": Pahawh_Hmong,
+ "Palmyrene": Palmyrene,
+ "Pau_Cin_Hau": Pau_Cin_Hau,
"Phags_Pa": Phags_Pa,
"Phoenician": Phoenician,
+ "Psalter_Pahlavi": Psalter_Pahlavi,
"Rejang": Rejang,
"Runic": Runic,
"Samaritan": Samaritan,
"Saurashtra": Saurashtra,
"Sharada": Sharada,
"Shavian": Shavian,
+ "Siddham": Siddham,
"Sinhala": Sinhala,
"Sora_Sompeng": Sora_Sompeng,
"Sundanese": Sundanese,
@@ -3006,8 +3305,10 @@ var Scripts = map[string]*RangeTable{
"Thai": Thai,
"Tibetan": Tibetan,
"Tifinagh": Tifinagh,
+ "Tirhuta": Tirhuta,
"Ugaritic": Ugaritic,
"Vai": Vai,
+ "Warang_Citi": Warang_Citi,
"Yi": Yi,
}
@@ -3024,14 +3325,13 @@ var _Arabic = &RangeTable{
{0x0671, 0x06dc, 1},
{0x06de, 0x06ff, 1},
{0x0750, 0x077f, 1},
- {0x08a0, 0x08a0, 1},
- {0x08a2, 0x08ac, 1},
- {0x08e4, 0x08fe, 1},
+ {0x08a0, 0x08b2, 1},
+ {0x08e4, 0x08ff, 1},
{0xfb50, 0xfbc1, 1},
{0xfbd3, 0xfd3d, 1},
{0xfd50, 0xfd8f, 1},
{0xfd92, 0xfdc7, 1},
- {0xfdf0, 0xfdfc, 1},
+ {0xfdf0, 0xfdfd, 1},
{0xfe70, 0xfe74, 1},
{0xfe76, 0xfefc, 1},
},
@@ -3080,7 +3380,7 @@ var _Armenian = &RangeTable{
{0x0559, 0x055f, 1},
{0x0561, 0x0587, 1},
{0x058a, 0x058a, 1},
- {0x058f, 0x058f, 1},
+ {0x058d, 0x058f, 1},
{0xfb13, 0xfb17, 1},
},
}
@@ -3109,6 +3409,14 @@ var _Bamum = &RangeTable{
},
}
+var _Bassa_Vah = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x16ad0, 0x16aed, 1},
+ {0x16af0, 0x16af5, 1},
+ },
+}
+
var _Batak = &RangeTable{
R16: []Range16{
{0x1bc0, 0x1bf3, 1},
@@ -3118,7 +3426,7 @@ var _Batak = &RangeTable{
var _Bengali = &RangeTable{
R16: []Range16{
- {0x0981, 0x0983, 1},
+ {0x0980, 0x0983, 1},
{0x0985, 0x098c, 1},
{0x098f, 0x0990, 1},
{0x0993, 0x09a8, 1},
@@ -3148,6 +3456,7 @@ var _Brahmi = &RangeTable{
R32: []Range32{
{0x11000, 0x1104d, 1},
{0x11052, 0x1106f, 1},
+ {0x1107f, 0x1107f, 1},
},
}
@@ -3184,6 +3493,14 @@ var _Carian = &RangeTable{
},
}
+var _Caucasian_Albanian = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10530, 0x10563, 1},
+ {0x1056f, 0x1056f, 1},
+ },
+}
+
var _Chakma = &RangeTable{
R16: []Range16{},
R32: []Range32{
@@ -3224,8 +3541,9 @@ var _Common = &RangeTable{
{0x0385, 0x0385, 1},
{0x0387, 0x0387, 1},
{0x0589, 0x0589, 1},
+ {0x0605, 0x0605, 1},
{0x060c, 0x060c, 1},
- {0x061b, 0x061b, 1},
+ {0x061b, 0x061c, 1},
{0x061f, 0x061f, 1},
{0x0640, 0x0640, 1},
{0x0660, 0x0669, 1},
@@ -3245,24 +3563,26 @@ var _Common = &RangeTable{
{0x1cf5, 0x1cf6, 1},
{0x2000, 0x200b, 1},
{0x200e, 0x2064, 1},
- {0x206a, 0x2070, 1},
+ {0x2066, 0x2070, 1},
{0x2074, 0x207e, 1},
{0x2080, 0x208e, 1},
- {0x20a0, 0x20ba, 1},
+ {0x20a0, 0x20bd, 1},
{0x2100, 0x2125, 1},
{0x2127, 0x2129, 1},
{0x212c, 0x2131, 1},
{0x2133, 0x214d, 1},
{0x214f, 0x215f, 1},
{0x2189, 0x2189, 1},
- {0x2190, 0x23f3, 1},
+ {0x2190, 0x23fa, 1},
{0x2400, 0x2426, 1},
{0x2440, 0x244a, 1},
- {0x2460, 0x26ff, 1},
- {0x2701, 0x27ff, 1},
- {0x2900, 0x2b4c, 1},
- {0x2b50, 0x2b59, 1},
- {0x2e00, 0x2e3b, 1},
+ {0x2460, 0x27ff, 1},
+ {0x2900, 0x2b73, 1},
+ {0x2b76, 0x2b95, 1},
+ {0x2b98, 0x2bb9, 1},
+ {0x2bbd, 0x2bc8, 1},
+ {0x2bca, 0x2bd1, 1},
+ {0x2e00, 0x2e42, 1},
{0x2ff0, 0x2ffb, 1},
{0x3000, 0x3004, 1},
{0x3006, 0x3006, 1},
@@ -3281,8 +3601,10 @@ var _Common = &RangeTable{
{0xa700, 0xa721, 1},
{0xa788, 0xa78a, 1},
{0xa830, 0xa839, 1},
+ {0xa92e, 0xa92e, 1},
+ {0xa9cf, 0xa9cf, 1},
+ {0xab5b, 0xab5b, 1},
{0xfd3e, 0xfd3f, 1},
- {0xfdfd, 0xfdfd, 1},
{0xfe10, 0xfe19, 1},
{0xfe30, 0xfe52, 1},
{0xfe54, 0xfe66, 1},
@@ -3303,6 +3625,8 @@ var _Common = &RangeTable{
{0x10137, 0x1013f, 1},
{0x10190, 0x1019b, 1},
{0x101d0, 0x101fc, 1},
+ {0x102e1, 0x102fb, 1},
+ {0x1bca0, 0x1bca3, 1},
{0x1d000, 0x1d0f5, 1},
{0x1d100, 0x1d126, 1},
{0x1d129, 0x1d166, 1},
@@ -3336,10 +3660,10 @@ var _Common = &RangeTable{
{0x1f000, 0x1f02b, 1},
{0x1f030, 0x1f093, 1},
{0x1f0a0, 0x1f0ae, 1},
- {0x1f0b1, 0x1f0be, 1},
+ {0x1f0b1, 0x1f0bf, 1},
{0x1f0c1, 0x1f0cf, 1},
- {0x1f0d1, 0x1f0df, 1},
- {0x1f100, 0x1f10a, 1},
+ {0x1f0d1, 0x1f0f5, 1},
+ {0x1f100, 0x1f10c, 1},
{0x1f110, 0x1f12e, 1},
{0x1f130, 0x1f16b, 1},
{0x1f170, 0x1f19a, 1},
@@ -3348,24 +3672,25 @@ var _Common = &RangeTable{
{0x1f210, 0x1f23a, 1},
{0x1f240, 0x1f248, 1},
{0x1f250, 0x1f251, 1},
- {0x1f300, 0x1f320, 1},
- {0x1f330, 0x1f335, 1},
- {0x1f337, 0x1f37c, 1},
- {0x1f380, 0x1f393, 1},
- {0x1f3a0, 0x1f3c4, 1},
- {0x1f3c6, 0x1f3ca, 1},
- {0x1f3e0, 0x1f3f0, 1},
- {0x1f400, 0x1f43e, 1},
- {0x1f440, 0x1f440, 1},
- {0x1f442, 0x1f4f7, 1},
- {0x1f4f9, 0x1f4fc, 1},
- {0x1f500, 0x1f53d, 1},
- {0x1f540, 0x1f543, 1},
- {0x1f550, 0x1f567, 1},
- {0x1f5fb, 0x1f640, 1},
- {0x1f645, 0x1f64f, 1},
- {0x1f680, 0x1f6c5, 1},
+ {0x1f300, 0x1f32c, 1},
+ {0x1f330, 0x1f37d, 1},
+ {0x1f380, 0x1f3ce, 1},
+ {0x1f3d4, 0x1f3f7, 1},
+ {0x1f400, 0x1f4fe, 1},
+ {0x1f500, 0x1f54a, 1},
+ {0x1f550, 0x1f579, 1},
+ {0x1f57b, 0x1f5a3, 1},
+ {0x1f5a5, 0x1f642, 1},
+ {0x1f645, 0x1f6cf, 1},
+ {0x1f6e0, 0x1f6ec, 1},
+ {0x1f6f0, 0x1f6f3, 1},
{0x1f700, 0x1f773, 1},
+ {0x1f780, 0x1f7d4, 1},
+ {0x1f800, 0x1f80b, 1},
+ {0x1f810, 0x1f847, 1},
+ {0x1f850, 0x1f859, 1},
+ {0x1f860, 0x1f887, 1},
+ {0x1f890, 0x1f8ad, 1},
{0xe0001, 0xe0001, 1},
{0xe0020, 0xe007f, 1},
},
@@ -3383,9 +3708,9 @@ var _Coptic = &RangeTable{
var _Cuneiform = &RangeTable{
R16: []Range16{},
R32: []Range32{
- {0x12000, 0x1236e, 1},
- {0x12400, 0x12462, 1},
- {0x12470, 0x12473, 1},
+ {0x12000, 0x12398, 1},
+ {0x12400, 0x1246e, 1},
+ {0x12470, 0x12474, 1},
},
}
@@ -3404,11 +3729,11 @@ var _Cypriot = &RangeTable{
var _Cyrillic = &RangeTable{
R16: []Range16{
{0x0400, 0x0484, 1},
- {0x0487, 0x0527, 1},
+ {0x0487, 0x052f, 1},
{0x1d2b, 0x1d2b, 1},
{0x1d78, 0x1d78, 1},
{0x2de0, 0x2dff, 1},
- {0xa640, 0xa697, 1},
+ {0xa640, 0xa69d, 1},
{0xa69f, 0xa69f, 1},
},
}
@@ -3424,12 +3749,22 @@ var _Devanagari = &RangeTable{
R16: []Range16{
{0x0900, 0x0950, 1},
{0x0953, 0x0963, 1},
- {0x0966, 0x0977, 1},
- {0x0979, 0x097f, 1},
+ {0x0966, 0x097f, 1},
{0xa8e0, 0xa8fb, 1},
},
}
+var _Duployan = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x1bc00, 0x1bc6a, 1},
+ {0x1bc70, 0x1bc7c, 1},
+ {0x1bc80, 0x1bc88, 1},
+ {0x1bc90, 0x1bc99, 1},
+ {0x1bc9c, 0x1bc9f, 1},
+ },
+}
+
var _Egyptian_Hieroglyphs = &RangeTable{
R16: []Range16{},
R32: []Range32{
@@ -3437,6 +3772,13 @@ var _Egyptian_Hieroglyphs = &RangeTable{
},
}
+var _Elbasan = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10500, 0x10527, 1},
+ },
+}
+
var _Ethiopic = &RangeTable{
R16: []Range16{
{0x1200, 0x1248, 1},
@@ -3501,11 +3843,32 @@ var _Gothic = &RangeTable{
},
}
+var _Grantha = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x11301, 0x11303, 1},
+ {0x11305, 0x1130c, 1},
+ {0x1130f, 0x11310, 1},
+ {0x11313, 0x11328, 1},
+ {0x1132a, 0x11330, 1},
+ {0x11332, 0x11333, 1},
+ {0x11335, 0x11339, 1},
+ {0x1133c, 0x11344, 1},
+ {0x11347, 0x11348, 1},
+ {0x1134b, 0x1134d, 1},
+ {0x11357, 0x11357, 1},
+ {0x1135d, 0x11363, 1},
+ {0x11366, 0x1136c, 1},
+ {0x11370, 0x11374, 1},
+ },
+}
+
var _Greek = &RangeTable{
R16: []Range16{
{0x0370, 0x0373, 1},
{0x0375, 0x0377, 1},
{0x037a, 0x037d, 1},
+ {0x037f, 0x037f, 1},
{0x0384, 0x0384, 1},
{0x0386, 0x0386, 1},
{0x0388, 0x038a, 1},
@@ -3534,9 +3897,11 @@ var _Greek = &RangeTable{
{0x1ff2, 0x1ff4, 1},
{0x1ff6, 0x1ffe, 1},
{0x2126, 0x2126, 1},
+ {0xab65, 0xab65, 1},
},
R32: []Range32{
- {0x10140, 0x1018a, 1},
+ {0x10140, 0x1018c, 1},
+ {0x101a0, 0x101a0, 1},
{0x1d200, 0x1d245, 1},
},
}
@@ -3667,22 +4032,25 @@ var _Inherited = &RangeTable{
{0x064b, 0x0655, 1},
{0x0670, 0x0670, 1},
{0x0951, 0x0952, 1},
+ {0x1ab0, 0x1abe, 1},
{0x1cd0, 0x1cd2, 1},
{0x1cd4, 0x1ce0, 1},
{0x1ce2, 0x1ce8, 1},
{0x1ced, 0x1ced, 1},
{0x1cf4, 0x1cf4, 1},
- {0x1dc0, 0x1de6, 1},
+ {0x1cf8, 0x1cf9, 1},
+ {0x1dc0, 0x1df5, 1},
{0x1dfc, 0x1dff, 1},
{0x200c, 0x200d, 1},
{0x20d0, 0x20f0, 1},
{0x302a, 0x302d, 1},
{0x3099, 0x309a, 1},
{0xfe00, 0xfe0f, 1},
- {0xfe20, 0xfe26, 1},
+ {0xfe20, 0xfe2d, 1},
},
R32: []Range32{
{0x101fd, 0x101fd, 1},
+ {0x102e0, 0x102e0, 1},
{0x1d167, 0x1d169, 1},
{0x1d17b, 0x1d182, 1},
{0x1d185, 0x1d18b, 1},
@@ -3710,7 +4078,7 @@ var _Inscriptional_Parthian = &RangeTable{
var _Javanese = &RangeTable{
R16: []Range16{
{0xa980, 0xa9cd, 1},
- {0xa9cf, 0xa9d9, 1},
+ {0xa9d0, 0xa9d9, 1},
{0xa9de, 0xa9df, 1},
},
}
@@ -3724,7 +4092,7 @@ var _Kaithi = &RangeTable{
var _Kannada = &RangeTable{
R16: []Range16{
- {0x0c82, 0x0c83, 1},
+ {0x0c81, 0x0c83, 1},
{0x0c85, 0x0c8c, 1},
{0x0c8e, 0x0c90, 1},
{0x0c92, 0x0ca8, 1},
@@ -3758,7 +4126,8 @@ var _Katakana = &RangeTable{
var _Kayah_Li = &RangeTable{
R16: []Range16{
- {0xa900, 0xa92f, 1},
+ {0xa900, 0xa92d, 1},
+ {0xa92f, 0xa92f, 1},
},
}
@@ -3785,6 +4154,22 @@ var _Khmer = &RangeTable{
},
}
+var _Khojki = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x11200, 0x11211, 1},
+ {0x11213, 0x1123d, 1},
+ },
+}
+
+var _Khudawadi = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x112b0, 0x112ea, 1},
+ {0x112f0, 0x112f9, 1},
+ },
+}
+
var _Lao = &RangeTable{
R16: []Range16{
{0x0e81, 0x0e82, 1},
@@ -3834,9 +4219,12 @@ var _Latin = &RangeTable{
{0x2c60, 0x2c7f, 1},
{0xa722, 0xa787, 1},
{0xa78b, 0xa78e, 1},
- {0xa790, 0xa793, 1},
- {0xa7a0, 0xa7aa, 1},
- {0xa7f8, 0xa7ff, 1},
+ {0xa790, 0xa7ad, 1},
+ {0xa7b0, 0xa7b1, 1},
+ {0xa7f7, 0xa7ff, 1},
+ {0xab30, 0xab5a, 1},
+ {0xab5c, 0xab5f, 1},
+ {0xab64, 0xab64, 1},
{0xfb00, 0xfb06, 1},
{0xff21, 0xff3a, 1},
{0xff41, 0xff5a, 1},
@@ -3854,7 +4242,7 @@ var _Lepcha = &RangeTable{
var _Limbu = &RangeTable{
R16: []Range16{
- {0x1900, 0x191c, 1},
+ {0x1900, 0x191e, 1},
{0x1920, 0x192b, 1},
{0x1930, 0x193b, 1},
{0x1940, 0x1940, 1},
@@ -3862,6 +4250,15 @@ var _Limbu = &RangeTable{
},
}
+var _Linear_A = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10600, 0x10736, 1},
+ {0x10740, 0x10755, 1},
+ {0x10760, 0x10767, 1},
+ },
+}
+
var _Linear_B = &RangeTable{
R16: []Range16{},
R32: []Range32{
@@ -3896,9 +4293,16 @@ var _Lydian = &RangeTable{
},
}
+var _Mahajani = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x11150, 0x11176, 1},
+ },
+}
+
var _Malayalam = &RangeTable{
R16: []Range16{
- {0x0d02, 0x0d03, 1},
+ {0x0d01, 0x0d03, 1},
{0x0d05, 0x0d0c, 1},
{0x0d0e, 0x0d10, 1},
{0x0d12, 0x0d3a, 1},
@@ -3919,6 +4323,14 @@ var _Mandaic = &RangeTable{
},
}
+var _Manichaean = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10ac0, 0x10ae6, 1},
+ {0x10aeb, 0x10af6, 1},
+ },
+}
+
var _Meetei_Mayek = &RangeTable{
R16: []Range16{
{0xaae0, 0xaaf6, 1},
@@ -3927,6 +4339,14 @@ var _Meetei_Mayek = &RangeTable{
},
}
+var _Mende_Kikakui = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x1e800, 0x1e8c4, 1},
+ {0x1e8c7, 0x1e8d6, 1},
+ },
+}
+
var _Meroitic_Cursive = &RangeTable{
R16: []Range16{},
R32: []Range32{
@@ -3951,6 +4371,14 @@ var _Miao = &RangeTable{
},
}
+var _Modi = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x11600, 0x11644, 1},
+ {0x11650, 0x11659, 1},
+ },
+}
+
var _Mongolian = &RangeTable{
R16: []Range16{
{0x1800, 0x1801, 1},
@@ -3962,10 +4390,28 @@ var _Mongolian = &RangeTable{
},
}
+var _Mro = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x16a40, 0x16a5e, 1},
+ {0x16a60, 0x16a69, 1},
+ {0x16a6e, 0x16a6f, 1},
+ },
+}
+
var _Myanmar = &RangeTable{
R16: []Range16{
{0x1000, 0x109f, 1},
- {0xaa60, 0xaa7b, 1},
+ {0xa9e0, 0xa9fe, 1},
+ {0xaa60, 0xaa7f, 1},
+ },
+}
+
+var _Nabataean = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10880, 0x1089e, 1},
+ {0x108a7, 0x108af, 1},
},
}
@@ -3999,8 +4445,21 @@ var _Ol_Chiki = &RangeTable{
var _Old_Italic = &RangeTable{
R16: []Range16{},
R32: []Range32{
- {0x10300, 0x1031e, 1},
- {0x10320, 0x10323, 1},
+ {0x10300, 0x10323, 1},
+ },
+}
+
+var _Old_North_Arabian = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10a80, 0x10a9f, 1},
+ },
+}
+
+var _Old_Permic = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10350, 0x1037a, 1},
},
}
@@ -4053,6 +4512,31 @@ var _Osmanya = &RangeTable{
},
}
+var _Pahawh_Hmong = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x16b00, 0x16b45, 1},
+ {0x16b50, 0x16b59, 1},
+ {0x16b5b, 0x16b61, 1},
+ {0x16b63, 0x16b77, 1},
+ {0x16b7d, 0x16b8f, 1},
+ },
+}
+
+var _Palmyrene = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10860, 0x1087f, 1},
+ },
+}
+
+var _Pau_Cin_Hau = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x11ac0, 0x11af8, 1},
+ },
+}
+
var _Phags_Pa = &RangeTable{
R16: []Range16{
{0xa840, 0xa877, 1},
@@ -4067,6 +4551,15 @@ var _Phoenician = &RangeTable{
},
}
+var _Psalter_Pahlavi = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10b80, 0x10b91, 1},
+ {0x10b99, 0x10b9c, 1},
+ {0x10ba9, 0x10baf, 1},
+ },
+}
+
var _Rejang = &RangeTable{
R16: []Range16{
{0xa930, 0xa953, 1},
@@ -4077,7 +4570,7 @@ var _Rejang = &RangeTable{
var _Runic = &RangeTable{
R16: []Range16{
{0x16a0, 0x16ea, 1},
- {0x16ee, 0x16f0, 1},
+ {0x16ee, 0x16f8, 1},
},
}
@@ -4099,7 +4592,8 @@ var _Sharada = &RangeTable{
R16: []Range16{},
R32: []Range32{
{0x11180, 0x111c8, 1},
- {0x111d0, 0x111d9, 1},
+ {0x111cd, 0x111cd, 1},
+ {0x111d0, 0x111da, 1},
},
}
@@ -4110,6 +4604,14 @@ var _Shavian = &RangeTable{
},
}
+var _Siddham = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x11580, 0x115b5, 1},
+ {0x115b8, 0x115c9, 1},
+ },
+}
+
var _Sinhala = &RangeTable{
R16: []Range16{
{0x0d82, 0x0d83, 1},
@@ -4122,8 +4624,12 @@ var _Sinhala = &RangeTable{
{0x0dcf, 0x0dd4, 1},
{0x0dd6, 0x0dd6, 1},
{0x0dd8, 0x0ddf, 1},
+ {0x0de6, 0x0def, 1},
{0x0df2, 0x0df4, 1},
},
+ R32: []Range32{
+ {0x111e1, 0x111f4, 1},
+ },
}
var _Sora_Sompeng = &RangeTable{
@@ -4225,12 +4731,11 @@ var _Tamil = &RangeTable{
var _Telugu = &RangeTable{
R16: []Range16{
- {0x0c01, 0x0c03, 1},
+ {0x0c00, 0x0c03, 1},
{0x0c05, 0x0c0c, 1},
{0x0c0e, 0x0c10, 1},
{0x0c12, 0x0c28, 1},
- {0x0c2a, 0x0c33, 1},
- {0x0c35, 0x0c39, 1},
+ {0x0c2a, 0x0c39, 1},
{0x0c3d, 0x0c44, 1},
{0x0c46, 0x0c48, 1},
{0x0c4a, 0x0c4d, 1},
@@ -4275,6 +4780,14 @@ var _Tifinagh = &RangeTable{
},
}
+var _Tirhuta = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x11480, 0x114c7, 1},
+ {0x114d0, 0x114d9, 1},
+ },
+}
+
var _Ugaritic = &RangeTable{
R16: []Range16{},
R32: []Range32{
@@ -4289,6 +4802,14 @@ var _Vai = &RangeTable{
},
}
+var _Warang_Citi = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x118a0, 0x118f2, 1},
+ {0x118ff, 0x118ff, 1},
+ },
+}
+
var _Yi = &RangeTable{
R16: []Range16{
{0xa000, 0xa48c, 1},
@@ -4303,6 +4824,7 @@ var (
Avestan = _Avestan // Avestan is the set of Unicode characters in script Avestan.
Balinese = _Balinese // Balinese is the set of Unicode characters in script Balinese.
Bamum = _Bamum // Bamum is the set of Unicode characters in script Bamum.
+ Bassa_Vah = _Bassa_Vah // Bassa_Vah is the set of Unicode characters in script Bassa_Vah.
Batak = _Batak // Batak is the set of Unicode characters in script Batak.
Bengali = _Bengali // Bengali is the set of Unicode characters in script Bengali.
Bopomofo = _Bopomofo // Bopomofo is the set of Unicode characters in script Bopomofo.
@@ -4312,6 +4834,7 @@ var (
Buhid = _Buhid // Buhid is the set of Unicode characters in script Buhid.
Canadian_Aboriginal = _Canadian_Aboriginal // Canadian_Aboriginal is the set of Unicode characters in script Canadian_Aboriginal.
Carian = _Carian // Carian is the set of Unicode characters in script Carian.
+ Caucasian_Albanian = _Caucasian_Albanian // Caucasian_Albanian is the set of Unicode characters in script Caucasian_Albanian.
Chakma = _Chakma // Chakma is the set of Unicode characters in script Chakma.
Cham = _Cham // Cham is the set of Unicode characters in script Cham.
Cherokee = _Cherokee // Cherokee is the set of Unicode characters in script Cherokee.
@@ -4322,11 +4845,14 @@ var (
Cyrillic = _Cyrillic // Cyrillic is the set of Unicode characters in script Cyrillic.
Deseret = _Deseret // Deseret is the set of Unicode characters in script Deseret.
Devanagari = _Devanagari // Devanagari is the set of Unicode characters in script Devanagari.
+ Duployan = _Duployan // Duployan is the set of Unicode characters in script Duployan.
Egyptian_Hieroglyphs = _Egyptian_Hieroglyphs // Egyptian_Hieroglyphs is the set of Unicode characters in script Egyptian_Hieroglyphs.
+ Elbasan = _Elbasan // Elbasan is the set of Unicode characters in script Elbasan.
Ethiopic = _Ethiopic // Ethiopic is the set of Unicode characters in script Ethiopic.
Georgian = _Georgian // Georgian is the set of Unicode characters in script Georgian.
Glagolitic = _Glagolitic // Glagolitic is the set of Unicode characters in script Glagolitic.
Gothic = _Gothic // Gothic is the set of Unicode characters in script Gothic.
+ Grantha = _Grantha // Grantha is the set of Unicode characters in script Grantha.
Greek = _Greek // Greek is the set of Unicode characters in script Greek.
Gujarati = _Gujarati // Gujarati is the set of Unicode characters in script Gujarati.
Gurmukhi = _Gurmukhi // Gurmukhi is the set of Unicode characters in script Gurmukhi.
@@ -4346,40 +4872,56 @@ var (
Kayah_Li = _Kayah_Li // Kayah_Li is the set of Unicode characters in script Kayah_Li.
Kharoshthi = _Kharoshthi // Kharoshthi is the set of Unicode characters in script Kharoshthi.
Khmer = _Khmer // Khmer is the set of Unicode characters in script Khmer.
+ Khojki = _Khojki // Khojki is the set of Unicode characters in script Khojki.
+ Khudawadi = _Khudawadi // Khudawadi is the set of Unicode characters in script Khudawadi.
Lao = _Lao // Lao is the set of Unicode characters in script Lao.
Latin = _Latin // Latin is the set of Unicode characters in script Latin.
Lepcha = _Lepcha // Lepcha is the set of Unicode characters in script Lepcha.
Limbu = _Limbu // Limbu is the set of Unicode characters in script Limbu.
+ Linear_A = _Linear_A // Linear_A is the set of Unicode characters in script Linear_A.
Linear_B = _Linear_B // Linear_B is the set of Unicode characters in script Linear_B.
Lisu = _Lisu // Lisu is the set of Unicode characters in script Lisu.
Lycian = _Lycian // Lycian is the set of Unicode characters in script Lycian.
Lydian = _Lydian // Lydian is the set of Unicode characters in script Lydian.
+ Mahajani = _Mahajani // Mahajani is the set of Unicode characters in script Mahajani.
Malayalam = _Malayalam // Malayalam is the set of Unicode characters in script Malayalam.
Mandaic = _Mandaic // Mandaic is the set of Unicode characters in script Mandaic.
+ Manichaean = _Manichaean // Manichaean is the set of Unicode characters in script Manichaean.
Meetei_Mayek = _Meetei_Mayek // Meetei_Mayek is the set of Unicode characters in script Meetei_Mayek.
+ Mende_Kikakui = _Mende_Kikakui // Mende_Kikakui is the set of Unicode characters in script Mende_Kikakui.
Meroitic_Cursive = _Meroitic_Cursive // Meroitic_Cursive is the set of Unicode characters in script Meroitic_Cursive.
Meroitic_Hieroglyphs = _Meroitic_Hieroglyphs // Meroitic_Hieroglyphs is the set of Unicode characters in script Meroitic_Hieroglyphs.
Miao = _Miao // Miao is the set of Unicode characters in script Miao.
+ 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.
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_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.
Old_Persian = _Old_Persian // Old_Persian is the set of Unicode characters in script Old_Persian.
Old_South_Arabian = _Old_South_Arabian // Old_South_Arabian is the set of Unicode characters in script Old_South_Arabian.
Old_Turkic = _Old_Turkic // Old_Turkic is the set of Unicode characters in script Old_Turkic.
Oriya = _Oriya // Oriya is the set of Unicode characters in script Oriya.
Osmanya = _Osmanya // Osmanya is the set of Unicode characters in script Osmanya.
+ Pahawh_Hmong = _Pahawh_Hmong // Pahawh_Hmong is the set of Unicode characters in script Pahawh_Hmong.
+ Palmyrene = _Palmyrene // Palmyrene is the set of Unicode characters in script Palmyrene.
+ Pau_Cin_Hau = _Pau_Cin_Hau // Pau_Cin_Hau is the set of Unicode characters in script Pau_Cin_Hau.
Phags_Pa = _Phags_Pa // Phags_Pa is the set of Unicode characters in script Phags_Pa.
Phoenician = _Phoenician // Phoenician is the set of Unicode characters in script Phoenician.
+ Psalter_Pahlavi = _Psalter_Pahlavi // Psalter_Pahlavi is the set of Unicode characters in script Psalter_Pahlavi.
Rejang = _Rejang // Rejang is the set of Unicode characters in script Rejang.
Runic = _Runic // Runic is the set of Unicode characters in script Runic.
Samaritan = _Samaritan // Samaritan is the set of Unicode characters in script Samaritan.
Saurashtra = _Saurashtra // Saurashtra is the set of Unicode characters in script Saurashtra.
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.
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.
@@ -4397,13 +4939,15 @@ var (
Thai = _Thai // Thai is the set of Unicode characters in script Thai.
Tibetan = _Tibetan // Tibetan is the set of Unicode characters in script Tibetan.
Tifinagh = _Tifinagh // Tifinagh is the set of Unicode characters in script Tifinagh.
+ Tirhuta = _Tirhuta // Tirhuta is the set of Unicode characters in script Tirhuta.
Ugaritic = _Ugaritic // Ugaritic is the set of Unicode characters in script Ugaritic.
Vai = _Vai // Vai is the set of Unicode characters in script Vai.
+ Warang_Citi = _Warang_Citi // Warang_Citi is the set of Unicode characters in script Warang_Citi.
Yi = _Yi // Yi is the set of Unicode characters in script Yi.
)
// Generated by running
-// maketables --props=all --url=http://www.unicode.org/Public/6.2.0/ucd/
+// maketables --props=all --url=http://www.unicode.org/Public/7.0.0/ucd/
// DO NOT EDIT
// Properties is the set of Unicode property tables.
@@ -4453,8 +4997,10 @@ var _ASCII_Hex_Digit = &RangeTable{
var _Bidi_Control = &RangeTable{
R16: []Range16{
+ {0x061c, 0x061c, 1},
{0x200e, 0x200f, 1},
{0x202a, 0x202e, 1},
+ {0x2066, 0x2069, 1},
},
}
@@ -4473,6 +5019,7 @@ var _Dash = &RangeTable{
{0x2e17, 0x2e17, 1},
{0x2e1a, 0x2e1a, 1},
{0x2e3a, 0x2e3b, 1},
+ {0x2e40, 0x2e40, 1},
{0x301c, 0x301c, 1},
{0x3030, 0x3030, 1},
{0x30a0, 0x30a0, 1},
@@ -4570,6 +5117,7 @@ var _Diacritic = &RangeTable{
{0x1939, 0x193b, 1},
{0x1a75, 0x1a7c, 1},
{0x1a7f, 0x1a7f, 1},
+ {0x1ab0, 0x1abd, 1},
{0x1b34, 0x1b34, 1},
{0x1b44, 0x1b44, 1},
{0x1b6b, 0x1b73, 1},
@@ -4579,8 +5127,10 @@ var _Diacritic = &RangeTable{
{0x1cd0, 0x1ce8, 1},
{0x1ced, 0x1ced, 1},
{0x1cf4, 0x1cf4, 1},
+ {0x1cf8, 0x1cf9, 1},
{0x1d2c, 0x1d6a, 1},
{0x1dc4, 0x1dcf, 1},
+ {0x1df5, 0x1df5, 1},
{0x1dfd, 0x1dff, 1},
{0x1fbd, 0x1fbd, 1},
{0x1fbf, 0x1fc1, 1},
@@ -4596,6 +5146,7 @@ var _Diacritic = &RangeTable{
{0xa66f, 0xa66f, 1},
{0xa67c, 0xa67d, 1},
{0xa67f, 0xa67f, 1},
+ {0xa69c, 0xa69d, 1},
{0xa6f0, 0xa6f1, 1},
{0xa717, 0xa721, 1},
{0xa788, 0xa788, 1},
@@ -4606,12 +5157,14 @@ var _Diacritic = &RangeTable{
{0xa953, 0xa953, 1},
{0xa9b3, 0xa9b3, 1},
{0xa9c0, 0xa9c0, 1},
- {0xaa7b, 0xaa7b, 1},
+ {0xa9e5, 0xa9e5, 1},
+ {0xaa7b, 0xaa7d, 1},
{0xaabf, 0xaac2, 1},
{0xaaf6, 0xaaf6, 1},
+ {0xab5b, 0xab5f, 1},
{0xabec, 0xabed, 1},
{0xfb1e, 0xfb1e, 1},
- {0xfe20, 0xfe26, 1},
+ {0xfe20, 0xfe2d, 1},
{0xff3e, 0xff3e, 1},
{0xff40, 0xff40, 1},
{0xff70, 0xff70, 1},
@@ -4619,16 +5172,30 @@ var _Diacritic = &RangeTable{
{0xffe3, 0xffe3, 1},
},
R32: []Range32{
+ {0x102e0, 0x102e0, 1},
+ {0x10ae5, 0x10ae6, 1},
{0x110b9, 0x110ba, 1},
{0x11133, 0x11134, 1},
+ {0x11173, 0x11173, 1},
{0x111c0, 0x111c0, 1},
+ {0x11235, 0x11236, 1},
+ {0x112e9, 0x112ea, 1},
+ {0x1133c, 0x1133c, 1},
+ {0x1134d, 0x1134d, 1},
+ {0x11366, 0x1136c, 1},
+ {0x11370, 0x11374, 1},
+ {0x114c2, 0x114c3, 1},
+ {0x115bf, 0x115c0, 1},
+ {0x1163f, 0x1163f, 1},
{0x116b6, 0x116b7, 1},
+ {0x16af0, 0x16af4, 1},
{0x16f8f, 0x16f9f, 1},
{0x1d167, 0x1d169, 1},
{0x1d16d, 0x1d172, 1},
{0x1d17b, 0x1d182, 1},
{0x1d185, 0x1d18b, 1},
{0x1d1aa, 0x1d1ad, 1},
+ {0x1e8d0, 0x1e8d6, 1},
},
LatinOffset: 6,
}
@@ -4653,11 +5220,17 @@ var _Extender = &RangeTable{
{0xa015, 0xa015, 1},
{0xa60c, 0xa60c, 1},
{0xa9cf, 0xa9cf, 1},
+ {0xa9e6, 0xa9e6, 1},
{0xaa70, 0xaa70, 1},
{0xaadd, 0xaadd, 1},
{0xaaf3, 0xaaf4, 1},
{0xff70, 0xff70, 1},
},
+ R32: []Range32{
+ {0x1135d, 0x1135d, 1},
+ {0x115c6, 0x115c8, 1},
+ {0x16b42, 0x16b43, 1},
+ },
LatinOffset: 1,
}
@@ -4785,8 +5358,7 @@ var _Other_Alphabetic = &RangeTable{
{0x0825, 0x0827, 1},
{0x0829, 0x082c, 1},
{0x08e4, 0x08e9, 1},
- {0x08f0, 0x08fe, 1},
- {0x0900, 0x0903, 1},
+ {0x08f0, 0x0903, 1},
{0x093a, 0x093b, 1},
{0x093e, 0x094c, 1},
{0x094e, 0x094f, 1},
@@ -4821,19 +5393,19 @@ var _Other_Alphabetic = &RangeTable{
{0x0bc6, 0x0bc8, 1},
{0x0bca, 0x0bcc, 1},
{0x0bd7, 0x0bd7, 1},
- {0x0c01, 0x0c03, 1},
+ {0x0c00, 0x0c03, 1},
{0x0c3e, 0x0c44, 1},
{0x0c46, 0x0c48, 1},
{0x0c4a, 0x0c4c, 1},
{0x0c55, 0x0c56, 1},
{0x0c62, 0x0c63, 1},
- {0x0c82, 0x0c83, 1},
+ {0x0c81, 0x0c83, 1},
{0x0cbe, 0x0cc4, 1},
{0x0cc6, 0x0cc8, 1},
{0x0cca, 0x0ccc, 1},
{0x0cd5, 0x0cd6, 1},
{0x0ce2, 0x0ce3, 1},
- {0x0d02, 0x0d03, 1},
+ {0x0d01, 0x0d03, 1},
{0x0d3e, 0x0d44, 1},
{0x0d46, 0x0d48, 1},
{0x0d4a, 0x0d4c, 1},
@@ -4886,6 +5458,7 @@ var _Other_Alphabetic = &RangeTable{
{0x1be7, 0x1bf1, 1},
{0x1c24, 0x1c35, 1},
{0x1cf2, 0x1cf3, 1},
+ {0x1de7, 0x1df4, 1},
{0x24b6, 0x24e9, 1},
{0x2de0, 0x2dff, 1},
{0xa674, 0xa67b, 1},
@@ -4910,6 +5483,7 @@ var _Other_Alphabetic = &RangeTable{
{0xfb1e, 0xfb1e, 1},
},
R32: []Range32{
+ {0x10376, 0x1037a, 1},
{0x10a01, 0x10a03, 1},
{0x10a05, 0x10a06, 1},
{0x10a0c, 0x10a0f, 1},
@@ -4921,8 +5495,27 @@ var _Other_Alphabetic = &RangeTable{
{0x11127, 0x11132, 1},
{0x11180, 0x11182, 1},
{0x111b3, 0x111bf, 1},
+ {0x1122c, 0x11234, 1},
+ {0x11237, 0x11237, 1},
+ {0x112df, 0x112e8, 1},
+ {0x11301, 0x11303, 1},
+ {0x1133e, 0x11344, 1},
+ {0x11347, 0x11348, 1},
+ {0x1134b, 0x1134c, 1},
+ {0x11357, 0x11357, 1},
+ {0x11362, 0x11363, 1},
+ {0x114b0, 0x114c1, 1},
+ {0x115af, 0x115b5, 1},
+ {0x115b8, 0x115be, 1},
+ {0x11630, 0x1163e, 1},
+ {0x11640, 0x11640, 1},
{0x116ab, 0x116b5, 1},
+ {0x16b30, 0x16b36, 1},
{0x16f51, 0x16f7e, 1},
+ {0x1bc9e, 0x1bc9e, 1},
+ {0x1f130, 0x1f149, 1},
+ {0x1f150, 0x1f169, 1},
+ {0x1f170, 0x1f189, 1},
},
}
@@ -4931,7 +5524,7 @@ var _Other_Default_Ignorable_Code_Point = &RangeTable{
{0x034f, 0x034f, 1},
{0x115f, 0x1160, 1},
{0x17b4, 0x17b5, 1},
- {0x2065, 0x2069, 1},
+ {0x2065, 0x2065, 1},
{0x3164, 0x3164, 1},
{0xffa0, 0xffa0, 1},
{0xfff0, 0xfff8, 1},
@@ -4963,6 +5556,11 @@ var _Other_Grapheme_Extend = &RangeTable{
{0xff9e, 0xff9f, 1},
},
R32: []Range32{
+ {0x1133e, 0x1133e, 1},
+ {0x11357, 0x11357, 1},
+ {0x114b0, 0x114b0, 1},
+ {0x114bd, 0x114bd, 1},
+ {0x115af, 0x115af, 1},
{0x1d165, 0x1d165, 1},
{0x1d16e, 0x1d172, 1},
},
@@ -5004,8 +5602,10 @@ var _Other_Lowercase = &RangeTable{
{0x2170, 0x217f, 1},
{0x24d0, 0x24e9, 1},
{0x2c7c, 0x2c7d, 1},
+ {0xa69c, 0xa69d, 1},
{0xa770, 0xa770, 1},
{0xa7f8, 0xa7f9, 1},
+ {0xab5c, 0xab5f, 1},
},
LatinOffset: 2,
}
@@ -5053,6 +5653,7 @@ var _Other_Math = &RangeTable{
{0x21d5, 0x21db, 1},
{0x21dd, 0x21dd, 1},
{0x21e4, 0x21e5, 1},
+ {0x2308, 0x230b, 1},
{0x23b4, 0x23b5, 1},
{0x23b7, 0x23b7, 1},
{0x23d0, 0x23d0, 1},
@@ -5156,6 +5757,11 @@ var _Other_Uppercase = &RangeTable{
{0x2160, 0x216f, 1},
{0x24b6, 0x24cf, 1},
},
+ R32: []Range32{
+ {0x1f130, 0x1f149, 1},
+ {0x1f150, 0x1f169, 1},
+ {0x1f170, 0x1f189, 1},
+ },
}
var _Pattern_Syntax = &RangeTable{
@@ -5211,6 +5817,7 @@ var _Quotation_Mark = &RangeTable{
{0x00bb, 0x00bb, 1},
{0x2018, 0x201f, 1},
{0x2039, 0x203a, 1},
+ {0x2e42, 0x2e42, 1},
{0x300c, 0x300f, 1},
{0x301d, 0x301f, 1},
{0xfe41, 0xfe44, 1},
@@ -5234,8 +5841,6 @@ var _STerm = &RangeTable{
{0x0021, 0x0021, 1},
{0x002e, 0x002e, 1},
{0x003f, 0x003f, 1},
- {0x055c, 0x055c, 1},
- {0x055e, 0x055e, 1},
{0x0589, 0x0589, 1},
{0x061f, 0x061f, 1},
{0x06d4, 0x06d4, 1},
@@ -5258,6 +5863,7 @@ var _STerm = &RangeTable{
{0x203c, 0x203d, 1},
{0x2047, 0x2049, 1},
{0x2e2e, 0x2e2e, 1},
+ {0x2e3c, 0x2e3c, 1},
{0x3002, 0x3002, 1},
{0xa4ff, 0xa4ff, 1},
{0xa60e, 0xa60f, 1},
@@ -5283,6 +5889,17 @@ var _STerm = &RangeTable{
{0x110be, 0x110c1, 1},
{0x11141, 0x11143, 1},
{0x111c5, 0x111c6, 1},
+ {0x111cd, 0x111cd, 1},
+ {0x11238, 0x11239, 1},
+ {0x1123b, 0x1123c, 1},
+ {0x115c2, 0x115c3, 1},
+ {0x115c9, 0x115c9, 1},
+ {0x11641, 0x11642, 1},
+ {0x16a6e, 0x16a6f, 1},
+ {0x16af5, 0x16af5, 1},
+ {0x16b37, 0x16b38, 1},
+ {0x16b44, 0x16b44, 1},
+ {0x1bc9f, 0x1bc9f, 1},
},
LatinOffset: 3,
}
@@ -5354,6 +5971,7 @@ var _Terminal_Punctuation = &RangeTable{
{0x1361, 0x1368, 1},
{0x166d, 0x166e, 1},
{0x16eb, 0x16ed, 1},
+ {0x1735, 0x1736, 1},
{0x17d4, 0x17d6, 1},
{0x17da, 0x17da, 1},
{0x1802, 0x1805, 1},
@@ -5367,6 +5985,8 @@ var _Terminal_Punctuation = &RangeTable{
{0x203c, 0x203d, 1},
{0x2047, 0x2049, 1},
{0x2e2e, 0x2e2e, 1},
+ {0x2e3c, 0x2e3c, 1},
+ {0x2e41, 0x2e41, 1},
{0x3001, 0x3002, 1},
{0xa4fe, 0xa4ff, 1},
{0xa60d, 0xa60f, 1},
@@ -5394,12 +6014,25 @@ var _Terminal_Punctuation = &RangeTable{
{0x103d0, 0x103d0, 1},
{0x10857, 0x10857, 1},
{0x1091f, 0x1091f, 1},
+ {0x10a56, 0x10a57, 1},
+ {0x10af0, 0x10af5, 1},
{0x10b3a, 0x10b3f, 1},
+ {0x10b99, 0x10b9c, 1},
{0x11047, 0x1104d, 1},
{0x110be, 0x110c1, 1},
{0x11141, 0x11143, 1},
{0x111c5, 0x111c6, 1},
- {0x12470, 0x12473, 1},
+ {0x111cd, 0x111cd, 1},
+ {0x11238, 0x1123c, 1},
+ {0x115c2, 0x115c5, 1},
+ {0x115c9, 0x115c9, 1},
+ {0x11641, 0x11642, 1},
+ {0x12470, 0x12474, 1},
+ {0x16a6e, 0x16a6f, 1},
+ {0x16af5, 0x16af5, 1},
+ {0x16b37, 0x16b39, 1},
+ {0x16b44, 0x16b44, 1},
+ {0x1bc9f, 0x1bc9f, 1},
},
LatinOffset: 5,
}
@@ -5440,7 +6073,6 @@ var _White_Space = &RangeTable{
{0x0085, 0x0085, 1},
{0x00a0, 0x00a0, 1},
{0x1680, 0x1680, 1},
- {0x180e, 0x180e, 1},
{0x2000, 0x200a, 1},
{0x2028, 0x2029, 1},
{0x202f, 0x202f, 1},
@@ -5487,7 +6119,7 @@ var (
)
// Generated by running
-// maketables --data=http://www.unicode.org/Public/6.2.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/6.2.0/ucd/CaseFolding.txt
+// 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
// DO NOT EDIT
// CaseRanges is the table describing case mappings for all letters with
@@ -5585,13 +6217,16 @@ var _CaseRanges = []CaseRange{
{0x0256, 0x0257, d{-205, 0, -205}},
{0x0259, 0x0259, d{-202, 0, -202}},
{0x025B, 0x025B, d{-203, 0, -203}},
+ {0x025C, 0x025C, d{42319, 0, 42319}},
{0x0260, 0x0260, d{-205, 0, -205}},
+ {0x0261, 0x0261, d{42315, 0, 42315}},
{0x0263, 0x0263, d{-207, 0, -207}},
{0x0265, 0x0265, d{42280, 0, 42280}},
{0x0266, 0x0266, d{42308, 0, 42308}},
{0x0268, 0x0268, d{-209, 0, -209}},
{0x0269, 0x0269, d{-211, 0, -211}},
{0x026B, 0x026B, d{10743, 0, 10743}},
+ {0x026C, 0x026C, d{42305, 0, 42305}},
{0x026F, 0x026F, d{-211, 0, -211}},
{0x0271, 0x0271, d{10749, 0, 10749}},
{0x0272, 0x0272, d{-213, 0, -213}},
@@ -5599,15 +6234,18 @@ var _CaseRanges = []CaseRange{
{0x027D, 0x027D, d{10727, 0, 10727}},
{0x0280, 0x0280, d{-218, 0, -218}},
{0x0283, 0x0283, d{-218, 0, -218}},
+ {0x0287, 0x0287, d{42282, 0, 42282}},
{0x0288, 0x0288, d{-218, 0, -218}},
{0x0289, 0x0289, d{-69, 0, -69}},
{0x028A, 0x028B, d{-217, 0, -217}},
{0x028C, 0x028C, d{-71, 0, -71}},
{0x0292, 0x0292, d{-219, 0, -219}},
+ {0x029E, 0x029E, d{42258, 0, 42258}},
{0x0345, 0x0345, d{84, 0, 84}},
{0x0370, 0x0373, d{UpperLower, UpperLower, UpperLower}},
{0x0376, 0x0377, d{UpperLower, UpperLower, UpperLower}},
{0x037B, 0x037D, d{130, 0, 130}},
+ {0x037F, 0x037F, d{0, 116, 0}},
{0x0386, 0x0386, d{0, 38, 0}},
{0x0388, 0x038A, d{0, 37, 0}},
{0x038C, 0x038C, d{0, 64, 0}},
@@ -5631,6 +6269,7 @@ var _CaseRanges = []CaseRange{
{0x03F0, 0x03F0, d{-86, 0, -86}},
{0x03F1, 0x03F1, d{-80, 0, -80}},
{0x03F2, 0x03F2, d{7, 0, 7}},
+ {0x03F3, 0x03F3, d{-116, 0, -116}},
{0x03F4, 0x03F4, d{0, -60, 0}},
{0x03F5, 0x03F5, d{-96, 0, -96}},
{0x03F7, 0x03F8, d{UpperLower, UpperLower, UpperLower}},
@@ -5646,7 +6285,7 @@ var _CaseRanges = []CaseRange{
{0x04C0, 0x04C0, d{0, 15, 0}},
{0x04C1, 0x04CE, d{UpperLower, UpperLower, UpperLower}},
{0x04CF, 0x04CF, d{-15, 0, -15}},
- {0x04D0, 0x0527, d{UpperLower, UpperLower, UpperLower}},
+ {0x04D0, 0x052F, d{UpperLower, UpperLower, UpperLower}},
{0x0531, 0x0556, d{0, 48, 0}},
{0x0561, 0x0586, d{-48, 0, -48}},
{0x10A0, 0x10C5, d{0, 7264, 0}},
@@ -5744,7 +6383,7 @@ var _CaseRanges = []CaseRange{
{0x2D27, 0x2D27, d{-7264, 0, -7264}},
{0x2D2D, 0x2D2D, d{-7264, 0, -7264}},
{0xA640, 0xA66D, d{UpperLower, UpperLower, UpperLower}},
- {0xA680, 0xA697, d{UpperLower, UpperLower, UpperLower}},
+ {0xA680, 0xA69B, d{UpperLower, UpperLower, UpperLower}},
{0xA722, 0xA72F, d{UpperLower, UpperLower, UpperLower}},
{0xA732, 0xA76F, d{UpperLower, UpperLower, UpperLower}},
{0xA779, 0xA77C, d{UpperLower, UpperLower, UpperLower}},
@@ -5753,12 +6392,19 @@ var _CaseRanges = []CaseRange{
{0xA78B, 0xA78C, d{UpperLower, UpperLower, UpperLower}},
{0xA78D, 0xA78D, d{0, -42280, 0}},
{0xA790, 0xA793, d{UpperLower, UpperLower, UpperLower}},
- {0xA7A0, 0xA7A9, d{UpperLower, UpperLower, UpperLower}},
+ {0xA796, 0xA7A9, d{UpperLower, UpperLower, UpperLower}},
{0xA7AA, 0xA7AA, d{0, -42308, 0}},
+ {0xA7AB, 0xA7AB, d{0, -42319, 0}},
+ {0xA7AC, 0xA7AC, d{0, -42315, 0}},
+ {0xA7AD, 0xA7AD, d{0, -42305, 0}},
+ {0xA7B0, 0xA7B0, d{0, -42258, 0}},
+ {0xA7B1, 0xA7B1, d{0, -42282, 0}},
{0xFF21, 0xFF3A, d{0, 32, 0}},
{0xFF41, 0xFF5A, d{-32, 0, -32}},
{0x10400, 0x10427, d{0, 40, 0}},
{0x10428, 0x1044F, d{-40, 0, -40}},
+ {0x118A0, 0x118BF, d{0, 32, 0}},
+ {0x118C0, 0x118DF, d{-32, 0, -32}},
}
var properties = [MaxLatin1 + 1]uint8{
0x00: pC, // '\x00'
@@ -6168,8 +6814,8 @@ var foldLl = &RangeTable{
{0x0248, 0x024e, 2},
{0x0345, 0x0370, 43},
{0x0372, 0x0376, 4},
- {0x0386, 0x0388, 2},
- {0x0389, 0x038a, 1},
+ {0x037f, 0x0386, 7},
+ {0x0388, 0x038a, 1},
{0x038c, 0x038e, 2},
{0x038f, 0x0391, 2},
{0x0392, 0x03a1, 1},
@@ -6182,7 +6828,7 @@ var foldLl = &RangeTable{
{0x0460, 0x0480, 2},
{0x048a, 0x04c0, 2},
{0x04c1, 0x04cd, 2},
- {0x04d0, 0x0526, 2},
+ {0x04d0, 0x052e, 2},
{0x0531, 0x0556, 1},
{0x10a0, 0x10c5, 1},
{0x10c7, 0x10cd, 6},
@@ -6217,18 +6863,21 @@ var foldLl = &RangeTable{
{0x2ceb, 0x2ced, 2},
{0x2cf2, 0xa640, 31054},
{0xa642, 0xa66c, 2},
- {0xa680, 0xa696, 2},
+ {0xa680, 0xa69a, 2},
{0xa722, 0xa72e, 2},
{0xa732, 0xa76e, 2},
{0xa779, 0xa77d, 2},
{0xa77e, 0xa786, 2},
{0xa78b, 0xa78d, 2},
{0xa790, 0xa792, 2},
- {0xa7a0, 0xa7aa, 2},
+ {0xa796, 0xa7aa, 2},
+ {0xa7ab, 0xa7ad, 1},
+ {0xa7b0, 0xa7b1, 1},
{0xff21, 0xff3a, 1},
},
R32: []Range32{
{0x10400, 0x10427, 1},
+ {0x118a0, 0x118bf, 1},
},
LatinOffset: 3,
}
@@ -6284,30 +6933,31 @@ var foldLu = &RangeTable{
{0x0250, 0x0254, 1},
{0x0256, 0x0257, 1},
{0x0259, 0x025b, 2},
- {0x0260, 0x0263, 3},
- {0x0265, 0x0266, 1},
- {0x0268, 0x0269, 1},
- {0x026b, 0x026f, 4},
+ {0x025c, 0x0260, 4},
+ {0x0261, 0x0265, 2},
+ {0x0266, 0x0268, 2},
+ {0x0269, 0x026b, 2},
+ {0x026c, 0x026f, 3},
{0x0271, 0x0272, 1},
{0x0275, 0x027d, 8},
{0x0280, 0x0283, 3},
- {0x0288, 0x028c, 1},
- {0x0292, 0x0345, 179},
- {0x0371, 0x0373, 2},
- {0x0377, 0x037b, 4},
+ {0x0287, 0x028c, 1},
+ {0x0292, 0x029e, 12},
+ {0x0345, 0x0371, 44},
+ {0x0373, 0x037b, 4},
{0x037c, 0x037d, 1},
{0x03ac, 0x03af, 1},
{0x03b1, 0x03ce, 1},
{0x03d0, 0x03d1, 1},
{0x03d5, 0x03d7, 1},
{0x03d9, 0x03ef, 2},
- {0x03f0, 0x03f2, 1},
+ {0x03f0, 0x03f3, 1},
{0x03f5, 0x03fb, 3},
{0x0430, 0x045f, 1},
{0x0461, 0x0481, 2},
{0x048b, 0x04bf, 2},
{0x04c2, 0x04ce, 2},
- {0x04cf, 0x0527, 2},
+ {0x04cf, 0x052f, 2},
{0x0561, 0x0586, 1},
{0x1d79, 0x1d7d, 4},
{0x1e01, 0x1e95, 2},
@@ -6336,18 +6986,19 @@ var foldLu = &RangeTable{
{0x2d01, 0x2d25, 1},
{0x2d27, 0x2d2d, 6},
{0xa641, 0xa66d, 2},
- {0xa681, 0xa697, 2},
+ {0xa681, 0xa69b, 2},
{0xa723, 0xa72f, 2},
{0xa733, 0xa76f, 2},
{0xa77a, 0xa77c, 2},
{0xa77f, 0xa787, 2},
{0xa78c, 0xa791, 5},
- {0xa793, 0xa7a1, 14},
- {0xa7a3, 0xa7a9, 2},
+ {0xa793, 0xa797, 4},
+ {0xa799, 0xa7a9, 2},
{0xff41, 0xff5a, 1},
},
R32: []Range32{
{0x10428, 0x1044f, 1},
+ {0x118c0, 0x118df, 1},
},
LatinOffset: 4,
}
@@ -6372,7 +7023,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: 3462 16-bit, 832 32-bit, 4294 total.
-// Range bytes: 20772 16-bit, 9984 32-bit, 30756 total.
+// Range entries: 3532 16-bit, 1204 32-bit, 4736 total.
+// Range bytes: 21192 16-bit, 14448 32-bit, 35640 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 903e4012aa..c0e47c535a 100644
--- a/libgo/go/unicode/utf16/utf16.go
+++ b/libgo/go/unicode/utf16/utf16.go
@@ -36,7 +36,7 @@ func IsSurrogate(r rune) bool {
// the Unicode replacement code point U+FFFD.
func DecodeRune(r1, r2 rune) rune {
if surr1 <= r1 && r1 < surr2 && surr2 <= r2 && r2 < surr3 {
- return (rune(r1)-surr1)<<10 | (rune(r2) - surr2) + 0x10000
+ return (r1-surr1)<<10 | (r2 - surr2) + 0x10000
}
return replacementChar
}
diff --git a/libgo/go/unicode/utf16/utf16_test.go b/libgo/go/unicode/utf16/utf16_test.go
index ee16a303df..3dca472bbe 100644
--- a/libgo/go/unicode/utf16/utf16_test.go
+++ b/libgo/go/unicode/utf16/utf16_test.go
@@ -99,3 +99,51 @@ func TestDecode(t *testing.T) {
}
}
}
+
+var decodeRuneTests = []struct {
+ r1, r2 rune
+ want rune
+}{
+ {0xd800, 0xdc00, 0x10000},
+ {0xd800, 0xdc01, 0x10001},
+ {0xd808, 0xdf45, 0x12345},
+ {0xdbff, 0xdfff, 0x10ffff},
+ {0xd800, 'a', 0xfffd}, // illegal, replacement rune substituted
+}
+
+func TestDecodeRune(t *testing.T) {
+ for i, tt := range decodeRuneTests {
+ got := DecodeRune(tt.r1, tt.r2)
+ if got != tt.want {
+ t.Errorf("%d: DecodeRune(%q, %q) = %v; want %v", i, tt.r1, tt.r2, got, tt.want)
+ }
+ }
+}
+
+var surrogateTests = []struct {
+ r rune
+ want bool
+}{
+ // from http://en.wikipedia.org/wiki/UTF-16
+ {'\u007A', false}, // LATIN SMALL LETTER Z
+ {'\u6C34', false}, // CJK UNIFIED IDEOGRAPH-6C34 (water)
+ {'\uFEFF', false}, // Byte Order Mark
+ {'\U00010000', false}, // LINEAR B SYLLABLE B008 A (first non-BMP code point)
+ {'\U0001D11E', false}, // MUSICAL SYMBOL G CLEF
+ {'\U0010FFFD', false}, // PRIVATE USE CHARACTER-10FFFD (last Unicode code point)
+
+ {rune(0xd7ff), false}, // surr1-1
+ {rune(0xd800), true}, // surr1
+ {rune(0xdc00), true}, // surr2
+ {rune(0xe000), false}, // surr3
+ {rune(0xdfff), true}, // surr3-1
+}
+
+func TestIsSurrogate(t *testing.T) {
+ for i, tt := range surrogateTests {
+ got := IsSurrogate(tt.r)
+ if got != tt.want {
+ t.Errorf("%d: IsSurrogate(%q) = %v; want %v", i, tt.r, got, tt.want)
+ }
+ }
+}
diff --git a/libgo/go/unicode/utf8/example_test.go b/libgo/go/unicode/utf8/example_test.go
index fe20373368..7b3e7ac742 100644
--- a/libgo/go/unicode/utf8/example_test.go
+++ b/libgo/go/unicode/utf8/example_test.go
@@ -1,3 +1,7 @@
+// 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 utf8_test
import (
diff --git a/libgo/go/unicode/utf8/utf8.go b/libgo/go/unicode/utf8/utf8.go
index 93d0be5e0c..9ac37184d6 100644
--- a/libgo/go/unicode/utf8/utf8.go
+++ b/libgo/go/unicode/utf8/utf8.go
@@ -211,8 +211,11 @@ func FullRuneInString(s string) bool {
return !short
}
-// DecodeRune unpacks the first UTF-8 encoding in p and returns the rune and its width in bytes.
-// If the encoding is invalid, it returns (RuneError, 1), an impossible result for correct UTF-8.
+// DecodeRune unpacks the first UTF-8 encoding in p and returns the rune and
+// its width in bytes. If p is empty it returns (RuneError, 0). Otherwise, if
+// the encoding is invalid, it returns (RuneError, 1). Both are impossible
+// results for correct UTF-8.
+//
// An encoding is invalid if it is incorrect UTF-8, encodes a rune that is
// out of range, or is not the shortest possible UTF-8 encoding for the
// value. No other validation is performed.
@@ -221,8 +224,10 @@ func DecodeRune(p []byte) (r rune, size int) {
return
}
-// DecodeRuneInString is like DecodeRune but its input is a string.
-// If the encoding is invalid, it returns (RuneError, 1), an impossible result for correct UTF-8.
+// DecodeRuneInString is like DecodeRune but its input is a string. If s is
+// empty it returns (RuneError, 0). Otherwise, if the encoding is invalid, it
+// returns (RuneError, 1). Both are impossible results for correct UTF-8.
+//
// An encoding is invalid if it is incorrect UTF-8, encodes a rune that is
// out of range, or is not the shortest possible UTF-8 encoding for the
// value. No other validation is performed.
@@ -231,8 +236,11 @@ func DecodeRuneInString(s string) (r rune, size int) {
return
}
-// DecodeLastRune unpacks the last UTF-8 encoding in p and returns the rune and its width in bytes.
-// If the encoding is invalid, it returns (RuneError, 1), an impossible result for correct UTF-8.
+// DecodeLastRune unpacks the last UTF-8 encoding in p and returns the rune and
+// its width in bytes. If p is empty it returns (RuneError, 0). Otherwise, if
+// the encoding is invalid, it returns (RuneError, 1). Both are impossible
+// results for correct UTF-8.
+//
// An encoding is invalid if it is incorrect UTF-8, encodes a rune that is
// out of range, or is not the shortest possible UTF-8 encoding for the
// value. No other validation is performed.
@@ -268,8 +276,10 @@ func DecodeLastRune(p []byte) (r rune, size int) {
return r, size
}
-// DecodeLastRuneInString is like DecodeLastRune but its input is a string.
-// If the encoding is invalid, it returns (RuneError, 1), an impossible result for correct UTF-8.
+// DecodeLastRuneInString is like DecodeLastRune but its input is a string. If
+// s is empty it returns (RuneError, 0). Otherwise, if the encoding is invalid,
+// it returns (RuneError, 1). Both are impossible results for correct UTF-8.
+//
// An encoding is invalid if it is incorrect UTF-8, encodes a rune that is
// out of range, or is not the shortest possible UTF-8 encoding for the
// value. No other validation is performed.
@@ -329,37 +339,29 @@ func RuneLen(r rune) int {
// It returns the number of bytes written.
func EncodeRune(p []byte, r rune) int {
// Negative values are erroneous. Making it unsigned addresses the problem.
- if uint32(r) <= rune1Max {
+ switch i := uint32(r); {
+ case i <= rune1Max:
p[0] = byte(r)
return 1
- }
-
- if uint32(r) <= rune2Max {
+ case i <= rune2Max:
p[0] = t2 | byte(r>>6)
p[1] = tx | byte(r)&maskx
return 2
- }
-
- if uint32(r) > MaxRune {
+ case i > MaxRune, surrogateMin <= i && i <= surrogateMax:
r = RuneError
- }
-
- if surrogateMin <= r && r <= surrogateMax {
- r = RuneError
- }
-
- if uint32(r) <= rune3Max {
+ fallthrough
+ case i <= rune3Max:
p[0] = t3 | byte(r>>12)
p[1] = tx | byte(r>>6)&maskx
p[2] = tx | byte(r)&maskx
return 3
+ default:
+ p[0] = t4 | byte(r>>18)
+ p[1] = tx | byte(r>>12)&maskx
+ p[2] = tx | byte(r>>6)&maskx
+ p[3] = tx | byte(r)&maskx
+ return 4
}
-
- p[0] = t4 | byte(r>>18)
- p[1] = tx | byte(r>>12)&maskx
- p[2] = tx | byte(r>>6)&maskx
- p[3] = tx | byte(r)&maskx
- return 4
}
// RuneCount returns the number of runes in p. Erroneous and short
@@ -380,7 +382,7 @@ func RuneCount(p []byte) int {
// RuneCountInString is like RuneCount but its input is a string.
func RuneCountInString(s string) (n int) {
- for _ = range s {
+ for range s {
n++
}
return
diff --git a/libgo/merge.sh b/libgo/merge.sh
index 65e9f3a1d8..c79f7596dc 100755
--- a/libgo/merge.sh
+++ b/libgo/merge.sh
@@ -40,12 +40,14 @@ repository=$1
old_rev=`sed 1q MERGE`
rm -rf ${OLDDIR}
-hg clone -r ${old_rev} ${repository} ${OLDDIR}
+git clone ${repository} ${OLDDIR}
+(cd ${OLDDIR} && git checkout ${old_rev})
rm -rf ${NEWDIR}
-hg clone -u ${rev} ${repository} ${NEWDIR}
+git clone ${repository} ${NEWDIR}
+(cd ${NEWDIR} && git checkout ${rev})
-new_rev=`cd ${NEWDIR} && hg log -r ${rev} | sed 1q | sed -e 's/.*://'`
+new_rev=`cd ${NEWDIR} && git log | sed 1q | sed -e 's/commit //'`
merge() {
name=$1
@@ -69,7 +71,7 @@ merge() {
elif test -f ${old}; then
# The file exists in the old version.
if ! test -f ${libgo}; then
- echo "merge.sh: $name: skipping: exists in old and new hg, but not in libgo"
+ echo "merge.sh: $name: skipping: exists in old and new git, but not in libgo"
continue
fi
if cmp -s ${old} ${libgo}; then
@@ -124,11 +126,11 @@ merge() {
merge_c() {
from=$1
to=$2
- oldfile=${OLDDIR}/src/pkg/runtime/$from
+ oldfile=${OLDDIR}/src/runtime/$from
if test -f ${oldfile}; then
sed -e 's/·/_/g' < ${oldfile} > ${oldfile}.tmp
oldfile=${oldfile}.tmp
- newfile=${NEWDIR}/src/pkg/runtime/$from
+ newfile=${NEWDIR}/src/runtime/$from
sed -e 's/·/_/g' < ${newfile} > ${newfile}.tmp
newfile=${newfile}.tmp
libgofile=runtime/$to
@@ -136,25 +138,34 @@ merge_c() {
fi
}
-(cd ${NEWDIR}/src/pkg && find . -name '*.go' -print) | while read f; do
- oldfile=${OLDDIR}/src/pkg/$f
- newfile=${NEWDIR}/src/pkg/$f
+if test -f VERSION; then
+ if ! cmp -s ${NEWDIR}/VERSION VERSION; then
+ cp ${NEWDIR}/VERSION .
+ fi
+else
+ if test -f ${NEWDIR}/VERSION; then
+ cp ${NEWDIR}/VERSION .
+ fi
+fi
+
+(cd ${NEWDIR}/src && find . -name '*.go' -print) | while read f; do
+ oldfile=${OLDDIR}/src/$f
+ newfile=${NEWDIR}/src/$f
libgofile=go/$f
merge $f ${oldfile} ${newfile} ${libgofile}
done
-(cd ${NEWDIR}/src/pkg && find . -name testdata -print) | while read d; do
- oldtd=${OLDDIR}/src/pkg/$d
- newtd=${NEWDIR}/src/pkg/$d
+(cd ${NEWDIR}/src && find . -name testdata -print) | while read d; do
+ oldtd=${OLDDIR}/src/$d
+ newtd=${NEWDIR}/src/$d
libgotd=go/$d
if ! test -d ${oldtd}; then
continue
fi
- (cd ${oldtd} && hg status -A .) | while read f; do
- if test "`basename $f`" = ".hgignore"; then
+ (cd ${oldtd} && git ls-files .) | while read f; do
+ if test "`basename $f`" = ".gitignore"; then
continue
fi
- f=`echo $f | sed -e 's/^..//'`
name=$d/$f
oldfile=${oldtd}/$f
newfile=${newtd}/$f
@@ -163,17 +174,47 @@ done
done
done
-runtime="chan.c cpuprof.c env_posix.c lock_futex.c lock_sema.c mcache.c mcentral.c mfinal.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 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"
+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
+ # merge_c $f $f
+ true
done
-merge_c os_linux.c thread-linux.c
-merge_c mem_linux.c mem.c
+# merge_c os_linux.c thread-linux.c
+# merge_c mem_linux.c mem.c
-(cd ${OLDDIR}/src/pkg && find . -name '*.go' -print) | while read f; do
- oldfile=${OLDDIR}/src/pkg/$f
- newfile=${NEWDIR}/src/pkg/$f
+(cd ${OLDDIR}/src && find . -name '*.go' -print) | while read f; do
+ oldfile=${OLDDIR}/src/$f
+ newfile=${NEWDIR}/src/$f
libgofile=go/$f
if test -f ${newfile}; then
continue
diff --git a/libgo/mksysinfo.sh b/libgo/mksysinfo.sh
index bb6abfd04b..c2e7c24974 100755
--- a/libgo/mksysinfo.sh
+++ b/libgo/mksysinfo.sh
@@ -174,6 +174,9 @@ enum {
#ifdef TIOCGWINSZ
TIOCGWINSZ_val = TIOCGWINSZ,
#endif
+#ifdef TIOCSWINSZ
+ TIOCSWINSZ_val = TIOCSWINSZ,
+#endif
#ifdef TIOCNOTTY
TIOCNOTTY_val = TIOCNOTTY,
#endif
@@ -192,6 +195,12 @@ enum {
#ifdef TIOCSIG
TIOCSIG_val = TIOCSIG,
#endif
+#ifdef TCGETS
+ TCGETS_val = TCGETS,
+#endif
+#ifdef TCSETS
+ TCSETS_val = TCSETS,
+#endif
};
EOF
@@ -250,6 +259,16 @@ for flag in F_GETLK F_SETLK F_SETLKW; do
fi
done
+# The Flock_t struct for fcntl.
+grep '^type _flock ' gen-sysinfo.go | \
+ sed -e 's/type _flock/type Flock_t/' \
+ -e 's/l_type/Type/' \
+ -e 's/l_whence/Whence/' \
+ -e 's/l_start/Start/' \
+ -e 's/l_len/Len/' \
+ -e 's/l_pid/Pid/' \
+ >> ${OUT}
+
# The signal numbers.
grep '^const _SIG[^_]' gen-sysinfo.go | \
grep -v '^const _SIGEV_' | \
@@ -420,12 +439,50 @@ if ! grep '^const _PTRACE_TRACEME' ${OUT} > /dev/null 2>&1; then
echo "const _PTRACE_TRACEME = 0" >> ${OUT}
fi
+# A helper function that prints a structure from gen-sysinfo.go with the first
+# letter of the field names in upper case. $1 is the name of structure. If $2
+# is not empty, the structure or type is renamed to $2.
+upcase_fields () {
+ name="$1"
+ def=`grep "^type $name" gen-sysinfo.go`
+ fields=`echo $def | sed -e 's/^[^{]*{\(.*\)}$/\1/'`
+ prefix=`echo $def | sed -e 's/{.*//'`
+ if test "$2" != ""; then
+ prefix=`echo $prefix | sed -e "s/$1/$2/"`
+ fi
+ if test "$fields" != ""; then
+ nfields=
+ while test -n "$fields"; do
+ field=`echo $fields | sed -e 's/^\([^;]*\);.*$/\1/'`
+ fields=`echo $fields | sed -e 's/^[^;]*; *\(.*\)$/\1/'`
+ # capitalize the next character.
+ f=`echo $field | sed -e 's/^\(.\).*$/\1/'`
+ r=`echo $field | sed -e 's/^.\(.*\)$/\1/'`
+ f=`echo $f | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ`
+ field="$f$r"
+ nfields="$nfields $field;"
+ done
+ echo "${prefix} {$nfields }"
+ fi
+}
+
# The registers returned by PTRACE_GETREGS. This is probably
# GNU/Linux specific; it should do no harm if there is no
# _user_regs_struct.
regs=`grep '^type _user_regs_struct struct' gen-sysinfo.go || true`
+if test "$regs" == ""; then
+ # s390
+ regs=`grep '^type __user_regs_struct struct' gen-sysinfo.go || true`
+ if test "$regs" != ""; then
+ # Substructures of __user_regs_struct on s390
+ upcase_fields "__user_psw_struct" "PtracePsw" >> ${OUT} || true
+ upcase_fields "__user_fpregs_struct" "PtraceFpregs" >> ${OUT} || true
+ upcase_fields "__user_per_struct" "PtracePer" >> ${OUT} || true
+ fi
+fi
if test "$regs" != ""; then
- regs=`echo $regs | sed -e 's/type _user_regs_struct struct //' -e 's/[{}]//g'`
+ regs=`echo $regs |
+ sed -e 's/type __*user_regs_struct struct //' -e 's/[{}]//g'`
regs=`echo $regs | sed -e s'/^ *//'`
nregs=
while test -n "$regs"; do
@@ -436,6 +493,10 @@ if test "$regs" != ""; then
r=`echo $field | sed -e 's/^.\(.*\)$/\1/'`
f=`echo $f | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ`
field="$f$r"
+ field=`echo "$field" | sed \
+ -e 's/__user_psw_struct/PtracePsw/' \
+ -e 's/__user_fpregs_struct/PtraceFpregs/' \
+ -e 's/__user_per_struct/PtracePer/'`
nregs="$nregs $field;"
done
echo "type PtraceRegs struct {$nregs }" >> ${OUT}
@@ -597,7 +658,7 @@ grep '^const _DT_' gen-sysinfo.go |
rusage=`grep '^type _rusage struct' gen-sysinfo.go`
if test "$rusage" != ""; then
# Remove anonymous unions from GNU/Linux <bits/resource.h>.
- rusage=`echo $rusage | sed -e 's/Godump_[0-9]* struct {\([^}]*\)};/\1/g'`
+ rusage=`echo $rusage | sed -e 's/Godump_[0-9][0-9]* struct {\([^}]*\)};/\1/g'`
rusage=`echo $rusage | sed -e 's/type _rusage struct //' -e 's/[{}]//g'`
rusage=`echo $rusage | sed -e 's/^ *//'`
nrusage=
@@ -685,12 +746,7 @@ grep '^const _SCM_' gen-sysinfo.go | \
sed -e 's/^\(const \)_\(SCM_[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
# The ucred struct.
-grep '^type _ucred ' gen-sysinfo.go | \
- sed -e 's/_ucred/Ucred/' \
- -e 's/pid/Pid/' \
- -e 's/uid/Uid/' \
- -e 's/gid/Gid/' \
- >> ${OUT}
+upcase_fields "_ucred" "Ucred" >> ${OUT} || true
# The ip_mreq struct.
grep '^type _ip_mreq ' gen-sysinfo.go | \
@@ -780,6 +836,11 @@ if ! grep '^const TIOCGWINSZ' ${OUT} >/dev/null 2>&1; then
echo 'const TIOCGWINSZ = _TIOCGWINSZ_val' >> ${OUT}
fi
fi
+if ! grep '^const TIOCSWINSZ' ${OUT} >/dev/null 2>&1; then
+ if grep '^const _TIOCSWINSZ_val' ${OUT} >/dev/null 2>&1; then
+ echo 'const TIOCSWINSZ = _TIOCSWINSZ_val' >> ${OUT}
+ fi
+fi
if ! grep '^const TIOCNOTTY' ${OUT} >/dev/null 2>&1; then
if grep '^const _TIOCNOTTY_val' ${OUT} >/dev/null 2>&1; then
echo 'const TIOCNOTTY = _TIOCNOTTY_val' >> ${OUT}
@@ -812,8 +873,18 @@ if ! grep '^const TIOCSIG' ${OUT} >/dev/null 2>&1; then
fi
# The ioctl flags for terminal control
-grep '^const _TC[GS]ET' gen-sysinfo.go | \
+grep '^const _TC[GS]ET' gen-sysinfo.go | grep -v _val | \
sed -e 's/^\(const \)_\(TC[GS]ET[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
+if ! grep '^const TCGETS' ${OUT} >/dev/null 2>&1; then
+ if grep '^const _TCGETS_val' ${OUT} >/dev/null 2>&1; then
+ echo 'const TCGETS = _TCGETS_val' >> ${OUT}
+ fi
+fi
+if ! grep '^const TCSETS' ${OUT} >/dev/null 2>&1; then
+ if grep '^const _TCSETS_val' ${OUT} >/dev/null 2>&1; then
+ echo 'const TCSETS = _TCSETS_val' >> ${OUT}
+ fi
+fi
# ioctl constants. Might fall back to 0 if TIOCNXCL is missing, too, but
# needs handling in syscalls.exec.go.
@@ -1169,11 +1240,6 @@ grep '^type _inotify_event ' gen-sysinfo.go | \
grep '^const _CLONE_' gen-sysinfo.go | \
sed -e 's/^\(const \)_\(CLONE_[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
-# The Solaris 11 Update 1 _zone_net_addr_t struct.
-grep '^type _zone_net_addr_t ' gen-sysinfo.go | \
- sed -e 's/_in6_addr/[16]byte/' \
- >> ${OUT}
-
# Struct sizes.
set cmsghdr Cmsghdr ip_mreq IPMreq ip_mreqn IPMreqn ipv6_mreq IPv6Mreq \
ifaddrmsg IfAddrmsg ifinfomsg IfInfomsg in_pktinfo Inet4Pktinfo \
@@ -1207,4 +1273,9 @@ if ! grep 'const SizeofICMPv6Filter ' ${OUT} >/dev/null 2>&1; then
echo 'const SizeofICMPv6Filter = 32' >> ${OUT}
fi
+# The Solaris 11 Update 1 _zone_net_addr_t struct.
+grep '^type _zone_net_addr_t ' gen-sysinfo.go | \
+ sed -e 's/_in6_addr/[16]byte/' \
+ >> ${OUT}
+
exit $?
diff --git a/libgo/mvifdiff.sh b/libgo/mvifdiff.sh
new file mode 100644
index 0000000000..6706e40de4
--- /dev/null
+++ b/libgo/mvifdiff.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+# 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.
+
+# The mvifdiff.sh script works like the mv(1) command, except
+# that it does not touch the destination file if its contents
+# are the same as the source file.
+
+if cmp -s "$1" "$2" ; then
+ rm "$1"
+else
+ mv "$1" "$2"
+fi
diff --git a/libgo/runtime/chan.c b/libgo/runtime/chan.goc
index 1d9e6681d3..0cc823d8ac 100644
--- a/libgo/runtime/chan.c
+++ b/libgo/runtime/chan.goc
@@ -2,95 +2,21 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+package runtime
#include "runtime.h"
#include "arch.h"
#include "go-type.h"
-#include "race.h"
#include "malloc.h"
-
-#define NOSELGEN 1
-
-typedef struct WaitQ WaitQ;
-typedef struct SudoG SudoG;
-typedef struct Select Select;
-typedef struct Scase Scase;
-
-typedef struct __go_type_descriptor Type;
-typedef struct __go_channel_type ChanType;
-
-struct SudoG
-{
- G* g; // g and selgen constitute
- uint32 selgen; // a weak pointer to g
- SudoG* link;
- int64 releasetime;
- byte* elem; // data element
-};
-
-struct WaitQ
-{
- SudoG* first;
- SudoG* last;
-};
-
-// The garbage collector is assuming that Hchan can only contain pointers into the stack
-// and cannot contain pointers into the heap.
-struct Hchan
-{
- uintgo qcount; // total data in the q
- uintgo dataqsiz; // size of the circular q
- uint16 elemsize;
- uint8 elemalign;
- uint8 pad; // ensures proper alignment of the buffer that follows Hchan in memory
- bool closed;
- uintgo sendx; // send index
- uintgo recvx; // receive index
- WaitQ recvq; // list of recv waiters
- WaitQ sendq; // list of send waiters
- Lock;
-};
+#include "chan.h"
uint32 runtime_Hchansize = sizeof(Hchan);
-// Buffer follows Hchan immediately in memory.
-// chanbuf(c, i) is pointer to the i'th slot in the buffer.
-#define chanbuf(c, i) ((byte*)((c)+1)+(uintptr)(c)->elemsize*(i))
-
-enum
-{
- debug = 0,
-
- // Scase.kind
- CaseRecv,
- CaseSend,
- CaseDefault,
-};
-
-struct Scase
-{
- SudoG sg; // must be first member (cast to Scase)
- Hchan* chan; // chan
- uint16 kind;
- uint16 index; // index to return
- bool* receivedp; // pointer to received bool (recv2)
-};
-
-struct Select
-{
- uint16 tcase; // total count of scase[]
- uint16 ncase; // currently filled scase[]
- uint16* pollorder; // case poll order
- Hchan** lockorder; // channel lock order
- Scase scase[1]; // one per case (in order of appearance)
-};
-
static void dequeueg(WaitQ*);
static SudoG* dequeue(WaitQ*);
static void enqueue(WaitQ*, SudoG*);
-static void racesync(Hchan*, SudoG*);
-Hchan*
-runtime_makechan_c(ChanType *t, int64 hint)
+static Hchan*
+makechan(ChanType *t, int64 hint)
{
Hchan *c;
uintptr n;
@@ -102,16 +28,16 @@ runtime_makechan_c(ChanType *t, int64 hint)
if(elem->__size >= (1<<16))
runtime_throw("makechan: invalid channel element type");
- if(hint < 0 || (intgo)hint != hint || (elem->__size > 0 && (uintptr)hint > MaxMem / elem->__size))
+ if(hint < 0 || (intgo)hint != hint || (elem->__size > 0 && (uintptr)hint > (MaxMem - sizeof(*c)) / elem->__size))
runtime_panicstring("makechan: size out of range");
n = sizeof(*c);
n = ROUND(n, elem->__align);
// allocate memory in one call
- c = (Hchan*)runtime_mallocgc(n + hint*elem->__size, (uintptr)t | TypeInfo_Chan, 0);
+ c = (Hchan*)runtime_mallocgc(sizeof(*c) + hint*elem->__size, (uintptr)t | TypeInfo_Chan, 0);
c->elemsize = elem->__size;
- c->elemalign = elem->__align;
+ c->elemtype = elem;
c->dataqsiz = hint;
if(debug)
@@ -121,34 +47,20 @@ runtime_makechan_c(ChanType *t, int64 hint)
return c;
}
-// For reflect
-// func makechan(typ *ChanType, size uint64) (chan)
-uintptr reflect_makechan(ChanType *, uint64)
- __asm__ (GOSYM_PREFIX "reflect.makechan");
-
-uintptr
-reflect_makechan(ChanType *t, uint64 size)
-{
- void *ret;
- Hchan *c;
-
- c = runtime_makechan_c(t, size);
- ret = runtime_mal(sizeof(void*));
- __builtin_memcpy(ret, &c, sizeof(void*));
- return (uintptr)ret;
+func reflect.makechan(t *ChanType, size uint64) (c *Hchan) {
+ c = makechan(t, size);
}
-// makechan(t *ChanType, hint int64) (hchan *chan any);
Hchan*
__go_new_channel(ChanType *t, uintptr hint)
{
- return runtime_makechan_c(t, hint);
+ return makechan(t, hint);
}
Hchan*
__go_new_channel_big(ChanType *t, uint64 hint)
{
- return runtime_makechan_c(t, hint);
+ return makechan(t, hint);
}
/*
@@ -165,9 +77,10 @@ __go_new_channel_big(ChanType *t, uint64 hint)
* been closed. it is easiest to loop and re-run
* the operation; we'll see that it's now closed.
*/
-void
-runtime_chansend(ChanType *t, Hchan *c, byte *ep, bool *pres, void *pc)
+static bool
+chansend(ChanType *t, Hchan *c, byte *ep, bool block, void *pc)
{
+ USED(pc);
SudoG *sg;
SudoG mysg;
G* gp;
@@ -178,12 +91,10 @@ runtime_chansend(ChanType *t, Hchan *c, byte *ep, bool *pres, void *pc)
if(c == nil) {
USED(t);
- if(pres != nil) {
- *pres = false;
- return;
- }
+ if(!block)
+ return false;
runtime_park(nil, nil, "chan send (nil chan)");
- return; // not reached
+ return false; // not reached
}
if(runtime_gcwaiting())
@@ -201,8 +112,6 @@ runtime_chansend(ChanType *t, Hchan *c, byte *ep, bool *pres, void *pc)
}
runtime_lock(c);
- if(raceenabled)
- runtime_racereadpc(c, pc, runtime_chansend);
if(c->closed)
goto closed;
@@ -211,8 +120,6 @@ runtime_chansend(ChanType *t, Hchan *c, byte *ep, bool *pres, void *pc)
sg = dequeue(&c->recvq);
if(sg != nil) {
- if(raceenabled)
- racesync(c, sg);
runtime_unlock(c);
gp = sg->g;
@@ -222,24 +129,20 @@ runtime_chansend(ChanType *t, Hchan *c, byte *ep, bool *pres, void *pc)
if(sg->releasetime)
sg->releasetime = runtime_cputicks();
runtime_ready(gp);
-
- if(pres != nil)
- *pres = true;
- return;
+ return true;
}
- if(pres != nil) {
+ if(!block) {
runtime_unlock(c);
- *pres = false;
- return;
+ return false;
}
mysg.elem = ep;
mysg.g = g;
- mysg.selgen = NOSELGEN;
+ mysg.selectdone = nil;
g->param = nil;
enqueue(&c->sendq, &mysg);
- runtime_park(runtime_unlock, c, "chan send");
+ runtime_parkunlock(c, "chan send");
if(g->param == nil) {
runtime_lock(c);
@@ -251,31 +154,27 @@ runtime_chansend(ChanType *t, Hchan *c, byte *ep, bool *pres, void *pc)
if(mysg.releasetime > 0)
runtime_blockevent(mysg.releasetime - t0, 2);
- return;
+ return true;
asynch:
if(c->closed)
goto closed;
if(c->qcount >= c->dataqsiz) {
- if(pres != nil) {
+ if(!block) {
runtime_unlock(c);
- *pres = false;
- return;
+ return false;
}
mysg.g = g;
mysg.elem = nil;
- mysg.selgen = NOSELGEN;
+ mysg.selectdone = nil;
enqueue(&c->sendq, &mysg);
- runtime_park(runtime_unlock, c, "chan send");
+ runtime_parkunlock(c, "chan send");
runtime_lock(c);
goto asynch;
}
- if(raceenabled)
- runtime_racerelease(chanbuf(c, c->sendx));
-
runtime_memmove(chanbuf(c, c->sendx), ep, c->elemsize);
if(++c->sendx == c->dataqsiz)
c->sendx = 0;
@@ -290,20 +189,19 @@ asynch:
runtime_ready(gp);
} else
runtime_unlock(c);
- if(pres != nil)
- *pres = true;
if(mysg.releasetime > 0)
runtime_blockevent(mysg.releasetime - t0, 2);
- return;
+ return true;
closed:
runtime_unlock(c);
runtime_panicstring("send on closed channel");
+ return false; // not reached
}
-void
-runtime_chanrecv(ChanType *t, Hchan* c, byte *ep, bool *selected, bool *received)
+static bool
+chanrecv(ChanType *t, Hchan* c, byte *ep, bool block, bool *received)
{
SudoG *sg;
SudoG mysg;
@@ -321,12 +219,10 @@ runtime_chanrecv(ChanType *t, Hchan* c, byte *ep, bool *selected, bool *received
if(c == nil) {
USED(t);
- if(selected != nil) {
- *selected = false;
- return;
- }
+ if(!block)
+ return false;
runtime_park(nil, nil, "chan receive (nil chan)");
- return; // not reached
+ return false; // not reached
}
t0 = 0;
@@ -345,8 +241,6 @@ runtime_chanrecv(ChanType *t, Hchan* c, byte *ep, bool *selected, bool *received
sg = dequeue(&c->sendq);
if(sg != nil) {
- if(raceenabled)
- racesync(c, sg);
runtime_unlock(c);
if(ep != nil)
@@ -357,25 +251,22 @@ runtime_chanrecv(ChanType *t, Hchan* c, byte *ep, bool *selected, bool *received
sg->releasetime = runtime_cputicks();
runtime_ready(gp);
- if(selected != nil)
- *selected = true;
if(received != nil)
*received = true;
- return;
+ return true;
}
- if(selected != nil) {
+ if(!block) {
runtime_unlock(c);
- *selected = false;
- return;
+ return false;
}
mysg.elem = ep;
mysg.g = g;
- mysg.selgen = NOSELGEN;
+ mysg.selectdone = nil;
g->param = nil;
enqueue(&c->recvq, &mysg);
- runtime_park(runtime_unlock, c, "chan receive");
+ runtime_parkunlock(c, "chan receive");
if(g->param == nil) {
runtime_lock(c);
@@ -388,33 +279,29 @@ runtime_chanrecv(ChanType *t, Hchan* c, byte *ep, bool *selected, bool *received
*received = true;
if(mysg.releasetime > 0)
runtime_blockevent(mysg.releasetime - t0, 2);
- return;
+ return true;
asynch:
if(c->qcount <= 0) {
if(c->closed)
goto closed;
- if(selected != nil) {
+ if(!block) {
runtime_unlock(c);
- *selected = false;
if(received != nil)
*received = false;
- return;
+ return false;
}
mysg.g = g;
mysg.elem = nil;
- mysg.selgen = NOSELGEN;
+ mysg.selectdone = nil;
enqueue(&c->recvq, &mysg);
- runtime_park(runtime_unlock, c, "chan receive");
+ runtime_parkunlock(c, "chan receive");
runtime_lock(c);
goto asynch;
}
- if(raceenabled)
- runtime_raceacquire(chanbuf(c, c->recvx));
-
if(ep != nil)
runtime_memmove(ep, chanbuf(c, c->recvx), c->elemsize);
runtime_memclr(chanbuf(c, c->recvx), c->elemsize);
@@ -432,26 +319,21 @@ asynch:
} else
runtime_unlock(c);
- if(selected != nil)
- *selected = true;
if(received != nil)
*received = true;
if(mysg.releasetime > 0)
runtime_blockevent(mysg.releasetime - t0, 2);
- return;
+ return true;
closed:
if(ep != nil)
runtime_memclr(ep, c->elemsize);
- if(selected != nil)
- *selected = true;
if(received != nil)
*received = false;
- if(raceenabled)
- runtime_raceacquire(c);
runtime_unlock(c);
if(mysg.releasetime > 0)
runtime_blockevent(mysg.releasetime - t0, 2);
+ return true;
}
// The compiler generates a call to __go_send_small to send a value 8
@@ -464,68 +346,45 @@ __go_send_small(ChanType *t, Hchan* c, uint64 val)
byte b[sizeof(uint64)];
uint64 v;
} u;
- byte *p;
+ byte *v;
u.v = val;
#ifndef WORDS_BIGENDIAN
- p = u.b;
+ v = u.b;
#else
- p = u.b + sizeof(uint64) - t->__element_type->__size;
+ v = u.b + sizeof(uint64) - t->__element_type->__size;
#endif
- runtime_chansend(t, c, p, nil, runtime_getcallerpc(&t));
+ chansend(t, c, v, true, runtime_getcallerpc(&t));
}
// The compiler generates a call to __go_send_big to send a value
// larger than 8 bytes or smaller.
void
-__go_send_big(ChanType *t, Hchan* c, byte* p)
+__go_send_big(ChanType *t, Hchan* c, byte* v)
{
- runtime_chansend(t, c, p, nil, runtime_getcallerpc(&t));
+ chansend(t, c, v, true, runtime_getcallerpc(&t));
}
-// The compiler generates a call to __go_receive_small to receive a
-// value 8 bytes or smaller.
-uint64
-__go_receive_small(ChanType *t, Hchan* c)
-{
- union {
- byte b[sizeof(uint64)];
- uint64 v;
- } u;
- byte *p;
-
- u.v = 0;
-#ifndef WORDS_BIGENDIAN
- p = u.b;
-#else
- p = u.b + sizeof(uint64) - t->__element_type->__size;
-#endif
- runtime_chanrecv(t, c, p, nil, nil);
- return u.v;
-}
-
-// The compiler generates a call to __go_receive_big to receive a
-// value larger than 8 bytes.
+// The compiler generates a call to __go_receive to receive a
+// value from a channel.
void
-__go_receive_big(ChanType *t, Hchan* c, byte* p)
+__go_receive(ChanType *t, Hchan* c, byte* v)
{
- runtime_chanrecv(t, c, p, nil, nil);
+ chanrecv(t, c, v, true, nil);
}
-_Bool runtime_chanrecv2(ChanType *t, Hchan* c, byte* p)
+_Bool runtime_chanrecv2(ChanType *t, Hchan* c, byte* v)
__asm__ (GOSYM_PREFIX "runtime.chanrecv2");
_Bool
-runtime_chanrecv2(ChanType *t, Hchan* c, byte* p)
+runtime_chanrecv2(ChanType *t, Hchan* c, byte* v)
{
- bool received;
+ bool received = false;
- runtime_chanrecv(t, c, p, nil, &received);
+ chanrecv(t, c, v, true, &received);
return received;
}
-// func selectnbsend(c chan any, elem any) bool
-//
// compiler implements
//
// select {
@@ -543,17 +402,10 @@ runtime_chanrecv2(ChanType *t, Hchan* c, byte* p)
// ... bar
// }
//
-_Bool
-runtime_selectnbsend(ChanType *t, Hchan *c, byte *p)
-{
- bool res;
-
- runtime_chansend(t, c, p, &res, runtime_getcallerpc(&t));
- return res;
+func selectnbsend(t *ChanType, c *Hchan, elem *byte) (selected bool) {
+ selected = chansend(t, c, elem, false, runtime_getcallerpc(&t));
}
-// func selectnbrecv(elem *any, c chan any) bool
-//
// compiler implements
//
// select {
@@ -571,17 +423,10 @@ runtime_selectnbsend(ChanType *t, Hchan *c, byte *p)
// ... bar
// }
//
-_Bool
-runtime_selectnbrecv(ChanType *t, byte *v, Hchan *c)
-{
- bool selected;
-
- runtime_chanrecv(t, c, v, &selected, nil);
- return selected;
+func selectnbrecv(t *ChanType, elem *byte, c *Hchan) (selected bool) {
+ selected = chanrecv(t, c, elem, false, nil);
}
-// func selectnbrecv2(elem *any, ok *bool, c chan any) bool
-//
// compiler implements
//
// select {
@@ -599,111 +444,31 @@ runtime_selectnbrecv(ChanType *t, byte *v, Hchan *c)
// ... bar
// }
//
-_Bool
-runtime_selectnbrecv2(ChanType *t, byte *v, _Bool *received, Hchan *c)
-{
- bool selected;
+func selectnbrecv2(t *ChanType, elem *byte, received *bool, c *Hchan) (selected bool) {
bool r;
- r = false;
- runtime_chanrecv(t, c, v, &selected, received == nil ? nil : &r);
+ selected = chanrecv(t, c, elem, false, received == nil ? nil : &r);
if(received != nil)
*received = r;
- return selected;
}
-// For reflect:
-// func chansend(c chan, val iword, nb bool) (selected bool)
-// where an iword is the same word an interface value would use:
-// the actual data if it fits, or else a pointer to the data.
-
-_Bool reflect_chansend(ChanType *, Hchan *, uintptr, _Bool)
- __asm__ (GOSYM_PREFIX "reflect.chansend");
-
-_Bool
-reflect_chansend(ChanType *t, Hchan *c, uintptr val, _Bool nb)
-{
- bool selected;
- bool *sp;
- byte *vp;
-
- if(nb) {
- selected = false;
- sp = (bool*)&selected;
- } else {
- selected = true;
- sp = nil;
- }
- if(__go_is_pointer_type(t->__element_type))
- vp = (byte*)&val;
- else
- vp = (byte*)val;
- runtime_chansend(t, c, vp, sp, runtime_getcallerpc(&t));
- return selected;
+func reflect.chansend(t *ChanType, c *Hchan, elem *byte, nb bool) (selected bool) {
+ selected = chansend(t, c, elem, !nb, runtime_getcallerpc(&t));
}
-// For reflect:
-// func chanrecv(c chan, nb bool) (val iword, selected, received bool)
-// where an iword is the same word an interface value would use:
-// the actual data if it fits, or else a pointer to the data.
-
-struct chanrecv_ret
-{
- uintptr val;
- _Bool selected;
- _Bool received;
-};
-
-struct chanrecv_ret reflect_chanrecv(ChanType *, Hchan *, _Bool)
- __asm__ (GOSYM_PREFIX "reflect.chanrecv");
-
-struct chanrecv_ret
-reflect_chanrecv(ChanType *t, Hchan *c, _Bool nb)
-{
- struct chanrecv_ret ret;
- byte *vp;
- bool *sp;
- bool selected;
- bool received;
-
- if(nb) {
- selected = false;
- sp = &selected;
- } else {
- ret.selected = true;
- sp = nil;
- }
+func reflect.chanrecv(t *ChanType, c *Hchan, nb bool, elem *byte) (selected bool, received bool) {
received = false;
- if(__go_is_pointer_type(t->__element_type)) {
- vp = (byte*)&ret.val;
- } else {
- vp = runtime_mal(t->__element_type->__size);
- ret.val = (uintptr)vp;
- }
- runtime_chanrecv(t, c, vp, sp, &received);
- if(nb)
- ret.selected = selected;
- ret.received = received;
- return ret;
+ selected = chanrecv(t, c, elem, !nb, &received);
}
-static void newselect(int32, Select**);
+static Select* newselect(int32);
-// newselect(size uint32) (sel *byte);
-
-void* runtime_newselect(int32) __asm__ (GOSYM_PREFIX "runtime.newselect");
-
-void*
-runtime_newselect(int32 size)
-{
- Select *sel;
-
- newselect(size, &sel);
- return (void*)sel;
+func newselect(size int32) (sel *byte) {
+ sel = (byte*)newselect(size);
}
-static void
-newselect(int32 size, Select **selp)
+static Select*
+newselect(int32 size)
{
int32 n;
Select *sel;
@@ -725,28 +490,19 @@ newselect(int32 size, Select **selp)
sel->ncase = 0;
sel->lockorder = (void*)(sel->scase + size);
sel->pollorder = (void*)(sel->lockorder + size);
- *selp = sel;
if(debug)
runtime_printf("newselect s=%p size=%d\n", sel, size);
+ return sel;
}
// cut in half to give stack a chance to split
static void selectsend(Select *sel, Hchan *c, int index, void *elem);
-// selectsend(sel *byte, hchan *chan any, elem *any) (selected bool);
-
-void runtime_selectsend(Select *, Hchan *, void *, int32)
- __asm__ (GOSYM_PREFIX "runtime.selectsend");
-
-void
-runtime_selectsend(Select *sel, Hchan *c, void *elem, int32 index)
-{
+func selectsend(sel *Select, c *Hchan, elem *byte, index int32) {
// nil cases do not compete
- if(c == nil)
- return;
-
- selectsend(sel, c, index, elem);
+ if(c != nil)
+ selectsend(sel, c, index, elem);
}
static void
@@ -774,34 +530,16 @@ selectsend(Select *sel, Hchan *c, int index, void *elem)
// cut in half to give stack a chance to split
static void selectrecv(Select *sel, Hchan *c, int index, void *elem, bool*);
-// selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
-
-void runtime_selectrecv(Select *, Hchan *, void *, int32)
- __asm__ (GOSYM_PREFIX "runtime.selectrecv");
-
-void
-runtime_selectrecv(Select *sel, Hchan *c, void *elem, int32 index)
-{
+func selectrecv(sel *Select, c *Hchan, elem *byte, index int32) {
// nil cases do not compete
- if(c == nil)
- return;
-
- selectrecv(sel, c, index, elem, nil);
+ if(c != nil)
+ selectrecv(sel, c, index, elem, nil);
}
-// selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool);
-
-void runtime_selectrecv2(Select *, Hchan *, void *, bool *, int32)
- __asm__ (GOSYM_PREFIX "runtime.selectrecv2");
-
-void
-runtime_selectrecv2(Select *sel, Hchan *c, void *elem, bool *received, int32 index)
-{
+func selectrecv2(sel *Select, c *Hchan, elem *byte, received *bool, index int32) {
// nil cases do not compete
- if(c == nil)
- return;
-
- selectrecv(sel, c, index, elem, received);
+ if(c != nil)
+ selectrecv(sel, c, index, elem, received);
}
static void
@@ -830,13 +568,7 @@ selectrecv(Select *sel, Hchan *c, int index, void *elem, bool *received)
// cut in half to give stack a chance to split
static void selectdefault(Select*, int);
-// selectdefault(sel *byte) (selected bool);
-
-void runtime_selectdefault(Select *, int32) __asm__ (GOSYM_PREFIX "runtime.selectdefault");
-
-void
-runtime_selectdefault(Select *sel, int32 index)
-{
+func selectdefault(sel *Select, index int32) {
selectdefault(sel, index);
}
@@ -904,9 +636,15 @@ selunlock(Select *sel)
}
}
-void
-runtime_block(void)
+static bool
+selparkcommit(G *gp, void *sel)
{
+ USED(gp);
+ selunlock(sel);
+ return true;
+}
+
+func block() {
runtime_park(nil, nil, "select (no cases)"); // forever
}
@@ -914,11 +652,7 @@ static int selectgo(Select**);
// selectgo(sel *byte);
-int runtime_selectgo(Select *) __asm__ (GOSYM_PREFIX "runtime.selectgo");
-
-int
-runtime_selectgo(Select *sel)
-{
+func selectgo(sel *Select) (ret int32) {
return selectgo(&sel);
}
@@ -926,7 +660,7 @@ static int
selectgo(Select **selp)
{
Select *sel;
- uint32 o, i, j, k;
+ uint32 o, i, j, k, done;
int64 t0;
Scase *cas, *dfl;
Hchan *c;
@@ -1031,8 +765,6 @@ loop:
break;
case CaseSend:
- if(raceenabled)
- runtime_racereadpc(c, runtime_selectgo, runtime_chansend);
if(c->closed)
goto sclose;
if(c->dataqsiz > 0) {
@@ -1059,13 +791,14 @@ loop:
// pass 2 - enqueue on all chans
+ done = 0;
for(i=0; i<sel->ncase; i++) {
o = sel->pollorder[i];
cas = &sel->scase[o];
c = cas->chan;
sg = &cas->sg;
sg->g = g;
- sg->selgen = g->selgen;
+ sg->selectdone = &done;
switch(cas->kind) {
case CaseRecv:
@@ -1079,7 +812,7 @@ loop:
}
g->param = nil;
- runtime_park((void(*)(Lock*))selunlock, (Lock*)sel, "select");
+ runtime_park(selparkcommit, sel, "select");
sellock(sel);
sg = g->param;
@@ -1120,8 +853,6 @@ loop:
asyncrecv:
// can receive from buffer
- if(raceenabled)
- runtime_raceacquire(chanbuf(c, c->recvx));
if(cas->receivedp != nil)
*cas->receivedp = true;
if(cas->sg.elem != nil)
@@ -1144,8 +875,6 @@ asyncrecv:
asyncsend:
// can send to buffer
- if(raceenabled)
- runtime_racerelease(chanbuf(c, c->sendx));
runtime_memmove(chanbuf(c, c->sendx), cas->sg.elem, c->elemsize);
if(++c->sendx == c->dataqsiz)
c->sendx = 0;
@@ -1164,8 +893,6 @@ asyncsend:
syncrecv:
// can receive from sleeping sender (sg)
- if(raceenabled)
- racesync(c, sg);
selunlock(sel);
if(debug)
runtime_printf("syncrecv: sel=%p c=%p o=%d\n", sel, c, o);
@@ -1187,14 +914,10 @@ rclose:
*cas->receivedp = false;
if(cas->sg.elem != nil)
runtime_memclr(cas->sg.elem, c->elemsize);
- if(raceenabled)
- runtime_raceacquire(c);
goto retc;
syncsend:
// can send to sleeping receiver (sg)
- if(raceenabled)
- racesync(c, sg);
selunlock(sel);
if(debug)
runtime_printf("syncsend: sel=%p c=%p o=%d\n", sel, c, o);
@@ -1228,7 +951,7 @@ struct runtimeSelect
uintptr dir;
ChanType *typ;
Hchan *ch;
- uintptr val;
+ byte *val;
};
// This enum must match ../reflect/value.go:/SelectDir.
@@ -1238,51 +961,17 @@ enum SelectDir {
SelectDefault,
};
-struct rselect_ret {
- intgo chosen;
- uintptr word;
- bool recvOK;
-};
-
-// func rselect(cases []runtimeSelect) (chosen int, word uintptr, recvOK bool)
-
-struct rselect_ret reflect_rselect(Slice)
- __asm__ (GOSYM_PREFIX "reflect.rselect");
-
-struct rselect_ret
-reflect_rselect(Slice cases)
-{
- struct rselect_ret ret;
+func reflect.rselect(cases Slice) (chosen int, recvOK bool) {
int32 i;
Select *sel;
runtimeSelect* rcase, *rc;
- void *elem;
- void *recvptr;
- uintptr maxsize;
- bool onlyptr;
- ret.chosen = -1;
- ret.word = 0;
- ret.recvOK = false;
+ chosen = -1;
+ recvOK = false;
- maxsize = 0;
- onlyptr = true;
rcase = (runtimeSelect*)cases.__values;
- for(i=0; i<cases.__count; i++) {
- rc = &rcase[i];
- if(rc->dir == SelectRecv && rc->ch != nil) {
- if(maxsize < rc->typ->__element_type->__size)
- maxsize = rc->typ->__element_type->__size;
- if(!__go_is_pointer_type(rc->typ->__element_type))
- onlyptr = false;
- }
- }
-
- recvptr = nil;
- if(!onlyptr)
- recvptr = runtime_mal(maxsize);
- newselect(cases.__count, &sel);
+ sel = newselect(cases.__count);
for(i=0; i<cases.__count; i++) {
rc = &rcase[i];
switch(rc->dir) {
@@ -1292,54 +981,33 @@ reflect_rselect(Slice cases)
case SelectSend:
if(rc->ch == nil)
break;
- if(!__go_is_pointer_type(rc->typ->__element_type))
- elem = (void*)rc->val;
- else
- elem = (void*)&rc->val;
- selectsend(sel, rc->ch, i, elem);
+ selectsend(sel, rc->ch, i, rc->val);
break;
case SelectRecv:
if(rc->ch == nil)
break;
- if(!__go_is_pointer_type(rc->typ->__element_type))
- elem = recvptr;
- else
- elem = &ret.word;
- selectrecv(sel, rc->ch, i, elem, &ret.recvOK);
+ selectrecv(sel, rc->ch, i, rc->val, &recvOK);
break;
}
}
- ret.chosen = (intgo)(uintptr)selectgo(&sel);
- if(rcase[ret.chosen].dir == SelectRecv && !__go_is_pointer_type(rcase[ret.chosen].typ->__element_type))
- ret.word = (uintptr)recvptr;
-
- return ret;
+ chosen = (intgo)(uintptr)selectgo(&sel);
}
static void closechan(Hchan *c, void *pc);
-// closechan(sel *byte);
-void
-runtime_closechan(Hchan *c)
-{
+func closechan(c *Hchan) {
closechan(c, runtime_getcallerpc(&c));
}
-// For reflect
-// func chanclose(c chan)
-
-void reflect_chanclose(uintptr) __asm__ (GOSYM_PREFIX "reflect.chanclose");
-
-void
-reflect_chanclose(uintptr c)
-{
- closechan((Hchan*)c, runtime_getcallerpc(&c));
+func reflect.chanclose(c *Hchan) {
+ closechan(c, runtime_getcallerpc(&c));
}
static void
closechan(Hchan *c, void *pc)
{
+ USED(pc);
SudoG *sg;
G* gp;
@@ -1354,12 +1022,6 @@ closechan(Hchan *c, void *pc)
runtime_unlock(c);
runtime_panicstring("close of closed channel");
}
-
- if(raceenabled) {
- runtime_racewritepc(c, pc, runtime_closechan);
- runtime_racerelease(c);
- }
-
c->closed = true;
// release all readers
@@ -1395,54 +1057,30 @@ __go_builtin_close(Hchan *c)
runtime_closechan(c);
}
-// For reflect
-// func chanlen(c chan) (len int)
-
-intgo reflect_chanlen(uintptr) __asm__ (GOSYM_PREFIX "reflect.chanlen");
-
-intgo
-reflect_chanlen(uintptr ca)
-{
- Hchan *c;
- intgo len;
-
- c = (Hchan*)ca;
+func reflect.chanlen(c *Hchan) (len int) {
if(c == nil)
len = 0;
else
len = c->qcount;
- return len;
}
intgo
__go_chan_len(Hchan *c)
{
- return reflect_chanlen((uintptr)c);
+ return reflect_chanlen(c);
}
-// For reflect
-// func chancap(c chan) (cap intgo)
-
-intgo reflect_chancap(uintptr) __asm__ (GOSYM_PREFIX "reflect.chancap");
-
-intgo
-reflect_chancap(uintptr ca)
-{
- Hchan *c;
- intgo cap;
-
- c = (Hchan*)ca;
+func reflect.chancap(c *Hchan) (cap int) {
if(c == nil)
cap = 0;
else
cap = c->dataqsiz;
- return cap;
}
intgo
__go_chan_cap(Hchan *c)
{
- return reflect_chancap((uintptr)c);
+ return reflect_chancap(c);
}
static SudoG*
@@ -1456,12 +1094,11 @@ loop:
return nil;
q->first = sgp->link;
- // if sgp is stale, ignore it
- if(sgp->selgen != NOSELGEN &&
- (sgp->selgen != sgp->g->selgen ||
- !runtime_cas(&sgp->g->selgen, sgp->selgen, sgp->selgen + 2))) {
- //prints("INVALID PSEUDOG POINTER\n");
- goto loop;
+ // 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 || !runtime_cas(sgp->selectdone, 0, 1))
+ goto loop;
}
return sgp;
@@ -1497,12 +1134,3 @@ enqueue(WaitQ *q, SudoG *sgp)
q->last->link = sgp;
q->last = sgp;
}
-
-static void
-racesync(Hchan *c, SudoG *sg)
-{
- runtime_racerelease(chanbuf(c, 0));
- runtime_raceacquireg(sg->g, chanbuf(c, 0));
- runtime_racereleaseg(sg->g, chanbuf(c, 0));
- runtime_raceacquire(chanbuf(c, 0));
-}
diff --git a/libgo/runtime/chan.h b/libgo/runtime/chan.h
new file mode 100644
index 0000000000..70b0b9d909
--- /dev/null
+++ b/libgo/runtime/chan.h
@@ -0,0 +1,75 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+typedef struct WaitQ WaitQ;
+typedef struct SudoG SudoG;
+typedef struct Select Select;
+typedef struct Scase Scase;
+
+typedef struct __go_type_descriptor Type;
+typedef struct __go_channel_type ChanType;
+
+struct SudoG
+{
+ G* g;
+ uint32* selectdone;
+ SudoG* link;
+ int64 releasetime;
+ byte* elem; // data element
+};
+
+struct WaitQ
+{
+ SudoG* first;
+ SudoG* last;
+};
+
+// The garbage collector is assuming that Hchan can only contain pointers into the stack
+// and cannot contain pointers into the heap.
+struct Hchan
+{
+ uintgo qcount; // total data in the q
+ uintgo dataqsiz; // size of the circular q
+ uint16 elemsize;
+ uint16 pad; // ensures proper alignment of the buffer that follows Hchan in memory
+ bool closed;
+ const Type* elemtype; // element type
+ uintgo sendx; // send index
+ uintgo recvx; // receive index
+ WaitQ recvq; // list of recv waiters
+ WaitQ sendq; // list of send waiters
+ Lock;
+};
+
+// Buffer follows Hchan immediately in memory.
+// chanbuf(c, i) is pointer to the i'th slot in the buffer.
+#define chanbuf(c, i) ((byte*)((c)+1)+(uintptr)(c)->elemsize*(i))
+
+enum
+{
+ debug = 0,
+
+ // Scase.kind
+ CaseRecv,
+ CaseSend,
+ CaseDefault,
+};
+
+struct Scase
+{
+ SudoG sg; // must be first member (cast to Scase)
+ Hchan* chan; // chan
+ uint16 kind;
+ uint16 index; // index to return
+ bool* receivedp; // pointer to received bool (recv2)
+};
+
+struct Select
+{
+ uint16 tcase; // total count of scase[]
+ uint16 ncase; // currently filled scase[]
+ uint16* pollorder; // case poll order
+ Hchan** lockorder; // channel lock order
+ Scase scase[1]; // one per case (in order of appearance)
+};
diff --git a/libgo/runtime/cpuprof.c b/libgo/runtime/cpuprof.goc
index a2a1a05ce3..7d27bc6a43 100644
--- a/libgo/runtime/cpuprof.c
+++ b/libgo/runtime/cpuprof.goc
@@ -48,6 +48,7 @@
// 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
#include "runtime.h"
#include "arch.h"
#include "malloc.h"
@@ -86,7 +87,6 @@ struct Profile {
uintptr count; // tick count
uintptr evicts; // eviction count
uintptr lost; // lost ticks that need to be logged
- uintptr totallost; // total lost ticks
// Active recent stack traces.
Bucket hash[HashSize];
@@ -177,7 +177,7 @@ runtime_SetCPUProfileRate(intgo hz)
runtime_noteclear(&prof->wait);
runtime_setcpuprofilerate(tick, hz);
- } else if(prof->on) {
+ } else if(prof != nil && prof->on) {
runtime_setcpuprofilerate(nil, 0);
prof->on = false;
@@ -252,7 +252,6 @@ add(Profile *p, uintptr *pc, int32 n)
if(!evict(p, e)) {
// Could not evict entry. Record lost stack.
p->lost++;
- p->totallost++;
return;
}
p->evicts++;
@@ -316,6 +315,7 @@ flushlog(Profile *p)
*q++ = p->lost;
*q++ = 1;
*q++ = (uintptr)LostProfileData;
+ p->lost = 0;
}
p->nlog = q - log;
return true;
@@ -435,13 +435,8 @@ breakflush:
return ret; // set to nil at top of function
}
-extern Slice runtime_CPUProfile(void)
- __asm__ (GOSYM_PREFIX "runtime.CPUProfile");
-
// CPUProfile returns the next cpu profile block as a []byte.
// The user documentation is in debug.go.
-Slice
-runtime_CPUProfile(void)
-{
- return getprofile(prof);
+func CPUProfile() (ret Slice) {
+ ret = getprofile(prof);
}
diff --git a/libgo/runtime/env_posix.c b/libgo/runtime/env_posix.c
index 3219550af9..ee3e451455 100644
--- a/libgo/runtime/env_posix.c
+++ b/libgo/runtime/env_posix.c
@@ -2,12 +2,14 @@
// 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 windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
#include "runtime.h"
#include "array.h"
+#include "arch.h"
+#include "malloc.h"
-extern Slice syscall_Envs __asm__ (GOSYM_PREFIX "syscall.Envs");
+extern Slice envs;
const byte*
runtime_getenv(const char *s)
@@ -20,8 +22,8 @@ runtime_getenv(const char *s)
bs = (const byte*)s;
len = runtime_findnull(bs);
- envv = (String*)syscall_Envs.__values;
- envc = syscall_Envs.__count;
+ envv = (String*)envs.__values;
+ envc = envs.__count;
for(i=0; i<envc; i++){
if(envv[i].len <= len)
continue;
diff --git a/libgo/runtime/go-append.c b/libgo/runtime/go-append.c
index 8d5dee2161..1b2d49e53c 100644
--- a/libgo/runtime/go-append.c
+++ b/libgo/runtime/go-append.c
@@ -37,6 +37,7 @@ __go_append (struct __go_open_array a, void *bvalues, uintptr_t bcount,
if (count > a.__capacity)
{
intgo m;
+ uintptr capmem;
void *n;
m = a.__capacity;
@@ -57,7 +58,9 @@ __go_append (struct __go_open_array a, void *bvalues, uintptr_t bcount,
if (element_size > 0 && (uintptr) m > MaxMem / element_size)
runtime_panicstring ("growslice: cap out of range");
- n = __go_alloc (m * element_size);
+ capmem = runtime_roundupsize (m * element_size);
+
+ n = __go_alloc (capmem);
__builtin_memcpy (n, a.__values, a.__count * element_size);
a.__values = n;
diff --git a/libgo/runtime/go-assert-interface.c b/libgo/runtime/go-assert-interface.c
index 2510f9aef8..427916f8c4 100644
--- a/libgo/runtime/go-assert-interface.c
+++ b/libgo/runtime/go-assert-interface.c
@@ -36,7 +36,7 @@ __go_assert_interface (const struct __go_type_descriptor *lhs_descriptor,
/* A type assertion to an empty interface just returns the object
descriptor. */
- __go_assert (lhs_descriptor->__code == GO_INTERFACE);
+ __go_assert ((lhs_descriptor->__code & GO_CODE_MASK) == GO_INTERFACE);
lhs_interface = (const struct __go_interface_type *) lhs_descriptor;
if (lhs_interface->__methods.__count == 0)
return rhs_descriptor;
diff --git a/libgo/runtime/go-caller.c b/libgo/runtime/go-caller.c
index a3e04240d9..ed6fd107b0 100644
--- a/libgo/runtime/go-caller.c
+++ b/libgo/runtime/go-caller.c
@@ -37,36 +37,12 @@ callback (void *data, uintptr_t pc __attribute__ ((unused)),
{
struct caller *c = (struct caller *) data;
- if (function == NULL)
- {
- c->fn.str = NULL;
- c->fn.len = 0;
- }
- else
- {
- byte *s;
-
- c->fn.len = __builtin_strlen (function);
- s = runtime_malloc (c->fn.len);
- __builtin_memcpy (s, function, c->fn.len);
- c->fn.str = s;
- }
-
- if (filename == NULL)
- {
- c->file.str = NULL;
- c->file.len = 0;
- }
- else
- {
- byte *s;
-
- c->file.len = __builtin_strlen (filename);
- s = runtime_malloc (c->file.len);
- __builtin_memcpy (s, filename, c->file.len);
- c->file.str = s;
- }
-
+ /* The libbacktrace library says that these strings might disappear,
+ but with the current implementation they won't. We can't easily
+ allocate memory here, so for now assume that we can save a
+ pointer to the strings. */
+ c->fn = runtime_gostringnocopy ((const byte *) function);
+ c->file = runtime_gostringnocopy ((const byte *) filename);
c->line = lineno;
return 0;
@@ -189,8 +165,8 @@ Caller (int skip)
int32 n;
runtime_memclr (&ret, sizeof ret);
- n = runtime_callers (skip + 1, &loc, 1);
- if (n < 1)
+ n = runtime_callers (skip + 1, &loc, 1, false);
+ if (n < 1 || loc.pc == 0)
return ret;
ret.pc = loc.pc;
ret.file = loc.filename;
diff --git a/libgo/runtime/go-callers.c b/libgo/runtime/go-callers.c
index ae411d9c83..b5ab3be647 100644
--- a/libgo/runtime/go-callers.c
+++ b/libgo/runtime/go-callers.c
@@ -26,6 +26,7 @@ struct callers_data
int skip;
int index;
int max;
+ int keep_thunks;
};
/* Callback function for backtrace_full. Just collect the locations.
@@ -63,7 +64,7 @@ callback (void *data, uintptr_t pc, const char *filename, int lineno,
/* Skip thunks and recover functions. There is no equivalent to
these functions in the gc toolchain, so returning them here means
significantly different results for runtime.Caller(N). */
- if (function != NULL)
+ if (function != NULL && !arg->keep_thunks)
{
const char *p;
@@ -82,7 +83,20 @@ callback (void *data, uintptr_t pc, const char *filename, int lineno,
}
loc = &arg->locbuf[arg->index];
- loc->pc = pc;
+
+ /* On the call to backtrace_full the pc value was most likely
+ decremented if there was a normal call, since the pc referred to
+ the instruction where the call returned and not the call itself.
+ This was done so that the line number referred to the call
+ instruction. To make sure the actual pc from the call stack is
+ used, it is incremented here.
+
+ In the case of a signal, the pc was not decremented by
+ backtrace_full but still incremented here. That doesn't really
+ hurt anything since the line number is right and the pc refers to
+ the same instruction. */
+
+ loc->pc = pc + 1;
/* The libbacktrace library says that these strings might disappear,
but with the current implementation they won't. We can't easily
@@ -93,6 +107,32 @@ callback (void *data, uintptr_t pc, const char *filename, int lineno,
loc->lineno = lineno;
++arg->index;
+
+ /* There is no point to tracing past certain runtime functions.
+ Stopping the backtrace here can avoid problems on systems that
+ don't provide proper unwind information for makecontext, such as
+ Solaris (http://gcc.gnu.org/PR52583 comment #21). */
+ if (function != NULL)
+ {
+ if (__builtin_strcmp (function, "makecontext") == 0)
+ return 1;
+ if (filename != NULL)
+ {
+ const char *p;
+
+ p = strrchr (filename, '/');
+ if (p == NULL)
+ p = filename;
+ if (__builtin_strcmp (p, "/proc.c") == 0)
+ {
+ if (__builtin_strcmp (function, "kickoff") == 0
+ || __builtin_strcmp (function, "runtime_mstart") == 0
+ || __builtin_strcmp (function, "runtime_main") == 0)
+ return 1;
+ }
+ }
+ }
+
return arg->index >= arg->max;
}
@@ -102,6 +142,11 @@ static void
error_callback (void *data __attribute__ ((unused)),
const char *msg, int errnum)
{
+ if (errnum == -1)
+ {
+ /* No debug info available. Carry on as best we can. */
+ return;
+ }
if (errnum != 0)
runtime_printf ("%s errno %d\n", msg, errnum);
runtime_throw (msg);
@@ -110,7 +155,7 @@ error_callback (void *data __attribute__ ((unused)),
/* Gather caller PC's. */
int32
-runtime_callers (int32 skip, Location *locbuf, int32 m)
+runtime_callers (int32 skip, Location *locbuf, int32 m, bool keep_thunks)
{
struct callers_data data;
@@ -118,6 +163,7 @@ runtime_callers (int32 skip, Location *locbuf, int32 m)
data.skip = skip + 1;
data.index = 0;
data.max = m;
+ data.keep_thunks = keep_thunks;
runtime_xadd (&runtime_in_callers, 1);
backtrace_full (__go_get_backtrace_state (), 0, callback, error_callback,
&data);
@@ -141,7 +187,7 @@ Callers (int skip, struct __go_open_array pc)
which we can not correct because it would break backward
compatibility. Normally we would add 1 to SKIP here, but we
don't so that we are compatible. */
- ret = runtime_callers (skip, locbuf, pc.__count);
+ ret = runtime_callers (skip, locbuf, pc.__count, false);
for (i = 0; i < ret; i++)
((uintptr *) pc.__values)[i] = locbuf[i].pc;
diff --git a/libgo/runtime/go-can-convert-interface.c b/libgo/runtime/go-can-convert-interface.c
index 4de558077a..aac889d346 100644
--- a/libgo/runtime/go-can-convert-interface.c
+++ b/libgo/runtime/go-can-convert-interface.c
@@ -31,7 +31,7 @@ __go_can_convert_to_interface (
if (from_descriptor == NULL)
return 0;
- __go_assert (to_descriptor->__code == GO_INTERFACE);
+ __go_assert ((to_descriptor->__code & GO_CODE_MASK) == GO_INTERFACE);
to_interface = (const struct __go_interface_type *) to_descriptor;
to_method_count = to_interface->__methods.__count;
to_method = ((const struct __go_interface_method *)
diff --git a/libgo/runtime/go-cdiv.c b/libgo/runtime/go-cdiv.c
index 0a81e458c8..0355e26fc8 100644
--- a/libgo/runtime/go-cdiv.c
+++ b/libgo/runtime/go-cdiv.c
@@ -4,6 +4,9 @@
Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file. */
+#include <complex.h>
+#include <math.h>
+
/* Calls to these functions are generated by the Go frontend for
division of complex64 or complex128. We use these because Go's
complex division expects slightly different results from the GCC
@@ -13,33 +16,33 @@
the the whole number is Inf, but an operation involving NaN ought
to result in NaN, not Inf. */
-__complex float
-__go_complex64_div (__complex float a, __complex float b)
+complex float
+__go_complex64_div (complex float a, complex float b)
{
- if (__builtin_expect (b == 0+0i, 0))
+ if (__builtin_expect (b == 0, 0))
{
- if (!__builtin_isinff (__real__ a)
- && !__builtin_isinff (__imag__ a)
- && (__builtin_isnanf (__real__ a) || __builtin_isnanf (__imag__ a)))
+ if (!isinf (crealf (a))
+ && !isinf (cimagf (a))
+ && (isnan (crealf (a)) || isnan (cimagf (a))))
{
/* Pass "1" to nanf to match math/bits.go. */
- return __builtin_nanf("1") + __builtin_nanf("1")*1i;
+ return nanf("1") + nanf("1")*I;
}
}
return a / b;
}
-__complex double
-__go_complex128_div (__complex double a, __complex double b)
+complex double
+__go_complex128_div (complex double a, complex double b)
{
- if (__builtin_expect (b == 0+0i, 0))
+ if (__builtin_expect (b == 0, 0))
{
- if (!__builtin_isinf (__real__ a)
- && !__builtin_isinf (__imag__ a)
- && (__builtin_isnan (__real__ a) || __builtin_isnan (__imag__ a)))
+ if (!isinf (creal (a))
+ && !isinf (cimag (a))
+ && (isnan (creal (a)) || isnan (cimag (a))))
{
/* Pass "1" to nan to match math/bits.go. */
- return __builtin_nan("1") + __builtin_nan("1")*1i;
+ return nan("1") + nan("1")*I;
}
}
return a / b;
diff --git a/libgo/runtime/go-cgo.c b/libgo/runtime/go-cgo.c
index 9ba1ea7d04..2b7baa4df9 100644
--- a/libgo/runtime/go-cgo.c
+++ b/libgo/runtime/go-cgo.c
@@ -177,19 +177,3 @@ _cgo_panic (const char *p)
__go_panic (e);
}
-
-/* Return the number of CGO calls. */
-
-int64 runtime_NumCgoCall (void) __asm__ (GOSYM_PREFIX "runtime.NumCgoCall");
-
-int64
-runtime_NumCgoCall (void)
-{
- int64 ret;
- M* m;
-
- ret = 0;
- for (m = runtime_atomicloadp (&runtime_allm); m != NULL; m = m->alllink)
- ret += m->ncgocall;
- return ret;
-}
diff --git a/libgo/runtime/go-check-interface.c b/libgo/runtime/go-check-interface.c
index c29971adac..722a4219ab 100644
--- a/libgo/runtime/go-check-interface.c
+++ b/libgo/runtime/go-check-interface.c
@@ -30,9 +30,9 @@ __go_check_interface_type (
if (lhs_descriptor != rhs_descriptor
&& !__go_type_descriptors_equal (lhs_descriptor, rhs_descriptor)
- && (lhs_descriptor->__code != GO_UNSAFE_POINTER
+ && ((lhs_descriptor->__code & GO_CODE_MASK) != GO_UNSAFE_POINTER
|| !__go_is_pointer_type (rhs_descriptor))
- && (rhs_descriptor->__code != GO_UNSAFE_POINTER
+ && ((rhs_descriptor->__code & GO_CODE_MASK) != GO_UNSAFE_POINTER
|| !__go_is_pointer_type (lhs_descriptor)))
{
struct __go_empty_interface panic_arg;
diff --git a/libgo/runtime/go-convert-interface.c b/libgo/runtime/go-convert-interface.c
index 3eee6bf4a8..0e8a306243 100644
--- a/libgo/runtime/go-convert-interface.c
+++ b/libgo/runtime/go-convert-interface.c
@@ -41,7 +41,7 @@ __go_convert_interface_2 (const struct __go_type_descriptor *lhs_descriptor,
return NULL;
}
- __go_assert (lhs_descriptor->__code == GO_INTERFACE);
+ __go_assert ((lhs_descriptor->__code & GO_CODE_MASK) == GO_INTERFACE);
lhs_interface = (const struct __go_interface_type *) lhs_descriptor;
lhs_method_count = lhs_interface->__methods.__count;
lhs_methods = ((const struct __go_interface_method *)
diff --git a/libgo/runtime/go-defer.c b/libgo/runtime/go-defer.c
index 4c61ae7db2..3a48fe1130 100644
--- a/libgo/runtime/go-defer.c
+++ b/libgo/runtime/go-defer.c
@@ -20,7 +20,7 @@ __go_defer (_Bool *frame, void (*pfn) (void *), void *arg)
struct __go_defer_stack *n;
g = runtime_g ();
- n = (struct __go_defer_stack *) __go_alloc (sizeof (struct __go_defer_stack));
+ n = runtime_newdefer ();
n->__next = g->defer;
n->__frame = frame;
n->__panic = g->panic;
@@ -28,7 +28,7 @@ __go_defer (_Bool *frame, void (*pfn) (void *), void *arg)
n->__arg = arg;
n->__retaddr = NULL;
n->__makefunc_can_recover = 0;
- n->__free = 1;
+ n->__special = 0;
g->defer = n;
}
@@ -44,7 +44,6 @@ __go_undefer (_Bool *frame)
{
struct __go_defer_stack *d;
void (*pfn) (void *);
- M *m;
d = g->defer;
pfn = d->__pfn;
@@ -59,9 +58,8 @@ __go_undefer (_Bool *frame)
call to syscall.CgocallBackDone, in which case we will not
have a memory context. Don't try to free anything in that
case--the GC will release it later. */
- m = runtime_m ();
- if (m != NULL && m->mcache != NULL && d->__free)
- __go_free (d);
+ if (runtime_m () != NULL)
+ runtime_freedefer (d);
/* Since we are executing a defer function here, we know we are
returning from the calling function. If the calling
@@ -82,6 +80,6 @@ __go_set_defer_retaddr (void *retaddr)
g = runtime_g ();
if (g->defer != NULL)
- g->defer->__retaddr = retaddr;
+ g->defer->__retaddr = __builtin_extract_return_addr (retaddr);
return 0;
}
diff --git a/libgo/runtime/go-defer.h b/libgo/runtime/go-defer.h
index d110a8766e..acf2d40c69 100644
--- a/libgo/runtime/go-defer.h
+++ b/libgo/runtime/go-defer.h
@@ -20,8 +20,8 @@ struct __go_defer_stack
/* The value of the panic stack when this function is deferred.
This function can not recover this value from the panic stack.
- This can happen if a deferred function uses its own defer
- statement. */
+ This can happen if a deferred function has a defer statement
+ itself. */
struct __go_panic_stack *__panic;
/* The function to call. */
@@ -41,7 +41,7 @@ struct __go_defer_stack
useful. */
_Bool __makefunc_can_recover;
- /* Set to true if this defer stack entry should be freed when
- done. */
- _Bool __free;
+ /* Set to true if this defer stack entry is not part of the defer
+ pool. */
+ _Bool __special;
};
diff --git a/libgo/runtime/go-eface-compare.c b/libgo/runtime/go-eface-compare.c
index e738efced8..3555a65d9c 100644
--- a/libgo/runtime/go-eface-compare.c
+++ b/libgo/runtime/go-eface-compare.c
@@ -19,10 +19,6 @@ __go_empty_interface_compare (struct __go_empty_interface left,
left_descriptor = left.__type_descriptor;
- if (((uintptr_t) left_descriptor & reflectFlags) != 0
- || ((uintptr_t) right.__type_descriptor & reflectFlags) != 0)
- runtime_panicstring ("invalid interface value");
-
if (left_descriptor == NULL && right.__type_descriptor == NULL)
return 0;
if (left_descriptor == NULL || right.__type_descriptor == NULL)
diff --git a/libgo/runtime/go-eface-val-compare.c b/libgo/runtime/go-eface-val-compare.c
index 454ea3ebae..743f126ec1 100644
--- a/libgo/runtime/go-eface-val-compare.c
+++ b/libgo/runtime/go-eface-val-compare.c
@@ -20,8 +20,6 @@ __go_empty_interface_value_compare (
const struct __go_type_descriptor *left_descriptor;
left_descriptor = left.__type_descriptor;
- if (((uintptr_t) left_descriptor & reflectFlags) != 0)
- runtime_panicstring ("invalid interface value");
if (left_descriptor == NULL)
return 1;
if (!__go_type_descriptors_equal (left_descriptor, right_descriptor))
diff --git a/libgo/runtime/go-ffi.c b/libgo/runtime/go-ffi.c
new file mode 100644
index 0000000000..aafc7b205e
--- /dev/null
+++ b/libgo/runtime/go-ffi.c
@@ -0,0 +1,346 @@
+/* go-ffi.c -- convert Go type description to libffi.
+
+ Copyright 2009 The Go Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style
+ license that can be found in the LICENSE file. */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "runtime.h"
+#include "go-alloc.h"
+#include "go-assert.h"
+#include "go-type.h"
+
+#ifdef USE_LIBFFI
+
+#include "ffi.h"
+
+/* The functions in this file are only called from reflect_call and
+ reflect.ffi. As these functions call libffi functions, which will
+ be compiled without -fsplit-stack, they will always run with a
+ large stack. */
+
+static ffi_type *go_array_to_ffi (const struct __go_array_type *)
+ __attribute__ ((no_split_stack));
+static ffi_type *go_slice_to_ffi (const struct __go_slice_type *)
+ __attribute__ ((no_split_stack));
+static ffi_type *go_struct_to_ffi (const struct __go_struct_type *)
+ __attribute__ ((no_split_stack));
+static ffi_type *go_string_to_ffi (void) __attribute__ ((no_split_stack));
+static ffi_type *go_interface_to_ffi (void) __attribute__ ((no_split_stack));
+static ffi_type *go_type_to_ffi (const struct __go_type_descriptor *)
+ __attribute__ ((no_split_stack));
+static ffi_type *go_func_return_ffi (const struct __go_func_type *)
+ __attribute__ ((no_split_stack));
+
+/* Return an ffi_type for a Go array type. The libffi library does
+ not have any builtin support for passing arrays as values. We work
+ around this by pretending that the array is a struct. */
+
+static ffi_type *
+go_array_to_ffi (const struct __go_array_type *descriptor)
+{
+ ffi_type *ret;
+ uintptr_t len;
+ ffi_type *element;
+ uintptr_t i;
+
+ ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
+ ret->type = FFI_TYPE_STRUCT;
+ len = descriptor->__len;
+ if (len == 0)
+ {
+ /* The libffi library won't accept an empty struct. */
+ ret->elements = (ffi_type **) __go_alloc (2 * sizeof (ffi_type *));
+ ret->elements[0] = &ffi_type_void;
+ ret->elements[1] = NULL;
+ return ret;
+ }
+ ret->elements = (ffi_type **) __go_alloc ((len + 1) * sizeof (ffi_type *));
+ element = go_type_to_ffi (descriptor->__element_type);
+ for (i = 0; i < len; ++i)
+ ret->elements[i] = element;
+ ret->elements[len] = NULL;
+ return ret;
+}
+
+/* Return an ffi_type for a Go slice type. This describes the
+ __go_open_array type defines in array.h. */
+
+static ffi_type *
+go_slice_to_ffi (
+ const struct __go_slice_type *descriptor __attribute__ ((unused)))
+{
+ ffi_type *ret;
+ ffi_type *ffi_intgo;
+
+ ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
+ ret->type = FFI_TYPE_STRUCT;
+ ret->elements = (ffi_type **) __go_alloc (4 * sizeof (ffi_type *));
+ ret->elements[0] = &ffi_type_pointer;
+ ffi_intgo = sizeof (intgo) == 4 ? &ffi_type_sint32 : &ffi_type_sint64;
+ ret->elements[1] = ffi_intgo;
+ ret->elements[2] = ffi_intgo;
+ ret->elements[3] = NULL;
+ return ret;
+}
+
+/* Return an ffi_type for a Go struct type. */
+
+static ffi_type *
+go_struct_to_ffi (const struct __go_struct_type *descriptor)
+{
+ ffi_type *ret;
+ int field_count;
+ const struct __go_struct_field *fields;
+ int i;
+
+ field_count = descriptor->__fields.__count;
+ ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
+ ret->type = FFI_TYPE_STRUCT;
+ if (field_count == 0)
+ {
+ /* The libffi library won't accept an empty struct. */
+ ret->elements = (ffi_type **) __go_alloc (2 * sizeof (ffi_type *));
+ ret->elements[0] = &ffi_type_void;
+ ret->elements[1] = NULL;
+ return ret;
+ }
+ fields = (const struct __go_struct_field *) descriptor->__fields.__values;
+ ret->elements = (ffi_type **) __go_alloc ((field_count + 1)
+ * sizeof (ffi_type *));
+ for (i = 0; i < field_count; ++i)
+ ret->elements[i] = go_type_to_ffi (fields[i].__type);
+ ret->elements[field_count] = NULL;
+ return ret;
+}
+
+/* Return an ffi_type for a Go string type. This describes the String
+ struct. */
+
+static ffi_type *
+go_string_to_ffi (void)
+{
+ ffi_type *ret;
+ ffi_type *ffi_intgo;
+
+ ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
+ ret->type = FFI_TYPE_STRUCT;
+ ret->elements = (ffi_type **) __go_alloc (3 * sizeof (ffi_type *));
+ ret->elements[0] = &ffi_type_pointer;
+ ffi_intgo = sizeof (intgo) == 4 ? &ffi_type_sint32 : &ffi_type_sint64;
+ ret->elements[1] = ffi_intgo;
+ ret->elements[2] = NULL;
+ return ret;
+}
+
+/* Return an ffi_type for a Go interface type. This describes the
+ __go_interface and __go_empty_interface structs. */
+
+static ffi_type *
+go_interface_to_ffi (void)
+{
+ ffi_type *ret;
+
+ ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
+ ret->type = FFI_TYPE_STRUCT;
+ ret->elements = (ffi_type **) __go_alloc (3 * sizeof (ffi_type *));
+ ret->elements[0] = &ffi_type_pointer;
+ ret->elements[1] = &ffi_type_pointer;
+ ret->elements[2] = NULL;
+ return ret;
+}
+
+
+#ifndef FFI_TARGET_HAS_COMPLEX_TYPE
+/* If libffi hasn't been updated for this target to support complex,
+ pretend complex is a structure. Warning: This does not work for
+ all ABIs. Eventually libffi should be updated for all targets
+ and this should go away. */
+
+static ffi_type *go_complex_to_ffi (ffi_type *)
+ __attribute__ ((no_split_stack));
+
+static ffi_type *
+go_complex_to_ffi (ffi_type *float_type)
+{
+ ffi_type *ret;
+
+ ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
+ ret->type = FFI_TYPE_STRUCT;
+ ret->elements = (ffi_type **) __go_alloc (3 * sizeof (ffi_type *));
+ ret->elements[0] = float_type;
+ ret->elements[1] = float_type;
+ ret->elements[2] = NULL;
+ return ret;
+}
+#endif
+
+/* Return an ffi_type for a type described by a
+ __go_type_descriptor. */
+
+static ffi_type *
+go_type_to_ffi (const struct __go_type_descriptor *descriptor)
+{
+ switch (descriptor->__code & GO_CODE_MASK)
+ {
+ case GO_BOOL:
+ if (sizeof (_Bool) == 1)
+ return &ffi_type_uint8;
+ else if (sizeof (_Bool) == sizeof (int))
+ return &ffi_type_uint;
+ abort ();
+ case GO_FLOAT32:
+ if (sizeof (float) == 4)
+ return &ffi_type_float;
+ abort ();
+ case GO_FLOAT64:
+ if (sizeof (double) == 8)
+ return &ffi_type_double;
+ abort ();
+ case GO_COMPLEX64:
+ if (sizeof (float) == 4)
+ {
+#ifdef FFI_TARGET_HAS_COMPLEX_TYPE
+ return &ffi_type_complex_float;
+#else
+ return go_complex_to_ffi (&ffi_type_float);
+#endif
+ }
+ abort ();
+ case GO_COMPLEX128:
+ if (sizeof (double) == 8)
+ {
+#ifdef FFI_TARGET_HAS_COMPLEX_TYPE
+ return &ffi_type_complex_double;
+#else
+ return go_complex_to_ffi (&ffi_type_double);
+#endif
+ }
+ abort ();
+ case GO_INT16:
+ return &ffi_type_sint16;
+ case GO_INT32:
+ return &ffi_type_sint32;
+ case GO_INT64:
+ return &ffi_type_sint64;
+ case GO_INT8:
+ return &ffi_type_sint8;
+ case GO_INT:
+ return sizeof (intgo) == 4 ? &ffi_type_sint32 : &ffi_type_sint64;
+ case GO_UINT16:
+ return &ffi_type_uint16;
+ case GO_UINT32:
+ return &ffi_type_uint32;
+ case GO_UINT64:
+ return &ffi_type_uint64;
+ case GO_UINT8:
+ return &ffi_type_uint8;
+ case GO_UINT:
+ return sizeof (uintgo) == 4 ? &ffi_type_uint32 : &ffi_type_uint64;
+ case GO_UINTPTR:
+ if (sizeof (void *) == 2)
+ return &ffi_type_uint16;
+ else if (sizeof (void *) == 4)
+ return &ffi_type_uint32;
+ else if (sizeof (void *) == 8)
+ return &ffi_type_uint64;
+ abort ();
+ case GO_ARRAY:
+ return go_array_to_ffi ((const struct __go_array_type *) descriptor);
+ case GO_SLICE:
+ return go_slice_to_ffi ((const struct __go_slice_type *) descriptor);
+ case GO_STRUCT:
+ return go_struct_to_ffi ((const struct __go_struct_type *) descriptor);
+ case GO_STRING:
+ return go_string_to_ffi ();
+ case GO_INTERFACE:
+ return go_interface_to_ffi ();
+ case GO_CHAN:
+ case GO_FUNC:
+ case GO_MAP:
+ case GO_PTR:
+ case GO_UNSAFE_POINTER:
+ /* These types are always pointers, and for FFI purposes nothing
+ else matters. */
+ return &ffi_type_pointer;
+ default:
+ abort ();
+ }
+}
+
+/* Return the return type for a function, given the number of out
+ parameters and their types. */
+
+static ffi_type *
+go_func_return_ffi (const struct __go_func_type *func)
+{
+ int count;
+ const struct __go_type_descriptor **types;
+ ffi_type *ret;
+ int i;
+
+ count = func->__out.__count;
+ if (count == 0)
+ return &ffi_type_void;
+
+ types = (const struct __go_type_descriptor **) func->__out.__values;
+
+ if (count == 1)
+ return go_type_to_ffi (types[0]);
+
+ ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
+ ret->type = FFI_TYPE_STRUCT;
+ ret->elements = (ffi_type **) __go_alloc ((count + 1) * sizeof (ffi_type *));
+ for (i = 0; i < count; ++i)
+ ret->elements[i] = go_type_to_ffi (types[i]);
+ ret->elements[count] = NULL;
+ return ret;
+}
+
+/* Build an ffi_cif structure for a function described by a
+ __go_func_type structure. */
+
+void
+__go_func_to_cif (const struct __go_func_type *func, _Bool is_interface,
+ _Bool is_method, ffi_cif *cif)
+{
+ int num_params;
+ const struct __go_type_descriptor **in_types;
+ size_t num_args;
+ ffi_type **args;
+ int off;
+ int i;
+ ffi_type *rettype;
+ ffi_status status;
+
+ num_params = func->__in.__count;
+ in_types = ((const struct __go_type_descriptor **)
+ func->__in.__values);
+
+ num_args = num_params + (is_interface ? 1 : 0);
+ args = (ffi_type **) __go_alloc (num_args * sizeof (ffi_type *));
+ i = 0;
+ off = 0;
+ if (is_interface)
+ {
+ args[0] = &ffi_type_pointer;
+ off = 1;
+ }
+ else if (is_method)
+ {
+ args[0] = &ffi_type_pointer;
+ i = 1;
+ }
+ for (; i < num_params; ++i)
+ args[i + off] = go_type_to_ffi (in_types[i]);
+
+ rettype = go_func_return_ffi (func);
+
+ status = ffi_prep_cif (cif, FFI_DEFAULT_ABI, num_args, rettype, args);
+ __go_assert (status == FFI_OK);
+}
+
+#endif /* defined(USE_LIBFFI) */
diff --git a/libgo/runtime/go-ffi.h b/libgo/runtime/go-ffi.h
new file mode 100644
index 0000000000..afae4b6d6e
--- /dev/null
+++ b/libgo/runtime/go-ffi.h
@@ -0,0 +1,16 @@
+/* go-ffi.c -- convert Go type description to libffi.
+
+ Copyright 2014 The Go Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style
+ license that can be found in the LICENSE file. */
+
+#include "config.h"
+#include "go-type.h"
+
+#ifdef USE_LIBFFI
+
+#include "ffi.h"
+
+void __go_func_to_cif (const struct __go_func_type *, _Bool, _Bool, ffi_cif *);
+
+#endif
diff --git a/libgo/runtime/go-getgoroot.c b/libgo/runtime/go-getgoroot.c
deleted file mode 100644
index 1b52d44043..0000000000
--- a/libgo/runtime/go-getgoroot.c
+++ /dev/null
@@ -1,26 +0,0 @@
-/* go-getgoroot.c -- getgoroot function for runtime package.
-
- 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. */
-
-#include <stdlib.h>
-
-#include "runtime.h"
-
-String getgoroot (void) __asm__ (GOSYM_PREFIX "runtime.getgoroot");
-
-String
-getgoroot ()
-{
- const char *p;
- String ret;
-
- p = getenv ("GOROOT");
- ret.str = (const byte *) p;
- if (ret.str == NULL)
- ret.len = 0;
- else
- ret.len = __builtin_strlen (p);
- return ret;
-}
diff --git a/libgo/runtime/iface.goc b/libgo/runtime/go-iface.goc
index 7c74e80ac3..0d5cb5e97a 100644
--- a/libgo/runtime/iface.goc
+++ b/libgo/runtime/go-iface.goc
@@ -32,8 +32,6 @@ func ifacetype(i interface) (d *const_descriptor) {
// Convert an empty interface to an empty interface.
func ifaceE2E2(e empty_interface) (ret empty_interface, ok bool) {
- if(((uintptr_t)e.__type_descriptor&reflectFlags) != 0)
- runtime_panicstring("invalid interface value");
ret = e;
ok = ret.__type_descriptor != nil;
}
@@ -53,8 +51,6 @@ func ifaceI2E2(i interface) (ret empty_interface, ok bool) {
// Convert an empty interface to a non-empty interface.
func ifaceE2I2(inter *descriptor, e empty_interface) (ret interface, ok bool) {
- if(((uintptr_t)e.__type_descriptor&reflectFlags) != 0)
- runtime_panicstring("invalid interface value");
if (e.__type_descriptor == nil) {
ret.__methods = nil;
ret.__object = nil;
@@ -84,8 +80,6 @@ func ifaceI2I2(inter *descriptor, i interface) (ret interface, ok bool) {
// Convert an empty interface to a pointer type.
func ifaceE2T2P(inter *descriptor, e empty_interface) (ret *void, ok bool) {
- if(((uintptr_t)e.__type_descriptor&reflectFlags) != 0)
- runtime_panicstring("invalid interface value");
if (!__go_type_descriptors_equal(inter, e.__type_descriptor)) {
ret = nil;
ok = 0;
@@ -109,8 +103,6 @@ func ifaceI2T2P(inter *descriptor, i interface) (ret *void, ok bool) {
// Convert an empty interface to a non-pointer type.
func ifaceE2T2(inter *descriptor, e empty_interface, ret *void) (ok bool) {
- if(((uintptr_t)e.__type_descriptor&reflectFlags) != 0)
- runtime_panicstring("invalid interface value");
if (!__go_type_descriptors_equal(inter, e.__type_descriptor)) {
__builtin_memset(ret, 0, inter->__size);
ok = 0;
diff --git a/libgo/runtime/go-interface-eface-compare.c b/libgo/runtime/go-interface-eface-compare.c
index bb81ff813a..a38917fd0c 100644
--- a/libgo/runtime/go-interface-eface-compare.c
+++ b/libgo/runtime/go-interface-eface-compare.c
@@ -18,8 +18,6 @@ __go_interface_empty_compare (struct __go_interface left,
{
const struct __go_type_descriptor *left_descriptor;
- if (((uintptr_t) right.__type_descriptor & reflectFlags) != 0)
- runtime_panicstring ("invalid interface value");
if (left.__methods == NULL && right.__type_descriptor == NULL)
return 0;
if (left.__methods == NULL || right.__type_descriptor == NULL)
diff --git a/libgo/runtime/go-make-slice.c b/libgo/runtime/go-make-slice.c
index 855bb17ce5..ccd07e5ac5 100644
--- a/libgo/runtime/go-make-slice.c
+++ b/libgo/runtime/go-make-slice.c
@@ -30,7 +30,7 @@ __go_make_slice2 (const struct __go_type_descriptor *td, uintptr_t len,
uintptr_t size;
struct __go_open_array ret;
- __go_assert (td->__code == GO_SLICE);
+ __go_assert ((td->__code & GO_CODE_MASK) == GO_SLICE);
std = (const struct __go_slice_type *) td;
ilen = (intgo) len;
diff --git a/libgo/runtime/go-map-delete.c b/libgo/runtime/go-map-delete.c
index f8f8907c34..aff25d104b 100644
--- a/libgo/runtime/go-map-delete.c
+++ b/libgo/runtime/go-map-delete.c
@@ -8,6 +8,7 @@
#include <stdlib.h>
#include "runtime.h"
+#include "malloc.h"
#include "go-alloc.h"
#include "go-assert.h"
#include "map.h"
@@ -34,7 +35,10 @@ __go_map_delete (struct __go_map *map, const void *key)
key_descriptor = descriptor->__map_descriptor->__key_type;
key_offset = descriptor->__key_offset;
key_size = key_descriptor->__size;
- __go_assert (key_size != 0 && key_size != -1UL);
+ if (key_size == 0)
+ return;
+
+ __go_assert (key_size != -1UL);
equalfn = key_descriptor->__equalfn;
key_hash = key_descriptor->__hashfn (key, key_size);
@@ -47,7 +51,8 @@ __go_map_delete (struct __go_map *map, const void *key)
if (equalfn (key, entry + key_offset, key_size))
{
*pentry = *(void **) entry;
- __go_free (entry);
+ if (descriptor->__entry_size >= TinySize)
+ __go_free (entry);
map->__element_count -= 1;
break;
}
diff --git a/libgo/runtime/go-map-index.c b/libgo/runtime/go-map-index.c
index 499641c5e1..616b00c68c 100644
--- a/libgo/runtime/go-map-index.c
+++ b/libgo/runtime/go-map-index.c
@@ -8,6 +8,7 @@
#include <stdlib.h>
#include "runtime.h"
+#include "malloc.h"
#include "go-alloc.h"
#include "go-assert.h"
#include "map.h"
@@ -63,7 +64,8 @@ __go_map_rehash (struct __go_map *map)
}
}
- __go_free (old_buckets);
+ if (old_bucket_count * sizeof (void *) >= TinySize)
+ __go_free (old_buckets);
map->__bucket_count = new_bucket_count;
map->__buckets = new_buckets;
diff --git a/libgo/runtime/go-new.c b/libgo/runtime/go-new.c
index 9d46706eaa..dad6efb30c 100644
--- a/libgo/runtime/go-new.c
+++ b/libgo/runtime/go-new.c
@@ -10,13 +10,17 @@
#include "malloc.h"
void *
-__go_new (uintptr_t size)
+__go_new (const struct __go_type_descriptor *td, uintptr_t size)
{
- return runtime_mallocgc (size, 0, 0);
+ return runtime_mallocgc (size,
+ (uintptr) td | TypeInfo_SingleObject,
+ 0);
}
void *
-__go_new_nopointers (uintptr_t size)
+__go_new_nopointers (const struct __go_type_descriptor *td, uintptr_t size)
{
- return runtime_mallocgc (size, 0, FlagNoScan);
+ return runtime_mallocgc (size,
+ (uintptr) td | TypeInfo_SingleObject,
+ FlagNoScan);
}
diff --git a/libgo/runtime/go-now.c b/libgo/runtime/go-now.c
index 73cc1602df..ea8d070e9f 100644
--- a/libgo/runtime/go-now.c
+++ b/libgo/runtime/go-now.c
@@ -11,16 +11,6 @@
// Return current time. This is the implementation of time.now().
struct time_now_ret
-{
- int64_t sec;
- int32_t nsec;
-};
-
-struct time_now_ret now()
- __asm__ (GOSYM_PREFIX "time.now")
- __attribute__ ((no_split_stack));
-
-struct time_now_ret
now()
{
struct timeval tv;
diff --git a/libgo/runtime/go-panic.c b/libgo/runtime/go-panic.c
index 0cacbcd91c..77975c6e08 100644
--- a/libgo/runtime/go-panic.c
+++ b/libgo/runtime/go-panic.c
@@ -54,7 +54,6 @@ __go_panic (struct __go_empty_interface arg)
{
struct __go_defer_stack *d;
void (*pfn) (void *);
- M *m;
d = g->defer;
if (d == NULL)
@@ -101,9 +100,8 @@ __go_panic (struct __go_empty_interface arg)
call to syscall.CgocallBackDone, in which case we will not
have a memory context. Don't try to free anything in that
case--the GC will release it later. */
- m = runtime_m ();
- if (m != NULL && m->mcache != NULL && d->__free)
- __go_free (d);
+ if (runtime_m () != NULL)
+ runtime_freedefer (d);
}
/* The panic was not recovered. */
diff --git a/libgo/runtime/go-panic.h b/libgo/runtime/go-panic.h
index e7031d4040..d29fe88b57 100644
--- a/libgo/runtime/go-panic.h
+++ b/libgo/runtime/go-panic.h
@@ -38,6 +38,15 @@ extern void __go_print_string (struct String);
extern struct __go_empty_interface __go_recover (void);
+extern _Bool __go_can_recover (void *);
+
+extern void __go_makefunc_can_recover (void *retaddr);
+
+struct Location;
+extern void __go_makefunc_ffi_can_recover (struct Location *, int);
+
+extern void __go_makefunc_returning (void);
+
extern void __go_unwind_stack (void);
#endif /* !defined(LIBGO_GO_PANIC_H) */
diff --git a/libgo/runtime/go-recover.c b/libgo/runtime/go-recover.c
index ceb9b57258..fc66f61cab 100644
--- a/libgo/runtime/go-recover.c
+++ b/libgo/runtime/go-recover.c
@@ -9,6 +9,36 @@
#include "go-panic.h"
#include "go-defer.h"
+/* If the top of the defer stack can be recovered, then return it.
+ Otherwise return NULL. */
+
+static struct __go_defer_stack *
+current_defer ()
+{
+ G *g;
+ struct __go_defer_stack *d;
+
+ g = runtime_g ();
+
+ d = g->defer;
+ if (d == NULL)
+ return NULL;
+
+ /* The panic which would be recovered is the one on the top of the
+ panic stack. We do not want to recover it if that panic was on
+ the top of the panic stack when this function was deferred. */
+ if (d->__panic == g->panic)
+ return NULL;
+
+ /* The deferred thunk will call _go_set_defer_retaddr. If this has
+ not happened, then we have not been called via defer, and we can
+ not recover. */
+ if (d->__retaddr == NULL)
+ return NULL;
+
+ return d;
+}
+
/* This is called by a thunk to see if the real function should be
permitted to recover a panic value. Recovering a value is
permitted if the thunk was called directly by defer. RETADDR is
@@ -16,78 +46,126 @@
__go_can_recover--this is, the thunk. */
_Bool
-__go_can_recover (const void *retaddr)
+__go_can_recover (void *retaddr)
{
- G *g;
struct __go_defer_stack *d;
const char* ret;
const char* dret;
- Location loc;
+ Location locs[16];
const byte *name;
+ intgo len;
+ int n;
+ int i;
+ _Bool found_ffi_callback;
- g = runtime_g ();
-
- d = g->defer;
+ d = current_defer ();
if (d == NULL)
return 0;
- /* The panic which this function would recover is the one on the top
- of the panic stack. We do not want to recover it if that panic
- was on the top of the panic stack when this function was
- deferred. */
- if (d->__panic == g->panic)
- return 0;
-
- /* D->__RETADDR is the address of a label immediately following the
- call to the thunk. We can recover a panic if that is the same as
- the return address of the thunk. We permit a bit of slack in
- case there is any code between the function return and the label,
- such as an instruction to adjust the stack pointer. */
-
- ret = (const char *) retaddr;
-
-#ifdef __sparc__
- /* On SPARC the address we get, from __builtin_return_address, is
- the address of the call instruction. Adjust forward, also
- skipping the delayed instruction following the call. */
- ret += 8;
-#endif
+ ret = (const char *) __builtin_extract_return_addr (retaddr);
dret = (const char *) d->__retaddr;
if (ret <= dret && ret + 16 >= dret)
return 1;
- /* If the function calling recover was created by reflect.MakeFunc,
- then RETADDR will be somewhere in libffi. Our caller is
- permitted to recover if it was called from libffi. */
- if (!d->__makefunc_can_recover)
- return 0;
+ /* On some systems, in some cases, the return address does not work
+ reliably. See http://gcc.gnu.org/PR60406. If we are permitted
+ to call recover, the call stack will look like this:
+ __go_panic, __go_undefer, etc.
+ thunk to call deferred function (calls __go_set_defer_retaddr)
+ function that calls __go_can_recover (passing return address)
+ __go_can_recover
+ Calling runtime_callers will skip the thunks. So if our caller's
+ caller starts with __go, then we are permitted to call
+ recover. */
- if (runtime_callers (2, &loc, 1) < 1)
+ if (runtime_callers (1, &locs[0], 2, false) < 2)
return 0;
- /* If we have no function name, then we weren't called by Go code.
- Guess that we were called by libffi. */
- if (loc.function.len == 0)
+ name = locs[1].function.str;
+ len = locs[1].function.len;
+
+ /* Although locs[1].function is a Go string, we know it is
+ NUL-terminated. */
+ if (len > 4
+ && __builtin_strchr ((const char *) name, '.') == NULL
+ && __builtin_strncmp ((const char *) name, "__go_", 4) == 0)
return 1;
- if (loc.function.len < 4)
- return 0;
- name = loc.function.str;
- if (*name == '_')
+ /* If we are called from __go_makefunc_can_recover, then we need to
+ look one level higher. */
+ if (locs[0].function.len > 0
+ && __builtin_strcmp ((const char *) locs[0].function.str,
+ "__go_makefunc_can_recover") == 0)
{
- if (loc.function.len < 5)
+ if (runtime_callers (3, &locs[0], 1, false) < 1)
return 0;
- ++name;
+ name = locs[0].function.str;
+ len = locs[0].function.len;
+ if (len > 4
+ && __builtin_strchr ((const char *) name, '.') == NULL
+ && __builtin_strncmp ((const char *) name, "__go_", 4) == 0)
+ return 1;
}
- if (name[0] == 'f' && name[1] == 'f' && name[2] == 'i' && name[3] == '_')
- return 1;
+ /* If the function calling recover was created by reflect.MakeFunc,
+ then __go_makefunc_can_recover or __go_makefunc_ffi_can_recover
+ will have set the __makefunc_can_recover field. */
+ if (!d->__makefunc_can_recover)
+ return 0;
- /* We may also be called by reflect.makeFuncImpl.call, for a
- function created by reflect.MakeFunc. */
- if (__builtin_strstr ((const char *) name, "makeFuncImpl") != NULL)
- return 1;
+ /* We look up the stack, ignoring libffi functions and functions in
+ the reflect package, until we find reflect.makeFuncStub or
+ reflect.ffi_callback called by FFI functions. Then we check the
+ caller of that function. */
+
+ n = runtime_callers (2, &locs[0], sizeof locs / sizeof locs[0], false);
+ found_ffi_callback = 0;
+ for (i = 0; i < n; i++)
+ {
+ const byte *name;
+
+ if (locs[i].function.len == 0)
+ {
+ /* No function name means this caller isn't Go code. Assume
+ that this is libffi. */
+ continue;
+ }
+
+ /* Ignore functions in libffi. */
+ name = locs[i].function.str;
+ if (__builtin_strncmp ((const char *) name, "ffi_", 4) == 0)
+ continue;
+
+ if (found_ffi_callback)
+ break;
+
+ if (__builtin_strcmp ((const char *) name, "reflect.ffi_callback") == 0)
+ {
+ found_ffi_callback = 1;
+ continue;
+ }
+
+ if (__builtin_strcmp ((const char *) name, "reflect.makeFuncStub") == 0)
+ {
+ i++;
+ break;
+ }
+
+ /* Ignore other functions in the reflect package. */
+ if (__builtin_strncmp ((const char *) name, "reflect.", 8) == 0)
+ continue;
+
+ /* We should now be looking at the real caller. */
+ break;
+ }
+
+ if (i < n && locs[i].function.len > 0)
+ {
+ name = locs[i].function.str;
+ if (__builtin_strncmp ((const char *) name, "__go_", 4) == 0)
+ return 1;
+ }
return 0;
}
@@ -98,14 +176,58 @@ __go_can_recover (const void *retaddr)
real MakeFunc function is permitted to call recover. */
void
-__go_makefunc_can_recover (const void *retaddr)
+__go_makefunc_can_recover (void *retaddr)
{
struct __go_defer_stack *d;
- d = runtime_g ()->defer;
- if (d != NULL
- && !d->__makefunc_can_recover
- && __go_can_recover (retaddr))
+ d = current_defer ();
+ if (d == NULL)
+ return;
+
+ /* If we are already in a call stack of MakeFunc functions, there is
+ nothing we can usefully check here. */
+ if (d->__makefunc_can_recover)
+ return;
+
+ if (__go_can_recover (retaddr))
+ d->__makefunc_can_recover = 1;
+}
+
+/* This function is called when code is about to enter a function
+ created by the libffi version of reflect.MakeFunc. This function
+ is passed the names of the callers of the libffi code that called
+ the stub. It uses to decide whether it is permitted to call
+ recover, and sets d->__makefunc_can_recover so that __go_recover
+ can make the same decision. */
+
+void
+__go_makefunc_ffi_can_recover (struct Location *loc, int n)
+{
+ struct __go_defer_stack *d;
+ const byte *name;
+ intgo len;
+
+ d = current_defer ();
+ if (d == NULL)
+ return;
+
+ /* If we are already in a call stack of MakeFunc functions, there is
+ nothing we can usefully check here. */
+ if (d->__makefunc_can_recover)
+ return;
+
+ /* LOC points to the caller of our caller. That will be a thunk.
+ If its caller was a runtime function, then it was called directly
+ by defer. */
+
+ if (n < 2)
+ return;
+
+ name = (loc + 1)->function.str;
+ len = (loc + 1)->function.len;
+ if (len > 4
+ && __builtin_strchr ((const char *) name, '.') == NULL
+ && __builtin_strncmp ((const char *) name, "__go_", 4) == 0)
d->__makefunc_can_recover = 1;
}
diff --git a/libgo/runtime/go-reflect-call.c b/libgo/runtime/go-reflect-call.c
index 07b99d7433..29e814a793 100644
--- a/libgo/runtime/go-reflect-call.c
+++ b/libgo/runtime/go-reflect-call.c
@@ -12,336 +12,20 @@
#include "go-alloc.h"
#include "go-assert.h"
#include "go-type.h"
+#include "go-ffi.h"
-#ifdef USE_LIBFFI
-
-#include "ffi.h"
+#if defined(USE_LIBFFI) && FFI_GO_CLOSURES
/* The functions in this file are only called from reflect_call. As
reflect_call calls a libffi function, which will be compiled
without -fsplit-stack, it will always run with a large stack. */
-static ffi_type *go_array_to_ffi (const struct __go_array_type *)
- __attribute__ ((no_split_stack));
-static ffi_type *go_slice_to_ffi (const struct __go_slice_type *)
- __attribute__ ((no_split_stack));
-static ffi_type *go_struct_to_ffi (const struct __go_struct_type *)
- __attribute__ ((no_split_stack));
-static ffi_type *go_string_to_ffi (void) __attribute__ ((no_split_stack));
-static ffi_type *go_interface_to_ffi (void) __attribute__ ((no_split_stack));
-static ffi_type *go_complex_to_ffi (ffi_type *)
- __attribute__ ((no_split_stack, unused));
-static ffi_type *go_type_to_ffi (const struct __go_type_descriptor *)
- __attribute__ ((no_split_stack));
-static ffi_type *go_func_return_ffi (const struct __go_func_type *)
- __attribute__ ((no_split_stack));
-static void go_func_to_cif (const struct __go_func_type *, _Bool, _Bool,
- ffi_cif *)
- __attribute__ ((no_split_stack));
static size_t go_results_size (const struct __go_func_type *)
__attribute__ ((no_split_stack));
static void go_set_results (const struct __go_func_type *, unsigned char *,
void **)
__attribute__ ((no_split_stack));
-/* Return an ffi_type for a Go array type. The libffi library does
- not have any builtin support for passing arrays as values. We work
- around this by pretending that the array is a struct. */
-
-static ffi_type *
-go_array_to_ffi (const struct __go_array_type *descriptor)
-{
- ffi_type *ret;
- uintptr_t len;
- ffi_type *element;
- uintptr_t i;
-
- ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
- ret->type = FFI_TYPE_STRUCT;
- len = descriptor->__len;
- ret->elements = (ffi_type **) __go_alloc ((len + 1) * sizeof (ffi_type *));
- element = go_type_to_ffi (descriptor->__element_type);
- for (i = 0; i < len; ++i)
- ret->elements[i] = element;
- ret->elements[len] = NULL;
- return ret;
-}
-
-/* Return an ffi_type for a Go slice type. This describes the
- __go_open_array type defines in array.h. */
-
-static ffi_type *
-go_slice_to_ffi (
- const struct __go_slice_type *descriptor __attribute__ ((unused)))
-{
- ffi_type *ret;
- ffi_type *ffi_intgo;
-
- ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
- ret->type = FFI_TYPE_STRUCT;
- ret->elements = (ffi_type **) __go_alloc (4 * sizeof (ffi_type *));
- ret->elements[0] = &ffi_type_pointer;
- ffi_intgo = sizeof (intgo) == 4 ? &ffi_type_sint32 : &ffi_type_sint64;
- ret->elements[1] = ffi_intgo;
- ret->elements[2] = ffi_intgo;
- ret->elements[3] = NULL;
- return ret;
-}
-
-/* Return an ffi_type for a Go struct type. */
-
-static ffi_type *
-go_struct_to_ffi (const struct __go_struct_type *descriptor)
-{
- ffi_type *ret;
- int field_count;
- const struct __go_struct_field *fields;
- int i;
-
- field_count = descriptor->__fields.__count;
- if (field_count == 0) {
- return &ffi_type_void;
- }
- ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
- ret->type = FFI_TYPE_STRUCT;
- fields = (const struct __go_struct_field *) descriptor->__fields.__values;
- ret->elements = (ffi_type **) __go_alloc ((field_count + 1)
- * sizeof (ffi_type *));
- for (i = 0; i < field_count; ++i)
- ret->elements[i] = go_type_to_ffi (fields[i].__type);
- ret->elements[field_count] = NULL;
- return ret;
-}
-
-/* Return an ffi_type for a Go string type. This describes the String
- struct. */
-
-static ffi_type *
-go_string_to_ffi (void)
-{
- ffi_type *ret;
- ffi_type *ffi_intgo;
-
- ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
- ret->type = FFI_TYPE_STRUCT;
- ret->elements = (ffi_type **) __go_alloc (3 * sizeof (ffi_type *));
- ret->elements[0] = &ffi_type_pointer;
- ffi_intgo = sizeof (intgo) == 4 ? &ffi_type_sint32 : &ffi_type_sint64;
- ret->elements[1] = ffi_intgo;
- ret->elements[2] = NULL;
- return ret;
-}
-
-/* Return an ffi_type for a Go interface type. This describes the
- __go_interface and __go_empty_interface structs. */
-
-static ffi_type *
-go_interface_to_ffi (void)
-{
- ffi_type *ret;
-
- ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
- ret->type = FFI_TYPE_STRUCT;
- ret->elements = (ffi_type **) __go_alloc (3 * sizeof (ffi_type *));
- ret->elements[0] = &ffi_type_pointer;
- ret->elements[1] = &ffi_type_pointer;
- ret->elements[2] = NULL;
- return ret;
-}
-
-/* Return an ffi_type for a Go complex type. */
-
-static ffi_type *
-go_complex_to_ffi (ffi_type *float_type)
-{
- ffi_type *ret;
-
- ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
- ret->type = FFI_TYPE_STRUCT;
- ret->elements = (ffi_type **) __go_alloc (3 * sizeof (ffi_type *));
- ret->elements[0] = float_type;
- ret->elements[1] = float_type;
- ret->elements[2] = NULL;
- return ret;
-}
-
-/* Return an ffi_type for a type described by a
- __go_type_descriptor. */
-
-static ffi_type *
-go_type_to_ffi (const struct __go_type_descriptor *descriptor)
-{
- switch (descriptor->__code & GO_CODE_MASK)
- {
- case GO_BOOL:
- if (sizeof (_Bool) == 1)
- return &ffi_type_uint8;
- else if (sizeof (_Bool) == sizeof (int))
- return &ffi_type_uint;
- abort ();
- case GO_FLOAT32:
- if (sizeof (float) == 4)
- return &ffi_type_float;
- abort ();
- case GO_FLOAT64:
- if (sizeof (double) == 8)
- return &ffi_type_double;
- abort ();
- case GO_COMPLEX64:
-#ifdef __alpha__
- runtime_throw("the libffi library does not support Complex64 type with "
- "reflect.Call or runtime.SetFinalizer");
-#else
- if (sizeof (float) == 4)
- return go_complex_to_ffi (&ffi_type_float);
- abort ();
-#endif
- case GO_COMPLEX128:
-#ifdef __alpha__
- runtime_throw("the libffi library does not support Complex128 type with "
- "reflect.Call or runtime.SetFinalizer");
-#else
- if (sizeof (double) == 8)
- return go_complex_to_ffi (&ffi_type_double);
- abort ();
-#endif
- case GO_INT16:
- return &ffi_type_sint16;
- case GO_INT32:
- return &ffi_type_sint32;
- case GO_INT64:
- return &ffi_type_sint64;
- case GO_INT8:
- return &ffi_type_sint8;
- case GO_INT:
- return sizeof (intgo) == 4 ? &ffi_type_sint32 : &ffi_type_sint64;
- case GO_UINT16:
- return &ffi_type_uint16;
- case GO_UINT32:
- return &ffi_type_uint32;
- case GO_UINT64:
- return &ffi_type_uint64;
- case GO_UINT8:
- return &ffi_type_uint8;
- case GO_UINT:
- return sizeof (uintgo) == 4 ? &ffi_type_uint32 : &ffi_type_uint64;
- case GO_UINTPTR:
- if (sizeof (void *) == 2)
- return &ffi_type_uint16;
- else if (sizeof (void *) == 4)
- return &ffi_type_uint32;
- else if (sizeof (void *) == 8)
- return &ffi_type_uint64;
- abort ();
- case GO_ARRAY:
- return go_array_to_ffi ((const struct __go_array_type *) descriptor);
- case GO_SLICE:
- return go_slice_to_ffi ((const struct __go_slice_type *) descriptor);
- case GO_STRUCT:
- return go_struct_to_ffi ((const struct __go_struct_type *) descriptor);
- case GO_STRING:
- return go_string_to_ffi ();
- case GO_INTERFACE:
- return go_interface_to_ffi ();
- case GO_CHAN:
- case GO_FUNC:
- case GO_MAP:
- case GO_PTR:
- case GO_UNSAFE_POINTER:
- /* These types are always pointers, and for FFI purposes nothing
- else matters. */
- return &ffi_type_pointer;
- default:
- abort ();
- }
-}
-
-/* Return the return type for a function, given the number of out
- parameters and their types. */
-
-static ffi_type *
-go_func_return_ffi (const struct __go_func_type *func)
-{
- int count;
- const struct __go_type_descriptor **types;
- ffi_type *ret;
- int i;
-
- count = func->__out.__count;
- if (count == 0)
- return &ffi_type_void;
-
- types = (const struct __go_type_descriptor **) func->__out.__values;
-
- if (count == 1)
- {
-
-#if defined (__i386__) && !defined (__x86_64__)
- /* FFI does not support complex types. On 32-bit x86, a
- complex64 will be returned in %eax/%edx. We normally tell
- FFI that a complex64 is a struct of two floats. On 32-bit
- x86 a struct of two floats is returned via a hidden first
- pointer parameter. Fortunately we can make everything work
- by pretending that complex64 is int64. */
- if ((types[0]->__code & GO_CODE_MASK) == GO_COMPLEX64)
- return &ffi_type_sint64;
-#endif
-
- return go_type_to_ffi (types[0]);
- }
-
- ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
- ret->type = FFI_TYPE_STRUCT;
- ret->elements = (ffi_type **) __go_alloc ((count + 1) * sizeof (ffi_type *));
- for (i = 0; i < count; ++i)
- ret->elements[i] = go_type_to_ffi (types[i]);
- ret->elements[count] = NULL;
- return ret;
-}
-
-/* Build an ffi_cif structure for a function described by a
- __go_func_type structure. */
-
-static void
-go_func_to_cif (const struct __go_func_type *func, _Bool is_interface,
- _Bool is_method, ffi_cif *cif)
-{
- int num_params;
- const struct __go_type_descriptor **in_types;
- size_t num_args;
- ffi_type **args;
- int off;
- int i;
- ffi_type *rettype;
- ffi_status status;
-
- num_params = func->__in.__count;
- in_types = ((const struct __go_type_descriptor **)
- func->__in.__values);
-
- num_args = num_params + (is_interface ? 1 : 0);
- args = (ffi_type **) __go_alloc (num_args * sizeof (ffi_type *));
- i = 0;
- off = 0;
- if (is_interface)
- {
- args[0] = &ffi_type_pointer;
- off = 1;
- }
- else if (is_method)
- {
- args[0] = &ffi_type_pointer;
- i = 1;
- }
- for (; i < num_params; ++i)
- args[i + off] = go_type_to_ffi (in_types[i]);
-
- rettype = go_func_return_ffi (func);
-
- status = ffi_prep_cif (cif, FFI_DEFAULT_ABI, num_args, rettype, args);
- __go_assert (status == FFI_OK);
-}
-
/* Get the total size required for the result parameters of a
function. */
@@ -517,11 +201,7 @@ go_set_results (const struct __go_func_type *func, unsigned char *call_result,
If IS_METHOD is true this is a call to a method expression. The
first argument is the receiver. It is described in FUNC_TYPE, but
- regardless of FUNC_TYPE, it is passed as a pointer.
-
- If neither IS_INTERFACE nor IS_METHOD is true then we are calling a
- function indirectly, and we must pass a closure pointer via
- __go_set_closure. The pointer to pass is simply FUNC_VAL. */
+ regardless of FUNC_TYPE, it is passed as a pointer. */
void
reflect_call (const struct __go_func_type *func_type, FuncVal *func_val,
@@ -532,13 +212,11 @@ reflect_call (const struct __go_func_type *func_type, FuncVal *func_val,
unsigned char *call_result;
__go_assert ((func_type->__common.__code & GO_CODE_MASK) == GO_FUNC);
- go_func_to_cif (func_type, is_interface, is_method, &cif);
+ __go_func_to_cif (func_type, is_interface, is_method, &cif);
call_result = (unsigned char *) malloc (go_results_size (func_type));
- if (!is_interface && !is_method)
- __go_set_closure (func_val);
- ffi_call (&cif, func_val->fn, call_result, params);
+ ffi_call_go (&cif, func_val->fn, call_result, params, func_val);
/* Some day we may need to free result values if RESULTS is
NULL. */
diff --git a/libgo/runtime/go-reflect-map.c b/libgo/runtime/go-reflect-map.c
index 1ae7c96adc..58e1b34a1e 100644
--- a/libgo/runtime/go-reflect-map.c
+++ b/libgo/runtime/go-reflect-map.c
@@ -16,112 +16,55 @@
/* This file implements support for reflection on maps. These
functions are called from reflect/value.go. */
-struct mapaccess_ret
-{
- uintptr_t val;
- _Bool pres;
-};
-
-extern struct mapaccess_ret mapaccess (struct __go_map_type *, uintptr_t,
- uintptr_t)
+extern void *mapaccess (struct __go_map_type *, void *, void *)
__asm__ (GOSYM_PREFIX "reflect.mapaccess");
-struct mapaccess_ret
-mapaccess (struct __go_map_type *mt, uintptr_t m, uintptr_t key_i)
+void *
+mapaccess (struct __go_map_type *mt, void *m, void *key)
{
struct __go_map *map = (struct __go_map *) m;
- void *key;
- const struct __go_type_descriptor *key_descriptor;
- void *p;
- const struct __go_type_descriptor *val_descriptor;
- struct mapaccess_ret ret;
- void *val;
- void *pv;
-
- __go_assert (mt->__common.__code == GO_MAP);
-
- key_descriptor = mt->__key_type;
- if (__go_is_pointer_type (key_descriptor))
- key = &key_i;
- else
- key = (void *) key_i;
+ __go_assert ((mt->__common.__code & GO_CODE_MASK) == GO_MAP);
if (map == NULL)
- p = NULL;
+ return NULL;
else
- p = __go_map_index (map, key, 0);
-
- val_descriptor = mt->__val_type;
- if (__go_is_pointer_type (val_descriptor))
- {
- val = NULL;
- pv = &val;
- }
- else
- {
- val = __go_alloc (val_descriptor->__size);
- pv = val;
- }
-
- if (p == NULL)
- ret.pres = 0;
- else
- {
- __builtin_memcpy (pv, p, val_descriptor->__size);
- ret.pres = 1;
- }
-
- ret.val = (uintptr_t) val;
- return ret;
+ return __go_map_index (map, key, 0);
}
-extern void mapassign (struct __go_map_type *, uintptr_t, uintptr_t,
- uintptr_t, _Bool)
+extern void mapassign (struct __go_map_type *, void *, void *, void *)
__asm__ (GOSYM_PREFIX "reflect.mapassign");
void
-mapassign (struct __go_map_type *mt, uintptr_t m, uintptr_t key_i,
- uintptr_t val_i, _Bool pres)
+mapassign (struct __go_map_type *mt, void *m, void *key, void *val)
{
struct __go_map *map = (struct __go_map *) m;
- const struct __go_type_descriptor *key_descriptor;
- void *key;
-
- __go_assert (mt->__common.__code == GO_MAP);
+ void *p;
+ __go_assert ((mt->__common.__code & GO_CODE_MASK) == GO_MAP);
if (map == NULL)
runtime_panicstring ("assignment to entry in nil map");
+ p = __go_map_index (map, key, 1);
+ __builtin_memcpy (p, val, mt->__val_type->__size);
+}
- key_descriptor = mt->__key_type;
- if (__go_is_pointer_type (key_descriptor))
- key = &key_i;
- else
- key = (void *) key_i;
+extern void mapdelete (struct __go_map_type *, void *, void *)
+ __asm__ (GOSYM_PREFIX "reflect.mapdelete");
- if (!pres)
- __go_map_delete (map, key);
- else
- {
- void *p;
- const struct __go_type_descriptor *val_descriptor;
- void *pv;
-
- p = __go_map_index (map, key, 1);
-
- val_descriptor = mt->__val_type;
- if (__go_is_pointer_type (val_descriptor))
- pv = &val_i;
- else
- pv = (void *) val_i;
- __builtin_memcpy (p, pv, val_descriptor->__size);
- }
+void
+mapdelete (struct __go_map_type *mt, void *m, void *key)
+{
+ struct __go_map *map = (struct __go_map *) m;
+
+ __go_assert ((mt->__common.__code & GO_CODE_MASK) == GO_MAP);
+ if (map == NULL)
+ return;
+ __go_map_delete (map, key);
}
-extern int32_t maplen (uintptr_t)
- __asm__ (GOSYM_PREFIX "reflect.maplen");
+extern int32_t maplen (void *) __asm__ (GOSYM_PREFIX "reflect.maplen");
int32_t
-maplen (uintptr_t m)
+maplen (void *m)
{
struct __go_map *map = (struct __go_map *) m;
@@ -130,92 +73,59 @@ maplen (uintptr_t m)
return (int32_t) map->__element_count;
}
-extern unsigned char *mapiterinit (struct __go_map_type *, uintptr_t)
+extern unsigned char *mapiterinit (struct __go_map_type *, void *)
__asm__ (GOSYM_PREFIX "reflect.mapiterinit");
unsigned char *
-mapiterinit (struct __go_map_type *mt, uintptr_t m)
+mapiterinit (struct __go_map_type *mt, void *m)
{
struct __go_hash_iter *it;
- __go_assert (mt->__common.__code == GO_MAP);
+ __go_assert ((mt->__common.__code & GO_CODE_MASK) == GO_MAP);
it = __go_alloc (sizeof (struct __go_hash_iter));
__go_mapiterinit ((struct __go_map *) m, it);
return (unsigned char *) it;
}
-extern void mapiternext (unsigned char *)
- __asm__ (GOSYM_PREFIX "reflect.mapiternext");
+extern void mapiternext (void *) __asm__ (GOSYM_PREFIX "reflect.mapiternext");
void
-mapiternext (unsigned char *it)
+mapiternext (void *it)
{
__go_mapiternext ((struct __go_hash_iter *) it);
}
-struct mapiterkey_ret
-{
- uintptr_t key;
- _Bool ok;
-};
-
-extern struct mapiterkey_ret mapiterkey (unsigned char *)
- __asm__ (GOSYM_PREFIX "reflect.mapiterkey");
+extern void *mapiterkey (void *) __asm__ (GOSYM_PREFIX "reflect.mapiterkey");
-struct mapiterkey_ret
-mapiterkey (unsigned char *ita)
+void *
+mapiterkey (void *ita)
{
struct __go_hash_iter *it = (struct __go_hash_iter *) ita;
- struct mapiterkey_ret ret;
+ const struct __go_type_descriptor *key_descriptor;
+ void *key;
if (it->entry == NULL)
- {
- ret.key = 0;
- ret.ok = 0;
- }
- else
- {
- const struct __go_type_descriptor *key_descriptor;
- void *key;
- void *pk;
-
- key_descriptor = it->map->__descriptor->__map_descriptor->__key_type;
- if (__go_is_pointer_type (key_descriptor))
- {
- key = NULL;
- pk = &key;
- }
- else
- {
- key = __go_alloc (key_descriptor->__size);
- pk = key;
- }
-
- __go_mapiter1 (it, pk);
-
- ret.key = (uintptr_t) key;
- ret.ok = 1;
- }
-
- return ret;
+ return NULL;
+
+ key_descriptor = it->map->__descriptor->__map_descriptor->__key_type;
+ key = __go_alloc (key_descriptor->__size);
+ __go_mapiter1 (it, key);
+ return key;
}
/* Make a new map. We have to build our own map descriptor. */
-extern uintptr_t makemap (const struct __go_map_type *)
+extern struct __go_map *makemap (const struct __go_map_type *)
__asm__ (GOSYM_PREFIX "reflect.makemap");
-uintptr_t
+struct __go_map *
makemap (const struct __go_map_type *t)
{
struct __go_map_descriptor *md;
unsigned int o;
const struct __go_type_descriptor *kt;
const struct __go_type_descriptor *vt;
- struct __go_map* map;
- void *ret;
- /* FIXME: Reference count. */
md = (struct __go_map_descriptor *) __go_alloc (sizeof (*md));
md->__map_descriptor = t;
o = sizeof (void *);
@@ -232,11 +142,7 @@ makemap (const struct __go_map_type *t)
o = (o + vt->__field_align - 1) & ~ (vt->__field_align - 1);
md->__entry_size = o;
- map = __go_new_map (md, 0);
-
- ret = __go_alloc (sizeof (void *));
- __builtin_memcpy (ret, &map, sizeof (void *));
- return (uintptr_t) ret;
+ return __go_new_map (md, 0);
}
extern _Bool ismapkey (const struct __go_type_descriptor *)
diff --git a/libgo/runtime/go-setenv.c b/libgo/runtime/go-setenv.c
index 6c7378c9ec..a75d7c4127 100644
--- a/libgo/runtime/go-setenv.c
+++ b/libgo/runtime/go-setenv.c
@@ -11,6 +11,8 @@
#include "go-alloc.h"
#include "runtime.h"
+#include "arch.h"
+#include "malloc.h"
/* Set the C environment from Go. This is called by syscall.Setenv. */
@@ -23,6 +25,7 @@ setenv_c (String k, String v)
unsigned char *kn;
const byte *vs;
unsigned char *vn;
+ intgo len;
ks = k.str;
if (ks == NULL)
@@ -38,14 +41,22 @@ setenv_c (String k, String v)
if (ks != NULL && ks[k.len] != 0)
{
- kn = __go_alloc (k.len + 1);
+ // Objects that are explicitly freed must be at least 16 bytes in size,
+ // so that they are not allocated using tiny alloc.
+ len = k.len + 1;
+ if (len < TinySize)
+ len = TinySize;
+ kn = __go_alloc (len);
__builtin_memcpy (kn, ks, k.len);
ks = kn;
}
if (vs != NULL && vs[v.len] != 0)
{
- vn = __go_alloc (v.len + 1);
+ len = v.len + 1;
+ if (len < TinySize)
+ len = TinySize;
+ vn = __go_alloc (len);
__builtin_memcpy (vn, vs, v.len);
vs = vn;
}
@@ -54,7 +65,10 @@ setenv_c (String k, String v)
#else /* !defined(HAVE_SETENV) */
- kn = __go_alloc (k.len + v.len + 2);
+ len = k.len + v.len + 2;
+ if (len < TinySize)
+ len = TinySize;
+ kn = __go_alloc (len);
__builtin_memcpy (kn, ks, k.len);
kn[k.len] = '=';
__builtin_memcpy (kn + k.len + 1, vs, v.len);
diff --git a/libgo/runtime/go-signal.c b/libgo/runtime/go-signal.c
index 1624122dac..4a1bf5636e 100644
--- a/libgo/runtime/go-signal.c
+++ b/libgo/runtime/go-signal.c
@@ -238,16 +238,13 @@ runtime_sighandler (int sig, Siginfo *info,
/* The start of handling a signal which panics. */
static void
-sig_panic_leadin (int sig)
+sig_panic_leadin (G *gp)
{
int i;
sigset_t clear;
- if (runtime_m ()->mallocing)
- {
- runtime_printf ("caught signal while mallocing: %d\n", sig);
- runtime_throw ("caught signal while mallocing");
- }
+ if (!runtime_canpanic (gp))
+ runtime_throw ("unexpected signal during runtime execution");
/* The signal handler blocked signals; unblock them. */
i = sigfillset (&clear);
@@ -281,13 +278,14 @@ sig_panic_info_handler (int sig, Siginfo *info, void *context)
/* It would be nice to set g->sigpc here as the gc library does, but
I don't know how to get it portably. */
- sig_panic_leadin (sig);
+ sig_panic_leadin (g);
switch (sig)
{
#ifdef SIGBUS
case SIGBUS:
- if (info->si_code == BUS_ADRERR && (uintptr_t) info->si_addr < 0x1000)
+ if ((info->si_code == BUS_ADRERR && (uintptr_t) info->si_addr < 0x1000)
+ || g->paniconfault)
runtime_panicstring ("invalid memory address or "
"nil pointer dereference");
runtime_printf ("unexpected fault address %p\n", info->si_addr);
@@ -296,10 +294,11 @@ sig_panic_info_handler (int sig, Siginfo *info, void *context)
#ifdef SIGSEGV
case SIGSEGV:
- if ((info->si_code == 0
- || info->si_code == SEGV_MAPERR
- || info->si_code == SEGV_ACCERR)
- && (uintptr_t) info->si_addr < 0x1000)
+ if (((info->si_code == 0
+ || info->si_code == SEGV_MAPERR
+ || info->si_code == SEGV_ACCERR)
+ && (uintptr_t) info->si_addr < 0x1000)
+ || g->paniconfault)
runtime_panicstring ("invalid memory address or "
"nil pointer dereference");
runtime_printf ("unexpected fault address %p\n", info->si_addr);
@@ -342,7 +341,7 @@ sig_panic_handler (int sig)
g->sigcode0 = 0;
g->sigcode1 = 0;
- sig_panic_leadin (sig);
+ sig_panic_leadin (g);
switch (sig)
{
diff --git a/libgo/runtime/go-string-to-byte-array.c b/libgo/runtime/go-string-to-byte-array.c
index 5e030330f2..a4edb50da5 100644
--- a/libgo/runtime/go-string-to-byte-array.c
+++ b/libgo/runtime/go-string-to-byte-array.c
@@ -12,14 +12,17 @@
struct __go_open_array
__go_string_to_byte_array (String str)
{
+ uintptr cap;
unsigned char *data;
struct __go_open_array ret;
- data = (unsigned char *) runtime_mallocgc (str.len, 0,
- FlagNoScan | FlagNoZero);
+ cap = runtime_roundupsize (str.len);
+ data = (unsigned char *) runtime_mallocgc (cap, 0, FlagNoScan | FlagNoZero);
__builtin_memcpy (data, str.str, str.len);
+ if (cap != (uintptr) str.len)
+ __builtin_memset (data + str.len, 0, cap - (uintptr) str.len);
ret.__values = (void *) data;
ret.__count = str.len;
- ret.__capacity = str.len;
+ ret.__capacity = (intgo) cap;
return ret;
}
diff --git a/libgo/runtime/go-string-to-int-array.c b/libgo/runtime/go-string-to-int-array.c
index d91c9e2df8..5546889131 100644
--- a/libgo/runtime/go-string-to-int-array.c
+++ b/libgo/runtime/go-string-to-int-array.c
@@ -17,6 +17,7 @@ __go_string_to_int_array (String str)
size_t c;
const unsigned char *p;
const unsigned char *pend;
+ uintptr mem;
uint32_t *data;
uint32_t *pd;
struct __go_open_array ret;
@@ -32,8 +33,11 @@ __go_string_to_int_array (String str)
p += __go_get_rune (p, pend - p, &rune);
}
- data = (uint32_t *) runtime_mallocgc (c * sizeof (uint32_t), 0,
- FlagNoScan | FlagNoZero);
+ if (c > MaxMem / sizeof (uint32_t))
+ runtime_throw ("out of memory");
+
+ mem = runtime_roundupsize (c * sizeof (uint32_t));
+ data = (uint32_t *) runtime_mallocgc (mem, 0, FlagNoScan | FlagNoZero);
p = str.str;
pd = data;
while (p < pend)
@@ -43,9 +47,10 @@ __go_string_to_int_array (String str)
p += __go_get_rune (p, pend - p, &rune);
*pd++ = rune;
}
-
+ if (mem > (uintptr) c * sizeof (uint32_t))
+ __builtin_memset (data + c, 0, mem - (uintptr) c * sizeof (uint32_t));
ret.__values = (void *) data;
ret.__count = c;
- ret.__capacity = c;
+ ret.__capacity = (intgo) (mem / sizeof (uint32_t));
return ret;
}
diff --git a/libgo/runtime/go-traceback.c b/libgo/runtime/go-traceback.c
index f397f07523..7b33cca868 100644
--- a/libgo/runtime/go-traceback.c
+++ b/libgo/runtime/go-traceback.c
@@ -16,7 +16,7 @@ runtime_traceback ()
Location locbuf[100];
int32 c;
- c = runtime_callers (1, locbuf, nelem (locbuf));
+ c = runtime_callers (1, locbuf, nelem (locbuf), false);
runtime_printtrace (locbuf, c, true);
}
diff --git a/libgo/runtime/go-type-complex.c b/libgo/runtime/go-type-complex.c
index 106024f5c8..0f8f0627d7 100644
--- a/libgo/runtime/go-type-complex.c
+++ b/libgo/runtime/go-type-complex.c
@@ -4,13 +4,13 @@
Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file. */
+#include <complex.h>
+#include <math.h>
+#include <stdint.h>
+#include <string.h>
#include "runtime.h"
#include "go-type.h"
-/* The 64-bit type. */
-
-typedef unsigned int DItype __attribute__ ((mode (DI)));
-
/* Hash function for float types. */
uintptr_t
@@ -18,69 +18,67 @@ __go_type_hash_complex (const void *vkey, uintptr_t key_size)
{
if (key_size == 8)
{
- union
- {
- unsigned char a[8];
- __complex float cf;
- DItype di;
- } ucf;
- __complex float cf;
+ const complex float *cfp;
+ complex float cf;
float cfr;
float cfi;
+ uint64_t fi;
+
+ cfp = (const complex float *) vkey;
+ cf = *cfp;
+
+ cfr = crealf (cf);
+ cfi = cimagf (cf);
- __builtin_memcpy (ucf.a, vkey, 8);
- cf = ucf.cf;
- cfr = __builtin_crealf (cf);
- cfi = __builtin_cimagf (cf);
- if (__builtin_isinff (cfr) || __builtin_isinff (cfi))
+ if (isinf (cfr) || isinf (cfi))
return 0;
/* NaN != NaN, so the hash code of a NaN is irrelevant. Make it
random so that not all NaNs wind up in the same place. */
- if (__builtin_isnanf (cfr) || __builtin_isnanf (cfi))
+ if (isnan (cfr) || isnan (cfi))
return runtime_fastrand1 ();
/* Avoid negative zero. */
if (cfr == 0 && cfi == 0)
return 0;
else if (cfr == 0)
- ucf.cf = cfi * 1.0iF;
+ cf = cfi * I;
else if (cfi == 0)
- ucf.cf = cfr;
+ cf = cfr;
- return ucf.di;
+ memcpy (&fi, &cf, 8);
+ return (uintptr_t) cfi;
}
else if (key_size == 16)
{
- union
- {
- unsigned char a[16];
- __complex double cd;
- DItype adi[2];
- } ucd;
- __complex double cd;
+ const complex double *cdp;
+ complex double cd;
double cdr;
double cdi;
+ uint64_t di[2];
- __builtin_memcpy (ucd.a, vkey, 16);
- cd = ucd.cd;
- cdr = __builtin_crealf (cd);
- cdi = __builtin_cimagf (cd);
- if (__builtin_isinf (cdr) || __builtin_isinf (cdi))
+ cdp = (const complex double *) vkey;
+ cd = *cdp;
+
+ cdr = creal (cd);
+ cdi = cimag (cd);
+
+ if (isinf (cdr) || isinf (cdi))
return 0;
- if (__builtin_isnan (cdr) || __builtin_isnan (cdi))
+ if (isnan (cdr) || isnan (cdi))
return runtime_fastrand1 ();
/* Avoid negative zero. */
if (cdr == 0 && cdi == 0)
return 0;
else if (cdr == 0)
- ucd.cd = cdi * 1.0i;
+ cd = cdi * I;
else if (cdi == 0)
- ucd.cd = cdr;
+ cd = cdr;
- return ucd.adi[0] ^ ucd.adi[1];
+ memcpy (&di, &cd, 16);
+ return di[0] ^ di[1];
}
else
runtime_throw ("__go_type_hash_complex: invalid complex size");
@@ -93,35 +91,23 @@ __go_type_equal_complex (const void *vk1, const void *vk2, uintptr_t key_size)
{
if (key_size == 8)
{
- union
- {
- unsigned char a[8];
- __complex float cf;
- } ucf;
- __complex float cf1;
- __complex float cf2;
-
- __builtin_memcpy (ucf.a, vk1, 8);
- cf1 = ucf.cf;
- __builtin_memcpy (ucf.a, vk2, 8);
- cf2 = ucf.cf;
- return cf1 == cf2;
+ const complex float *cfp1;
+ const complex float *cfp2;
+
+ cfp1 = (const complex float *) vk1;
+ cfp2 = (const complex float *) vk2;
+
+ return *cfp1 == *cfp2;
}
else if (key_size == 16)
{
- union
- {
- unsigned char a[16];
- __complex double cd;
- } ucd;
- __complex double cd1;
- __complex double cd2;
-
- __builtin_memcpy (ucd.a, vk1, 16);
- cd1 = ucd.cd;
- __builtin_memcpy (ucd.a, vk2, 16);
- cd2 = ucd.cd;
- return cd1 == cd2;
+ const complex double *cdp1;
+ const complex double *cdp2;
+
+ cdp1 = (const complex double *) vk1;
+ cdp2 = (const complex double *) vk2;
+
+ return *cdp1 == *cdp2;
}
else
runtime_throw ("__go_type_equal_complex: invalid complex size");
diff --git a/libgo/runtime/go-type-eface.c b/libgo/runtime/go-type-eface.c
index cb3424b98d..30614d2511 100644
--- a/libgo/runtime/go-type-eface.c
+++ b/libgo/runtime/go-type-eface.c
@@ -44,9 +44,6 @@ __go_type_equal_empty_interface (const void *vv1, const void *vv2,
v2 = (const struct __go_empty_interface *) vv2;
v1_descriptor = v1->__type_descriptor;
v2_descriptor = v2->__type_descriptor;
- if (((uintptr_t) v1_descriptor & reflectFlags) != 0
- || ((uintptr_t) v2_descriptor & reflectFlags) != 0)
- runtime_panicstring ("invalid interface value");
if (v1_descriptor == NULL || v2_descriptor == NULL)
return v1_descriptor == v2_descriptor;
if (!__go_type_descriptors_equal (v1_descriptor, v2_descriptor))
diff --git a/libgo/runtime/go-type-float.c b/libgo/runtime/go-type-float.c
index e1c03e4284..4ae73470de 100644
--- a/libgo/runtime/go-type-float.c
+++ b/libgo/runtime/go-type-float.c
@@ -4,14 +4,11 @@
Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file. */
+#include <math.h>
+#include <stdint.h>
#include "runtime.h"
#include "go-type.h"
-/* The 32-bit and 64-bit types. */
-
-typedef unsigned int SItype __attribute__ ((mode (SI)));
-typedef unsigned int DItype __attribute__ ((mode (DI)));
-
/* Hash function for float types. */
uintptr_t
@@ -19,45 +16,41 @@ __go_type_hash_float (const void *vkey, uintptr_t key_size)
{
if (key_size == 4)
{
- union
- {
- unsigned char a[4];
- float f;
- SItype si;
- } uf;
+ const float *fp;
float f;
+ uint32_t si;
- __builtin_memcpy (uf.a, vkey, 4);
- f = uf.f;
- if (__builtin_isinff (f) || f == 0)
+ fp = (const float *) vkey;
+ f = *fp;
+
+ if (isinf (f) || f == 0)
return 0;
/* NaN != NaN, so the hash code of a NaN is irrelevant. Make it
random so that not all NaNs wind up in the same place. */
- if (__builtin_isnanf (f))
+ if (isnan (f))
return runtime_fastrand1 ();
- return (uintptr_t) uf.si;
+ memcpy (&si, vkey, 4);
+ return (uintptr_t) si;
}
else if (key_size == 8)
{
- union
- {
- unsigned char a[8];
- double d;
- DItype di;
- } ud;
+ const double *dp;
double d;
+ uint64_t di;
+
+ dp = (const double *) vkey;
+ d = *dp;
- __builtin_memcpy (ud.a, vkey, 8);
- d = ud.d;
- if (__builtin_isinf (d) || d == 0)
+ if (isinf (d) || d == 0)
return 0;
- if (__builtin_isnan (d))
+ if (isnan (d))
return runtime_fastrand1 ();
- return (uintptr_t) ud.di;
+ memcpy (&di, vkey, 8);
+ return (uintptr_t) di;
}
else
runtime_throw ("__go_type_hash_float: invalid float size");
@@ -70,36 +63,23 @@ __go_type_equal_float (const void *vk1, const void *vk2, uintptr_t key_size)
{
if (key_size == 4)
{
- union
- {
- unsigned char a[4];
- float f;
- } uf;
- float f1;
- float f2;
-
- __builtin_memcpy (uf.a, vk1, 4);
- f1 = uf.f;
- __builtin_memcpy (uf.a, vk2, 4);
- f2 = uf.f;
- return f1 == f2;
+ const float *fp1;
+ const float *fp2;
+
+ fp1 = (const float *) vk1;
+ fp2 = (const float *) vk2;
+
+ return *fp1 == *fp2;
}
else if (key_size == 8)
{
- union
- {
- unsigned char a[8];
- double d;
- DItype di;
- } ud;
- double d1;
- double d2;
-
- __builtin_memcpy (ud.a, vk1, 8);
- d1 = ud.d;
- __builtin_memcpy (ud.a, vk2, 8);
- d2 = ud.d;
- return d1 == d2;
+ const double *dp1;
+ const double *dp2;
+
+ dp1 = (const double *) vk1;
+ dp2 = (const double *) vk2;
+
+ return *dp1 == *dp2;
}
else
runtime_throw ("__go_type_equal_float: invalid float size");
diff --git a/libgo/runtime/go-type.h b/libgo/runtime/go-type.h
index 2269ae6339..d769335303 100644
--- a/libgo/runtime/go-type.h
+++ b/libgo/runtime/go-type.h
@@ -54,12 +54,14 @@ struct String;
#define GO_STRUCT 25
#define GO_UNSAFE_POINTER 26
+#define GO_DIRECT_IFACE (1 << 5)
+#define GO_GC_PROG (1 << 6)
#define GO_NO_POINTERS (1 << 7)
-#define GO_CODE_MASK 0x7f
+#define GO_CODE_MASK 0x1f
/* For each Go type the compiler constructs one of these structures.
- This is used for type reflectin, interfaces, maps, and reference
+ This is used for type reflection, interfaces, maps, and reference
counting. */
struct __go_type_descriptor
@@ -93,6 +95,9 @@ struct __go_type_descriptor
size of this type, and returns whether the values are equal. */
_Bool (*__equalfn) (const void *, const void *, uintptr_t);
+ /* The garbage collection data. */
+ const uintptr *__gc;
+
/* A string describing this type. This is only used for
debugging. */
const struct String *__reflection;
@@ -103,6 +108,11 @@ struct __go_type_descriptor
/* The descriptor for the type which is a pointer to this type.
This may be NULL. */
const struct __go_type_descriptor *__pointer_to_this;
+
+ /* A pointer to a zero value for this type. All types will point to
+ the same zero value, go$zerovalue, which is a common variable so
+ that it will be large enough. */
+ void *__zero;
};
/* The information we store for each method of a type. */
@@ -297,21 +307,13 @@ struct __go_struct_type
struct __go_open_array __fields;
};
-/* If an empty interface has these bits set in its type pointer, it
- was copied from a reflect.Value and is not a valid empty
- interface. */
-
-enum
-{
- reflectFlags = 3,
-};
-
/* Whether a type descriptor is a pointer. */
static inline _Bool
__go_is_pointer_type (const struct __go_type_descriptor *td)
{
- return td->__code == GO_PTR || td->__code == GO_UNSAFE_POINTER;
+ return ((td->__code & GO_CODE_MASK) == GO_PTR
+ || (td->__code & GO_CODE_MASK) == GO_UNSAFE_POINTER);
}
extern _Bool
diff --git a/libgo/runtime/go-typestring.c b/libgo/runtime/go-typestring.c
deleted file mode 100644
index 0a90e84bc1..0000000000
--- a/libgo/runtime/go-typestring.c
+++ /dev/null
@@ -1,17 +0,0 @@
-/* go-typestring.c -- the runtime.typestring function.
-
- 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. */
-
-#include "runtime.h"
-#include "interface.h"
-#include "go-type.h"
-
-String typestring(struct __go_empty_interface) __asm__ (GOSYM_PREFIX "runtime.typestring");
-
-String
-typestring (struct __go_empty_interface e)
-{
- return *e.__type_descriptor->__reflection;
-}
diff --git a/libgo/runtime/go-unsafe-pointer.c b/libgo/runtime/go-unsafe-pointer.c
index ca1d253641..71364f511b 100644
--- a/libgo/runtime/go-unsafe-pointer.c
+++ b/libgo/runtime/go-unsafe-pointer.c
@@ -8,6 +8,10 @@
#include "runtime.h"
#include "go-type.h"
+#include "mgc0.h"
+
+/* A pointer with a zero value. */
+static void *zero_pointer;
/* This file provides the type descriptor for the unsafe.Pointer type.
The unsafe package is defined by the compiler itself, which means
@@ -17,6 +21,9 @@
extern const struct __go_type_descriptor unsafe_Pointer
__asm__ (GOSYM_PREFIX "__go_tdn_unsafe.Pointer");
+extern const uintptr unsafe_Pointer_gc[]
+ __asm__ (GOSYM_PREFIX "__go_tdn_unsafe.Pointer$gc");
+
/* Used to determine the field alignment. */
struct field_align
{
@@ -32,10 +39,12 @@ static const String reflection_string =
sizeof REFLECTION - 1
};
+const uintptr unsafe_Pointer_gc[] = {sizeof(void*), GC_APTR, 0, GC_END};
+
const struct __go_type_descriptor unsafe_Pointer =
{
/* __code */
- GO_UNSAFE_POINTER,
+ GO_UNSAFE_POINTER | GO_DIRECT_IFACE,
/* __align */
__alignof (void *),
/* __field_align */
@@ -48,12 +57,16 @@ const struct __go_type_descriptor unsafe_Pointer =
__go_type_hash_identity,
/* __equalfn */
__go_type_equal_identity,
+ /* __gc */
+ unsafe_Pointer_gc,
/* __reflection */
&reflection_string,
/* __uncommon */
NULL,
/* __pointer_to_this */
- NULL
+ NULL,
+ /* __zero */
+ &zero_pointer
};
/* We also need the type descriptor for the pointer to unsafe.Pointer,
@@ -76,7 +89,7 @@ const struct __go_ptr_type pointer_unsafe_Pointer =
/* __common */
{
/* __code */
- GO_PTR,
+ GO_PTR | GO_DIRECT_IFACE,
/* __align */
__alignof (void *),
/* __field_align */
@@ -89,12 +102,16 @@ const struct __go_ptr_type pointer_unsafe_Pointer =
__go_type_hash_identity,
/* __equalfn */
__go_type_equal_identity,
+ /* __gc */
+ unsafe_Pointer_gc,
/* __reflection */
&preflection_string,
/* __uncommon */
NULL,
/* __pointer_to_this */
- NULL
+ NULL,
+ /* __zero */
+ &zero_pointer
},
/* __element_type */
&unsafe_Pointer
diff --git a/libgo/runtime/go-unsetenv.c b/libgo/runtime/go-unsetenv.c
new file mode 100644
index 0000000000..409436a0d3
--- /dev/null
+++ b/libgo/runtime/go-unsetenv.c
@@ -0,0 +1,54 @@
+/* go-unsetenv.c -- unset an environment variable from Go.
+
+ 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. */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "go-alloc.h"
+#include "runtime.h"
+#include "arch.h"
+#include "malloc.h"
+
+/* Unset an environment variable from Go. This is called by
+ syscall.Unsetenv. */
+
+void unsetenv_c (String) __asm__ (GOSYM_PREFIX "syscall.unsetenv_c");
+
+void
+unsetenv_c (String k)
+{
+ const byte *ks;
+ unsigned char *kn;
+ intgo len;
+
+ ks = k.str;
+ if (ks == NULL)
+ ks = (const byte *) "";
+ kn = NULL;
+
+#ifdef HAVE_UNSETENV
+
+ if (ks != NULL && ks[k.len] != 0)
+ {
+ // Objects that are explicitly freed must be at least 16 bytes in size,
+ // so that they are not allocated using tiny alloc.
+ len = k.len + 1;
+ if (len < TinySize)
+ len = TinySize;
+ kn = __go_alloc (len);
+ __builtin_memcpy (kn, ks, k.len);
+ ks = kn;
+ }
+
+ unsetenv ((const char *) ks);
+
+#endif /* !defined(HAVE_UNSETENV) */
+
+ if (kn != NULL)
+ __go_free (kn);
+}
diff --git a/libgo/runtime/go-unwind.c b/libgo/runtime/go-unwind.c
index 04b0a28607..849256b631 100644
--- a/libgo/runtime/go-unwind.c
+++ b/libgo/runtime/go-unwind.c
@@ -80,7 +80,6 @@ __go_check_defer (_Bool *frame)
{
struct __go_defer_stack *d;
void (*pfn) (void *);
- M *m;
d = g->defer;
if (d == NULL || d->__frame != frame || d->__pfn == NULL)
@@ -91,9 +90,8 @@ __go_check_defer (_Bool *frame)
(*pfn) (d->__arg);
- m = runtime_m ();
- if (m != NULL && m->mcache != NULL && d->__free)
- __go_free (d);
+ if (runtime_m () != NULL)
+ runtime_freedefer (d);
if (n->__was_recovered)
{
@@ -122,7 +120,6 @@ __go_check_defer (_Bool *frame)
&& g->defer->__frame == frame)
{
struct __go_defer_stack *d;
- M *m;
/* This is the defer function which called recover. Simply
return to stop the stack unwind, and let the Go code continue
@@ -130,9 +127,8 @@ __go_check_defer (_Bool *frame)
d = g->defer;
g->defer = d->__next;
- m = runtime_m ();
- if (m != NULL && m->mcache != NULL && d->__free)
- __go_free (d);
+ if (runtime_m () != NULL)
+ runtime_freedefer (d);
/* We are returning from this function. */
*frame = 1;
diff --git a/libgo/runtime/go-varargs.c b/libgo/runtime/go-varargs.c
index 682c08d64d..705f55ee20 100644
--- a/libgo/runtime/go-varargs.c
+++ b/libgo/runtime/go-varargs.c
@@ -26,6 +26,12 @@ __go_fcntl (int fd, int cmd, int arg)
return fcntl (fd, cmd, arg);
}
+int
+__go_fcntl_flock (int fd, int cmd, struct flock *arg)
+{
+ return fcntl (fd, cmd, arg);
+}
+
#ifdef HAVE_OPEN64
int
diff --git a/libgo/runtime/goc2c.c b/libgo/runtime/goc2c.c
index 87db58f50e..68281c36bc 100644
--- a/libgo/runtime/goc2c.c
+++ b/libgo/runtime/goc2c.c
@@ -617,9 +617,22 @@ process_file(void)
package = read_package();
read_preprocessor_lines();
while (read_func_header(&name, &params, &rets)) {
- write_func_header(package, name, params, rets);
+ char *p;
+ char *pkg;
+ char *nm;
+
+ p = strchr(name, '.');
+ if (p == NULL) {
+ pkg = package;
+ nm = name;
+ } else {
+ pkg = name;
+ nm = p + 1;
+ *p = '\0';
+ }
+ write_func_header(pkg, nm, params, rets);
copy_body();
- write_func_trailer(package, name, rets);
+ write_func_trailer(pkg, nm, rets);
free(name);
free_params(params);
free_params(rets);
diff --git a/libgo/runtime/heapdump.c b/libgo/runtime/heapdump.c
new file mode 100644
index 0000000000..d0cfb01478
--- /dev/null
+++ b/libgo/runtime/heapdump.c
@@ -0,0 +1,776 @@
+// 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.
+
+// Implementation of runtime/debug.WriteHeapDump. Writes all
+// objects in the heap plus additional info (roots, threads,
+// finalizers, etc.) to a file.
+
+// The format of the dumped file is described at
+// http://code.google.com/p/go-wiki/wiki/heapdump13
+
+#include "runtime.h"
+#include "arch.h"
+#include "malloc.h"
+#include "mgc0.h"
+#include "go-type.h"
+#include "go-defer.h"
+#include "go-panic.h"
+
+#define hash __hash
+#define KindNoPointers GO_NO_POINTERS
+
+enum {
+ FieldKindEol = 0,
+ FieldKindPtr = 1,
+ FieldKindString = 2,
+ FieldKindSlice = 3,
+ FieldKindIface = 4,
+ FieldKindEface = 5,
+
+ TagEOF = 0,
+ TagObject = 1,
+ TagOtherRoot = 2,
+ TagType = 3,
+ TagGoRoutine = 4,
+ TagStackFrame = 5,
+ TagParams = 6,
+ TagFinalizer = 7,
+ TagItab = 8,
+ TagOSThread = 9,
+ TagMemStats = 10,
+ TagQueuedFinalizer = 11,
+ TagData = 12,
+ TagBss = 13,
+ TagDefer = 14,
+ TagPanic = 15,
+ TagMemProf = 16,
+ TagAllocSample = 17,
+
+ TypeInfo_Conservative = 127,
+};
+
+// static uintptr* playgcprog(uintptr offset, uintptr *prog, void (*callback)(void*,uintptr,uintptr), void *arg);
+// static void dumpfields(uintptr *prog);
+static void dumpefacetypes(void *obj, uintptr size, const Type *type, uintptr kind);
+
+// fd to write the dump to.
+static uintptr dumpfd;
+
+// buffer of pending write data
+enum {
+ BufSize = 4096,
+};
+static byte buf[BufSize];
+static uintptr nbuf;
+
+static void
+hwrite(const byte *data, uintptr len)
+{
+ if(len + nbuf <= BufSize) {
+ runtime_memmove(buf + nbuf, data, len);
+ nbuf += len;
+ return;
+ }
+ runtime_write(dumpfd, buf, nbuf);
+ if(len >= BufSize) {
+ runtime_write(dumpfd, data, len);
+ nbuf = 0;
+ } else {
+ runtime_memmove(buf, data, len);
+ nbuf = len;
+ }
+}
+
+static void
+flush(void)
+{
+ runtime_write(dumpfd, buf, nbuf);
+ nbuf = 0;
+}
+
+// Cache of types that have been serialized already.
+// We use a type's hash field to pick a bucket.
+// Inside a bucket, we keep a list of types that
+// have been serialized so far, most recently used first.
+// Note: when a bucket overflows we may end up
+// serializing a type more than once. That's ok.
+enum {
+ TypeCacheBuckets = 256, // must be a power of 2
+ TypeCacheAssoc = 4,
+};
+typedef struct TypeCacheBucket TypeCacheBucket;
+struct TypeCacheBucket {
+ const Type *t[TypeCacheAssoc];
+};
+static TypeCacheBucket typecache[TypeCacheBuckets];
+
+// dump a uint64 in a varint format parseable by encoding/binary
+static void
+dumpint(uint64 v)
+{
+ byte buf[10];
+ int32 n;
+ n = 0;
+ while(v >= 0x80) {
+ buf[n++] = v | 0x80;
+ v >>= 7;
+ }
+ buf[n++] = v;
+ hwrite(buf, n);
+}
+
+static void
+dumpbool(bool b)
+{
+ dumpint(b ? 1 : 0);
+}
+
+// dump varint uint64 length followed by memory contents
+static void
+dumpmemrange(const byte *data, uintptr len)
+{
+ dumpint(len);
+ hwrite(data, len);
+}
+
+static void
+dumpstr(String s)
+{
+ dumpmemrange(s.str, s.len);
+}
+
+static void
+dumpcstr(const int8 *c)
+{
+ dumpmemrange((const byte*)c, runtime_findnull((const byte*)c));
+}
+
+// dump information for a type
+static void
+dumptype(const Type *t)
+{
+ TypeCacheBucket *b;
+ int32 i, j;
+
+ if(t == nil) {
+ return;
+ }
+
+ // If we've definitely serialized the type before,
+ // no need to do it again.
+ b = &typecache[t->hash & (TypeCacheBuckets-1)];
+ if(t == b->t[0]) return;
+ for(i = 1; i < TypeCacheAssoc; i++) {
+ if(t == b->t[i]) {
+ // Move-to-front
+ for(j = i; j > 0; j--) {
+ b->t[j] = b->t[j-1];
+ }
+ b->t[0] = t;
+ return;
+ }
+ }
+ // Might not have been dumped yet. Dump it and
+ // remember we did so.
+ for(j = TypeCacheAssoc-1; j > 0; j--) {
+ b->t[j] = b->t[j-1];
+ }
+ b->t[0] = t;
+
+ // dump the type
+ dumpint(TagType);
+ dumpint((uintptr)t);
+ dumpint(t->__size);
+ if(t->__uncommon == nil || t->__uncommon->__pkg_path == nil || t->__uncommon->__name == nil) {
+ dumpstr(*t->__reflection);
+ } else {
+ dumpint(t->__uncommon->__pkg_path->len + 1 + t->__uncommon->__name->len);
+ hwrite(t->__uncommon->__pkg_path->str, t->__uncommon->__pkg_path->len);
+ hwrite((const byte*)".", 1);
+ hwrite(t->__uncommon->__name->str, t->__uncommon->__name->len);
+ }
+ dumpbool(t->__size > PtrSize || (t->__code & KindNoPointers) == 0);
+ // dumpfields((uintptr*)t->gc + 1);
+}
+
+// returns true if object is scannable
+static bool
+scannable(byte *obj)
+{
+ uintptr *b, off, shift;
+
+ off = (uintptr*)obj - (uintptr*)runtime_mheap.arena_start; // word offset
+ b = (uintptr*)runtime_mheap.arena_start - off/wordsPerBitmapWord - 1;
+ shift = off % wordsPerBitmapWord;
+ return ((*b >> shift) & bitScan) != 0;
+}
+
+// dump an object
+static void
+dumpobj(byte *obj, uintptr size, const Type *type, uintptr kind)
+{
+ if(type != nil) {
+ dumptype(type);
+ dumpefacetypes(obj, size, type, kind);
+ }
+
+ dumpint(TagObject);
+ dumpint((uintptr)obj);
+ dumpint((uintptr)type);
+ dumpint(kind);
+ dumpmemrange(obj, size);
+}
+
+static void
+dumpotherroot(const char *description, byte *to)
+{
+ dumpint(TagOtherRoot);
+ dumpcstr((const int8 *)description);
+ dumpint((uintptr)to);
+}
+
+static void
+dumpfinalizer(byte *obj, FuncVal *fn, const FuncType* ft, const PtrType *ot)
+{
+ dumpint(TagFinalizer);
+ dumpint((uintptr)obj);
+ dumpint((uintptr)fn);
+ dumpint((uintptr)fn->fn);
+ dumpint((uintptr)ft);
+ dumpint((uintptr)ot);
+}
+
+typedef struct ChildInfo ChildInfo;
+struct ChildInfo {
+ // Information passed up from the callee frame about
+ // the layout of the outargs region.
+ uintptr argoff; // where the arguments start in the frame
+ uintptr arglen; // size of args region
+ BitVector args; // if args.n >= 0, pointer map of args region
+
+ byte *sp; // callee sp
+ uintptr depth; // depth in call stack (0 == most recent)
+};
+
+static void
+dumpgoroutine(G *gp)
+{
+ // ChildInfo child;
+ Defer *d;
+ Panic *p;
+
+ dumpint(TagGoRoutine);
+ dumpint((uintptr)gp);
+ dumpint((uintptr)0);
+ dumpint(gp->goid);
+ dumpint(gp->gopc);
+ dumpint(gp->status);
+ dumpbool(gp->issystem);
+ dumpbool(gp->isbackground);
+ dumpint(gp->waitsince);
+ dumpcstr((const int8 *)gp->waitreason);
+ dumpint((uintptr)0);
+ dumpint((uintptr)gp->m);
+ dumpint((uintptr)gp->defer);
+ dumpint((uintptr)gp->panic);
+
+ // dump stack
+ // child.args.n = -1;
+ // child.arglen = 0;
+ // child.sp = nil;
+ // child.depth = 0;
+ // if(!ScanStackByFrames)
+ // runtime_throw("need frame info to dump stacks");
+ // runtime_gentraceback(pc, sp, lr, gp, 0, nil, 0x7fffffff, dumpframe, &child, false);
+
+ // dump defer & panic records
+ for(d = gp->defer; d != nil; d = d->__next) {
+ dumpint(TagDefer);
+ dumpint((uintptr)d);
+ dumpint((uintptr)gp);
+ dumpint((uintptr)d->__arg);
+ dumpint((uintptr)d->__frame);
+ dumpint((uintptr)d->__pfn);
+ dumpint((uintptr)0);
+ dumpint((uintptr)d->__next);
+ }
+ for (p = gp->panic; p != nil; p = p->__next) {
+ dumpint(TagPanic);
+ dumpint((uintptr)p);
+ dumpint((uintptr)gp);
+ dumpint((uintptr)p->__arg.__type_descriptor);
+ dumpint((uintptr)p->__arg.__object);
+ dumpint((uintptr)0);
+ dumpint((uintptr)p->__next);
+ }
+}
+
+static void
+dumpgs(void)
+{
+ G *gp;
+ uint32 i;
+
+ // goroutines & stacks
+ for(i = 0; i < runtime_allglen; i++) {
+ gp = runtime_allg[i];
+ switch(gp->status){
+ default:
+ runtime_printf("unexpected G.status %d\n", gp->status);
+ runtime_throw("mark - bad status");
+ case Gdead:
+ break;
+ case Grunnable:
+ case Gsyscall:
+ case Gwaiting:
+ dumpgoroutine(gp);
+ break;
+ }
+ }
+}
+
+static void
+finq_callback(FuncVal *fn, void *obj, const FuncType *ft, const PtrType *ot)
+{
+ dumpint(TagQueuedFinalizer);
+ dumpint((uintptr)obj);
+ dumpint((uintptr)fn);
+ dumpint((uintptr)fn->fn);
+ dumpint((uintptr)ft);
+ dumpint((uintptr)ot);
+}
+
+
+static void
+dumproots(void)
+{
+ MSpan *s, **allspans;
+ uint32 spanidx;
+ Special *sp;
+ SpecialFinalizer *spf;
+ byte *p;
+
+ // data segment
+ // dumpint(TagData);
+ // dumpint((uintptr)data);
+ // dumpmemrange(data, edata - data);
+ // dumpfields((uintptr*)gcdata + 1);
+
+ // bss segment
+ // dumpint(TagBss);
+ // dumpint((uintptr)bss);
+ // dumpmemrange(bss, ebss - bss);
+ // dumpfields((uintptr*)gcbss + 1);
+
+ // MSpan.types
+ allspans = runtime_mheap.allspans;
+ for(spanidx=0; spanidx<runtime_mheap.nspan; spanidx++) {
+ s = allspans[spanidx];
+ if(s->state == MSpanInUse) {
+ // The garbage collector ignores type pointers stored in MSpan.types:
+ // - Compiler-generated types are stored outside of heap.
+ // - The reflect package has runtime-generated types cached in its data structures.
+ // The garbage collector relies on finding the references via that cache.
+ switch(s->types.compression) {
+ case MTypes_Empty:
+ case MTypes_Single:
+ break;
+ case MTypes_Words:
+ case MTypes_Bytes:
+ dumpotherroot("runtime type info", (byte*)s->types.data);
+ break;
+ }
+
+ // Finalizers
+ for(sp = s->specials; sp != nil; sp = sp->next) {
+ if(sp->kind != KindSpecialFinalizer)
+ continue;
+ spf = (SpecialFinalizer*)sp;
+ p = (byte*)((s->start << PageShift) + spf->offset);
+ dumpfinalizer(p, spf->fn, spf->ft, spf->ot);
+ }
+ }
+ }
+
+ // Finalizer queue
+ runtime_iterate_finq(finq_callback);
+}
+
+// Bit vector of free marks.
+// Needs to be as big as the largest number of objects per span.
+static byte hfree[PageSize/8];
+
+static void
+dumpobjs(void)
+{
+ uintptr i, j, size, n, off, shift, *bitp, bits, ti, kind;
+ MSpan *s;
+ MLink *l;
+ byte *p;
+ const Type *t;
+
+ for(i = 0; i < runtime_mheap.nspan; i++) {
+ s = runtime_mheap.allspans[i];
+ if(s->state != MSpanInUse)
+ continue;
+ p = (byte*)(s->start << PageShift);
+ size = s->elemsize;
+ n = (s->npages << PageShift) / size;
+ if(n > PageSize/8)
+ runtime_throw("free array doesn't have enough entries");
+ for(l = s->freelist; l != nil; l = l->next) {
+ hfree[((byte*)l - p) / size] = true;
+ }
+ for(j = 0; j < n; j++, p += size) {
+ if(hfree[j]) {
+ hfree[j] = false;
+ continue;
+ }
+ off = (uintptr*)p - (uintptr*)runtime_mheap.arena_start;
+ bitp = (uintptr*)runtime_mheap.arena_start - off/wordsPerBitmapWord - 1;
+ shift = off % wordsPerBitmapWord;
+ bits = *bitp >> shift;
+
+ // Skip FlagNoGC allocations (stacks)
+ if((bits & bitAllocated) == 0)
+ continue;
+
+ // extract type and kind
+ ti = runtime_gettype(p);
+ t = (Type*)(ti & ~(uintptr)(PtrSize-1));
+ kind = ti & (PtrSize-1);
+
+ // dump it
+ if(kind == TypeInfo_Chan)
+ t = ((const ChanType*)t)->__element_type; // use element type for chan encoding
+ if(t == nil && scannable(p))
+ kind = TypeInfo_Conservative; // special kind for conservatively scanned objects
+ dumpobj(p, size, t, kind);
+ }
+ }
+}
+
+static void
+dumpparams(void)
+{
+ byte *x;
+
+ dumpint(TagParams);
+ x = (byte*)1;
+ if(*(byte*)&x == 1)
+ dumpbool(false); // little-endian ptrs
+ else
+ dumpbool(true); // big-endian ptrs
+ dumpint(PtrSize);
+ dumpint(runtime_Hchansize);
+ dumpint((uintptr)runtime_mheap.arena_start);
+ dumpint((uintptr)runtime_mheap.arena_used);
+ dumpint(0);
+ dumpcstr((const int8 *)"");
+ dumpint(runtime_ncpu);
+}
+
+static void
+dumpms(void)
+{
+ M *mp;
+
+ for(mp = runtime_allm; mp != nil; mp = mp->alllink) {
+ dumpint(TagOSThread);
+ dumpint((uintptr)mp);
+ dumpint(mp->id);
+ dumpint(0);
+ }
+}
+
+static void
+dumpmemstats(void)
+{
+ int32 i;
+
+ dumpint(TagMemStats);
+ dumpint(mstats.alloc);
+ dumpint(mstats.total_alloc);
+ dumpint(mstats.sys);
+ dumpint(mstats.nlookup);
+ dumpint(mstats.nmalloc);
+ dumpint(mstats.nfree);
+ dumpint(mstats.heap_alloc);
+ dumpint(mstats.heap_sys);
+ dumpint(mstats.heap_idle);
+ dumpint(mstats.heap_inuse);
+ dumpint(mstats.heap_released);
+ dumpint(mstats.heap_objects);
+ dumpint(mstats.stacks_inuse);
+ dumpint(mstats.stacks_sys);
+ dumpint(mstats.mspan_inuse);
+ dumpint(mstats.mspan_sys);
+ dumpint(mstats.mcache_inuse);
+ dumpint(mstats.mcache_sys);
+ dumpint(mstats.buckhash_sys);
+ dumpint(mstats.gc_sys);
+ dumpint(mstats.other_sys);
+ dumpint(mstats.next_gc);
+ dumpint(mstats.last_gc);
+ dumpint(mstats.pause_total_ns);
+ for(i = 0; i < 256; i++)
+ dumpint(mstats.pause_ns[i]);
+ dumpint(mstats.numgc);
+}
+
+static void
+dumpmemprof_callback(Bucket *b, uintptr nstk, Location *stk, uintptr size, uintptr allocs, uintptr frees)
+{
+ uintptr i, pc;
+ byte buf[20];
+
+ dumpint(TagMemProf);
+ dumpint((uintptr)b);
+ dumpint(size);
+ dumpint(nstk);
+ for(i = 0; i < nstk; i++) {
+ pc = stk[i].pc;
+ if(stk[i].function.len == 0) {
+ runtime_snprintf(buf, sizeof(buf), "%X", (uint64)pc);
+ dumpcstr((int8*)buf);
+ dumpcstr((const int8*)"?");
+ dumpint(0);
+ } else {
+ dumpstr(stk[i].function);
+ dumpstr(stk[i].filename);
+ dumpint(stk[i].lineno);
+ }
+ }
+ dumpint(allocs);
+ dumpint(frees);
+}
+
+static void
+dumpmemprof(void)
+{
+ MSpan *s, **allspans;
+ uint32 spanidx;
+ Special *sp;
+ SpecialProfile *spp;
+ byte *p;
+
+ runtime_iterate_memprof(dumpmemprof_callback);
+
+ allspans = runtime_mheap.allspans;
+ for(spanidx=0; spanidx<runtime_mheap.nspan; spanidx++) {
+ s = allspans[spanidx];
+ if(s->state != MSpanInUse)
+ continue;
+ for(sp = s->specials; sp != nil; sp = sp->next) {
+ if(sp->kind != KindSpecialProfile)
+ continue;
+ spp = (SpecialProfile*)sp;
+ p = (byte*)((s->start << PageShift) + spp->offset);
+ dumpint(TagAllocSample);
+ dumpint((uintptr)p);
+ dumpint((uintptr)spp->b);
+ }
+ }
+}
+
+static void
+mdump(G *gp)
+{
+ const byte *hdr;
+ uintptr i;
+ MSpan *s;
+
+ // make sure we're done sweeping
+ for(i = 0; i < runtime_mheap.nspan; i++) {
+ s = runtime_mheap.allspans[i];
+ if(s->state == MSpanInUse)
+ runtime_MSpan_EnsureSwept(s);
+ }
+
+ runtime_memclr((byte*)&typecache[0], sizeof(typecache));
+ hdr = (const byte*)"go1.3 heap dump\n";
+ hwrite(hdr, runtime_findnull(hdr));
+ dumpparams();
+ dumpobjs();
+ dumpgs();
+ dumpms();
+ dumproots();
+ dumpmemstats();
+ dumpmemprof();
+ dumpint(TagEOF);
+ flush();
+
+ gp->param = nil;
+ gp->status = Grunning;
+ runtime_gogo(gp);
+}
+
+void runtime_debug_WriteHeapDump(uintptr)
+ __asm__(GOSYM_PREFIX "runtime_debug.WriteHeapDump");
+
+void
+runtime_debug_WriteHeapDump(uintptr fd)
+{
+ M *m;
+ G *g;
+
+ // Stop the world.
+ runtime_semacquire(&runtime_worldsema, false);
+ m = runtime_m();
+ m->gcing = 1;
+ m->locks++;
+ runtime_stoptheworld();
+
+ // Update stats so we can dump them.
+ // As a side effect, flushes all the MCaches so the MSpan.freelist
+ // lists contain all the free objects.
+ runtime_updatememstats(nil);
+
+ // Set dump file.
+ dumpfd = fd;
+
+ // Call dump routine on M stack.
+ g = runtime_g();
+ g->status = Gwaiting;
+ g->waitreason = "dumping heap";
+ runtime_mcall(mdump);
+
+ // Reset dump file.
+ dumpfd = 0;
+
+ // Start up the world again.
+ m->gcing = 0;
+ runtime_semrelease(&runtime_worldsema);
+ runtime_starttheworld();
+ m->locks--;
+}
+
+// Runs the specified gc program. Calls the callback for every
+// pointer-like field specified by the program and passes to the
+// callback the kind and offset of that field within the object.
+// offset is the offset in the object of the start of the program.
+// Returns a pointer to the opcode that ended the gc program (either
+// GC_END or GC_ARRAY_NEXT).
+/*
+static uintptr*
+playgcprog(uintptr offset, uintptr *prog, void (*callback)(void*,uintptr,uintptr), void *arg)
+{
+ uintptr len, elemsize, i, *end;
+
+ for(;;) {
+ switch(prog[0]) {
+ case GC_END:
+ return prog;
+ case GC_PTR:
+ callback(arg, FieldKindPtr, offset + prog[1]);
+ prog += 3;
+ break;
+ case GC_APTR:
+ callback(arg, FieldKindPtr, offset + prog[1]);
+ prog += 2;
+ break;
+ case GC_ARRAY_START:
+ len = prog[2];
+ elemsize = prog[3];
+ end = nil;
+ for(i = 0; i < len; i++) {
+ end = playgcprog(offset + prog[1] + i * elemsize, prog + 4, callback, arg);
+ if(end[0] != GC_ARRAY_NEXT)
+ runtime_throw("GC_ARRAY_START did not have matching GC_ARRAY_NEXT");
+ }
+ prog = end + 1;
+ break;
+ case GC_ARRAY_NEXT:
+ return prog;
+ case GC_CALL:
+ playgcprog(offset + prog[1], (uintptr*)((byte*)prog + *(int32*)&prog[2]), callback, arg);
+ prog += 3;
+ break;
+ case GC_CHAN_PTR:
+ callback(arg, FieldKindPtr, offset + prog[1]);
+ prog += 3;
+ break;
+ case GC_STRING:
+ callback(arg, FieldKindString, offset + prog[1]);
+ prog += 2;
+ break;
+ case GC_EFACE:
+ callback(arg, FieldKindEface, offset + prog[1]);
+ prog += 2;
+ break;
+ case GC_IFACE:
+ callback(arg, FieldKindIface, offset + prog[1]);
+ prog += 2;
+ break;
+ case GC_SLICE:
+ callback(arg, FieldKindSlice, offset + prog[1]);
+ prog += 3;
+ break;
+ case GC_REGION:
+ playgcprog(offset + prog[1], (uintptr*)prog[3] + 1, callback, arg);
+ prog += 4;
+ break;
+ default:
+ runtime_printf("%D\n", (uint64)prog[0]);
+ runtime_throw("bad gc op");
+ }
+ }
+}
+
+static void
+dump_callback(void *p, uintptr kind, uintptr offset)
+{
+ USED(&p);
+ dumpint(kind);
+ dumpint(offset);
+}
+
+// dumpint() the kind & offset of each field in an object.
+static void
+dumpfields(uintptr *prog)
+{
+ playgcprog(0, prog, dump_callback, nil);
+ dumpint(FieldKindEol);
+}
+
+static void
+dumpeface_callback(void *p, uintptr kind, uintptr offset)
+{
+ Eface *e;
+
+ if(kind != FieldKindEface)
+ return;
+ e = (Eface*)((byte*)p + offset);
+ dumptype(e->__type_descriptor);
+}
+*/
+
+// The heap dump reader needs to be able to disambiguate
+// Eface entries. So it needs to know every type that might
+// appear in such an entry. The following two routines accomplish
+// that.
+
+// Dump all the types that appear in the type field of
+// any Eface contained in obj.
+static void
+dumpefacetypes(void *obj __attribute__ ((unused)), uintptr size, const Type *type, uintptr kind)
+{
+ uintptr i;
+
+ switch(kind) {
+ case TypeInfo_SingleObject:
+ //playgcprog(0, (uintptr*)type->gc + 1, dumpeface_callback, obj);
+ break;
+ case TypeInfo_Array:
+ for(i = 0; i <= size - type->__size; i += type->__size)
+ //playgcprog(i, (uintptr*)type->gc + 1, dumpeface_callback, obj);
+ break;
+ case TypeInfo_Chan:
+ if(type->__size == 0) // channels may have zero-sized objects in them
+ break;
+ for(i = runtime_Hchansize; i <= size - type->__size; i += type->__size)
+ //playgcprog(i, (uintptr*)type->gc + 1, dumpeface_callback, obj);
+ break;
+ }
+}
diff --git a/libgo/runtime/lfstack.c b/libgo/runtime/lfstack.goc
index 132783c364..060a0cc594 100644
--- a/libgo/runtime/lfstack.c
+++ b/libgo/runtime/lfstack.goc
@@ -4,6 +4,7 @@
// Lock-free stack.
+package runtime
#include "runtime.h"
#include "arch.h"
@@ -69,11 +70,10 @@ runtime_lfstackpop(uint64 *head)
}
}
-LFNode* runtime_lfstackpop2(uint64*)
- __asm__ (GOSYM_PREFIX "runtime.lfstackpop2");
+func lfstackpush_go(head *uint64, node *LFNode) {
+ runtime_lfstackpush(head, node);
+}
-LFNode*
-runtime_lfstackpop2(uint64 *head)
-{
- return runtime_lfstackpop(head);
+func lfstackpop_go(head *uint64) (node *LFNode) {
+ node = runtime_lfstackpop(head);
}
diff --git a/libgo/runtime/lock_futex.c b/libgo/runtime/lock_futex.c
index fa27013289..33ef073c90 100644
--- a/libgo/runtime/lock_futex.c
+++ b/libgo/runtime/lock_futex.c
@@ -124,26 +124,36 @@ runtime_notewakeup(Note *n)
void
runtime_notesleep(Note *n)
{
+ M *m = runtime_m();
+
/* For gccgo it's OK to sleep in non-g0, and it happens in
stoptheworld because we have not implemented preemption.
if(runtime_g() != runtime_m()->g0)
runtime_throw("notesleep not on g0");
*/
- while(runtime_atomicload((uint32*)&n->key) == 0)
+ while(runtime_atomicload((uint32*)&n->key) == 0) {
+ m->blocked = true;
runtime_futexsleep((uint32*)&n->key, 0, -1);
+ m->blocked = false;
+ }
}
static bool
notetsleep(Note *n, int64 ns, int64 deadline, int64 now)
{
+ M *m = runtime_m();
+
// Conceptually, deadline and now are local variables.
// They are passed as arguments so that the space for them
// does not count against our nosplit stack sequence.
if(ns < 0) {
- while(runtime_atomicload((uint32*)&n->key) == 0)
+ while(runtime_atomicload((uint32*)&n->key) == 0) {
+ m->blocked = true;
runtime_futexsleep((uint32*)&n->key, 0, -1);
+ m->blocked = false;
+ }
return true;
}
@@ -152,7 +162,9 @@ notetsleep(Note *n, int64 ns, int64 deadline, int64 now)
deadline = runtime_nanotime() + ns;
for(;;) {
+ m->blocked = true;
runtime_futexsleep((uint32*)&n->key, 0, ns);
+ m->blocked = false;
if(runtime_atomicload((uint32*)&n->key) != 0)
break;
now = runtime_nanotime();
diff --git a/libgo/runtime/lock_sema.c b/libgo/runtime/lock_sema.c
index 000b9fcf70..ef611fb36a 100644
--- a/libgo/runtime/lock_sema.c
+++ b/libgo/runtime/lock_sema.c
@@ -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 netbsd openbsd plan9 windows
+// +build darwin nacl netbsd openbsd plan9 solaris windows
#include "runtime.h"
@@ -167,7 +167,9 @@ runtime_notesleep(Note *n)
return;
}
// Queued. Sleep.
+ m->blocked = true;
runtime_semasleep(-1);
+ m->blocked = false;
}
static bool
@@ -190,18 +192,23 @@ notetsleep(Note *n, int64 ns, int64 deadline, M *mp)
if(ns < 0) {
// Queued. Sleep.
+ m->blocked = true;
runtime_semasleep(-1);
+ m->blocked = false;
return true;
}
deadline = runtime_nanotime() + ns;
for(;;) {
// Registered. Sleep.
+ m->blocked = true;
if(runtime_semasleep(ns) >= 0) {
+ m->blocked = false;
// Acquired semaphore, semawakeup unregistered us.
// Done.
return true;
}
+ m->blocked = false;
// Interrupted or timed out. Still registered. Semaphore not acquired.
ns = deadline - runtime_nanotime();
@@ -223,8 +230,10 @@ notetsleep(Note *n, int64 ns, int64 deadline, M *mp)
} else if(mp == (M*)LOCKED) {
// Wakeup happened so semaphore is available.
// Grab it to avoid getting out of sync.
+ m->blocked = true;
if(runtime_semasleep(-1) < 0)
runtime_throw("runtime: unable to acquire - semaphore out of sync");
+ m->blocked = false;
return true;
} else
runtime_throw("runtime: unexpected waitm - semaphore out of sync");
diff --git a/libgo/runtime/malloc.goc b/libgo/runtime/malloc.goc
index 37bbf5ef63..43323e2587 100644
--- a/libgo/runtime/malloc.goc
+++ b/libgo/runtime/malloc.goc
@@ -16,7 +16,6 @@ package runtime
#include "malloc.h"
#include "interface.h"
#include "go-type.h"
-#include "race.h"
// Map gccgo field names to gc field names.
// Eface aka __go_empty_interface.
@@ -26,6 +25,7 @@ package runtime
#define string __reflection
#define KindPtr GO_PTR
#define KindNoPointers GO_NO_POINTERS
+#define kindMask GO_CODE_MASK
// GCCGO SPECIFIC CHANGE
//
@@ -54,6 +54,7 @@ package runtime
// Mark mheap as 'no pointers', it does not contain interesting pointers but occupies ~45K.
MHeap runtime_mheap;
+MStats mstats;
int32 runtime_checking;
@@ -62,6 +63,10 @@ extern MStats mstats; // defined in zruntime_def_$GOOS_$GOARCH.go
extern volatile intgo runtime_MemProfileRate
__asm__ (GOSYM_PREFIX "runtime.MemProfileRate");
+static MSpan* largealloc(uint32, uintptr*);
+static void profilealloc(void *v, uintptr size);
+static void settype(MSpan *s, void *v, uintptr typ);
+
// Allocate an object of at least size bytes.
// Small objects are allocated from the per-thread cache's free lists.
// Large objects (> 32 kB) are allocated straight from the heap.
@@ -72,14 +77,13 @@ runtime_mallocgc(uintptr size, uintptr typ, uint32 flag)
M *m;
G *g;
int32 sizeclass;
+ uintptr tinysize, size1;
intgo rate;
MCache *c;
- MCacheList *l;
- uintptr npages;
MSpan *s;
- MLink *v;
+ MLink *v, *next;
+ byte *tiny;
bool incallback;
- void *closure;
if(size == 0) {
// All 0-length allocations use this pointer.
@@ -91,10 +95,6 @@ runtime_mallocgc(uintptr size, uintptr typ, uint32 flag)
m = runtime_m();
g = runtime_g();
- // We should not be called in between __go_set_closure and the
- // actual function call, but cope with it if we are.
- closure = g->closure;
-
incallback = false;
if(m->mcache == nil && g->ncgo > 0) {
// For gccgo this case can occur when a cgo or SWIG function
@@ -114,8 +114,8 @@ runtime_mallocgc(uintptr size, uintptr typ, uint32 flag)
}
if(m->mallocing)
runtime_throw("malloc/free - deadlock");
- // Disable preemption during settype_flush.
- // We can not use m->mallocing for this, because settype_flush calls mallocgc.
+ // Disable preemption during settype.
+ // We can not use m->mallocing for this, because settype calls mallocgc.
m->locks++;
m->mallocing = 1;
@@ -123,7 +123,82 @@ runtime_mallocgc(uintptr size, uintptr typ, uint32 flag)
size += sizeof(uintptr);
c = m->mcache;
- if(size <= MaxSmallSize) {
+ if(!runtime_debug.efence && size <= MaxSmallSize) {
+ if((flag&(FlagNoScan|FlagNoGC)) == FlagNoScan && size < TinySize) {
+ // 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 (TinySize) 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 >= TinySize.
+ //
+ // 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 = c->tinysize;
+ if(size <= tinysize) {
+ tiny = c->tiny;
+ // Align tiny pointer for required (conservative) alignment.
+ if((size&7) == 0)
+ tiny = (byte*)ROUND((uintptr)tiny, 8);
+ else if((size&3) == 0)
+ tiny = (byte*)ROUND((uintptr)tiny, 4);
+ else if((size&1) == 0)
+ tiny = (byte*)ROUND((uintptr)tiny, 2);
+ size1 = size + (tiny - c->tiny);
+ if(size1 <= tinysize) {
+ // The object fits into existing tiny block.
+ v = (MLink*)tiny;
+ c->tiny += size1;
+ c->tinysize -= size1;
+ m->mallocing = 0;
+ m->locks--;
+ if(incallback)
+ runtime_entersyscall();
+ return v;
+ }
+ }
+ // Allocate a new TinySize block.
+ s = c->alloc[TinySizeClass];
+ if(s->freelist == nil)
+ s = runtime_MCache_Refill(c, TinySizeClass);
+ v = s->freelist;
+ next = v->next;
+ s->freelist = next;
+ s->ref++;
+ if(next != nil) // prefetching nil leads to a DTLB miss
+ PREFETCH(next);
+ ((uint64*)v)[0] = 0;
+ ((uint64*)v)[1] = 0;
+ // See if we need to replace the existing tiny block with the new one
+ // based on amount of remaining free space.
+ if(TinySize-size > tinysize) {
+ c->tiny = (byte*)v + size;
+ c->tinysize = TinySize - size;
+ }
+ size = TinySize;
+ goto done;
+ }
// Allocate from mcache free lists.
// Inlined version of SizeToClass().
if(size <= 1024-8)
@@ -131,91 +206,115 @@ runtime_mallocgc(uintptr size, uintptr typ, uint32 flag)
else
sizeclass = runtime_size_to_class128[(size-1024+127) >> 7];
size = runtime_class_to_size[sizeclass];
- l = &c->list[sizeclass];
- if(l->list == nil)
- runtime_MCache_Refill(c, sizeclass);
- v = l->list;
- l->list = v->next;
- l->nlist--;
+ s = c->alloc[sizeclass];
+ if(s->freelist == nil)
+ s = runtime_MCache_Refill(c, sizeclass);
+ v = s->freelist;
+ next = v->next;
+ s->freelist = next;
+ s->ref++;
+ if(next != nil) // prefetching nil leads to a DTLB miss
+ PREFETCH(next);
if(!(flag & FlagNoZero)) {
v->next = nil;
// block is zeroed iff second word is zero ...
- if(size > sizeof(uintptr) && ((uintptr*)v)[1] != 0)
+ if(size > 2*sizeof(uintptr) && ((uintptr*)v)[1] != 0)
runtime_memclr((byte*)v, size);
}
+ done:
c->local_cachealloc += size;
} else {
- // TODO(rsc): Report tracebacks for very large allocations.
-
// Allocate directly from heap.
- npages = size >> PageShift;
- if((size & PageMask) != 0)
- npages++;
- s = runtime_MHeap_Alloc(&runtime_mheap, npages, 0, 1, !(flag & FlagNoZero));
- if(s == nil)
- runtime_throw("out of memory");
- s->limit = (byte*)(s->start<<PageShift) + size;
- size = npages<<PageShift;
+ s = largealloc(flag, &size);
v = (void*)(s->start << PageShift);
-
- // setup for mark sweep
- runtime_markspan(v, 0, 0, true);
}
- if(!(flag & FlagNoGC))
- runtime_markallocated(v, size, (flag&FlagNoScan) != 0);
+ if(flag & FlagNoGC)
+ runtime_marknogc(v);
+ else if(!(flag & FlagNoScan))
+ runtime_markscan(v);
if(DebugTypeAtBlockEnd)
*(uintptr*)((uintptr)v+size-sizeof(uintptr)) = typ;
+ m->mallocing = 0;
// TODO: save type even if FlagNoScan? Potentially expensive but might help
// heap profiling/tracing.
- if(UseSpanType && !(flag & FlagNoScan) && typ != 0) {
- uintptr *buf, i;
-
- buf = m->settype_buf;
- i = m->settype_bufsize;
- buf[i++] = (uintptr)v;
- buf[i++] = typ;
- m->settype_bufsize = i;
- }
+ if(UseSpanType && !(flag & FlagNoScan) && typ != 0)
+ settype(s, v, typ);
- m->mallocing = 0;
- if(UseSpanType && !(flag & FlagNoScan) && typ != 0 && m->settype_bufsize == nelem(m->settype_buf))
- runtime_settype_flush(m);
- m->locks--;
+ if(runtime_debug.allocfreetrace)
+ runtime_tracealloc(v, size, typ);
if(!(flag & FlagNoProfiling) && (rate = runtime_MemProfileRate) > 0) {
- if(size >= (uint32) rate)
- goto profile;
- if((uint32) m->mcache->next_sample > size)
- m->mcache->next_sample -= size;
- else {
- // pick next profile time
- // If you change this, also change allocmcache.
- if(rate > 0x3fffffff) // make 2*rate not overflow
- rate = 0x3fffffff;
- m->mcache->next_sample = runtime_fastrand1() % (2*rate);
- profile:
- runtime_setblockspecial(v, true);
- runtime_MProf_Malloc(v, size);
- }
+ if(size < (uintptr)rate && size < (uintptr)(uint32)c->next_sample)
+ c->next_sample -= size;
+ else
+ profilealloc(v, size);
}
+ m->locks--;
+
if(!(flag & FlagNoInvokeGC) && mstats.heap_alloc >= mstats.next_gc)
runtime_gc(0);
- if(raceenabled)
- runtime_racemalloc(v, size);
-
if(incallback)
runtime_entersyscall();
- g->closure = closure;
-
return v;
}
+static MSpan*
+largealloc(uint32 flag, uintptr *sizep)
+{
+ uintptr npages, size;
+ MSpan *s;
+ void *v;
+
+ // Allocate directly from heap.
+ size = *sizep;
+ if(size + PageSize < size)
+ runtime_throw("out of memory");
+ npages = size >> PageShift;
+ if((size & PageMask) != 0)
+ npages++;
+ s = runtime_MHeap_Alloc(&runtime_mheap, npages, 0, 1, !(flag & FlagNoZero));
+ if(s == nil)
+ runtime_throw("out of memory");
+ s->limit = (byte*)(s->start<<PageShift) + size;
+ *sizep = npages<<PageShift;
+ v = (void*)(s->start << PageShift);
+ // setup for mark sweep
+ runtime_markspan(v, 0, 0, true);
+ return s;
+}
+
+static void
+profilealloc(void *v, uintptr size)
+{
+ uintptr rate;
+ int32 next;
+ MCache *c;
+
+ c = runtime_m()->mcache;
+ rate = runtime_MemProfileRate;
+ if(size < rate) {
+ // pick next profile time
+ // If you change this, also change allocmcache.
+ if(rate > 0x3fffffff) // make 2*rate not overflow
+ rate = 0x3fffffff;
+ next = runtime_fastrand1() % (2*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 -= (size - c->next_sample);
+ if(next < 0)
+ next = 0;
+ c->next_sample = next;
+ }
+ runtime_MProf_Malloc(v, size);
+}
+
void*
__go_alloc(uintptr size)
{
@@ -230,7 +329,6 @@ __go_free(void *v)
int32 sizeclass;
MSpan *s;
MCache *c;
- uint32 prof;
uintptr size;
if(v == nil)
@@ -248,39 +346,73 @@ __go_free(void *v)
runtime_printf("free %p: not an allocated block\n", v);
runtime_throw("free runtime_mlookup");
}
- prof = runtime_blockspecial(v);
+ size = s->elemsize;
+ sizeclass = s->sizeclass;
+ // Objects that are smaller than TinySize can be allocated using tiny alloc,
+ // if then such object is combined with an object with finalizer, we will crash.
+ if(size < TinySize)
+ runtime_throw("freeing too small block");
- if(raceenabled)
- runtime_racefree(v);
+ if(runtime_debug.allocfreetrace)
+ runtime_tracefree(v, size);
+
+ // Ensure that the span is swept.
+ // If we free into an unswept span, we will corrupt GC bitmaps.
+ runtime_MSpan_EnsureSwept(s);
+
+ if(s->specials != nil)
+ runtime_freeallspecials(s, v, size);
- // Find size class for v.
- sizeclass = s->sizeclass;
c = m->mcache;
if(sizeclass == 0) {
// Large object.
- size = s->npages<<PageShift;
- *(uintptr*)(s->start<<PageShift) = (uintptr)0xfeedfeedfeedfeedll; // mark as "needs to be zeroed"
+ s->needzero = 1;
// Must mark v freed before calling unmarkspan and MHeap_Free:
// they might coalesce v into other spans and change the bitmap further.
- runtime_markfreed(v, size);
+ runtime_markfreed(v);
runtime_unmarkspan(v, 1<<PageShift);
- runtime_MHeap_Free(&runtime_mheap, s, 1);
+ // NOTE(rsc,dvyukov): The original implementation of efence
+ // in CL 22060046 used SysFree instead of SysFault, so that
+ // the operating system would eventually give the memory
+ // back to us again, so that an efence program could run
+ // longer without running out of memory. Unfortunately,
+ // calling SysFree here without any kind of adjustment of the
+ // heap data structures means that when the memory does
+ // come back to us, we have the wrong metadata for it, either in
+ // the MSpan structures or in the garbage collection bitmap.
+ // Using SysFault here means that the program will run out of
+ // memory fairly quickly in efence mode, but at least it won't
+ // have mysterious crashes due to confused memory reuse.
+ // It should be possible to switch back to SysFree if we also
+ // implement and then call some kind of MHeap_DeleteSpan.
+ if(runtime_debug.efence)
+ runtime_SysFault((void*)(s->start<<PageShift), size);
+ else
+ runtime_MHeap_Free(&runtime_mheap, s, 1);
c->local_nlargefree++;
c->local_largefree += size;
} else {
// Small object.
- size = runtime_class_to_size[sizeclass];
- if(size > sizeof(uintptr))
+ if(size > 2*sizeof(uintptr))
((uintptr*)v)[1] = (uintptr)0xfeedfeedfeedfeedll; // mark as "needs to be zeroed"
+ else if(size > sizeof(uintptr))
+ ((uintptr*)v)[1] = 0;
// Must mark v freed before calling MCache_Free:
// it might coalesce v and other blocks into a bigger span
// and change the bitmap further.
- runtime_markfreed(v, size);
c->local_nsmallfree[sizeclass]++;
- runtime_MCache_Free(c, v, sizeclass, size);
+ c->local_cachealloc -= size;
+ if(c->alloc[sizeclass] == s) {
+ // We own the span, so we can just add v to the freelist
+ runtime_markfreed(v);
+ ((MLink*)v)->next = s->freelist;
+ s->freelist = v;
+ s->ref--;
+ } else {
+ // Someone else owns this span. Add to free queue.
+ runtime_MCache_Free(c, v, sizeclass, size);
+ }
}
- if(prof)
- runtime_MProf_Free(v, size);
m->mallocing = 0;
}
@@ -335,37 +467,6 @@ runtime_mlookup(void *v, byte **base, uintptr *size, MSpan **sp)
return 1;
}
-MCache*
-runtime_allocmcache(void)
-{
- intgo rate;
- MCache *c;
-
- runtime_lock(&runtime_mheap);
- c = runtime_FixAlloc_Alloc(&runtime_mheap.cachealloc);
- runtime_unlock(&runtime_mheap);
- runtime_memclr((byte*)c, sizeof(*c));
-
- // Set first allocation sample size.
- rate = runtime_MemProfileRate;
- if(rate > 0x3fffffff) // make 2*rate not overflow
- rate = 0x3fffffff;
- if(rate != 0)
- c->next_sample = runtime_fastrand1() % (2*rate);
-
- return c;
-}
-
-void
-runtime_freemcache(MCache *c)
-{
- runtime_MCache_ReleaseAll(c);
- runtime_lock(&runtime_mheap);
- runtime_purgecachedstats(c);
- runtime_FixAlloc_Free(&runtime_mheap.cachealloc, c);
- runtime_unlock(&runtime_mheap);
-}
-
void
runtime_purgecachedstats(MCache *c)
{
@@ -391,33 +492,45 @@ runtime_purgecachedstats(MCache *c)
extern uintptr runtime_sizeof_C_MStats
__asm__ (GOSYM_PREFIX "runtime.Sizeof_C_MStats");
+// Size of the trailing by_size array differs between Go and C,
+// NumSizeClasses was changed, but we can not change Go struct because of backward compatibility.
+// sizeof_C_MStats is what C thinks about size of Go struct.
+
+// Initialized in mallocinit because it's defined in go/runtime/mem.go.
+
#define MaxArena32 (2U<<30)
void
runtime_mallocinit(void)
{
- byte *p;
- uintptr arena_size, bitmap_size, spans_size;
+ byte *p, *p1;
+ uintptr arena_size, bitmap_size, spans_size, p_size;
extern byte _end[];
- byte *want;
uintptr limit;
uint64 i;
+ bool reserved;
- runtime_sizeof_C_MStats = sizeof(MStats);
+ runtime_sizeof_C_MStats = sizeof(MStats) - (NumSizeClasses - 61) * sizeof(mstats.by_size[0]);
p = nil;
+ p_size = 0;
arena_size = 0;
bitmap_size = 0;
spans_size = 0;
+ reserved = false;
// for 64-bit build
USED(p);
+ USED(p_size);
USED(arena_size);
USED(bitmap_size);
USED(spans_size);
runtime_InitSizes();
+ if(runtime_class_to_size[TinySizeClass] != TinySize)
+ runtime_throw("bad TinySizeClass");
+
// limit = runtime_memlimit();
// See https://code.google.com/p/go/issues/detail?id=5049
// TODO(rsc): Fix after 1.1.
@@ -456,7 +569,9 @@ runtime_mallocinit(void)
spans_size = arena_size / PageSize * sizeof(runtime_mheap.spans[0]);
spans_size = ROUND(spans_size, PageSize);
for(i = 0; i < HeapBaseOptions; i++) {
- p = runtime_SysReserve(HeapBase(i), bitmap_size + spans_size + arena_size);
+ p = HeapBase(i);
+ p_size = bitmap_size + spans_size + arena_size + PageSize;
+ p = runtime_SysReserve(p, p_size, &reserved);
if(p != nil)
break;
}
@@ -498,94 +613,116 @@ runtime_mallocinit(void)
// So adjust it upward a little bit ourselves: 1/4 MB to get
// away from the running binary image and then round up
// to a MB boundary.
- want = (byte*)ROUND((uintptr)_end + (1<<18), 1<<20);
- if(0xffffffff - (uintptr)want <= bitmap_size + spans_size + arena_size)
- want = 0;
- p = runtime_SysReserve(want, bitmap_size + spans_size + arena_size);
+ p = (byte*)ROUND((uintptr)_end + (1<<18), 1<<20);
+ p_size = bitmap_size + spans_size + arena_size + PageSize;
+ p = runtime_SysReserve(p, p_size, &reserved);
if(p == nil)
runtime_throw("runtime: cannot reserve arena virtual address space");
- if((uintptr)p & (((uintptr)1<<PageShift)-1))
- runtime_printf("runtime: SysReserve returned unaligned address %p; asked for %p", p,
- bitmap_size+spans_size+arena_size);
}
- if((uintptr)p & (((uintptr)1<<PageShift)-1))
- runtime_throw("runtime: SysReserve returned unaligned address");
- runtime_mheap.spans = (MSpan**)p;
- runtime_mheap.bitmap = p + spans_size;
- runtime_mheap.arena_start = p + spans_size + bitmap_size;
+ // PageSize can be larger than OS definition of page size,
+ // so SysReserve can give us a PageSize-unaligned pointer.
+ // To overcome this we ask for PageSize more and round up the pointer.
+ p1 = (byte*)ROUND((uintptr)p, PageSize);
+
+ runtime_mheap.spans = (MSpan**)p1;
+ runtime_mheap.bitmap = p1 + spans_size;
+ runtime_mheap.arena_start = p1 + spans_size + bitmap_size;
runtime_mheap.arena_used = runtime_mheap.arena_start;
- runtime_mheap.arena_end = runtime_mheap.arena_start + arena_size;
+ runtime_mheap.arena_end = p + p_size;
+ runtime_mheap.arena_reserved = reserved;
+
+ if(((uintptr)runtime_mheap.arena_start & (PageSize-1)) != 0)
+ runtime_throw("misrounded allocation in mallocinit");
// Initialize the rest of the allocator.
runtime_MHeap_Init(&runtime_mheap);
runtime_m()->mcache = runtime_allocmcache();
// See if it works.
- runtime_free(runtime_malloc(1));
+ runtime_free(runtime_malloc(TinySize));
}
void*
runtime_MHeap_SysAlloc(MHeap *h, uintptr n)
{
- byte *p;
+ byte *p, *p_end;
+ uintptr p_size;
+ bool reserved;
if(n > (uintptr)(h->arena_end - h->arena_used)) {
// We are in 32-bit mode, maybe we didn't use all possible address space yet.
// Reserve some more space.
byte *new_end;
- uintptr needed;
- needed = (uintptr)h->arena_used + n - (uintptr)h->arena_end;
- needed = ROUND(needed, 256<<20);
- new_end = h->arena_end + needed;
+ p_size = ROUND(n + PageSize, 256<<20);
+ new_end = h->arena_end + p_size;
if(new_end <= h->arena_start + MaxArena32) {
- p = runtime_SysReserve(h->arena_end, new_end - h->arena_end);
- if(p == h->arena_end)
+ // TODO: It would be bad if part of the arena
+ // is reserved and part is not.
+ p = runtime_SysReserve(h->arena_end, p_size, &reserved);
+ if(p == h->arena_end) {
h->arena_end = new_end;
+ h->arena_reserved = reserved;
+ }
+ else if(p+p_size <= h->arena_start + MaxArena32) {
+ // Keep everything page-aligned.
+ // Our pages are bigger than hardware pages.
+ h->arena_end = p+p_size;
+ h->arena_used = p + (-(uintptr)p&(PageSize-1));
+ h->arena_reserved = reserved;
+ } else {
+ uint64 stat;
+ stat = 0;
+ runtime_SysFree(p, p_size, &stat);
+ }
}
}
if(n <= (uintptr)(h->arena_end - h->arena_used)) {
// Keep taking from our reservation.
p = h->arena_used;
- runtime_SysMap(p, n, &mstats.heap_sys);
+ runtime_SysMap(p, n, h->arena_reserved, &mstats.heap_sys);
h->arena_used += n;
runtime_MHeap_MapBits(h);
runtime_MHeap_MapSpans(h);
- if(raceenabled)
- runtime_racemapshadow(p, n);
+
+ if(((uintptr)p & (PageSize-1)) != 0)
+ runtime_throw("misrounded allocation in MHeap_SysAlloc");
return p;
}
// If using 64-bit, our reservation is all we have.
- if(sizeof(void*) == 8 && (uintptr)h->bitmap >= 0xffffffffU)
+ if((uintptr)(h->arena_end - h->arena_start) >= MaxArena32)
return nil;
// On 32-bit, once the reservation is gone we can
// try to get memory at a location chosen by the OS
// and hope that it is in the range we allocated bitmap for.
- p = runtime_SysAlloc(n, &mstats.heap_sys);
+ p_size = ROUND(n, PageSize) + PageSize;
+ p = runtime_SysAlloc(p_size, &mstats.heap_sys);
if(p == nil)
return nil;
- if(p < h->arena_start || (uintptr)(p+n - h->arena_start) >= MaxArena32) {
+ if(p < h->arena_start || (uintptr)(p+p_size - h->arena_start) >= MaxArena32) {
runtime_printf("runtime: memory allocated by OS (%p) not in usable range [%p,%p)\n",
p, h->arena_start, h->arena_start+MaxArena32);
- runtime_SysFree(p, n, &mstats.heap_sys);
+ runtime_SysFree(p, p_size, &mstats.heap_sys);
return nil;
}
-
+
+ p_end = p + p_size;
+ p += -(uintptr)p & (PageSize-1);
if(p+n > h->arena_used) {
h->arena_used = p+n;
- if(h->arena_used > h->arena_end)
- h->arena_end = h->arena_used;
+ if(p_end > h->arena_end)
+ h->arena_end = p_end;
runtime_MHeap_MapBits(h);
runtime_MHeap_MapSpans(h);
- if(raceenabled)
- runtime_racemapshadow(p, n);
}
+ if(((uintptr)p & (PageSize-1)) != 0)
+ runtime_throw("misrounded allocation in MHeap_SysAlloc");
return p;
}
@@ -613,7 +750,7 @@ runtime_persistentalloc(uintptr size, uintptr align, uint64 *stat)
if(align != 0) {
if(align&(align-1))
- runtime_throw("persistentalloc: align is now a power of 2");
+ runtime_throw("persistentalloc: align is not a power of 2");
if(align > PageSize)
runtime_throw("persistentalloc: align is too large");
} else
@@ -641,94 +778,67 @@ runtime_persistentalloc(uintptr size, uintptr align, uint64 *stat)
return p;
}
-static Lock settype_lock;
-
-void
-runtime_settype_flush(M *mp)
+static void
+settype(MSpan *s, void *v, uintptr typ)
{
- uintptr *buf, *endbuf;
uintptr size, ofs, j, t;
uintptr ntypes, nbytes2, nbytes3;
uintptr *data2;
byte *data3;
- void *v;
- uintptr typ, p;
- MSpan *s;
- buf = mp->settype_buf;
- endbuf = buf + mp->settype_bufsize;
-
- runtime_lock(&settype_lock);
- while(buf < endbuf) {
- v = (void*)*buf;
- *buf = 0;
- buf++;
- typ = *buf;
- buf++;
-
- // (Manually inlined copy of runtime_MHeap_Lookup)
- p = (uintptr)v>>PageShift;
- p -= (uintptr)runtime_mheap.arena_start >> PageShift;
- s = runtime_mheap.spans[p];
-
- if(s->sizeclass == 0) {
- s->types.compression = MTypes_Single;
- s->types.data = typ;
- continue;
+ if(s->sizeclass == 0) {
+ s->types.compression = MTypes_Single;
+ s->types.data = typ;
+ return;
+ }
+ size = s->elemsize;
+ ofs = ((uintptr)v - (s->start<<PageShift)) / size;
+
+ switch(s->types.compression) {
+ case MTypes_Empty:
+ ntypes = (s->npages << PageShift) / size;
+ nbytes3 = 8*sizeof(uintptr) + 1*ntypes;
+ data3 = runtime_mallocgc(nbytes3, 0, FlagNoProfiling|FlagNoScan|FlagNoInvokeGC);
+ s->types.compression = MTypes_Bytes;
+ s->types.data = (uintptr)data3;
+ ((uintptr*)data3)[1] = typ;
+ data3[8*sizeof(uintptr) + ofs] = 1;
+ break;
+
+ case MTypes_Words:
+ ((uintptr*)s->types.data)[ofs] = typ;
+ break;
+
+ case MTypes_Bytes:
+ data3 = (byte*)s->types.data;
+ for(j=1; j<8; j++) {
+ if(((uintptr*)data3)[j] == typ) {
+ break;
+ }
+ if(((uintptr*)data3)[j] == 0) {
+ ((uintptr*)data3)[j] = typ;
+ break;
+ }
}
-
- size = s->elemsize;
- ofs = ((uintptr)v - (s->start<<PageShift)) / size;
-
- switch(s->types.compression) {
- case MTypes_Empty:
+ if(j < 8) {
+ data3[8*sizeof(uintptr) + ofs] = j;
+ } else {
ntypes = (s->npages << PageShift) / size;
- nbytes3 = 8*sizeof(uintptr) + 1*ntypes;
- data3 = runtime_mallocgc(nbytes3, 0, FlagNoProfiling|FlagNoScan|FlagNoInvokeGC);
- s->types.compression = MTypes_Bytes;
- s->types.data = (uintptr)data3;
- ((uintptr*)data3)[1] = typ;
- data3[8*sizeof(uintptr) + ofs] = 1;
- break;
-
- case MTypes_Words:
- ((uintptr*)s->types.data)[ofs] = typ;
- break;
-
- case MTypes_Bytes:
- data3 = (byte*)s->types.data;
- for(j=1; j<8; j++) {
- if(((uintptr*)data3)[j] == typ) {
- break;
- }
- if(((uintptr*)data3)[j] == 0) {
- ((uintptr*)data3)[j] = typ;
- break;
- }
+ nbytes2 = ntypes * sizeof(uintptr);
+ data2 = runtime_mallocgc(nbytes2, 0, FlagNoProfiling|FlagNoScan|FlagNoInvokeGC);
+ s->types.compression = MTypes_Words;
+ s->types.data = (uintptr)data2;
+
+ // Move the contents of data3 to data2. Then deallocate data3.
+ for(j=0; j<ntypes; j++) {
+ t = data3[8*sizeof(uintptr) + j];
+ t = ((uintptr*)data3)[t];
+ data2[j] = t;
}
- if(j < 8) {
- data3[8*sizeof(uintptr) + ofs] = j;
- } else {
- ntypes = (s->npages << PageShift) / size;
- nbytes2 = ntypes * sizeof(uintptr);
- data2 = runtime_mallocgc(nbytes2, 0, FlagNoProfiling|FlagNoScan|FlagNoInvokeGC);
- s->types.compression = MTypes_Words;
- s->types.data = (uintptr)data2;
-
- // Move the contents of data3 to data2. Then deallocate data3.
- for(j=0; j<ntypes; j++) {
- t = data3[8*sizeof(uintptr) + j];
- t = ((uintptr*)data3)[t];
- data2[j] = t;
- }
- data2[ofs] = typ;
- }
- break;
+ data2[ofs] = typ;
}
+ break;
}
- runtime_unlock(&settype_lock);
-
- mp->settype_bufsize = 0;
}
uintptr
@@ -761,9 +871,7 @@ runtime_gettype(void *v)
runtime_throw("runtime_gettype: invalid compression kind");
}
if(0) {
- runtime_lock(&settype_lock);
runtime_printf("%p -> %d,%X\n", v, (int32)s->types.compression, (int64)t);
- runtime_unlock(&settype_lock);
}
return t;
}
@@ -778,10 +886,8 @@ runtime_mal(uintptr n)
return runtime_mallocgc(n, 0, 0);
}
-void *
-runtime_new(const Type *typ)
-{
- return runtime_mallocgc(typ->__size, (uintptr)typ | TypeInfo_SingleObject, typ->kind&KindNoPointers ? FlagNoScan : 0);
+func new(typ *Type) (ret *uint8) {
+ ret = runtime_mallocgc(typ->__size, (uintptr)typ | TypeInfo_SingleObject, typ->kind&KindNoPointers ? FlagNoScan : 0);
}
static void*
@@ -808,7 +914,7 @@ runtime_cnewarray(const Type *typ, intgo n)
}
func GC() {
- runtime_gc(1);
+ runtime_gc(2); // force GC and do eager sweep
}
func SetFinalizer(obj Eface, finalizer Eface) {
@@ -822,19 +928,35 @@ func SetFinalizer(obj Eface, finalizer Eface) {
runtime_printf("runtime.SetFinalizer: first argument is nil interface\n");
goto throw;
}
- if(obj.__type_descriptor->__code != GO_PTR) {
+ if((obj.__type_descriptor->kind&kindMask) != GO_PTR) {
runtime_printf("runtime.SetFinalizer: first argument is %S, not pointer\n", *obj.__type_descriptor->__reflection);
goto throw;
}
+ ot = (const PtrType*)obj.type;
+ // As an implementation detail we do not run finalizers for zero-sized objects,
+ // because we use &runtime_zerobase for all such allocations.
+ if(ot->__element_type != nil && ot->__element_type->__size == 0)
+ return;
+ // The following check is required for cases when a user passes a pointer to composite literal,
+ // but compiler makes it a pointer to global. For example:
+ // var Foo = &Object{}
+ // func main() {
+ // runtime.SetFinalizer(Foo, nil)
+ // }
+ // See issue 7656.
+ if((byte*)obj.__object < runtime_mheap.arena_start || runtime_mheap.arena_used <= (byte*)obj.__object)
+ return;
if(!runtime_mlookup(obj.__object, &base, &size, nil) || obj.__object != base) {
- runtime_printf("runtime.SetFinalizer: pointer not at beginning of allocated block\n");
- goto throw;
+ // 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->__element_type == nil || (ot->__element_type->kind&KindNoPointers) == 0 || ot->__element_type->__size >= TinySize) {
+ runtime_printf("runtime.SetFinalizer: pointer not at beginning of allocated block (%p)\n", obj.__object);
+ goto throw;
+ }
}
- ft = nil;
- ot = (const PtrType*)obj.__type_descriptor;
- fint = nil;
if(finalizer.__type_descriptor != nil) {
- if(finalizer.__type_descriptor->__code != GO_FUNC)
+ runtime_createfing();
+ if((finalizer.__type_descriptor->kind&kindMask) != GO_FUNC)
goto badfunc;
ft = (const FuncType*)finalizer.__type_descriptor;
if(ft->__dotdotdot || ft->__in.__count != 1)
@@ -842,20 +964,24 @@ func SetFinalizer(obj Eface, finalizer Eface) {
fint = *(Type**)ft->__in.__values;
if(__go_type_descriptors_equal(fint, obj.__type_descriptor)) {
// ok - same type
- } else if(fint->__code == GO_PTR && (fint->__uncommon == nil || fint->__uncommon->__name == nil || obj.type->__uncommon == nil || obj.type->__uncommon->__name == nil) && __go_type_descriptors_equal(((const PtrType*)fint)->__element_type, ((const PtrType*)obj.type)->__element_type)) {
+ } else if((fint->kind&kindMask) == GO_PTR && (fint->__uncommon == nil || fint->__uncommon->__name == nil || obj.type->__uncommon == nil || obj.type->__uncommon->__name == nil) && __go_type_descriptors_equal(((const PtrType*)fint)->__element_type, ((const PtrType*)obj.type)->__element_type)) {
// ok - not same type, but both pointers,
// one or the other is unnamed, and same element type, so assignable.
- } else if(fint->kind == GO_INTERFACE && ((const InterfaceType*)fint)->__methods.__count == 0) {
+ } else if((fint->kind&kindMask) == GO_INTERFACE && ((const InterfaceType*)fint)->__methods.__count == 0) {
// ok - satisfies empty interface
- } else if(fint->kind == GO_INTERFACE && __go_convert_interface_2(fint, obj.__type_descriptor, 1) != nil) {
+ } else if((fint->kind&kindMask) == GO_INTERFACE && __go_convert_interface_2(fint, obj.__type_descriptor, 1) != nil) {
// ok - satisfies non-empty interface
} else
goto badfunc;
- }
- if(!runtime_addfinalizer(obj.__object, finalizer.__type_descriptor != nil ? *(void**)finalizer.__object : nil, ft, ot)) {
- runtime_printf("runtime.SetFinalizer: finalizer already set\n");
- goto throw;
+ ot = (const PtrType*)obj.__type_descriptor;
+ if(!runtime_addfinalizer(obj.__object, *(FuncVal**)finalizer.__object, ft, ot)) {
+ runtime_printf("runtime.SetFinalizer: finalizer already set\n");
+ goto throw;
+ }
+ } else {
+ // NOTE: asking to remove a finalizer when there currently isn't one set is OK.
+ runtime_removefinalizer(obj.__object);
}
return;
diff --git a/libgo/runtime/malloc.h b/libgo/runtime/malloc.h
index e1a5be9991..86b9fccf90 100644
--- a/libgo/runtime/malloc.h
+++ b/libgo/runtime/malloc.h
@@ -20,7 +20,7 @@
// MHeap: the malloc heap, managed at page (4096-byte) granularity.
// MSpan: a run of pages managed by the MHeap.
// MCentral: a shared free list for a given size class.
-// MCache: a per-thread (in Go, per-M) cache for small objects.
+// MCache: a per-thread (in Go, per-P) cache for small objects.
// MStats: allocation statistics.
//
// Allocating a small object proceeds up a hierarchy of caches:
@@ -66,14 +66,14 @@
//
// The small objects on the MCache and MCentral free lists
// may or may not be zeroed. They are zeroed if and only if
-// the second word of the object is zero. The spans in the
-// page heap are always zeroed. When a span full of objects
-// is returned to the page heap, the objects that need to be
-// are zeroed first. There are two main benefits to delaying the
+// the second word of the object is zero. A span in the
+// page heap is zeroed unless s->needzero is set. When a span
+// is allocated to break into small objects, it is zeroed if needed
+// and s->needzero is set. There are two main benefits to delaying the
// zeroing this way:
//
// 1. stack frames allocated from the small object lists
-// can avoid zeroing altogether.
+// or the page heap can avoid zeroing altogether.
// 2. the cost of zeroing when reusing a small object is
// charged to the mutator, not the garbage collector.
//
@@ -90,7 +90,7 @@ typedef struct GCStats GCStats;
enum
{
- PageShift = 12,
+ PageShift = 13,
PageSize = 1<<PageShift,
PageMask = PageSize - 1,
};
@@ -103,11 +103,15 @@ enum
// size classes. NumSizeClasses is that number. It's needed here
// because there are static arrays of this length; when msize runs its
// size choosing algorithm it double-checks that NumSizeClasses agrees.
- NumSizeClasses = 61,
+ NumSizeClasses = 67,
// Tunable constants.
MaxSmallSize = 32<<10,
+ // Tiny allocator parameters, see "Tiny allocator" comment in malloc.goc.
+ TinySize = 16,
+ TinySizeClass = 2,
+
FixAllocChunk = 16<<10, // Chunk size for FixAlloc
MaxMHeapList = 1<<(20 - PageShift), // Maximum page length for fixed-size list in MHeap.
HeapAllocChunk = 1<<20, // Chunk size for heap growth
@@ -154,6 +158,9 @@ struct MLink
// SysAlloc obtains a large chunk of zeroed memory from the
// operating system, typically on the order of a hundred kilobytes
// or a megabyte.
+// NOTE: SysAlloc returns OS-aligned memory, but the heap allocator
+// may use larger alignment, so the caller must be careful to realign the
+// memory obtained by SysAlloc.
//
// SysUnused notifies the operating system that the contents
// of the memory region are no longer needed and can be reused
@@ -168,16 +175,29 @@ struct MLink
// SysReserve reserves address space without allocating memory.
// If the pointer passed to it is non-nil, the caller wants the
// reservation there, but SysReserve can still choose another
-// location if that one is unavailable.
+// location if that one is unavailable. On some systems and in some
+// cases SysReserve will simply check that the address space is
+// available and not actually reserve it. If SysReserve returns
+// non-nil, it sets *reserved to true if the address space is
+// reserved, false if it has merely been checked.
+// NOTE: SysReserve returns OS-aligned memory, but the heap allocator
+// may use larger alignment, so the caller must be careful to realign the
+// memory obtained by SysAlloc.
//
// SysMap maps previously reserved address space for use.
+// The reserved argument is true if the address space was really
+// reserved, not merely checked.
+//
+// SysFault marks a (already SysAlloc'd) region to fault
+// if accessed. Used only for debugging the runtime.
void* runtime_SysAlloc(uintptr nbytes, uint64 *stat);
void runtime_SysFree(void *v, uintptr nbytes, uint64 *stat);
void runtime_SysUnused(void *v, uintptr nbytes);
void runtime_SysUsed(void *v, uintptr nbytes);
-void runtime_SysMap(void *v, uintptr nbytes, uint64 *stat);
-void* runtime_SysReserve(void *v, uintptr nbytes);
+void runtime_SysMap(void *v, uintptr nbytes, bool reserved, uint64 *stat);
+void* runtime_SysReserve(void *v, uintptr nbytes, bool *reserved);
+void runtime_SysFault(void *v, uintptr nbytes);
// FixAlloc is a simple free-list allocator for fixed size objects.
// Malloc uses a FixAlloc wrapped around SysAlloc to manages its
@@ -256,7 +276,8 @@ struct MStats
};
extern MStats mstats
- __asm__ (GOSYM_PREFIX "runtime.VmemStats");
+ __asm__ (GOSYM_PREFIX "runtime.memStats");
+void runtime_updatememstats(GCStats *stats);
// Size classes. Computed and initialized by InitSizes.
//
@@ -269,6 +290,7 @@ extern MStats mstats
// making new objects in class i
int32 runtime_SizeToClass(int32);
+uintptr runtime_roundupsize(uintptr);
extern int32 runtime_class_to_size[NumSizeClasses];
extern int32 runtime_class_to_allocnpages[NumSizeClasses];
extern int8 runtime_size_to_class8[1024/8 + 1];
@@ -276,8 +298,6 @@ extern int8 runtime_size_to_class128[(MaxSmallSize-1024)/128 + 1];
extern void runtime_InitSizes(void);
-// Per-thread (in Go, per-M) cache for small objects.
-// No locking needed because it is per-thread (per-M).
typedef struct MCacheList MCacheList;
struct MCacheList
{
@@ -285,14 +305,21 @@ struct MCacheList
uint32 nlist;
};
+// Per-thread (in Go, per-P) cache for small objects.
+// No locking needed because it is per-thread (per-P).
struct MCache
{
// The following members are accessed on every malloc,
// so they are grouped here for better caching.
int32 next_sample; // trigger heap sample after allocating this many bytes
intptr local_cachealloc; // bytes allocated (or freed) from cache since last lock of heap
+ // Allocator cache for tiny objects w/o pointers.
+ // See "Tiny allocator" comment in malloc.goc.
+ byte* tiny;
+ uintptr tinysize;
// The rest is not accessed on every malloc.
- MCacheList list[NumSizeClasses];
+ MSpan* alloc[NumSizeClasses]; // spans to allocate from
+ MCacheList free[NumSizeClasses];// lists of explicitly freed objects
// Local allocator stats, flushed during GC.
uintptr local_nlookup; // number of pointer lookups
uintptr local_largefree; // bytes freed for large objects (>MaxSmallSize)
@@ -300,8 +327,8 @@ struct MCache
uintptr local_nsmallfree[NumSizeClasses]; // number of frees for small objects (<=MaxSmallSize)
};
-void runtime_MCache_Refill(MCache *c, int32 sizeclass);
-void runtime_MCache_Free(MCache *c, void *p, int32 sizeclass, uintptr size);
+MSpan* runtime_MCache_Refill(MCache *c, int32 sizeclass);
+void runtime_MCache_Free(MCache *c, MLink *p, int32 sizeclass, uintptr size);
void runtime_MCache_ReleaseAll(MCache *c);
// MTypes describes the types of blocks allocated within a span.
@@ -341,6 +368,43 @@ struct MTypes
uintptr data;
};
+enum
+{
+ KindSpecialFinalizer = 1,
+ KindSpecialProfile = 2,
+ // Note: The finalizer special must be first because if we're freeing
+ // an object, a finalizer special will cause the freeing operation
+ // to abort, and we want to keep the other special records around
+ // if that happens.
+};
+
+typedef struct Special Special;
+struct Special
+{
+ Special* next; // linked list in span
+ uint16 offset; // span offset of object
+ byte kind; // kind of Special
+};
+
+// The described object has a finalizer set for it.
+typedef struct SpecialFinalizer SpecialFinalizer;
+struct SpecialFinalizer
+{
+ Special;
+ FuncVal* fn;
+ const FuncType* ft;
+ const PtrType* ot;
+};
+
+// The described object is being heap profiled.
+typedef struct Bucket Bucket; // from mprof.goc
+typedef struct SpecialProfile SpecialProfile;
+struct SpecialProfile
+{
+ Special;
+ Bucket* b;
+};
+
// An MSpan is a run of pages.
enum
{
@@ -356,17 +420,30 @@ struct MSpan
PageID start; // starting page number
uintptr npages; // number of pages in span
MLink *freelist; // list of free objects
- uint32 ref; // number of allocated objects in this span
- int32 sizeclass; // size class
+ // sweep generation:
+ // if sweepgen == h->sweepgen - 2, the span needs sweeping
+ // if sweepgen == h->sweepgen - 1, the span is currently being swept
+ // if sweepgen == h->sweepgen, the span is swept and ready to use
+ // h->sweepgen is incremented by 2 after every GC
+ uint32 sweepgen;
+ uint16 ref; // capacity - number of objects in freelist
+ uint8 sizeclass; // size class
+ bool incache; // being used by an MCache
+ uint8 state; // MSpanInUse etc
+ uint8 needzero; // needs to be zeroed before allocation
uintptr elemsize; // computed from sizeclass or from npages
- uint32 state; // MSpanInUse etc
int64 unusedsince; // First time spotted by GC in MSpanFree state
uintptr npreleased; // number of pages released to the OS
byte *limit; // end of data in span
MTypes types; // types of allocated objects in this span
+ Lock specialLock; // guards specials list
+ Special *specials; // linked list of special records sorted by offset.
+ MLink *freebuf; // objects freed explicitly, not incorporated into freelist yet
};
void runtime_MSpan_Init(MSpan *span, PageID start, uintptr npages);
+void runtime_MSpan_EnsureSwept(MSpan *span);
+bool runtime_MSpan_Sweep(MSpan *span);
// Every MSpan is in one doubly-linked list,
// either one of the MHeap's free lists or one of the
@@ -374,6 +451,7 @@ void runtime_MSpan_Init(MSpan *span, PageID start, uintptr npages);
void runtime_MSpanList_Init(MSpan *list);
bool runtime_MSpanList_IsEmpty(MSpan *list);
void runtime_MSpanList_Insert(MSpan *list, MSpan *span);
+void runtime_MSpanList_InsertBack(MSpan *list, MSpan *span);
void runtime_MSpanList_Remove(MSpan *span); // from whatever list it is in
@@ -382,15 +460,16 @@ struct MCentral
{
Lock;
int32 sizeclass;
- MSpan nonempty;
- MSpan empty;
- int32 nfree;
+ MSpan nonempty; // list of spans with a free object
+ MSpan empty; // list of spans with no free objects (or cached in an MCache)
+ int32 nfree; // # of objects available in nonempty spans
};
void runtime_MCentral_Init(MCentral *c, int32 sizeclass);
-int32 runtime_MCentral_AllocList(MCentral *c, MLink **first);
-void runtime_MCentral_FreeList(MCentral *c, MLink *first);
-void runtime_MCentral_FreeSpan(MCentral *c, MSpan *s, int32 n, MLink *start, MLink *end);
+MSpan* runtime_MCentral_CacheSpan(MCentral *c);
+void runtime_MCentral_UncacheSpan(MCentral *c, MSpan *s);
+bool runtime_MCentral_FreeSpan(MCentral *c, MSpan *s, int32 n, MLink *start, MLink *end);
+void runtime_MCentral_FreeList(MCentral *c, MLink *start); // TODO: need this?
// Main malloc heap.
// The heap itself is the "free[]" and "large" arrays,
@@ -399,10 +478,15 @@ struct MHeap
{
Lock;
MSpan free[MaxMHeapList]; // free lists of given length
- MSpan large; // free lists length >= MaxMHeapList
- MSpan **allspans;
+ MSpan freelarge; // free lists length >= MaxMHeapList
+ MSpan busy[MaxMHeapList]; // busy lists of large objects of given length
+ MSpan busylarge; // busy lists of large objects length >= MaxMHeapList
+ MSpan **allspans; // all spans out there
+ MSpan **sweepspans; // copy of allspans referenced by sweeper
uint32 nspan;
uint32 nspancap;
+ uint32 sweepgen; // sweep generation, see comment in MSpan
+ uint32 sweepdone; // all spans are swept
// span lookup
MSpan** spans;
@@ -414,6 +498,7 @@ struct MHeap
byte *arena_start;
byte *arena_used;
byte *arena_end;
+ bool arena_reserved;
// central free lists for small size classes.
// the padding makes sure that the MCentrals are
@@ -426,6 +511,9 @@ struct MHeap
FixAlloc spanalloc; // allocator for Span*
FixAlloc cachealloc; // allocator for MCache*
+ FixAlloc specialfinalizeralloc; // allocator for SpecialFinalizer*
+ FixAlloc specialprofilealloc; // allocator for SpecialProfile*
+ Lock speciallock; // lock for sepcial record allocators.
// Malloc stats.
uint64 largefree; // bytes freed for large objects (>MaxSmallSize)
@@ -435,7 +523,7 @@ struct MHeap
extern MHeap runtime_mheap;
void runtime_MHeap_Init(MHeap *h);
-MSpan* runtime_MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, int32 acct, int32 zeroed);
+MSpan* runtime_MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, bool large, bool needzero);
void runtime_MHeap_Free(MHeap *h, MSpan *s, int32 acct);
MSpan* runtime_MHeap_Lookup(MHeap *h, void *v);
MSpan* runtime_MHeap_LookupMaybe(MHeap *h, void *v);
@@ -444,26 +532,28 @@ void* runtime_MHeap_SysAlloc(MHeap *h, uintptr n);
void runtime_MHeap_MapBits(MHeap *h);
void runtime_MHeap_MapSpans(MHeap *h);
void runtime_MHeap_Scavenger(void*);
+void runtime_MHeap_SplitSpan(MHeap *h, MSpan *s);
void* runtime_mallocgc(uintptr size, uintptr typ, uint32 flag);
void* runtime_persistentalloc(uintptr size, uintptr align, uint64 *stat);
int32 runtime_mlookup(void *v, byte **base, uintptr *size, MSpan **s);
void runtime_gc(int32 force);
-void runtime_markallocated(void *v, uintptr n, bool noptr);
+uintptr runtime_sweepone(void);
+void runtime_markscan(void *v);
+void runtime_marknogc(void *v);
void runtime_checkallocated(void *v, uintptr n);
-void runtime_markfreed(void *v, uintptr n);
+void runtime_markfreed(void *v);
void runtime_checkfreed(void *v, uintptr n);
extern int32 runtime_checking;
void runtime_markspan(void *v, uintptr size, uintptr n, bool leftover);
void runtime_unmarkspan(void *v, uintptr size);
-bool runtime_blockspecial(void*);
-void runtime_setblockspecial(void*, bool);
void runtime_purgecachedstats(MCache*);
void* runtime_cnew(const Type*);
void* runtime_cnewarray(const Type*, intgo);
+void runtime_tracealloc(void*, uintptr, uintptr);
+void runtime_tracefree(void*, uintptr);
+void runtime_tracegc(void);
-void runtime_settype_flush(M*);
-void runtime_settype_sysfree(MSpan*);
uintptr runtime_gettype(void*);
enum
@@ -485,17 +575,27 @@ struct Obj
};
void runtime_MProf_Malloc(void*, uintptr);
-void runtime_MProf_Free(void*, uintptr);
+void runtime_MProf_Free(Bucket*, uintptr, bool);
void runtime_MProf_GC(void);
-void runtime_MProf_Mark(void (*addroot)(Obj));
+void runtime_iterate_memprof(void (*callback)(Bucket*, uintptr, Location*, uintptr, uintptr, uintptr));
int32 runtime_gcprocs(void);
void runtime_helpgc(int32 nproc);
void runtime_gchelper(void);
+void runtime_createfing(void);
+G* runtime_wakefing(void);
+extern bool runtime_fingwait;
+extern bool runtime_fingwake;
+
+void runtime_setprofilebucket(void *p, Bucket *b);
struct __go_func_type;
struct __go_ptr_type;
-bool runtime_getfinalizer(void *p, bool del, FuncVal **fn, const struct __go_func_type **ft, const struct __go_ptr_type **ot);
-void runtime_walkfintab(void (*fn)(void*), void (*scan)(Obj));
+bool runtime_addfinalizer(void *p, FuncVal *fn, const struct __go_func_type*, const struct __go_ptr_type*);
+void runtime_removefinalizer(void*);
+void runtime_queuefinalizer(void *p, FuncVal *fn, const struct __go_func_type *ft, const struct __go_ptr_type *ot);
+
+void runtime_freeallspecials(MSpan *span, void *p, uintptr size);
+bool runtime_freespecial(Special *s, void *p, uintptr size, bool freed);
enum
{
@@ -507,12 +607,52 @@ enum
DebugTypeAtBlockEnd = 0,
};
+// Information from the compiler about the layout of stack frames.
+typedef struct BitVector BitVector;
+struct BitVector
+{
+ int32 n; // # of bits
+ uint32 *data;
+};
+typedef struct StackMap StackMap;
+struct StackMap
+{
+ int32 n; // number of bitmaps
+ int32 nbit; // number of bits in each bitmap
+ uint32 data[];
+};
+enum {
+ // Pointer map
+ BitsPerPointer = 2,
+ BitsDead = 0,
+ BitsScalar = 1,
+ BitsPointer = 2,
+ BitsMultiWord = 3,
+ // BitsMultiWord will be set for the first word of a multi-word item.
+ // When it is set, one of the following will be set for the second word.
+ BitsString = 0,
+ BitsSlice = 1,
+ BitsIface = 2,
+ BitsEface = 3,
+};
+// Returns pointer map data for the given stackmap index
+// (the index is encoded in PCDATA_StackMapIndex).
+BitVector runtime_stackmapdata(StackMap *stackmap, int32 n);
+
// defined in mgc0.go
void runtime_gc_m_ptr(Eface*);
+void runtime_gc_g_ptr(Eface*);
void runtime_gc_itab_ptr(Eface*);
void runtime_memorydump(void);
+int32 runtime_setgcpercent(int32);
+
+// Value we use to mark dead pointers when GODEBUG=gcdead=1.
+#define PoisonGC ((uintptr)0xf969696969696969ULL)
+#define PoisonStack ((uintptr)0x6868686868686868ULL)
-void runtime_proc_scan(void (*)(Obj));
-void runtime_time_scan(void (*)(Obj));
-void runtime_netpoll_scan(void (*)(Obj));
+struct Workbuf;
+void runtime_MProf_Mark(struct Workbuf**, void (*)(struct Workbuf**, Obj));
+void runtime_proc_scan(struct Workbuf**, void (*)(struct Workbuf**, Obj));
+void runtime_time_scan(struct Workbuf**, void (*)(struct Workbuf**, Obj));
+void runtime_netpoll_scan(struct Workbuf**, void (*)(struct Workbuf**, Obj));
diff --git a/libgo/runtime/mcache.c b/libgo/runtime/mcache.c
index 38f824a139..746711a0d3 100644
--- a/libgo/runtime/mcache.c
+++ b/libgo/runtime/mcache.c
@@ -10,69 +10,119 @@
#include "arch.h"
#include "malloc.h"
+extern volatile intgo runtime_MemProfileRate
+ __asm__ (GOSYM_PREFIX "runtime.MemProfileRate");
+
+// dummy MSpan that contains no free objects.
+static MSpan emptymspan;
+
+MCache*
+runtime_allocmcache(void)
+{
+ intgo rate;
+ MCache *c;
+ int32 i;
+
+ runtime_lock(&runtime_mheap);
+ c = runtime_FixAlloc_Alloc(&runtime_mheap.cachealloc);
+ runtime_unlock(&runtime_mheap);
+ runtime_memclr((byte*)c, sizeof(*c));
+ for(i = 0; i < NumSizeClasses; i++)
+ c->alloc[i] = &emptymspan;
+
+ // Set first allocation sample size.
+ rate = runtime_MemProfileRate;
+ if(rate > 0x3fffffff) // make 2*rate not overflow
+ rate = 0x3fffffff;
+ if(rate != 0)
+ c->next_sample = runtime_fastrand1() % (2*rate);
+
+ return c;
+}
+
void
+runtime_freemcache(MCache *c)
+{
+ runtime_MCache_ReleaseAll(c);
+ runtime_lock(&runtime_mheap);
+ runtime_purgecachedstats(c);
+ runtime_FixAlloc_Free(&runtime_mheap.cachealloc, c);
+ runtime_unlock(&runtime_mheap);
+}
+
+// Gets a span that has a free object in it and assigns it
+// to be the cached span for the given sizeclass. Returns this span.
+MSpan*
runtime_MCache_Refill(MCache *c, int32 sizeclass)
{
MCacheList *l;
+ MSpan *s;
- // Replenish using central lists.
- l = &c->list[sizeclass];
- if(l->list)
- runtime_throw("MCache_Refill: the list is not empty");
- l->nlist = runtime_MCentral_AllocList(&runtime_mheap.central[sizeclass], &l->list);
- if(l->list == nil)
- runtime_throw("out of memory");
-}
+ runtime_m()->locks++;
+ // Return the current cached span to the central lists.
+ s = c->alloc[sizeclass];
+ if(s->freelist != nil)
+ runtime_throw("refill on a nonempty span");
+ if(s != &emptymspan)
+ runtime_MCentral_UncacheSpan(&runtime_mheap.central[sizeclass], s);
-// Take n elements off l and return them to the central free list.
-static void
-ReleaseN(MCacheList *l, int32 n, int32 sizeclass)
-{
- MLink *first, **lp;
- int32 i;
+ // Push any explicitly freed objects to the central lists.
+ // Not required, but it seems like a good time to do it.
+ l = &c->free[sizeclass];
+ if(l->nlist > 0) {
+ runtime_MCentral_FreeList(&runtime_mheap.central[sizeclass], l->list);
+ l->list = nil;
+ l->nlist = 0;
+ }
- // Cut off first n elements.
- first = l->list;
- lp = &l->list;
- for(i=0; i<n; i++)
- lp = &(*lp)->next;
- l->list = *lp;
- *lp = nil;
- l->nlist -= n;
-
- // Return them to central free list.
- runtime_MCentral_FreeList(&runtime_mheap.central[sizeclass], first);
+ // Get a new cached span from the central lists.
+ s = runtime_MCentral_CacheSpan(&runtime_mheap.central[sizeclass]);
+ if(s == nil)
+ runtime_throw("out of memory");
+ if(s->freelist == nil) {
+ runtime_printf("%d %d\n", s->ref, (int32)((s->npages << PageShift) / s->elemsize));
+ runtime_throw("empty span");
+ }
+ c->alloc[sizeclass] = s;
+ runtime_m()->locks--;
+ return s;
}
void
-runtime_MCache_Free(MCache *c, void *v, int32 sizeclass, uintptr size)
+runtime_MCache_Free(MCache *c, MLink *p, int32 sizeclass, uintptr size)
{
MCacheList *l;
- MLink *p;
- // Put back on list.
- l = &c->list[sizeclass];
- p = v;
+ // Put on free list.
+ l = &c->free[sizeclass];
p->next = l->list;
l->list = p;
l->nlist++;
- c->local_cachealloc -= size;
- // We transfer span at a time from MCentral to MCache,
- // if we have 2 times more than that, release a half back.
- if(l->nlist >= 2*(runtime_class_to_allocnpages[sizeclass]<<PageShift)/size)
- ReleaseN(l, l->nlist/2, sizeclass);
+ // We transfer a span at a time from MCentral to MCache,
+ // so we'll do the same in the other direction.
+ if(l->nlist >= (runtime_class_to_allocnpages[sizeclass]<<PageShift)/size) {
+ runtime_MCentral_FreeList(&runtime_mheap.central[sizeclass], l->list);
+ l->list = nil;
+ l->nlist = 0;
+ }
}
void
runtime_MCache_ReleaseAll(MCache *c)
{
int32 i;
+ MSpan *s;
MCacheList *l;
for(i=0; i<NumSizeClasses; i++) {
- l = &c->list[i];
- if(l->list) {
+ s = c->alloc[i];
+ if(s != &emptymspan) {
+ runtime_MCentral_UncacheSpan(&runtime_mheap.central[i], s);
+ c->alloc[i] = &emptymspan;
+ }
+ l = &c->free[i];
+ if(l->nlist > 0) {
runtime_MCentral_FreeList(&runtime_mheap.central[i], l->list);
l->list = nil;
l->nlist = 0;
diff --git a/libgo/runtime/mcentral.c b/libgo/runtime/mcentral.c
index 81916101e4..e41a83fbf0 100644
--- a/libgo/runtime/mcentral.c
+++ b/libgo/runtime/mcentral.c
@@ -19,7 +19,8 @@
#include "malloc.h"
static bool MCentral_Grow(MCentral *c);
-static void MCentral_Free(MCentral *c, void *v);
+static void MCentral_Free(MCentral *c, MLink *v);
+static void MCentral_ReturnToHeap(MCentral *c, MSpan *s);
// Initialize a single central free list.
void
@@ -30,39 +31,115 @@ runtime_MCentral_Init(MCentral *c, int32 sizeclass)
runtime_MSpanList_Init(&c->empty);
}
-// Allocate a list of objects from the central free list.
-// Return the number of objects allocated.
-// The objects are linked together by their first words.
-// On return, *pfirst points at the first object.
-int32
-runtime_MCentral_AllocList(MCentral *c, MLink **pfirst)
+// Allocate a span to use in an MCache.
+MSpan*
+runtime_MCentral_CacheSpan(MCentral *c)
{
MSpan *s;
int32 cap, n;
+ uint32 sg;
runtime_lock(c);
- // Replenish central list if empty.
- if(runtime_MSpanList_IsEmpty(&c->nonempty)) {
- if(!MCentral_Grow(c)) {
+ sg = runtime_mheap.sweepgen;
+retry:
+ for(s = c->nonempty.next; s != &c->nonempty; s = s->next) {
+ if(s->sweepgen == sg-2 && runtime_cas(&s->sweepgen, sg-2, sg-1)) {
+ runtime_unlock(c);
+ runtime_MSpan_Sweep(s);
+ runtime_lock(c);
+ // the span could have been moved to heap, retry
+ goto retry;
+ }
+ if(s->sweepgen == sg-1) {
+ // the span is being swept by background sweeper, skip
+ continue;
+ }
+ // we have a nonempty span that does not require sweeping, allocate from it
+ goto havespan;
+ }
+
+ for(s = c->empty.next; s != &c->empty; s = s->next) {
+ if(s->sweepgen == sg-2 && runtime_cas(&s->sweepgen, sg-2, sg-1)) {
+ // we have an empty span that requires sweeping,
+ // sweep it and see if we can free some space in it
+ runtime_MSpanList_Remove(s);
+ // swept spans are at the end of the list
+ runtime_MSpanList_InsertBack(&c->empty, s);
runtime_unlock(c);
- *pfirst = nil;
- return 0;
+ runtime_MSpan_Sweep(s);
+ runtime_lock(c);
+ // the span could be moved to nonempty or heap, retry
+ goto retry;
}
+ if(s->sweepgen == sg-1) {
+ // the span is being swept by background sweeper, skip
+ continue;
+ }
+ // already swept empty span,
+ // all subsequent ones must also be either swept or in process of sweeping
+ break;
}
- s = c->nonempty.next;
+
+ // Replenish central list if empty.
+ if(!MCentral_Grow(c)) {
+ runtime_unlock(c);
+ return nil;
+ }
+ goto retry;
+
+havespan:
cap = (s->npages << PageShift) / s->elemsize;
n = cap - s->ref;
- *pfirst = s->freelist;
- s->freelist = nil;
- s->ref += n;
+ if(n == 0)
+ runtime_throw("empty span");
+ if(s->freelist == nil)
+ runtime_throw("freelist empty");
c->nfree -= n;
runtime_MSpanList_Remove(s);
- runtime_MSpanList_Insert(&c->empty, s);
+ runtime_MSpanList_InsertBack(&c->empty, s);
+ s->incache = true;
runtime_unlock(c);
- return n;
+ return s;
}
-// Free the list of objects back into the central free list.
+// Return span from an MCache.
+void
+runtime_MCentral_UncacheSpan(MCentral *c, MSpan *s)
+{
+ MLink *v;
+ int32 cap, n;
+
+ runtime_lock(c);
+
+ s->incache = false;
+
+ // Move any explicitly freed items from the freebuf to the freelist.
+ while((v = s->freebuf) != nil) {
+ s->freebuf = v->next;
+ runtime_markfreed(v);
+ v->next = s->freelist;
+ s->freelist = v;
+ s->ref--;
+ }
+
+ if(s->ref == 0) {
+ // Free back to heap. Unlikely, but possible.
+ MCentral_ReturnToHeap(c, s); // unlocks c
+ return;
+ }
+
+ cap = (s->npages << PageShift) / s->elemsize;
+ n = cap - s->ref;
+ if(n > 0) {
+ c->nfree += n;
+ runtime_MSpanList_Remove(s);
+ runtime_MSpanList_Insert(&c->nonempty, s);
+ }
+ runtime_unlock(c);
+}
+
+// Free the list of objects back into the central free list c.
+// Called from runtime_free.
void
runtime_MCentral_FreeList(MCentral *c, MLink *start)
{
@@ -77,51 +154,58 @@ runtime_MCentral_FreeList(MCentral *c, MLink *start)
}
// Helper: free one object back into the central free list.
+// Caller must hold lock on c on entry. Holds lock on exit.
static void
-MCentral_Free(MCentral *c, void *v)
+MCentral_Free(MCentral *c, MLink *v)
{
MSpan *s;
- MLink *p;
- int32 size;
// Find span for v.
s = runtime_MHeap_Lookup(&runtime_mheap, v);
if(s == nil || s->ref == 0)
runtime_throw("invalid free");
+ if(s->sweepgen != runtime_mheap.sweepgen)
+ runtime_throw("free into unswept span");
+
+ // If the span is currently being used unsynchronized by an MCache,
+ // we can't modify the freelist. Add to the freebuf instead. The
+ // items will get moved to the freelist when the span is returned
+ // by the MCache.
+ if(s->incache) {
+ v->next = s->freebuf;
+ s->freebuf = v;
+ return;
+ }
- // Move to nonempty if necessary.
+ // Move span to nonempty if necessary.
if(s->freelist == nil) {
runtime_MSpanList_Remove(s);
runtime_MSpanList_Insert(&c->nonempty, s);
}
- // Add v back to s's free list.
- p = v;
- p->next = s->freelist;
- s->freelist = p;
+ // Add the object to span's free list.
+ runtime_markfreed(v);
+ v->next = s->freelist;
+ s->freelist = v;
+ s->ref--;
c->nfree++;
// If s is completely freed, return it to the heap.
- if(--s->ref == 0) {
- size = runtime_class_to_size[c->sizeclass];
- runtime_MSpanList_Remove(s);
- runtime_unmarkspan((byte*)(s->start<<PageShift), s->npages<<PageShift);
- *(uintptr*)(s->start<<PageShift) = 1; // needs zeroing
- s->freelist = nil;
- c->nfree -= (s->npages << PageShift) / size;
- runtime_unlock(c);
- runtime_MHeap_Free(&runtime_mheap, s, 0);
+ if(s->ref == 0) {
+ MCentral_ReturnToHeap(c, s); // unlocks c
runtime_lock(c);
}
}
// Free n objects from a span s back into the central free list c.
-// Called from GC.
-void
+// Called during sweep.
+// Returns true if the span was returned to heap. Sets sweepgen to
+// the latest generation.
+bool
runtime_MCentral_FreeSpan(MCentral *c, MSpan *s, int32 n, MLink *start, MLink *end)
{
- int32 size;
-
+ if(s->incache)
+ runtime_throw("freespan into cached span");
runtime_lock(c);
// Move to nonempty if necessary.
@@ -135,20 +219,21 @@ runtime_MCentral_FreeSpan(MCentral *c, MSpan *s, int32 n, MLink *start, MLink *e
s->freelist = start;
s->ref -= n;
c->nfree += n;
+
+ // delay updating sweepgen until here. This is the signal that
+ // the span may be used in an MCache, so it must come after the
+ // linked list operations above (actually, just after the
+ // lock of c above.)
+ runtime_atomicstore(&s->sweepgen, runtime_mheap.sweepgen);
- // If s is completely freed, return it to the heap.
- if(s->ref == 0) {
- size = runtime_class_to_size[c->sizeclass];
- runtime_MSpanList_Remove(s);
- *(uintptr*)(s->start<<PageShift) = 1; // needs zeroing
- s->freelist = nil;
- c->nfree -= (s->npages << PageShift) / size;
- runtime_unlock(c);
- runtime_unmarkspan((byte*)(s->start<<PageShift), s->npages<<PageShift);
- runtime_MHeap_Free(&runtime_mheap, s, 0);
- } else {
+ if(s->ref != 0) {
runtime_unlock(c);
+ return false;
}
+
+ // s is completely freed, return it to the heap.
+ MCentral_ReturnToHeap(c, s); // unlocks c
+ return true;
}
void
@@ -202,3 +287,21 @@ MCentral_Grow(MCentral *c)
runtime_MSpanList_Insert(&c->nonempty, s);
return true;
}
+
+// Return s to the heap. s must be unused (s->ref == 0). Unlocks c.
+static void
+MCentral_ReturnToHeap(MCentral *c, MSpan *s)
+{
+ int32 size;
+
+ size = runtime_class_to_size[c->sizeclass];
+ runtime_MSpanList_Remove(s);
+ s->needzero = 1;
+ s->freelist = nil;
+ if(s->ref != 0)
+ runtime_throw("ref wrong");
+ c->nfree -= (s->npages << PageShift) / size;
+ runtime_unlock(c);
+ runtime_unmarkspan((byte*)(s->start<<PageShift), s->npages<<PageShift);
+ runtime_MHeap_Free(&runtime_mheap, s, 0);
+}
diff --git a/libgo/runtime/mem.c b/libgo/runtime/mem.c
index 78f7c51faf..6312480b69 100644
--- a/libgo/runtime/mem.c
+++ b/libgo/runtime/mem.c
@@ -26,19 +26,33 @@
static int dev_zero = -1;
#endif
-static _Bool
+static int32
addrspace_free(void *v __attribute__ ((unused)), uintptr n __attribute__ ((unused)))
{
#ifdef HAVE_MINCORE
size_t page_size = getpagesize();
- size_t off;
- char one_byte;
+ int32 errval;
+ uintptr chunk;
+ uintptr off;
+
+ // NOTE: vec must be just 1 byte long here.
+ // Mincore returns ENOMEM if any of the pages are unmapped,
+ // but we want to know that all of the pages are unmapped.
+ // To make these the same, we can only ask about one page
+ // at a time. See golang.org/issue/7476.
+ static byte vec[1];
errno = 0;
- for(off = 0; off < n; off += page_size)
- if(mincore((char *)v + off, page_size, (void *)&one_byte) != -1
- || errno != ENOMEM)
+ for(off = 0; off < n; off += chunk) {
+ chunk = page_size * sizeof vec;
+ if(chunk > (n - off))
+ chunk = n - off;
+ errval = mincore((char*)v + off, chunk, (void*)vec);
+ // ENOMEM means unmapped, which is what we want.
+ // Anything else we assume means the pages are mapped.
+ if(errval == 0 || errno != ENOMEM)
return 0;
+ }
#endif
return 1;
}
@@ -115,8 +129,27 @@ runtime_SysFree(void *v, uintptr n, uint64 *stat)
runtime_munmap(v, n);
}
+void
+runtime_SysFault(void *v, uintptr n)
+{
+ int fd = -1;
+
+#ifdef USE_DEV_ZERO
+ if (dev_zero == -1) {
+ dev_zero = open("/dev/zero", O_RDONLY);
+ if (dev_zero < 0) {
+ runtime_printf("open /dev/zero: errno=%d\n", errno);
+ exit(2);
+ }
+ }
+ fd = dev_zero;
+#endif
+
+ runtime_mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, fd, 0);
+}
+
void*
-runtime_SysReserve(void *v, uintptr n)
+runtime_SysReserve(void *v, uintptr n, bool *reserved)
{
int fd = -1;
void *p;
@@ -136,13 +169,14 @@ runtime_SysReserve(void *v, uintptr n)
// much address space. Instead, assume that the reservation is okay
// if we can reserve at least 64K and check the assumption in SysMap.
// Only user-mode Linux (UML) rejects these requests.
- if(sizeof(void*) == 8 && (uintptr)v >= 0xffffffffU) {
+ if(sizeof(void*) == 8 && (n >> 16) > 1LLU<<16) {
p = mmap_fixed(v, 64<<10, PROT_NONE, MAP_ANON|MAP_PRIVATE, fd, 0);
if (p != v) {
runtime_munmap(p, 64<<10);
return nil;
}
runtime_munmap(p, 64<<10);
+ *reserved = false;
return v;
}
@@ -153,11 +187,12 @@ runtime_SysReserve(void *v, uintptr n)
p = runtime_mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_NORESERVE, fd, 0);
if(p == MAP_FAILED)
return nil;
+ *reserved = true;
return p;
}
void
-runtime_SysMap(void *v, uintptr n, uint64 *stat)
+runtime_SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
{
void *p;
int fd = -1;
@@ -176,7 +211,7 @@ runtime_SysMap(void *v, uintptr n, uint64 *stat)
#endif
// On 64-bit, we don't actually have v reserved, so tread carefully.
- if(sizeof(void*) == 8 && (uintptr)v >= 0xffffffffU) {
+ if(!reserved) {
p = mmap_fixed(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, fd, 0);
if(p == MAP_FAILED && errno == ENOMEM)
runtime_throw("runtime: out of memory");
diff --git a/libgo/runtime/mfinal.c b/libgo/runtime/mfinal.c
deleted file mode 100644
index 625af528e1..0000000000
--- a/libgo/runtime/mfinal.c
+++ /dev/null
@@ -1,218 +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.
-
-#include "runtime.h"
-#include "arch.h"
-#include "malloc.h"
-#include "go-type.h"
-
-enum { debug = 0 };
-
-typedef struct Fin Fin;
-struct Fin
-{
- FuncVal *fn;
- const struct __go_func_type *ft;
- const struct __go_ptr_type *ot;
-};
-
-// Finalizer hash table. Direct hash, linear scan, at most 3/4 full.
-// Table size is power of 3 so that hash can be key % max.
-// Key[i] == (void*)-1 denotes free but formerly occupied entry
-// (doesn't stop the linear scan).
-// Key and val are separate tables because the garbage collector
-// must be instructed to ignore the pointers in key but follow the
-// pointers in val.
-typedef struct Fintab Fintab;
-struct Fintab
-{
- Lock;
- void **fkey;
- Fin *val;
- int32 nkey; // number of non-nil entries in key
- int32 ndead; // number of dead (-1) entries in key
- int32 max; // size of key, val allocations
-};
-
-#define TABSZ 17
-#define TAB(p) (&fintab[((uintptr)(p)>>3)%TABSZ])
-
-static struct {
- Fintab;
- uint8 pad[0 /* CacheLineSize - sizeof(Fintab) */];
-} fintab[TABSZ];
-
-static void
-addfintab(Fintab *t, void *k, FuncVal *fn, const struct __go_func_type *ft, const struct __go_ptr_type *ot)
-{
- int32 i, j;
-
- i = (uintptr)k % (uintptr)t->max;
- for(j=0; j<t->max; j++) {
- if(t->fkey[i] == nil) {
- t->nkey++;
- goto ret;
- }
- if(t->fkey[i] == (void*)-1) {
- t->ndead--;
- goto ret;
- }
- if(++i == t->max)
- i = 0;
- }
-
- // cannot happen - table is known to be non-full
- runtime_throw("finalizer table inconsistent");
-
-ret:
- t->fkey[i] = k;
- t->val[i].fn = fn;
- t->val[i].ft = ft;
- t->val[i].ot = ot;
-}
-
-static bool
-lookfintab(Fintab *t, void *k, bool del, Fin *f)
-{
- int32 i, j;
-
- if(t->max == 0)
- return false;
- i = (uintptr)k % (uintptr)t->max;
- for(j=0; j<t->max; j++) {
- if(t->fkey[i] == nil)
- return false;
- if(t->fkey[i] == k) {
- if(f)
- *f = t->val[i];
- if(del) {
- t->fkey[i] = (void*)-1;
- t->val[i].fn = nil;
- t->val[i].ft = nil;
- t->val[i].ot = nil;
- t->ndead++;
- }
- return true;
- }
- if(++i == t->max)
- i = 0;
- }
-
- // cannot happen - table is known to be non-full
- runtime_throw("finalizer table inconsistent");
- return false;
-}
-
-static void
-resizefintab(Fintab *tab)
-{
- Fintab newtab;
- void *k;
- int32 i;
-
- runtime_memclr((byte*)&newtab, sizeof newtab);
- newtab.max = tab->max;
- if(newtab.max == 0)
- newtab.max = 3*3*3;
- else if(tab->ndead < tab->nkey/2) {
- // grow table if not many dead values.
- // otherwise just rehash into table of same size.
- newtab.max *= 3;
- }
-
- newtab.fkey = runtime_mallocgc(newtab.max*sizeof newtab.fkey[0], 0, FlagNoInvokeGC|FlagNoScan);
- newtab.val = runtime_mallocgc(newtab.max*sizeof newtab.val[0], 0, FlagNoInvokeGC);
-
- for(i=0; i<tab->max; i++) {
- k = tab->fkey[i];
- if(k != nil && k != (void*)-1)
- addfintab(&newtab, k, tab->val[i].fn, tab->val[i].ft, tab->val[i].ot);
- }
-
- runtime_free(tab->fkey);
- runtime_free(tab->val);
-
- tab->fkey = newtab.fkey;
- tab->val = newtab.val;
- tab->nkey = newtab.nkey;
- tab->ndead = newtab.ndead;
- tab->max = newtab.max;
-}
-
-bool
-runtime_addfinalizer(void *p, FuncVal *f, const struct __go_func_type *ft, const struct __go_ptr_type *ot)
-{
- Fintab *tab;
- byte *base;
-
- if(debug) {
- if(!runtime_mlookup(p, &base, nil, nil) || p != base)
- runtime_throw("addfinalizer on invalid pointer");
- }
-
- tab = TAB(p);
- runtime_lock(tab);
- if(f == nil) {
- lookfintab(tab, p, true, nil);
- runtime_unlock(tab);
- return true;
- }
-
- if(lookfintab(tab, p, false, nil)) {
- runtime_unlock(tab);
- return false;
- }
-
- if(tab->nkey >= tab->max/2+tab->max/4) {
- // keep table at most 3/4 full:
- // allocate new table and rehash.
- resizefintab(tab);
- }
-
- addfintab(tab, p, f, ft, ot);
- runtime_setblockspecial(p, true);
- runtime_unlock(tab);
- return true;
-}
-
-// get finalizer; if del, delete finalizer.
-// caller is responsible for updating RefHasFinalizer (special) bit.
-bool
-runtime_getfinalizer(void *p, bool del, FuncVal **fn, const struct __go_func_type **ft, const struct __go_ptr_type **ot)
-{
- Fintab *tab;
- bool res;
- Fin f;
-
- tab = TAB(p);
- runtime_lock(tab);
- res = lookfintab(tab, p, del, &f);
- runtime_unlock(tab);
- if(res==false)
- return false;
- *fn = f.fn;
- *ft = f.ft;
- *ot = f.ot;
- return true;
-}
-
-void
-runtime_walkfintab(void (*fn)(void*), void (*addroot)(Obj))
-{
- void **key;
- void **ekey;
- int32 i;
-
- for(i=0; i<TABSZ; i++) {
- runtime_lock(&fintab[i]);
- key = fintab[i].fkey;
- ekey = key + fintab[i].max;
- for(; key < ekey; key++)
- if(*key != nil && *key != ((void*)-1))
- fn(*key);
- addroot((Obj){(byte*)&fintab[i].fkey, sizeof(void*), 0});
- addroot((Obj){(byte*)&fintab[i].val, sizeof(void*), 0});
- runtime_unlock(&fintab[i]);
- }
-}
diff --git a/libgo/runtime/mgc0.c b/libgo/runtime/mgc0.c
index b5a39d962a..662dd87576 100644
--- a/libgo/runtime/mgc0.c
+++ b/libgo/runtime/mgc0.c
@@ -2,7 +2,53 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Garbage collector.
+// Garbage collector (GC).
+//
+// GC is:
+// - mark&sweep
+// - mostly precise (with the exception of some C-allocated objects, assembly frames/arguments, etc)
+// - parallel (up to MaxGcproc threads)
+// - partially concurrent (mark is stop-the-world, while sweep is concurrent)
+// - non-moving/non-compacting
+// - full (non-partial)
+//
+// GC rate.
+// Next GC is after we've allocated an extra amount of memory proportional to
+// the amount already in use. The proportion is controlled by GOGC environment variable
+// (100 by default). If GOGC=100 and we're using 4M, we'll GC again when we get to 8M
+// (this mark is tracked in next_gc variable). This keeps the GC cost in linear
+// proportion to the allocation cost. Adjusting GOGC just changes the linear constant
+// (and also the amount of extra memory used).
+//
+// Concurrent sweep.
+// The sweep phase proceeds concurrently with normal program execution.
+// The heap is swept span-by-span both lazily (when a goroutine needs another span)
+// and concurrently in a background goroutine (this helps programs that are not CPU bound).
+// However, at the end of the stop-the-world GC phase we don't know the size of the live heap,
+// and so next_gc calculation is tricky and happens as follows.
+// At the end of the stop-the-world phase next_gc is conservatively set based on total
+// heap size; all spans are marked as "needs sweeping".
+// Whenever a span is swept, next_gc is decremented by GOGC*newly_freed_memory.
+// The background sweeper goroutine simply sweeps spans one-by-one bringing next_gc
+// closer to the target value. However, this is not enough to avoid over-allocating memory.
+// Consider that a goroutine wants to allocate a new span for a large object and
+// there are no free swept spans, but there are small-object unswept spans.
+// If the goroutine naively allocates a new span, it can surpass the yet-unknown
+// target next_gc value. In order to prevent such cases (1) when a goroutine needs
+// to allocate a new small-object span, it sweeps small-object spans for the same
+// object size until it frees at least one object; (2) when a goroutine needs to
+// allocate large-object span from heap, it sweeps spans until it frees at least
+// that many pages into heap. Together these two measures ensure that we don't surpass
+// target next_gc value by a large margin. There is an exception: if a goroutine sweeps
+// and frees two nonadjacent one-page spans to the heap, it will allocate a new two-page span,
+// but there can still be other one-page unswept spans which could be combined into a two-page span.
+// It's critical to ensure that no operations proceed on unswept spans (that would corrupt
+// mark bits in GC bitmap). During GC all mcaches are flushed into the central cache,
+// so they are empty. When a goroutine grabs a new span into mcache, it sweeps it.
+// When a goroutine explicitly frees an object or sets a finalizer, it ensures that
+// the span is swept (either by sweeping it, or by waiting for the concurrent sweep to finish).
+// The finalizer goroutine is kicked off only when all spans are swept.
+// When the next GC starts, it sweeps all not-yet-swept spans (if any).
#include <unistd.h>
@@ -10,7 +56,7 @@
#include "arch.h"
#include "malloc.h"
#include "mgc0.h"
-#include "race.h"
+#include "chan.h"
#include "go-type.h"
// Map gccgo field names to gc field names.
@@ -19,15 +65,13 @@
#define cap __capacity
// Iface aka __go_interface
#define tab __methods
-// Eface aka __go_empty_interface.
-#define type __type_descriptor
// Hmap aka __go_map
typedef struct __go_map Hmap;
// Type aka __go_type_descriptor
-#define kind __code
#define string __reflection
#define KindPtr GO_PTR
#define KindNoPointers GO_NO_POINTERS
+#define kindMask GO_CODE_MASK
// PtrType aka __go_ptr_type
#define elem __element_type
@@ -43,14 +87,11 @@ extern void * __splitstack_find_context (void *context[10], size_t *, void **,
enum {
Debug = 0,
- DebugMark = 0, // run second pass to check mark
CollectStats = 0,
- ScanStackByFrames = 0,
- IgnorePreciseGC = 0,
+ ConcurrentSweep = 1,
- // Four bits per word (see #defines below).
- wordsPerBitmapWord = sizeof(void*)*8/4,
- bitShift = sizeof(void*)*8/4,
+ WorkbufSize = 16*1024,
+ FinBlockSize = 4*1024,
handoffThreshold = 4,
IntermediateBufferCapacity = 64,
@@ -60,46 +101,53 @@ enum {
LOOP = 2,
PC_BITS = PRECISE | LOOP,
- // Pointer map
- BitsPerPointer = 2,
- BitsNoPointer = 0,
- BitsPointer = 1,
- BitsIface = 2,
- BitsEface = 3,
+ RootData = 0,
+ RootBss = 1,
+ RootFinalizers = 2,
+ RootSpanTypes = 3,
+ RootFlushCaches = 4,
+ RootCount = 5,
};
-// Bits in per-word bitmap.
-// #defines because enum might not be able to hold the values.
-//
-// Each word in the bitmap describes wordsPerBitmapWord words
-// of heap memory. There are 4 bitmap bits dedicated to each heap word,
-// so on a 64-bit system there is one bitmap word per 16 heap words.
-// The bits in the word are packed together by type first, then by
-// heap location, so each 64-bit bitmap word consists of, from top to bottom,
-// the 16 bitSpecial bits for the corresponding heap words, then the 16 bitMarked bits,
-// then the 16 bitNoScan/bitBlockBoundary bits, then the 16 bitAllocated bits.
-// This layout makes it easier to iterate over the bits of a given type.
-//
-// The bitmap starts at mheap.arena_start and extends *backward* from
-// there. On a 64-bit system the off'th word in the arena is tracked by
-// the off/16+1'th word before mheap.arena_start. (On a 32-bit system,
-// the only difference is that the divisor is 8.)
-//
-// To pull out the bits corresponding to a given pointer p, we use:
-//
-// off = p - (uintptr*)mheap.arena_start; // word offset
-// b = (uintptr*)mheap.arena_start - off/wordsPerBitmapWord - 1;
-// shift = off % wordsPerBitmapWord
-// bits = *b >> shift;
-// /* then test bits & bitAllocated, bits & bitMarked, etc. */
-//
-#define bitAllocated ((uintptr)1<<(bitShift*0))
-#define bitNoScan ((uintptr)1<<(bitShift*1)) /* when bitAllocated is set */
-#define bitMarked ((uintptr)1<<(bitShift*2)) /* when bitAllocated is set */
-#define bitSpecial ((uintptr)1<<(bitShift*3)) /* when bitAllocated is set - has finalizer or being profiled */
-#define bitBlockBoundary ((uintptr)1<<(bitShift*1)) /* when bitAllocated is NOT set */
+#define GcpercentUnknown (-2)
+
+// Initialized from $GOGC. GOGC=off means no gc.
+static int32 gcpercent = GcpercentUnknown;
+
+static FuncVal* poolcleanup;
+
+void sync_runtime_registerPoolCleanup(FuncVal*)
+ __asm__ (GOSYM_PREFIX "sync.runtime_registerPoolCleanup");
+
+void
+sync_runtime_registerPoolCleanup(FuncVal *f)
+{
+ poolcleanup = f;
+}
+
+static void
+clearpools(void)
+{
+ P *p, **pp;
+ MCache *c;
+
+ // clear sync.Pool's
+ if(poolcleanup != nil) {
+ __builtin_call_with_static_chain(poolcleanup->fn(),
+ poolcleanup);
+ }
-#define bitMask (bitBlockBoundary | bitAllocated | bitMarked | bitSpecial)
+ for(pp=runtime_allp; (p=*pp) != nil; pp++) {
+ // clear tinyalloc pool
+ c = p->mcache;
+ if(c != nil) {
+ c->tiny = nil;
+ c->tinysize = 0;
+ }
+ // clear defer pools
+ p->deferpool = nil;
+ }
+}
// Holding worldsema grants an M the right to try to stop the world.
// The procedure is:
@@ -116,11 +164,10 @@ enum {
//
uint32 runtime_worldsema = 1;
-// The size of Workbuf is N*PageSize.
typedef struct Workbuf Workbuf;
struct Workbuf
{
-#define SIZE (2*PageSize-sizeof(LFNode)-sizeof(uintptr))
+#define SIZE (WorkbufSize-sizeof(LFNode)-sizeof(uintptr))
LFNode node; // must be first
uintptr nobj;
Obj obj[SIZE/sizeof(Obj) - 1];
@@ -134,7 +181,7 @@ struct Finalizer
FuncVal *fn;
void *arg;
const struct __go_func_type *ft;
- const struct __go_ptr_type *ot;
+ const PtrType *ot;
};
typedef struct FinBlock FinBlock;
@@ -147,39 +194,40 @@ struct FinBlock
Finalizer fin[1];
};
-static G *fing;
-static FinBlock *finq; // list of finalizers that are to be executed
-static FinBlock *finc; // cache of free blocks
-static FinBlock *allfin; // list of all blocks
-static Lock finlock;
-static int32 fingwait;
+static Lock finlock; // protects the following variables
+static FinBlock *finq; // list of finalizers that are to be executed
+static FinBlock *finc; // cache of free blocks
+static FinBlock *allfin; // list of all blocks
+bool runtime_fingwait;
+bool runtime_fingwake;
-static void runfinq(void*);
+static Lock gclock;
+static G* fing;
+
+static void runfinq(void*);
+static void bgsweep(void*);
static Workbuf* getempty(Workbuf*);
static Workbuf* getfull(Workbuf*);
static void putempty(Workbuf*);
static Workbuf* handoff(Workbuf*);
static void gchelperstart(void);
+static void flushallmcaches(void);
+static void addstackroots(G *gp, Workbuf **wbufp);
static struct {
uint64 full; // lock-free list of full blocks
uint64 empty; // lock-free list of empty blocks
byte pad0[CacheLineSize]; // prevents false-sharing between full/empty and nproc/nwait
uint32 nproc;
+ int64 tstart;
volatile uint32 nwait;
volatile uint32 ndone;
- volatile uint32 debugmarkdone;
Note alldone;
ParFor *markfor;
- ParFor *sweepfor;
Lock;
byte *chunk;
uintptr nchunk;
-
- Obj *roots;
- uint32 nroot;
- uint32 rootcap;
} work __attribute__((aligned(8)));
enum {
@@ -216,13 +264,15 @@ static struct {
uint64 foundword;
uint64 foundspan;
} markonly;
+ uint32 nbgsweep;
+ uint32 npausesweep;
} gcstats;
// markonly marks an object. It returns true if the object
// has been marked by this function, false otherwise.
// This function doesn't append the object to any buffer.
static bool
-markonly(void *obj)
+markonly(const void *obj)
{
byte *p;
uintptr *bitp, bits, shift, x, xbits, off, j;
@@ -230,17 +280,17 @@ markonly(void *obj)
PageID k;
// Words outside the arena cannot be pointers.
- if((byte*)obj < runtime_mheap.arena_start || (byte*)obj >= runtime_mheap.arena_used)
+ if((const byte*)obj < runtime_mheap.arena_start || (const byte*)obj >= runtime_mheap.arena_used)
return false;
// obj may be a pointer to a live object.
// Try to find the beginning of the object.
// Round down to word boundary.
- obj = (void*)((uintptr)obj & ~((uintptr)PtrSize-1));
+ obj = (const void*)((uintptr)obj & ~((uintptr)PtrSize-1));
// Find bits for this word.
- off = (uintptr*)obj - (uintptr*)runtime_mheap.arena_start;
+ off = (const uintptr*)obj - (uintptr*)runtime_mheap.arena_start;
bitp = (uintptr*)runtime_mheap.arena_start - off/wordsPerBitmapWord - 1;
shift = off % wordsPerBitmapWord;
xbits = *bitp;
@@ -271,19 +321,19 @@ markonly(void *obj)
x = k;
x -= (uintptr)runtime_mheap.arena_start>>PageShift;
s = runtime_mheap.spans[x];
- if(s == nil || k < s->start || (byte*)obj >= s->limit || s->state != MSpanInUse)
+ if(s == nil || k < s->start || (const byte*)obj >= s->limit || s->state != MSpanInUse)
return false;
p = (byte*)((uintptr)s->start<<PageShift);
if(s->sizeclass == 0) {
obj = p;
} else {
uintptr size = s->elemsize;
- int32 i = ((byte*)obj - p)/size;
+ int32 i = ((const byte*)obj - p)/size;
obj = p+i*size;
}
// Now that we know the object header, reload bits.
- off = (uintptr*)obj - (uintptr*)runtime_mheap.arena_start;
+ off = (const uintptr*)obj - (uintptr*)runtime_mheap.arena_start;
bitp = (uintptr*)runtime_mheap.arena_start - off/wordsPerBitmapWord - 1;
shift = off % wordsPerBitmapWord;
xbits = *bitp;
@@ -325,6 +375,24 @@ struct PtrTarget
uintptr ti;
};
+typedef struct Scanbuf Scanbuf;
+struct Scanbuf
+{
+ struct {
+ PtrTarget *begin;
+ PtrTarget *end;
+ PtrTarget *pos;
+ } ptr;
+ struct {
+ Obj *begin;
+ Obj *end;
+ Obj *pos;
+ } obj;
+ Workbuf *wbuf;
+ Obj *wp;
+ uintptr nobj;
+};
+
typedef struct BufferList BufferList;
struct BufferList
{
@@ -335,8 +403,6 @@ struct BufferList
};
static BufferList bufferList[MaxGcproc];
-static Type *itabtype;
-
static void enqueue(Obj obj, Workbuf **_wbuf, Obj **_wp, uintptr *_nobj);
// flushptrbuf moves data from the PtrTarget buffer to the work buffer.
@@ -357,7 +423,7 @@ static void enqueue(Obj obj, Workbuf **_wbuf, Obj **_wp, uintptr *_nobj);
// flushptrbuf
// (find block start, mark and enqueue)
static void
-flushptrbuf(PtrTarget *ptrbuf, PtrTarget **ptrbufpos, Obj **_wp, Workbuf **_wbuf, uintptr *_nobj)
+flushptrbuf(Scanbuf *sbuf)
{
byte *p, *arena_start, *obj;
uintptr size, *bitp, bits, shift, j, x, xbits, off, nobj, ti, n;
@@ -365,17 +431,19 @@ flushptrbuf(PtrTarget *ptrbuf, PtrTarget **ptrbufpos, Obj **_wp, Workbuf **_wbuf
PageID k;
Obj *wp;
Workbuf *wbuf;
+ PtrTarget *ptrbuf;
PtrTarget *ptrbuf_end;
arena_start = runtime_mheap.arena_start;
- wp = *_wp;
- wbuf = *_wbuf;
- nobj = *_nobj;
+ wp = sbuf->wp;
+ wbuf = sbuf->wbuf;
+ nobj = sbuf->nobj;
- ptrbuf_end = *ptrbufpos;
- n = ptrbuf_end - ptrbuf;
- *ptrbufpos = ptrbuf;
+ ptrbuf = sbuf->ptr.begin;
+ ptrbuf_end = sbuf->ptr.pos;
+ n = ptrbuf_end - sbuf->ptr.begin;
+ sbuf->ptr.pos = sbuf->ptr.begin;
if(CollectStats) {
runtime_xadd64(&gcstats.ptr.sum, n);
@@ -394,150 +462,146 @@ flushptrbuf(PtrTarget *ptrbuf, PtrTarget **ptrbufpos, Obj **_wp, Workbuf **_wbuf
runtime_throw("ptrbuf has to be smaller than WorkBuf");
}
- // TODO(atom): This block is a branch of an if-then-else statement.
- // The single-threaded branch may be added in a next CL.
- {
- // Multi-threaded version.
+ while(ptrbuf < ptrbuf_end) {
+ obj = ptrbuf->p;
+ ti = ptrbuf->ti;
+ ptrbuf++;
- while(ptrbuf < ptrbuf_end) {
- obj = ptrbuf->p;
- ti = ptrbuf->ti;
- ptrbuf++;
+ // obj belongs to interval [mheap.arena_start, mheap.arena_used).
+ if(Debug > 1) {
+ if(obj < runtime_mheap.arena_start || obj >= runtime_mheap.arena_used)
+ runtime_throw("object is outside of mheap");
+ }
- // obj belongs to interval [mheap.arena_start, mheap.arena_used).
- if(Debug > 1) {
- if(obj < runtime_mheap.arena_start || obj >= runtime_mheap.arena_used)
- runtime_throw("object is outside of mheap");
- }
+ // obj may be a pointer to a live object.
+ // Try to find the beginning of the object.
- // obj may be a pointer to a live object.
- // Try to find the beginning of the object.
+ // Round down to word boundary.
+ if(((uintptr)obj & ((uintptr)PtrSize-1)) != 0) {
+ obj = (void*)((uintptr)obj & ~((uintptr)PtrSize-1));
+ ti = 0;
+ }
- // Round down to word boundary.
- if(((uintptr)obj & ((uintptr)PtrSize-1)) != 0) {
- obj = (void*)((uintptr)obj & ~((uintptr)PtrSize-1));
- ti = 0;
- }
+ // Find bits for this word.
+ off = (uintptr*)obj - (uintptr*)arena_start;
+ bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
+ shift = off % wordsPerBitmapWord;
+ xbits = *bitp;
+ bits = xbits >> shift;
+
+ // Pointing at the beginning of a block?
+ if((bits & (bitAllocated|bitBlockBoundary)) != 0) {
+ if(CollectStats)
+ runtime_xadd64(&gcstats.flushptrbuf.foundbit, 1);
+ goto found;
+ }
- // Find bits for this word.
- off = (uintptr*)obj - (uintptr*)arena_start;
- bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
- shift = off % wordsPerBitmapWord;
- xbits = *bitp;
- bits = xbits >> shift;
+ ti = 0;
- // Pointing at the beginning of a block?
- if((bits & (bitAllocated|bitBlockBoundary)) != 0) {
+ // Pointing just past the beginning?
+ // Scan backward a little to find a block boundary.
+ for(j=shift; j-->0; ) {
+ if(((xbits>>j) & (bitAllocated|bitBlockBoundary)) != 0) {
+ obj = (byte*)obj - (shift-j)*PtrSize;
+ shift = j;
+ bits = xbits>>shift;
if(CollectStats)
- runtime_xadd64(&gcstats.flushptrbuf.foundbit, 1);
+ runtime_xadd64(&gcstats.flushptrbuf.foundword, 1);
goto found;
}
+ }
- ti = 0;
-
- // Pointing just past the beginning?
- // Scan backward a little to find a block boundary.
- for(j=shift; j-->0; ) {
- if(((xbits>>j) & (bitAllocated|bitBlockBoundary)) != 0) {
- obj = (byte*)obj - (shift-j)*PtrSize;
- shift = j;
- bits = xbits>>shift;
- if(CollectStats)
- runtime_xadd64(&gcstats.flushptrbuf.foundword, 1);
- goto found;
- }
- }
-
- // Otherwise consult span table to find beginning.
- // (Manually inlined copy of MHeap_LookupMaybe.)
- k = (uintptr)obj>>PageShift;
- x = k;
- x -= (uintptr)arena_start>>PageShift;
- s = runtime_mheap.spans[x];
- if(s == nil || k < s->start || obj >= s->limit || s->state != MSpanInUse)
- continue;
- p = (byte*)((uintptr)s->start<<PageShift);
- if(s->sizeclass == 0) {
- obj = p;
- } else {
- size = s->elemsize;
- int32 i = ((byte*)obj - p)/size;
- obj = p+i*size;
- }
+ // Otherwise consult span table to find beginning.
+ // (Manually inlined copy of MHeap_LookupMaybe.)
+ k = (uintptr)obj>>PageShift;
+ x = k;
+ x -= (uintptr)arena_start>>PageShift;
+ s = runtime_mheap.spans[x];
+ if(s == nil || k < s->start || obj >= s->limit || s->state != MSpanInUse)
+ continue;
+ p = (byte*)((uintptr)s->start<<PageShift);
+ if(s->sizeclass == 0) {
+ obj = p;
+ } else {
+ size = s->elemsize;
+ int32 i = ((byte*)obj - p)/size;
+ obj = p+i*size;
+ }
- // Now that we know the object header, reload bits.
- off = (uintptr*)obj - (uintptr*)arena_start;
- bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
- shift = off % wordsPerBitmapWord;
- xbits = *bitp;
- bits = xbits >> shift;
- if(CollectStats)
- runtime_xadd64(&gcstats.flushptrbuf.foundspan, 1);
+ // Now that we know the object header, reload bits.
+ off = (uintptr*)obj - (uintptr*)arena_start;
+ bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
+ shift = off % wordsPerBitmapWord;
+ xbits = *bitp;
+ bits = xbits >> shift;
+ if(CollectStats)
+ runtime_xadd64(&gcstats.flushptrbuf.foundspan, 1);
- found:
- // Now we have bits, bitp, and shift correct for
- // obj pointing at the base of the object.
- // Only care about allocated and not marked.
- if((bits & (bitAllocated|bitMarked)) != bitAllocated)
- continue;
- if(work.nproc == 1)
- *bitp |= bitMarked<<shift;
- else {
- for(;;) {
- x = *bitp;
- if(x & (bitMarked<<shift))
- goto continue_obj;
- if(runtime_casp((void**)bitp, (void*)x, (void*)(x|(bitMarked<<shift))))
- break;
- }
+ found:
+ // Now we have bits, bitp, and shift correct for
+ // obj pointing at the base of the object.
+ // Only care about allocated and not marked.
+ if((bits & (bitAllocated|bitMarked)) != bitAllocated)
+ continue;
+ if(work.nproc == 1)
+ *bitp |= bitMarked<<shift;
+ else {
+ for(;;) {
+ x = *bitp;
+ if(x & (bitMarked<<shift))
+ goto continue_obj;
+ if(runtime_casp((void**)bitp, (void*)x, (void*)(x|(bitMarked<<shift))))
+ break;
}
+ }
- // If object has no pointers, don't need to scan further.
- if((bits & bitNoScan) != 0)
- continue;
+ // If object has no pointers, don't need to scan further.
+ if((bits & bitScan) == 0)
+ continue;
- // Ask span about size class.
- // (Manually inlined copy of MHeap_Lookup.)
- x = (uintptr)obj >> PageShift;
- x -= (uintptr)arena_start>>PageShift;
- s = runtime_mheap.spans[x];
+ // Ask span about size class.
+ // (Manually inlined copy of MHeap_Lookup.)
+ x = (uintptr)obj >> PageShift;
+ x -= (uintptr)arena_start>>PageShift;
+ s = runtime_mheap.spans[x];
- PREFETCH(obj);
+ PREFETCH(obj);
- *wp = (Obj){obj, s->elemsize, ti};
- wp++;
- nobj++;
- continue_obj:;
- }
+ *wp = (Obj){obj, s->elemsize, ti};
+ wp++;
+ nobj++;
+ continue_obj:;
+ }
- // If another proc wants a pointer, give it some.
- if(work.nwait > 0 && nobj > handoffThreshold && work.full == 0) {
- wbuf->nobj = nobj;
- wbuf = handoff(wbuf);
- nobj = wbuf->nobj;
- wp = wbuf->obj + nobj;
- }
+ // If another proc wants a pointer, give it some.
+ if(work.nwait > 0 && nobj > handoffThreshold && work.full == 0) {
+ wbuf->nobj = nobj;
+ wbuf = handoff(wbuf);
+ nobj = wbuf->nobj;
+ wp = wbuf->obj + nobj;
}
- *_wp = wp;
- *_wbuf = wbuf;
- *_nobj = nobj;
+ sbuf->wp = wp;
+ sbuf->wbuf = wbuf;
+ sbuf->nobj = nobj;
}
static void
-flushobjbuf(Obj *objbuf, Obj **objbufpos, Obj **_wp, Workbuf **_wbuf, uintptr *_nobj)
+flushobjbuf(Scanbuf *sbuf)
{
uintptr nobj, off;
Obj *wp, obj;
Workbuf *wbuf;
+ Obj *objbuf;
Obj *objbuf_end;
- wp = *_wp;
- wbuf = *_wbuf;
- nobj = *_nobj;
+ wp = sbuf->wp;
+ wbuf = sbuf->wbuf;
+ nobj = sbuf->nobj;
- objbuf_end = *objbufpos;
- *objbufpos = objbuf;
+ objbuf = sbuf->obj.begin;
+ objbuf_end = sbuf->obj.pos;
+ sbuf->obj.pos = sbuf->obj.begin;
while(objbuf < objbuf_end) {
obj = *objbuf++;
@@ -575,31 +639,30 @@ flushobjbuf(Obj *objbuf, Obj **objbufpos, Obj **_wp, Workbuf **_wbuf, uintptr *_
wp = wbuf->obj + nobj;
}
- *_wp = wp;
- *_wbuf = wbuf;
- *_nobj = nobj;
+ sbuf->wp = wp;
+ sbuf->wbuf = wbuf;
+ sbuf->nobj = nobj;
}
// Program that scans the whole block and treats every block element as a potential pointer
static uintptr defaultProg[2] = {PtrSize, GC_DEFAULT_PTR};
-#if 0
// Hchan program
static uintptr chanProg[2] = {0, GC_CHAN};
-#endif
// Local variables of a program fragment or loop
typedef struct Frame Frame;
struct Frame {
uintptr count, elemsize, b;
- uintptr *loop_or_ret;
+ const uintptr *loop_or_ret;
};
// Sanity check for the derived type info objti.
static void
checkptr(void *obj, uintptr objti)
{
- uintptr type, tisize, i, x;
+ uintptr *pc1, type, tisize, i, j, x;
+ const uintptr *pc2;
byte *objstart;
Type *t;
MSpan *s;
@@ -637,18 +700,16 @@ checkptr(void *obj, uintptr objti)
(runtime_strcmp((const char *)t->string->str, (const char*)"unsafe.Pointer") &&
// Runtime and gc think differently about closures.
runtime_strstr((const char *)t->string->str, (const char*)"struct { F uintptr") != (const char *)t->string->str)) {
-#if 0
pc1 = (uintptr*)objti;
- pc2 = (uintptr*)t->gc;
+ pc2 = (const uintptr*)t->__gc;
// A simple best-effort check until first GC_END.
for(j = 1; pc1[j] != GC_END && pc2[j] != GC_END; j++) {
if(pc1[j] != pc2[j]) {
- runtime_printf("invalid gc type info for '%s' at %p, type info %p, block info %p\n",
- t->string ? (const int8*)t->string->str : (const int8*)"?", j, pc1[j], pc2[j]);
+ runtime_printf("invalid gc type info for '%s', type info %p [%d]=%p, block info %p [%d]=%p\n",
+ t->string ? (const int8*)t->string->str : (const int8*)"?", pc1, (int32)j, pc1[j], pc2, (int32)j, pc2[j]);
runtime_throw("invalid gc type info");
}
}
-#endif
}
}
@@ -658,34 +719,28 @@ checkptr(void *obj, uintptr objti)
// a work list in the Workbuf* structures and loops in the main function
// body. Keeping an explicit work list is easier on the stack allocator and
// more efficient.
-//
-// wbuf: current work buffer
-// wp: storage for next queued pointer (write pointer)
-// nobj: number of queued objects
static void
-scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
+scanblock(Workbuf *wbuf, bool keepworking)
{
byte *b, *arena_start, *arena_used;
- uintptr n, i, end_b, elemsize, size, ti, objti, count /* , type */;
- uintptr *pc, precise_type, nominal_size;
-#if 0
- uintptr *chan_ret, chancap;
-#endif
+ uintptr n, i, end_b, elemsize, size, ti, objti, count, type, nobj;
+ uintptr precise_type, nominal_size;
+ const uintptr *pc, *chan_ret;
+ uintptr chancap;
void *obj;
- const Type *t;
+ const Type *t, *et;
Slice *sliceptr;
+ String *stringptr;
Frame *stack_ptr, stack_top, stack[GC_STACK_CAPACITY+4];
BufferList *scanbuffers;
- PtrTarget *ptrbuf, *ptrbuf_end, *ptrbufpos;
- Obj *objbuf, *objbuf_end, *objbufpos;
+ Scanbuf sbuf;
Eface *eface;
Iface *iface;
-#if 0
Hchan *chan;
- ChanType *chantype;
-#endif
+ const ChanType *chantype;
+ Obj *wp;
- if(sizeof(Workbuf) % PageSize != 0)
+ if(sizeof(Workbuf) % WorkbufSize != 0)
runtime_throw("scanblock: size of Workbuf is suboptimal");
// Memory arena parameters.
@@ -693,45 +748,52 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
arena_used = runtime_mheap.arena_used;
stack_ptr = stack+nelem(stack)-1;
-
+
precise_type = false;
nominal_size = 0;
- // Allocate ptrbuf
- {
- scanbuffers = &bufferList[runtime_m()->helpgc];
- ptrbuf = &scanbuffers->ptrtarget[0];
- ptrbuf_end = &scanbuffers->ptrtarget[0] + nelem(scanbuffers->ptrtarget);
- objbuf = &scanbuffers->obj[0];
- objbuf_end = &scanbuffers->obj[0] + nelem(scanbuffers->obj);
+ if(wbuf) {
+ nobj = wbuf->nobj;
+ wp = &wbuf->obj[nobj];
+ } else {
+ nobj = 0;
+ wp = nil;
}
- ptrbufpos = ptrbuf;
- objbufpos = objbuf;
+ // Initialize sbuf
+ scanbuffers = &bufferList[runtime_m()->helpgc];
+
+ sbuf.ptr.begin = sbuf.ptr.pos = &scanbuffers->ptrtarget[0];
+ sbuf.ptr.end = sbuf.ptr.begin + nelem(scanbuffers->ptrtarget);
+
+ sbuf.obj.begin = sbuf.obj.pos = &scanbuffers->obj[0];
+ sbuf.obj.end = sbuf.obj.begin + nelem(scanbuffers->obj);
+
+ sbuf.wbuf = wbuf;
+ sbuf.wp = wp;
+ sbuf.nobj = nobj;
// (Silence the compiler)
-#if 0
chan = nil;
chantype = nil;
chan_ret = nil;
-#endif
goto next_block;
for(;;) {
// Each iteration scans the block b of length n, queueing pointers in
// the work buffer.
- if(Debug > 1) {
- runtime_printf("scanblock %p %D\n", b, (int64)n);
- }
if(CollectStats) {
runtime_xadd64(&gcstats.nbytes, n);
- runtime_xadd64(&gcstats.obj.sum, nobj);
+ runtime_xadd64(&gcstats.obj.sum, sbuf.nobj);
runtime_xadd64(&gcstats.obj.cnt, 1);
}
- if(ti != 0 && false) {
+ if(ti != 0) {
+ if(Debug > 1) {
+ runtime_printf("scanblock %p %D ti %p\n", b, (int64)n, ti);
+ }
pc = (uintptr*)(ti & ~(uintptr)PC_BITS);
precise_type = (ti & PRECISE);
stack_top.elemsize = pc[0];
@@ -754,11 +816,10 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
runtime_throw("invalid gc type info");
}
}
- } else if(UseSpanType && false) {
+ } else if(UseSpanType) {
if(CollectStats)
runtime_xadd64(&gcstats.obj.notype, 1);
-#if 0
type = runtime_gettype(b);
if(type != 0) {
if(CollectStats)
@@ -767,13 +828,13 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
t = (Type*)(type & ~(uintptr)(PtrSize-1));
switch(type & (PtrSize-1)) {
case TypeInfo_SingleObject:
- pc = (uintptr*)t->gc;
+ pc = (const uintptr*)t->__gc;
precise_type = true; // type information about 'b' is precise
stack_top.count = 1;
stack_top.elemsize = pc[0];
break;
case TypeInfo_Array:
- pc = (uintptr*)t->gc;
+ pc = (const uintptr*)t->__gc;
if(pc[0] == 0)
goto next_block;
precise_type = true; // type information about 'b' is precise
@@ -783,20 +844,27 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
break;
case TypeInfo_Chan:
chan = (Hchan*)b;
- chantype = (ChanType*)t;
+ chantype = (const ChanType*)t;
chan_ret = nil;
pc = chanProg;
break;
default:
+ if(Debug > 1)
+ runtime_printf("scanblock %p %D type %p %S\n", b, (int64)n, type, *t->string);
runtime_throw("scanblock: invalid type");
return;
}
+ if(Debug > 1)
+ runtime_printf("scanblock %p %D type %p %S pc=%p\n", b, (int64)n, type, *t->string, pc);
} else {
pc = defaultProg;
+ if(Debug > 1)
+ runtime_printf("scanblock %p %D unknown type\n", b, (int64)n);
}
-#endif
} else {
pc = defaultProg;
+ if(Debug > 1)
+ runtime_printf("scanblock %p %D no span types\n", b, (int64)n);
}
if(IgnorePreciseGC)
@@ -804,7 +872,6 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
pc++;
stack_top.b = (uintptr)b;
-
end_b = (uintptr)b + n - PtrSize;
for(;;) {
@@ -817,6 +884,8 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
case GC_PTR:
obj = *(void**)(stack_top.b + pc[1]);
objti = pc[2];
+ if(Debug > 2)
+ runtime_printf("gc_ptr @%p: %p ti=%p\n", stack_top.b+pc[1], obj, objti);
pc += 3;
if(Debug)
checkptr(obj, objti);
@@ -824,6 +893,8 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
case GC_SLICE:
sliceptr = (Slice*)(stack_top.b + pc[1]);
+ if(Debug > 2)
+ runtime_printf("gc_slice @%p: %p/%D/%D\n", sliceptr, sliceptr->array, (int64)sliceptr->__count, (int64)sliceptr->cap);
if(sliceptr->cap != 0) {
obj = sliceptr->array;
// Can't use slice element type for scanning,
@@ -837,45 +908,56 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
case GC_APTR:
obj = *(void**)(stack_top.b + pc[1]);
+ if(Debug > 2)
+ runtime_printf("gc_aptr @%p: %p\n", stack_top.b+pc[1], obj);
pc += 2;
break;
case GC_STRING:
- obj = *(void**)(stack_top.b + pc[1]);
- markonly(obj);
+ stringptr = (String*)(stack_top.b + pc[1]);
+ if(Debug > 2)
+ runtime_printf("gc_string @%p: %p/%D\n", stack_top.b+pc[1], stringptr->str, (int64)stringptr->len);
+ if(stringptr->len != 0)
+ markonly(stringptr->str);
pc += 2;
continue;
case GC_EFACE:
eface = (Eface*)(stack_top.b + pc[1]);
pc += 2;
- if(eface->type == nil)
+ if(Debug > 2)
+ runtime_printf("gc_eface @%p: %p %p\n", stack_top.b+pc[1], eface->__type_descriptor, eface->__object);
+ if(eface->__type_descriptor == nil)
continue;
// eface->type
- t = eface->type;
+ t = eface->__type_descriptor;
if((const byte*)t >= arena_start && (const byte*)t < arena_used) {
union { const Type *tc; Type *tr; } u;
u.tc = t;
- *ptrbufpos++ = (struct PtrTarget){(void*)u.tr, 0};
- if(ptrbufpos == ptrbuf_end)
- flushptrbuf(ptrbuf, &ptrbufpos, &wp, &wbuf, &nobj);
+ *sbuf.ptr.pos++ = (PtrTarget){u.tr, 0};
+ if(sbuf.ptr.pos == sbuf.ptr.end)
+ flushptrbuf(&sbuf);
}
// eface->__object
if((byte*)eface->__object >= arena_start && (byte*)eface->__object < arena_used) {
- if(t->__size <= sizeof(void*)) {
- if((t->kind & KindNoPointers))
+ if(__go_is_pointer_type(t)) {
+ if((t->__code & KindNoPointers))
continue;
obj = eface->__object;
- if((t->kind & ~KindNoPointers) == KindPtr)
- // objti = (uintptr)((PtrType*)t)->elem->gc;
- objti = 0;
+ if((t->__code & kindMask) == KindPtr) {
+ // Only use type information if it is a pointer-containing type.
+ // This matches the GC programs written by cmd/gc/reflect.c's
+ // dgcsym1 in case TPTR32/case TPTR64. See rationale there.
+ et = ((const PtrType*)t)->elem;
+ if(!(et->__code & KindNoPointers))
+ objti = (uintptr)((const PtrType*)t)->elem->__gc;
+ }
} else {
obj = eface->__object;
- // objti = (uintptr)t->gc;
- objti = 0;
+ objti = (uintptr)t->__gc;
}
}
break;
@@ -883,33 +965,37 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
case GC_IFACE:
iface = (Iface*)(stack_top.b + pc[1]);
pc += 2;
+ if(Debug > 2)
+ runtime_printf("gc_iface @%p: %p/%p %p\n", stack_top.b+pc[1], iface->__methods[0], nil, iface->__object);
if(iface->tab == nil)
continue;
// iface->tab
if((byte*)iface->tab >= arena_start && (byte*)iface->tab < arena_used) {
- // *ptrbufpos++ = (struct PtrTarget){iface->tab, (uintptr)itabtype->gc};
- *ptrbufpos++ = (struct PtrTarget){iface->tab, 0};
- if(ptrbufpos == ptrbuf_end)
- flushptrbuf(ptrbuf, &ptrbufpos, &wp, &wbuf, &nobj);
+ *sbuf.ptr.pos++ = (PtrTarget){iface->tab, 0};
+ if(sbuf.ptr.pos == sbuf.ptr.end)
+ flushptrbuf(&sbuf);
}
// iface->data
if((byte*)iface->__object >= arena_start && (byte*)iface->__object < arena_used) {
- // t = iface->tab->type;
- t = nil;
- if(t->__size <= sizeof(void*)) {
- if((t->kind & KindNoPointers))
+ t = (const Type*)iface->tab[0];
+ if(__go_is_pointer_type(t)) {
+ if((t->__code & KindNoPointers))
continue;
obj = iface->__object;
- if((t->kind & ~KindNoPointers) == KindPtr)
- // objti = (uintptr)((const PtrType*)t)->elem->gc;
- objti = 0;
+ if((t->__code & kindMask) == KindPtr) {
+ // Only use type information if it is a pointer-containing type.
+ // This matches the GC programs written by cmd/gc/reflect.c's
+ // dgcsym1 in case TPTR32/case TPTR64. See rationale there.
+ et = ((const PtrType*)t)->elem;
+ if(!(et->__code & KindNoPointers))
+ objti = (uintptr)((const PtrType*)t)->elem->__gc;
+ }
} else {
obj = iface->__object;
- // objti = (uintptr)t->gc;
- objti = 0;
+ objti = (uintptr)t->__gc;
}
}
break;
@@ -917,11 +1003,13 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
case GC_DEFAULT_PTR:
while(stack_top.b <= end_b) {
obj = *(byte**)stack_top.b;
+ if(Debug > 2)
+ runtime_printf("gc_default_ptr @%p: %p\n", stack_top.b, obj);
stack_top.b += PtrSize;
if((byte*)obj >= arena_start && (byte*)obj < arena_used) {
- *ptrbufpos++ = (struct PtrTarget){obj, 0};
- if(ptrbufpos == ptrbuf_end)
- flushptrbuf(ptrbuf, &ptrbufpos, &wp, &wbuf, &nobj);
+ *sbuf.ptr.pos++ = (PtrTarget){obj, 0};
+ if(sbuf.ptr.pos == sbuf.ptr.end)
+ flushptrbuf(&sbuf);
}
}
goto next_block;
@@ -950,7 +1038,7 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
if(*(byte**)i != nil) {
// Found a value that may be a pointer.
// Do a rescan of the entire block.
- enqueue((Obj){b, n, 0}, &wbuf, &wp, &nobj);
+ enqueue((Obj){b, n, 0}, &sbuf.wbuf, &sbuf.wp, &sbuf.nobj);
if(CollectStats) {
runtime_xadd64(&gcstats.rescan, 1);
runtime_xadd64(&gcstats.rescanbytes, n);
@@ -987,7 +1075,7 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
// Stack push.
*stack_ptr-- = stack_top;
stack_top = (Frame){1, 0, stack_top.b + pc[1], pc+3 /*return address*/};
- pc = (uintptr*)((byte*)pc + *(int32*)(pc+2)); // target of the CALL instruction
+ pc = (const uintptr*)((const byte*)pc + *(const int32*)(pc+2)); // target of the CALL instruction
continue;
case GC_REGION:
@@ -996,21 +1084,24 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
objti = pc[3];
pc += 4;
- *objbufpos++ = (Obj){obj, size, objti};
- if(objbufpos == objbuf_end)
- flushobjbuf(objbuf, &objbufpos, &wp, &wbuf, &nobj);
+ if(Debug > 2)
+ runtime_printf("gc_region @%p: %D %p\n", stack_top.b+pc[1], (int64)size, objti);
+ *sbuf.obj.pos++ = (Obj){obj, size, objti};
+ if(sbuf.obj.pos == sbuf.obj.end)
+ flushobjbuf(&sbuf);
continue;
-#if 0
case GC_CHAN_PTR:
chan = *(Hchan**)(stack_top.b + pc[1]);
+ if(Debug > 2 && chan != nil)
+ runtime_printf("gc_chan_ptr @%p: %p/%D/%D %p\n", stack_top.b+pc[1], chan, (int64)chan->qcount, (int64)chan->dataqsiz, pc[2]);
if(chan == nil) {
pc += 3;
continue;
}
if(markonly(chan)) {
chantype = (ChanType*)pc[2];
- if(!(chantype->elem->kind & KindNoPointers)) {
+ if(!(chantype->elem->__code & KindNoPointers)) {
// Start chanProg.
chan_ret = pc+3;
pc = chanProg+1;
@@ -1023,7 +1114,7 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
case GC_CHAN:
// There are no heap pointers in struct Hchan,
// so we can ignore the leading sizeof(Hchan) bytes.
- if(!(chantype->elem->kind & KindNoPointers)) {
+ if(!(chantype->elem->__code & KindNoPointers)) {
// Channel's buffer follows Hchan immediately in memory.
// Size of buffer (cap(c)) is second int in the chan struct.
chancap = ((uintgo*)chan)[1];
@@ -1032,27 +1123,27 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
// in-use part of the circular buffer is scanned.
// (Channel routines zero the unused part, so the current
// code does not lead to leaks, it's just a little inefficient.)
- *objbufpos++ = (Obj){(byte*)chan+runtime_Hchansize, chancap*chantype->elem->size,
- (uintptr)chantype->elem->gc | PRECISE | LOOP};
- if(objbufpos == objbuf_end)
- flushobjbuf(objbuf, &objbufpos, &wp, &wbuf, &nobj);
+ *sbuf.obj.pos++ = (Obj){(byte*)chan+runtime_Hchansize, chancap*chantype->elem->__size,
+ (uintptr)chantype->elem->__gc | PRECISE | LOOP};
+ if(sbuf.obj.pos == sbuf.obj.end)
+ flushobjbuf(&sbuf);
}
}
if(chan_ret == nil)
goto next_block;
pc = chan_ret;
continue;
-#endif
default:
+ runtime_printf("runtime: invalid GC instruction %p at %p\n", pc[0], pc);
runtime_throw("scanblock: invalid GC instruction");
return;
}
if((byte*)obj >= arena_start && (byte*)obj < arena_used) {
- *ptrbufpos++ = (struct PtrTarget){obj, objti};
- if(ptrbufpos == ptrbuf_end)
- flushptrbuf(ptrbuf, &ptrbufpos, &wp, &wbuf, &nobj);
+ *sbuf.ptr.pos++ = (PtrTarget){obj, objti};
+ if(sbuf.ptr.pos == sbuf.ptr.end)
+ flushptrbuf(&sbuf);
}
}
@@ -1060,110 +1151,43 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
// Done scanning [b, b+n). Prepare for the next iteration of
// the loop by setting b, n, ti to the parameters for the next block.
- if(nobj == 0) {
- flushptrbuf(ptrbuf, &ptrbufpos, &wp, &wbuf, &nobj);
- flushobjbuf(objbuf, &objbufpos, &wp, &wbuf, &nobj);
+ if(sbuf.nobj == 0) {
+ flushptrbuf(&sbuf);
+ flushobjbuf(&sbuf);
- if(nobj == 0) {
+ if(sbuf.nobj == 0) {
if(!keepworking) {
- if(wbuf)
- putempty(wbuf);
- goto endscan;
+ if(sbuf.wbuf)
+ putempty(sbuf.wbuf);
+ return;
}
// Emptied our buffer: refill.
- wbuf = getfull(wbuf);
- if(wbuf == nil)
- goto endscan;
- nobj = wbuf->nobj;
- wp = wbuf->obj + wbuf->nobj;
+ sbuf.wbuf = getfull(sbuf.wbuf);
+ if(sbuf.wbuf == nil)
+ return;
+ sbuf.nobj = sbuf.wbuf->nobj;
+ sbuf.wp = sbuf.wbuf->obj + sbuf.wbuf->nobj;
}
}
// Fetch b from the work buffer.
- --wp;
- b = wp->p;
- n = wp->n;
- ti = wp->ti;
- nobj--;
+ --sbuf.wp;
+ b = sbuf.wp->p;
+ n = sbuf.wp->n;
+ ti = sbuf.wp->ti;
+ sbuf.nobj--;
}
-
-endscan:;
}
-// debug_scanblock is the debug copy of scanblock.
-// it is simpler, slower, single-threaded, recursive,
-// and uses bitSpecial as the mark bit.
-static void
-debug_scanblock(byte *b, uintptr n)
-{
- byte *obj, *p;
- void **vp;
- uintptr size, *bitp, bits, shift, i, xbits, off;
- MSpan *s;
-
- if(!DebugMark)
- runtime_throw("debug_scanblock without DebugMark");
-
- if((intptr)n < 0) {
- runtime_printf("debug_scanblock %p %D\n", b, (int64)n);
- runtime_throw("debug_scanblock");
- }
-
- // Align b to a word boundary.
- off = (uintptr)b & (PtrSize-1);
- if(off != 0) {
- b += PtrSize - off;
- n -= PtrSize - off;
- }
-
- vp = (void**)b;
- n /= PtrSize;
- for(i=0; i<(uintptr)n; i++) {
- obj = (byte*)vp[i];
-
- // Words outside the arena cannot be pointers.
- if((byte*)obj < runtime_mheap.arena_start || (byte*)obj >= runtime_mheap.arena_used)
- continue;
-
- // Round down to word boundary.
- obj = (void*)((uintptr)obj & ~((uintptr)PtrSize-1));
-
- // Consult span table to find beginning.
- s = runtime_MHeap_LookupMaybe(&runtime_mheap, obj);
- if(s == nil)
- continue;
-
- p = (byte*)((uintptr)s->start<<PageShift);
- size = s->elemsize;
- if(s->sizeclass == 0) {
- obj = p;
- } else {
- int32 i = ((byte*)obj - p)/size;
- obj = p+i*size;
- }
-
- // Now that we know the object header, reload bits.
- off = (uintptr*)obj - (uintptr*)runtime_mheap.arena_start;
- bitp = (uintptr*)runtime_mheap.arena_start - off/wordsPerBitmapWord - 1;
- shift = off % wordsPerBitmapWord;
- xbits = *bitp;
- bits = xbits >> shift;
-
- // Now we have bits, bitp, and shift correct for
- // obj pointing at the base of the object.
- // If not allocated or already marked, done.
- if((bits & bitAllocated) == 0 || (bits & bitSpecial) != 0) // NOTE: bitSpecial not bitMarked
- continue;
- *bitp |= bitSpecial<<shift;
- if(!(bits & bitMarked))
- runtime_printf("found unmarked block %p in %p\n", obj, vp+i);
-
- // If object has no pointers, don't need to scan further.
- if((bits & bitNoScan) != 0)
- continue;
+static struct root_list* roots;
- debug_scanblock(obj, size);
- }
+void
+__go_register_gc_roots (struct root_list* r)
+{
+ // FIXME: This needs locking if multiple goroutines can call
+ // dlopen simultaneously.
+ r->next = roots;
+ roots = r;
}
// Append obj to the work buffer.
@@ -1222,18 +1246,126 @@ enqueue(Obj obj, Workbuf **_wbuf, Obj **_wp, uintptr *_nobj)
}
static void
+enqueue1(Workbuf **wbufp, Obj obj)
+{
+ Workbuf *wbuf;
+
+ wbuf = *wbufp;
+ if(wbuf->nobj >= nelem(wbuf->obj))
+ *wbufp = wbuf = getempty(wbuf);
+ wbuf->obj[wbuf->nobj++] = obj;
+}
+
+static void
markroot(ParFor *desc, uint32 i)
{
- Obj *wp;
Workbuf *wbuf;
- uintptr nobj;
+ FinBlock *fb;
+ MHeap *h;
+ MSpan **allspans, *s;
+ uint32 spanidx, sg;
+ G *gp;
+ void *p;
USED(&desc);
- wp = nil;
- wbuf = nil;
- nobj = 0;
- enqueue(work.roots[i], &wbuf, &wp, &nobj);
- scanblock(wbuf, wp, nobj, false);
+ wbuf = getempty(nil);
+ // Note: if you add a case here, please also update heapdump.c:dumproots.
+ switch(i) {
+ case RootData:
+ // For gccgo this is both data and bss.
+ {
+ struct root_list *pl;
+
+ for(pl = roots; pl != nil; pl = pl->next) {
+ struct root *pr = &pl->roots[0];
+ while(1) {
+ void *decl = pr->decl;
+ if(decl == nil)
+ break;
+ enqueue1(&wbuf, (Obj){decl, pr->size, 0});
+ pr++;
+ }
+ }
+ }
+ break;
+
+ case RootBss:
+ // For gccgo we use this for all the other global roots.
+ enqueue1(&wbuf, (Obj){(byte*)&runtime_m0, sizeof runtime_m0, 0});
+ enqueue1(&wbuf, (Obj){(byte*)&runtime_g0, sizeof runtime_g0, 0});
+ enqueue1(&wbuf, (Obj){(byte*)&runtime_allg, sizeof runtime_allg, 0});
+ enqueue1(&wbuf, (Obj){(byte*)&runtime_allm, sizeof runtime_allm, 0});
+ enqueue1(&wbuf, (Obj){(byte*)&runtime_allp, sizeof runtime_allp, 0});
+ enqueue1(&wbuf, (Obj){(byte*)&work, sizeof work, 0});
+ runtime_proc_scan(&wbuf, enqueue1);
+ runtime_MProf_Mark(&wbuf, enqueue1);
+ runtime_time_scan(&wbuf, enqueue1);
+ runtime_netpoll_scan(&wbuf, enqueue1);
+ break;
+
+ case RootFinalizers:
+ for(fb=allfin; fb; fb=fb->alllink)
+ enqueue1(&wbuf, (Obj){(byte*)fb->fin, fb->cnt*sizeof(fb->fin[0]), 0});
+ break;
+
+ case RootSpanTypes:
+ // mark span types and MSpan.specials (to walk spans only once)
+ h = &runtime_mheap;
+ sg = h->sweepgen;
+ allspans = h->allspans;
+ for(spanidx=0; spanidx<runtime_mheap.nspan; spanidx++) {
+ Special *sp;
+ SpecialFinalizer *spf;
+
+ s = allspans[spanidx];
+ if(s->sweepgen != sg) {
+ runtime_printf("sweep %d %d\n", s->sweepgen, sg);
+ runtime_throw("gc: unswept span");
+ }
+ if(s->state != MSpanInUse)
+ continue;
+ // The garbage collector ignores type pointers stored in MSpan.types:
+ // - Compiler-generated types are stored outside of heap.
+ // - The reflect package has runtime-generated types cached in its data structures.
+ // The garbage collector relies on finding the references via that cache.
+ if(s->types.compression == MTypes_Words || s->types.compression == MTypes_Bytes)
+ markonly((byte*)s->types.data);
+ for(sp = s->specials; sp != nil; sp = sp->next) {
+ if(sp->kind != KindSpecialFinalizer)
+ continue;
+ // don't mark finalized object, but scan it so we
+ // retain everything it points to.
+ spf = (SpecialFinalizer*)sp;
+ // A finalizer can be set for an inner byte of an object, find object beginning.
+ p = (void*)((s->start << PageShift) + spf->offset/s->elemsize*s->elemsize);
+ enqueue1(&wbuf, (Obj){p, s->elemsize, 0});
+ enqueue1(&wbuf, (Obj){(void*)&spf->fn, PtrSize, 0});
+ enqueue1(&wbuf, (Obj){(void*)&spf->ft, PtrSize, 0});
+ enqueue1(&wbuf, (Obj){(void*)&spf->ot, PtrSize, 0});
+ }
+ }
+ break;
+
+ case RootFlushCaches:
+ flushallmcaches();
+ break;
+
+ default:
+ // the rest is scanning goroutine stacks
+ if(i - RootCount >= runtime_allglen)
+ runtime_throw("markroot: bad index");
+ gp = runtime_allg[i - RootCount];
+ // remember when we've first observed the G blocked
+ // needed only to output in traceback
+ if((gp->status == Gwaiting || gp->status == Gsyscall) && gp->waitsince == 0)
+ gp->waitsince = work.tstart;
+ addstackroots(gp, &wbuf);
+ break;
+
+ }
+
+ if(wbuf)
+ scanblock(wbuf, false);
}
// Get an empty work buffer off the work.empty list,
@@ -1336,32 +1468,22 @@ handoff(Workbuf *b)
}
static void
-addroot(Obj obj)
+addstackroots(G *gp, Workbuf **wbufp)
{
- uint32 cap;
- Obj *new;
-
- if(work.nroot >= work.rootcap) {
- cap = PageSize/sizeof(Obj);
- if(cap < 2*work.rootcap)
- cap = 2*work.rootcap;
- new = (Obj*)runtime_SysAlloc(cap*sizeof(Obj), &mstats.gc_sys);
- if(new == nil)
- runtime_throw("runtime: cannot allocate memory");
- if(work.roots != nil) {
- runtime_memmove(new, work.roots, work.rootcap*sizeof(Obj));
- runtime_SysFree(work.roots, work.rootcap*sizeof(Obj), &mstats.gc_sys);
- }
- work.roots = new;
- work.rootcap = cap;
+ switch(gp->status){
+ default:
+ runtime_printf("unexpected G.status %d (goroutine %p %D)\n", gp->status, gp, gp->goid);
+ runtime_throw("mark - bad status");
+ case Gdead:
+ return;
+ case Grunning:
+ runtime_throw("mark - world not stopped");
+ case Grunnable:
+ case Gsyscall:
+ case Gwaiting:
+ break;
}
- work.roots[work.nroot] = obj;
- work.nroot++;
-}
-static void
-addstackroots(G *gp)
-{
#ifdef USING_SPLIT_STACK
M *mp;
void* sp;
@@ -1399,11 +1521,11 @@ addstackroots(G *gp)
}
}
if(sp != nil) {
- addroot((Obj){sp, spsize, 0});
+ enqueue1(wbufp, (Obj){sp, spsize, 0});
while((sp = __splitstack_find(next_segment, next_sp,
&spsize, &next_segment,
&next_sp, &initial_sp)) != nil)
- addroot((Obj){sp, spsize, 0});
+ enqueue1(wbufp, (Obj){sp, spsize, 0});
}
#else
M *mp;
@@ -1425,137 +1547,23 @@ addstackroots(G *gp)
}
top = (byte*)gp->gcinitial_sp + gp->gcstack_size;
if(top > bottom)
- addroot((Obj){bottom, top - bottom, 0});
+ enqueue1(wbufp, (Obj){bottom, top - bottom, 0});
else
- addroot((Obj){top, bottom - top, 0});
+ enqueue1(wbufp, (Obj){top, bottom - top, 0});
#endif
}
-static void
-addfinroots(void *v)
-{
- uintptr size;
- void *base;
-
- size = 0;
- if(!runtime_mlookup(v, (byte**)&base, &size, nil) || !runtime_blockspecial(base))
- runtime_throw("mark - finalizer inconsistency");
-
- // do not mark the finalizer block itself. just mark the things it points at.
- addroot((Obj){base, size, 0});
-}
-
-static struct root_list* roots;
-
void
-__go_register_gc_roots (struct root_list* r)
-{
- // FIXME: This needs locking if multiple goroutines can call
- // dlopen simultaneously.
- r->next = roots;
- roots = r;
-}
-
-static void
-addroots(void)
+runtime_queuefinalizer(void *p, FuncVal *fn, const FuncType *ft, const PtrType *ot)
{
- struct root_list *pl;
- G *gp;
- FinBlock *fb;
- MSpan *s, **allspans;
- uint32 spanidx;
-
- work.nroot = 0;
-
- // mark data+bss.
- for(pl = roots; pl != nil; pl = pl->next) {
- struct root* pr = &pl->roots[0];
- while(1) {
- void *decl = pr->decl;
- if(decl == nil)
- break;
- addroot((Obj){decl, pr->size, 0});
- pr++;
- }
- }
-
- addroot((Obj){(byte*)&runtime_m0, sizeof runtime_m0, 0});
- addroot((Obj){(byte*)&runtime_g0, sizeof runtime_g0, 0});
- addroot((Obj){(byte*)&runtime_allg, sizeof runtime_allg, 0});
- addroot((Obj){(byte*)&runtime_allm, sizeof runtime_allm, 0});
- addroot((Obj){(byte*)&runtime_allp, sizeof runtime_allp, 0});
- runtime_proc_scan(addroot);
- runtime_MProf_Mark(addroot);
- runtime_time_scan(addroot);
- runtime_netpoll_scan(addroot);
-
- // MSpan.types
- allspans = runtime_mheap.allspans;
- for(spanidx=0; spanidx<runtime_mheap.nspan; spanidx++) {
- s = allspans[spanidx];
- if(s->state == MSpanInUse) {
- // The garbage collector ignores type pointers stored in MSpan.types:
- // - Compiler-generated types are stored outside of heap.
- // - The reflect package has runtime-generated types cached in its data structures.
- // The garbage collector relies on finding the references via that cache.
- switch(s->types.compression) {
- case MTypes_Empty:
- case MTypes_Single:
- break;
- case MTypes_Words:
- case MTypes_Bytes:
- markonly((byte*)s->types.data);
- break;
- }
- }
- }
-
- // stacks
- for(gp=runtime_allg; gp!=nil; gp=gp->alllink) {
- switch(gp->status){
- default:
- runtime_printf("unexpected G.status %d\n", gp->status);
- runtime_throw("mark - bad status");
- case Gdead:
- break;
- case Grunning:
- runtime_throw("mark - world not stopped");
- case Grunnable:
- case Gsyscall:
- case Gwaiting:
- addstackroots(gp);
- break;
- }
- }
-
- runtime_walkfintab(addfinroots, addroot);
-
- for(fb=allfin; fb; fb=fb->alllink)
- addroot((Obj){(byte*)fb->fin, fb->cnt*sizeof(fb->fin[0]), 0});
-
- addroot((Obj){(byte*)&work, sizeof work, 0});
-}
-
-static bool
-handlespecial(byte *p, uintptr size)
-{
- FuncVal *fn;
- const struct __go_func_type *ft;
- const struct __go_ptr_type *ot;
FinBlock *block;
Finalizer *f;
-
- if(!runtime_getfinalizer(p, true, &fn, &ft, &ot)) {
- runtime_setblockspecial(p, false);
- runtime_MProf_Free(p, size);
- return false;
- }
runtime_lock(&finlock);
if(finq == nil || finq->cnt == finq->cap) {
if(finc == nil) {
- finc = runtime_persistentalloc(PageSize, 0, &mstats.gc_sys);
- finc->cap = (PageSize - sizeof(FinBlock)) / sizeof(Finalizer) + 1;
+ finc = runtime_persistentalloc(FinBlockSize, 0, &mstats.gc_sys);
+ finc->cap = (FinBlockSize - sizeof(FinBlock)) / sizeof(Finalizer) + 1;
finc->alllink = allfin;
allfin = finc;
}
@@ -1570,36 +1578,84 @@ handlespecial(byte *p, uintptr size)
f->ft = ft;
f->ot = ot;
f->arg = p;
+ runtime_fingwake = true;
runtime_unlock(&finlock);
- return true;
+}
+
+void
+runtime_iterate_finq(void (*callback)(FuncVal*, void*, const FuncType*, const PtrType*))
+{
+ FinBlock *fb;
+ Finalizer *f;
+ int32 i;
+
+ for(fb = allfin; fb; fb = fb->alllink) {
+ for(i = 0; i < fb->cnt; i++) {
+ f = &fb->fin[i];
+ callback(f->fn, f->arg, f->ft, f->ot);
+ }
+ }
+}
+
+void
+runtime_MSpan_EnsureSwept(MSpan *s)
+{
+ M *m = runtime_m();
+ G *g = runtime_g();
+ uint32 sg;
+
+ // Caller must disable preemption.
+ // Otherwise when this function returns the span can become unswept again
+ // (if GC is triggered on another goroutine).
+ if(m->locks == 0 && m->mallocing == 0 && g != m->g0)
+ runtime_throw("MSpan_EnsureSwept: m is not locked");
+
+ sg = runtime_mheap.sweepgen;
+ if(runtime_atomicload(&s->sweepgen) == sg)
+ return;
+ if(runtime_cas(&s->sweepgen, sg-2, sg-1)) {
+ runtime_MSpan_Sweep(s);
+ return;
+ }
+ // unfortunate condition, and we don't have efficient means to wait
+ while(runtime_atomicload(&s->sweepgen) != sg)
+ runtime_osyield();
}
// Sweep frees or collects finalizers for blocks not marked in the mark phase.
// It clears the mark bits in preparation for the next GC round.
-static void
-sweepspan(ParFor *desc, uint32 idx)
+// Returns true if the span was returned to heap.
+bool
+runtime_MSpan_Sweep(MSpan *s)
{
M *m;
- int32 cl, n, npages;
- uintptr size;
+ int32 cl, n, npages, nfree;
+ uintptr size, off, *bitp, shift, bits;
+ uint32 sweepgen;
byte *p;
MCache *c;
byte *arena_start;
MLink head, *end;
- int32 nfree;
byte *type_data;
byte compression;
uintptr type_data_inc;
- MSpan *s;
+ MLink *x;
+ Special *special, **specialp, *y;
+ bool res, sweepgenset;
m = runtime_m();
- USED(&desc);
- s = runtime_mheap.allspans[idx];
- if(s->state != MSpanInUse)
- return;
+ // It's critical that we enter this function with preemption disabled,
+ // GC must not start while we are in the middle of this function.
+ if(m->locks == 0 && m->mallocing == 0 && runtime_g() != m->g0)
+ runtime_throw("MSpan_Sweep: m is not locked");
+ sweepgen = runtime_mheap.sweepgen;
+ if(s->state != MSpanInUse || s->sweepgen != sweepgen-1) {
+ runtime_printf("MSpan_Sweep: state=%d sweepgen=%d mheap.sweepgen=%d\n",
+ s->state, s->sweepgen, sweepgen);
+ runtime_throw("MSpan_Sweep: bad span state");
+ }
arena_start = runtime_mheap.arena_start;
- p = (byte*)(s->start << PageShift);
cl = s->sizeclass;
size = s->elemsize;
if(cl == 0) {
@@ -1609,10 +1665,52 @@ sweepspan(ParFor *desc, uint32 idx)
npages = runtime_class_to_allocnpages[cl];
n = (npages << PageShift) / size;
}
+ res = false;
nfree = 0;
end = &head;
c = m->mcache;
-
+ sweepgenset = false;
+
+ // mark any free objects in this span so we don't collect them
+ for(x = s->freelist; x != nil; x = x->next) {
+ // This is markonly(x) but faster because we don't need
+ // atomic access and we're guaranteed to be pointing at
+ // the head of a valid object.
+ off = (uintptr*)x - (uintptr*)runtime_mheap.arena_start;
+ bitp = (uintptr*)runtime_mheap.arena_start - off/wordsPerBitmapWord - 1;
+ shift = off % wordsPerBitmapWord;
+ *bitp |= bitMarked<<shift;
+ }
+
+ // Unlink & free special records for any objects we're about to free.
+ specialp = &s->specials;
+ special = *specialp;
+ while(special != nil) {
+ // A finalizer can be set for an inner byte of an object, find object beginning.
+ p = (byte*)(s->start << PageShift) + special->offset/size*size;
+ off = (uintptr*)p - (uintptr*)arena_start;
+ bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
+ shift = off % wordsPerBitmapWord;
+ bits = *bitp>>shift;
+ if((bits & (bitAllocated|bitMarked)) == bitAllocated) {
+ // Find the exact byte for which the special was setup
+ // (as opposed to object beginning).
+ p = (byte*)(s->start << PageShift) + special->offset;
+ // about to free object: splice out special record
+ y = special;
+ special = special->next;
+ *specialp = special;
+ if(!runtime_freespecial(y, p, size, false)) {
+ // stop freeing of object if it has a finalizer
+ *bitp |= bitMarked << shift;
+ }
+ } else {
+ // object is still live: keep special record
+ specialp = &special->next;
+ special = *specialp;
+ }
+ }
+
type_data = (byte*)s->types.data;
type_data_inc = sizeof(uintptr);
compression = s->types.compression;
@@ -1626,9 +1724,8 @@ sweepspan(ParFor *desc, uint32 idx)
// Sweep through n objects of given size starting at p.
// This thread owns the span now, so it can manipulate
// the block bitmap without atomic operations.
+ p = (byte*)(s->start << PageShift);
for(; n > 0; n--, p += size, type_data+=type_data_inc) {
- uintptr off, *bitp, shift, bits;
-
off = (uintptr*)p - (uintptr*)arena_start;
bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
shift = off % wordsPerBitmapWord;
@@ -1638,33 +1735,32 @@ sweepspan(ParFor *desc, uint32 idx)
continue;
if((bits & bitMarked) != 0) {
- if(DebugMark) {
- if(!(bits & bitSpecial))
- runtime_printf("found spurious mark on %p\n", p);
- *bitp &= ~(bitSpecial<<shift);
- }
*bitp &= ~(bitMarked<<shift);
continue;
}
- // Special means it has a finalizer or is being profiled.
- // In DebugMark mode, the bit has been coopted so
- // we have to assume all blocks are special.
- if(DebugMark || (bits & bitSpecial) != 0) {
- if(handlespecial(p, size))
- continue;
- }
+ if(runtime_debug.allocfreetrace)
+ runtime_tracefree(p, size);
- // Mark freed; restore block boundary bit.
- *bitp = (*bitp & ~(bitMask<<shift)) | (bitBlockBoundary<<shift);
+ // Clear mark and scan bits.
+ *bitp &= ~((bitScan|bitMarked)<<shift);
if(cl == 0) {
// Free large span.
runtime_unmarkspan(p, 1<<PageShift);
- *(uintptr*)p = (uintptr)0xdeaddeaddeaddeadll; // needs zeroing
- runtime_MHeap_Free(&runtime_mheap, s, 1);
+ s->needzero = 1;
+ // important to set sweepgen before returning it to heap
+ runtime_atomicstore(&s->sweepgen, sweepgen);
+ sweepgenset = true;
+ // See note about SysFault vs SysFree in malloc.goc.
+ if(runtime_debug.efence)
+ runtime_SysFault(p, size);
+ else
+ runtime_MHeap_Free(&runtime_mheap, s, 1);
c->local_nlargefree++;
c->local_largefree += size;
+ runtime_xadd64(&mstats.next_gc, -(uint64)(size * (gcpercent + 100)/100));
+ res = true;
} else {
// Free small object.
switch(compression) {
@@ -1675,19 +1771,114 @@ sweepspan(ParFor *desc, uint32 idx)
*(byte*)type_data = 0;
break;
}
- if(size > sizeof(uintptr))
+ if(size > 2*sizeof(uintptr))
((uintptr*)p)[1] = (uintptr)0xdeaddeaddeaddeadll; // mark as "needs to be zeroed"
-
+ else if(size > sizeof(uintptr))
+ ((uintptr*)p)[1] = 0;
+
end->next = (MLink*)p;
end = (MLink*)p;
nfree++;
}
}
- if(nfree) {
+ // We need to set s->sweepgen = h->sweepgen only when all blocks are swept,
+ // because of the potential for a concurrent free/SetFinalizer.
+ // But we need to set it before we make the span available for allocation
+ // (return it to heap or mcentral), because allocation code assumes that a
+ // span is already swept if available for allocation.
+
+ if(!sweepgenset && nfree == 0) {
+ // The span must be in our exclusive ownership until we update sweepgen,
+ // check for potential races.
+ if(s->state != MSpanInUse || s->sweepgen != sweepgen-1) {
+ runtime_printf("MSpan_Sweep: state=%d sweepgen=%d mheap.sweepgen=%d\n",
+ s->state, s->sweepgen, sweepgen);
+ runtime_throw("MSpan_Sweep: bad span state after sweep");
+ }
+ runtime_atomicstore(&s->sweepgen, sweepgen);
+ }
+ if(nfree > 0) {
c->local_nsmallfree[cl] += nfree;
c->local_cachealloc -= nfree * size;
- runtime_MCentral_FreeSpan(&runtime_mheap.central[cl], s, nfree, head.next, end);
+ runtime_xadd64(&mstats.next_gc, -(uint64)(nfree * size * (gcpercent + 100)/100));
+ res = runtime_MCentral_FreeSpan(&runtime_mheap.central[cl], s, nfree, head.next, end);
+ //MCentral_FreeSpan updates sweepgen
+ }
+ return res;
+}
+
+// State of background sweep.
+// Protected by gclock.
+static struct
+{
+ G* g;
+ bool parked;
+
+ MSpan** spans;
+ uint32 nspan;
+ uint32 spanidx;
+} sweep;
+
+// background sweeping goroutine
+static void
+bgsweep(void* dummy __attribute__ ((unused)))
+{
+ runtime_g()->issystem = 1;
+ for(;;) {
+ while(runtime_sweepone() != (uintptr)-1) {
+ gcstats.nbgsweep++;
+ runtime_gosched();
+ }
+ runtime_lock(&gclock);
+ if(!runtime_mheap.sweepdone) {
+ // It's possible if GC has happened between sweepone has
+ // returned -1 and gclock lock.
+ runtime_unlock(&gclock);
+ continue;
+ }
+ sweep.parked = true;
+ runtime_g()->isbackground = true;
+ runtime_parkunlock(&gclock, "GC sweep wait");
+ runtime_g()->isbackground = false;
+ }
+}
+
+// sweeps one span
+// returns number of pages returned to heap, or -1 if there is nothing to sweep
+uintptr
+runtime_sweepone(void)
+{
+ M *m = runtime_m();
+ MSpan *s;
+ uint32 idx, sg;
+ uintptr npages;
+
+ // increment locks to ensure that the goroutine is not preempted
+ // in the middle of sweep thus leaving the span in an inconsistent state for next GC
+ m->locks++;
+ sg = runtime_mheap.sweepgen;
+ for(;;) {
+ idx = runtime_xadd(&sweep.spanidx, 1) - 1;
+ if(idx >= sweep.nspan) {
+ runtime_mheap.sweepdone = true;
+ m->locks--;
+ return (uintptr)-1;
+ }
+ s = sweep.spans[idx];
+ if(s->state != MSpanInUse) {
+ s->sweepgen = sg;
+ continue;
+ }
+ if(s->sweepgen != sg-2 || !runtime_cas(&s->sweepgen, sg-2, sg-1))
+ continue;
+ if(s->incache)
+ runtime_throw("sweep of incache span");
+ npages = s->npages;
+ if(!runtime_MSpan_Sweep(s))
+ npages = 0;
+ m->locks--;
+ return npages;
}
}
@@ -1699,7 +1890,7 @@ dumpspan(uint32 idx)
byte *p;
byte *arena_start;
MSpan *s;
- bool allocated, special;
+ bool allocated;
s = runtime_mheap.allspans[idx];
if(s->state != MSpanInUse)
@@ -1726,7 +1917,6 @@ dumpspan(uint32 idx)
bits = *bitp>>shift;
allocated = ((bits & bitAllocated) != 0);
- special = ((bits & bitSpecial) != 0);
for(i=0; (uint32)i<size; i+=sizeof(void*)) {
if(column == 0) {
@@ -1734,7 +1924,6 @@ dumpspan(uint32 idx)
}
if(i == 0) {
runtime_printf(allocated ? "(" : "[");
- runtime_printf(special ? "@" : "");
runtime_printf("%p: ", p+i);
} else {
runtime_printf(" ");
@@ -1772,40 +1961,22 @@ runtime_gchelper(void)
{
uint32 nproc;
+ runtime_m()->traceback = 2;
gchelperstart();
// parallel mark for over gc roots
runtime_parfordo(work.markfor);
// help other threads scan secondary blocks
- scanblock(nil, nil, 0, true);
+ scanblock(nil, true);
- if(DebugMark) {
- // wait while the main thread executes mark(debug_scanblock)
- while(runtime_atomicload(&work.debugmarkdone) == 0)
- runtime_usleep(10);
- }
-
- runtime_parfordo(work.sweepfor);
bufferList[runtime_m()->helpgc].busy = 0;
nproc = work.nproc; // work.nproc can change right after we increment work.ndone
if(runtime_xadd(&work.ndone, +1) == nproc-1)
runtime_notewakeup(&work.alldone);
+ runtime_m()->traceback = 0;
}
-#define GcpercentUnknown (-2)
-
-// Initialized from $GOGC. GOGC=off means no gc.
-//
-// Next gc is after we've allocated an extra amount of
-// memory proportional to the amount already in use.
-// If gcpercent=100 and we're using 4M, we'll gc again
-// when we get to 8M. This keeps the gc cost in linear
-// proportion to the allocation cost. Adjusting gcpercent
-// just changes the linear constant (and also the amount of
-// extra memory used).
-static int32 gcpercent = GcpercentUnknown;
-
static void
cachestats(void)
{
@@ -1821,12 +1992,25 @@ cachestats(void)
}
static void
-updatememstats(GCStats *stats)
+flushallmcaches(void)
+{
+ P *p, **pp;
+ MCache *c;
+
+ // Flush MCache's to MCentral.
+ for(pp=runtime_allp; (p=*pp) != nil; pp++) {
+ c = p->mcache;
+ if(c==nil)
+ continue;
+ runtime_MCache_ReleaseAll(c);
+ }
+}
+
+void
+runtime_updatememstats(GCStats *stats)
{
M *mp;
MSpan *s;
- MCache *c;
- P *p, **pp;
uint32 i;
uint64 stacks_inuse, smallfree;
uint64 *src, *dst;
@@ -1867,12 +2051,7 @@ updatememstats(GCStats *stats)
}
// Flush MCache's to MCentral.
- for(pp=runtime_allp; (p=*pp) != nil; pp++) {
- c = p->mcache;
- if(c==nil)
- continue;
- runtime_MCache_ReleaseAll(c);
- }
+ flushallmcaches();
// Aggregate local stats.
cachestats();
@@ -1914,6 +2093,7 @@ updatememstats(GCStats *stats)
struct gc_args
{
int64 start_time; // start time of GC in ns (just before stoptheworld)
+ bool eagersweep;
};
static void gc(struct gc_args *args);
@@ -1932,6 +2112,8 @@ readgogc(void)
return runtime_atoi(p);
}
+// force = 1 - do GC regardless of current heap usage
+// force = 2 - go GC and eager sweep
void
runtime_gc(int32 force)
{
@@ -1974,7 +2156,7 @@ runtime_gc(int32 force)
return;
runtime_semacquire(&runtime_worldsema, false);
- if(!force && mstats.heap_alloc < mstats.next_gc) {
+ if(force==0 && mstats.heap_alloc < mstats.next_gc) {
// typically threads which lost the race to grab
// worldsema exit here when gc is done.
runtime_semrelease(&runtime_worldsema);
@@ -1983,23 +2165,26 @@ runtime_gc(int32 force)
// Ok, we're doing it! Stop everybody else
a.start_time = runtime_nanotime();
+ a.eagersweep = force >= 2;
m->gcing = 1;
runtime_stoptheworld();
+ 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). Also an
// enabler for copyable stacks.
for(i = 0; i < (runtime_debug.gctrace > 1 ? 2 : 1); i++) {
+ if(i > 0)
+ a.start_time = runtime_nanotime();
// switch to g0, call gc(&a), then switch back
g = runtime_g();
g->param = &a;
g->status = Gwaiting;
g->waitreason = "garbage collection";
runtime_mcall(mgc);
- // record a new start time in case we're going around again
- a.start_time = runtime_nanotime();
m = runtime_m();
}
@@ -2011,19 +2196,13 @@ runtime_gc(int32 force)
m->locks--;
// now that gc is done, kick off finalizer thread if needed
- if(finq != nil) {
- runtime_lock(&finlock);
- // kick off or wake up goroutine to run queued finalizers
- if(fing == nil)
- fing = __go_go(runfinq, nil);
- else if(fingwait) {
- fingwait = 0;
- runtime_ready(fing);
- }
- runtime_unlock(&finlock);
+ if(!ConcurrentSweep) {
+ // give the queued finalizers, if any, a chance to run
+ runtime_gosched();
+ } else {
+ // For gccgo, let other goroutines run.
+ runtime_gosched();
}
- // give the queued finalizers, if any, a chance to run
- runtime_gosched();
}
static void
@@ -2040,80 +2219,71 @@ gc(struct gc_args *args)
{
M *m;
int64 t0, t1, t2, t3, t4;
- uint64 heap0, heap1, obj0, obj1, ninstr;
+ uint64 heap0, heap1, obj, ninstr;
GCStats stats;
- M *mp;
uint32 i;
// Eface eface;
m = runtime_m();
+ if(runtime_debug.allocfreetrace)
+ runtime_tracegc();
+
+ m->traceback = 2;
t0 = args->start_time;
+ work.tstart = args->start_time;
if(CollectStats)
runtime_memclr((byte*)&gcstats, sizeof(gcstats));
- for(mp=runtime_allm; mp; mp=mp->alllink)
- runtime_settype_flush(mp);
-
- heap0 = 0;
- obj0 = 0;
- if(runtime_debug.gctrace) {
- updatememstats(nil);
- heap0 = mstats.heap_alloc;
- obj0 = mstats.nmalloc - mstats.nfree;
- }
-
m->locks++; // disable gc during mallocs in parforalloc
if(work.markfor == nil)
work.markfor = runtime_parforalloc(MaxGcproc);
- if(work.sweepfor == nil)
- work.sweepfor = runtime_parforalloc(MaxGcproc);
m->locks--;
- if(itabtype == nil) {
- // get C pointer to the Go type "itab"
- // runtime_gc_itab_ptr(&eface);
- // itabtype = ((PtrType*)eface.type)->elem;
- }
+ t1 = 0;
+ if(runtime_debug.gctrace)
+ t1 = runtime_nanotime();
+
+ // Sweep what is not sweeped by bgsweep.
+ while(runtime_sweepone() != (uintptr)-1)
+ gcstats.npausesweep++;
work.nwait = 0;
work.ndone = 0;
- work.debugmarkdone = 0;
work.nproc = runtime_gcprocs();
- addroots();
- runtime_parforsetup(work.markfor, work.nproc, work.nroot, nil, false, markroot);
- runtime_parforsetup(work.sweepfor, work.nproc, runtime_mheap.nspan, nil, true, sweepspan);
+ runtime_parforsetup(work.markfor, work.nproc, RootCount + runtime_allglen, nil, false, markroot);
if(work.nproc > 1) {
runtime_noteclear(&work.alldone);
runtime_helpgc(work.nproc);
}
- t1 = runtime_nanotime();
+ t2 = 0;
+ if(runtime_debug.gctrace)
+ t2 = runtime_nanotime();
gchelperstart();
runtime_parfordo(work.markfor);
- scanblock(nil, nil, 0, true);
+ scanblock(nil, true);
- if(DebugMark) {
- for(i=0; i<work.nroot; i++)
- debug_scanblock(work.roots[i].p, work.roots[i].n);
- runtime_atomicstore(&work.debugmarkdone, 1);
- }
- t2 = runtime_nanotime();
+ t3 = 0;
+ if(runtime_debug.gctrace)
+ t3 = runtime_nanotime();
- runtime_parfordo(work.sweepfor);
bufferList[m->helpgc].busy = 0;
- t3 = runtime_nanotime();
-
if(work.nproc > 1)
runtime_notesleep(&work.alldone);
cachestats();
+ // next_gc calculation is tricky with concurrent sweep since we don't know size of live heap
+ // estimate what was live heap size after previous GC (for tracing only)
+ heap0 = mstats.next_gc*100/(gcpercent+100);
+ // conservatively set next_gc to high value assuming that everything is live
+ // concurrent/lazy sweep will reduce this number while discovering new garbage
mstats.next_gc = mstats.heap_alloc+mstats.heap_alloc*gcpercent/100;
t4 = runtime_nanotime();
- mstats.last_gc = t4;
+ 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_total_ns += t4 - t0;
mstats.numgc++;
@@ -2121,22 +2291,29 @@ gc(struct gc_args *args)
runtime_printf("pause %D\n", t4-t0);
if(runtime_debug.gctrace) {
- updatememstats(&stats);
heap1 = mstats.heap_alloc;
- obj1 = mstats.nmalloc - mstats.nfree;
+ runtime_updatememstats(&stats);
+ if(heap1 != mstats.heap_alloc) {
+ runtime_printf("runtime: mstats skew: heap=%D/%D\n", heap1, mstats.heap_alloc);
+ runtime_throw("mstats skew");
+ }
+ obj = mstats.nmalloc - mstats.nfree;
- stats.nprocyield += work.sweepfor->nprocyield;
- stats.nosyield += work.sweepfor->nosyield;
- stats.nsleep += work.sweepfor->nsleep;
+ stats.nprocyield += work.markfor->nprocyield;
+ stats.nosyield += work.markfor->nosyield;
+ stats.nsleep += work.markfor->nsleep;
- runtime_printf("gc%d(%d): %D+%D+%D ms, %D -> %D MB %D -> %D (%D-%D) objects,"
+ runtime_printf("gc%d(%d): %D+%D+%D+%D us, %D -> %D MB, %D (%D-%D) objects,"
+ " %d/%d/%d sweeps,"
" %D(%D) handoff, %D(%D) steal, %D/%D/%D yields\n",
- mstats.numgc, work.nproc, (t2-t1)/1000000, (t3-t2)/1000000, (t1-t0+t4-t3)/1000000,
- heap0>>20, heap1>>20, obj0, obj1,
+ mstats.numgc, work.nproc, (t1-t0)/1000, (t2-t1)/1000, (t3-t2)/1000, (t4-t3)/1000,
+ heap0>>20, heap1>>20, obj,
mstats.nmalloc, mstats.nfree,
+ sweep.nspan, gcstats.nbgsweep, gcstats.npausesweep,
stats.nhandoff, stats.nhandoffcnt,
- work.sweepfor->nsteal, work.sweepfor->nstealcnt,
+ work.markfor->nsteal, work.markfor->nstealcnt,
stats.nprocyield, stats.nosyield, stats.nsleep);
+ gcstats.nbgsweep = gcstats.npausesweep = 0;
if(CollectStats) {
runtime_printf("scan: %D bytes, %D objects, %D untyped, %D types from MSpan\n",
gcstats.nbytes, gcstats.obj.cnt, gcstats.obj.notype, gcstats.obj.typelookup);
@@ -2163,9 +2340,47 @@ gc(struct gc_args *args)
}
}
+ // We cache current runtime_mheap.allspans array in sweep.spans,
+ // because the former can be resized and freed.
+ // Otherwise we would need to take heap lock every time
+ // we want to convert span index to span pointer.
+
+ // Free the old cached array if necessary.
+ if(sweep.spans && sweep.spans != runtime_mheap.allspans)
+ runtime_SysFree(sweep.spans, sweep.nspan*sizeof(sweep.spans[0]), &mstats.other_sys);
+ // Cache the current array.
+ runtime_mheap.sweepspans = runtime_mheap.allspans;
+ runtime_mheap.sweepgen += 2;
+ runtime_mheap.sweepdone = false;
+ sweep.spans = runtime_mheap.allspans;
+ sweep.nspan = runtime_mheap.nspan;
+ sweep.spanidx = 0;
+
+ // Temporary disable concurrent sweep, because we see failures on builders.
+ if(ConcurrentSweep && !args->eagersweep) {
+ runtime_lock(&gclock);
+ if(sweep.g == nil)
+ sweep.g = __go_go(bgsweep, nil);
+ else if(sweep.parked) {
+ sweep.parked = false;
+ runtime_ready(sweep.g);
+ }
+ runtime_unlock(&gclock);
+ } else {
+ // Sweep all spans eagerly.
+ while(runtime_sweepone() != (uintptr)-1)
+ gcstats.npausesweep++;
+ // Do an additional mProf_GC, because all 'free' events are now real as well.
+ runtime_MProf_GC();
+ }
+
runtime_MProf_GC();
+ m->traceback = 0;
}
+extern uintptr runtime_sizeof_C_MStats
+ __asm__ (GOSYM_PREFIX "runtime.Sizeof_C_MStats");
+
void runtime_ReadMemStats(MStats *)
__asm__ (GOSYM_PREFIX "runtime.ReadMemStats");
@@ -2182,8 +2397,10 @@ runtime_ReadMemStats(MStats *stats)
m = runtime_m();
m->gcing = 1;
runtime_stoptheworld();
- updatememstats(nil);
- *stats = mstats;
+ runtime_updatememstats(nil);
+ // Size of the trailing by_size array differs between Go and C,
+ // NumSizeClasses was changed, but we can not change Go struct because of backward compatibility.
+ runtime_memmove(stats, &mstats, runtime_sizeof_C_MStats);
m->gcing = 0;
m->locks++;
runtime_semrelease(&runtime_worldsema);
@@ -2225,13 +2442,9 @@ runtime_debug_readGCStats(Slice *pauses)
pauses->__count = n+3;
}
-intgo runtime_debug_setGCPercent(intgo)
- __asm__("runtime_debug.setGCPercent");
-
-intgo
-runtime_debug_setGCPercent(intgo in)
-{
- intgo out;
+int32
+runtime_setgcpercent(int32 in) {
+ int32 out;
runtime_lock(&runtime_mheap);
if(gcpercent == GcpercentUnknown)
@@ -2267,18 +2480,35 @@ runfinq(void* dummy __attribute__ ((unused)))
Eface ef;
Iface iface;
+ // This function blocks for long periods of time, and because it is written in C
+ // we have no liveness information. Zero everything so that uninitialized pointers
+ // do not cause memory leaks.
+ f = nil;
+ fb = nil;
+ next = nil;
+ i = 0;
+ ef.__type_descriptor = nil;
+ ef.__object = nil;
+
+ // force flush to memory
+ USED(&f);
+ USED(&fb);
+ USED(&next);
+ USED(&i);
+ USED(&ef);
+
for(;;) {
runtime_lock(&finlock);
fb = finq;
finq = nil;
if(fb == nil) {
- fingwait = 1;
- runtime_park(runtime_unlock, &finlock, "finalizer wait");
+ runtime_fingwait = true;
+ runtime_g()->isbackground = true;
+ runtime_parkunlock(&finlock, "finalizer wait");
+ runtime_g()->isbackground = false;
continue;
}
runtime_unlock(&finlock);
- if(raceenabled)
- runtime_racefingo();
for(; fb; fb=next) {
next = fb->next;
for(i=0; i<(uint32)fb->cnt; i++) {
@@ -2287,12 +2517,12 @@ runfinq(void* dummy __attribute__ ((unused)))
f = &fb->fin[i];
fint = ((const Type**)f->ft->__in.array)[0];
- if(fint->kind == KindPtr) {
+ if((fint->__code & kindMask) == KindPtr) {
// direct use of pointer
param = &f->arg;
} else if(((const InterfaceType*)fint)->__methods.__count == 0) {
// convert to empty interface
- ef.type = (const Type*)f->ot;
+ ef.__type_descriptor = (const Type*)f->ot;
ef.__object = f->arg;
param = &ef;
} else {
@@ -2311,74 +2541,92 @@ runfinq(void* dummy __attribute__ ((unused)))
f->ot = nil;
}
fb->cnt = 0;
+ runtime_lock(&finlock);
fb->next = finc;
finc = fb;
+ runtime_unlock(&finlock);
}
+
+ // Zero everything that's dead, to avoid memory leaks.
+ // See comment at top of function.
+ f = nil;
+ fb = nil;
+ next = nil;
+ i = 0;
+ ef.__type_descriptor = nil;
+ ef.__object = nil;
runtime_gc(1); // trigger another gc to clean up the finalized objects, if possible
}
}
-// mark the block at v of size n as allocated.
-// If noscan is true, mark it as not needing scanning.
void
-runtime_markallocated(void *v, uintptr n, bool noscan)
+runtime_createfing(void)
{
- uintptr *b, obits, bits, off, shift;
+ if(fing != nil)
+ return;
+ // Here we use gclock instead of finlock,
+ // because newproc1 can allocate, which can cause on-demand span sweep,
+ // which can queue finalizers, which would deadlock.
+ runtime_lock(&gclock);
+ if(fing == nil)
+ fing = __go_go(runfinq, nil);
+ runtime_unlock(&gclock);
+}
- if(0)
- runtime_printf("markallocated %p+%p\n", v, n);
+G*
+runtime_wakefing(void)
+{
+ G *res;
- if((byte*)v+n > (byte*)runtime_mheap.arena_used || (byte*)v < runtime_mheap.arena_start)
- runtime_throw("markallocated: bad pointer");
+ res = nil;
+ runtime_lock(&finlock);
+ if(runtime_fingwait && runtime_fingwake) {
+ runtime_fingwait = false;
+ runtime_fingwake = false;
+ res = fing;
+ }
+ runtime_unlock(&finlock);
+ return res;
+}
+
+void
+runtime_marknogc(void *v)
+{
+ uintptr *b, off, shift;
off = (uintptr*)v - (uintptr*)runtime_mheap.arena_start; // word offset
b = (uintptr*)runtime_mheap.arena_start - off/wordsPerBitmapWord - 1;
shift = off % wordsPerBitmapWord;
+ *b = (*b & ~(bitAllocated<<shift)) | bitBlockBoundary<<shift;
+}
- for(;;) {
- obits = *b;
- bits = (obits & ~(bitMask<<shift)) | (bitAllocated<<shift);
- if(noscan)
- bits |= bitNoScan<<shift;
- if(runtime_gomaxprocs == 1) {
- *b = bits;
- break;
- } else {
- // more than one goroutine is potentially running: use atomic op
- if(runtime_casp((void**)b, (void*)obits, (void*)bits))
- break;
- }
- }
+void
+runtime_markscan(void *v)
+{
+ uintptr *b, off, shift;
+
+ off = (uintptr*)v - (uintptr*)runtime_mheap.arena_start; // word offset
+ b = (uintptr*)runtime_mheap.arena_start - off/wordsPerBitmapWord - 1;
+ shift = off % wordsPerBitmapWord;
+ *b |= bitScan<<shift;
}
-// mark the block at v of size n as freed.
+// mark the block at v as freed.
void
-runtime_markfreed(void *v, uintptr n)
+runtime_markfreed(void *v)
{
- uintptr *b, obits, bits, off, shift;
+ uintptr *b, off, shift;
if(0)
- runtime_printf("markfreed %p+%p\n", v, n);
+ runtime_printf("markfreed %p\n", v);
- if((byte*)v+n > (byte*)runtime_mheap.arena_used || (byte*)v < runtime_mheap.arena_start)
+ if((byte*)v > (byte*)runtime_mheap.arena_used || (byte*)v < runtime_mheap.arena_start)
runtime_throw("markfreed: bad pointer");
off = (uintptr*)v - (uintptr*)runtime_mheap.arena_start; // word offset
b = (uintptr*)runtime_mheap.arena_start - off/wordsPerBitmapWord - 1;
shift = off % wordsPerBitmapWord;
-
- for(;;) {
- obits = *b;
- bits = (obits & ~(bitMask<<shift)) | (bitBlockBoundary<<shift);
- if(runtime_gomaxprocs == 1) {
- *b = bits;
- break;
- } else {
- // more than one goroutine is potentially running: use atomic op
- if(runtime_casp((void**)b, (void*)obits, (void*)bits))
- break;
- }
- }
+ *b = (*b & ~(bitMask<<shift)) | (bitAllocated<<shift);
}
// check that the block at v of size n is marked freed.
@@ -2410,15 +2658,28 @@ runtime_checkfreed(void *v, uintptr n)
void
runtime_markspan(void *v, uintptr size, uintptr n, bool leftover)
{
- uintptr *b, off, shift;
+ uintptr *b, *b0, off, shift, i, x;
byte *p;
if((byte*)v+size*n > (byte*)runtime_mheap.arena_used || (byte*)v < runtime_mheap.arena_start)
runtime_throw("markspan: bad pointer");
+ if(runtime_checking) {
+ // bits should be all zero at the start
+ off = (byte*)v + size - runtime_mheap.arena_start;
+ b = (uintptr*)(runtime_mheap.arena_start - off/wordsPerBitmapWord);
+ for(i = 0; i < size/PtrSize/wordsPerBitmapWord; i++) {
+ if(b[i] != 0)
+ runtime_throw("markspan: span bits not zero");
+ }
+ }
+
p = v;
if(leftover) // mark a boundary just past end of last block too
n++;
+
+ b0 = nil;
+ x = 0;
for(; n-- > 0; p += size) {
// Okay to use non-atomic ops here, because we control
// the entire span, and each bitmap word has bits for only
@@ -2427,8 +2688,15 @@ runtime_markspan(void *v, uintptr size, uintptr n, bool leftover)
off = (uintptr*)p - (uintptr*)runtime_mheap.arena_start; // word offset
b = (uintptr*)runtime_mheap.arena_start - off/wordsPerBitmapWord - 1;
shift = off % wordsPerBitmapWord;
- *b = (*b & ~(bitMask<<shift)) | (bitBlockBoundary<<shift);
+ if(b0 != b) {
+ if(b0 != nil)
+ *b0 = x;
+ b0 = b;
+ x = 0;
+ }
+ x |= bitAllocated<<shift;
}
+ *b0 = x;
}
// unmark the span of memory at v of length n bytes.
@@ -2457,50 +2725,6 @@ runtime_unmarkspan(void *v, uintptr n)
*b-- = 0;
}
-bool
-runtime_blockspecial(void *v)
-{
- uintptr *b, off, shift;
-
- if(DebugMark)
- return true;
-
- off = (uintptr*)v - (uintptr*)runtime_mheap.arena_start;
- b = (uintptr*)runtime_mheap.arena_start - off/wordsPerBitmapWord - 1;
- shift = off % wordsPerBitmapWord;
-
- return (*b & (bitSpecial<<shift)) != 0;
-}
-
-void
-runtime_setblockspecial(void *v, bool s)
-{
- uintptr *b, off, shift, bits, obits;
-
- if(DebugMark)
- return;
-
- off = (uintptr*)v - (uintptr*)runtime_mheap.arena_start;
- b = (uintptr*)runtime_mheap.arena_start - off/wordsPerBitmapWord - 1;
- shift = off % wordsPerBitmapWord;
-
- for(;;) {
- obits = *b;
- if(s)
- bits = obits | (bitSpecial<<shift);
- else
- bits = obits & ~(bitSpecial<<shift);
- if(runtime_gomaxprocs == 1) {
- *b = bits;
- break;
- } else {
- // more than one goroutine is potentially running: use atomic op
- if(runtime_casp((void**)b, (void*)obits, (void*)bits))
- break;
- }
- }
-}
-
void
runtime_MHeap_MapBits(MHeap *h)
{
@@ -2516,12 +2740,12 @@ runtime_MHeap_MapBits(MHeap *h)
n = (h->arena_used - h->arena_start) / wordsPerBitmapWord;
n = ROUND(n, bitmapChunk);
+ n = ROUND(n, PageSize);
+ page_size = getpagesize();
+ n = ROUND(n, page_size);
if(h->bitmap_mapped >= n)
return;
- page_size = getpagesize();
- n = (n+page_size-1) & ~(page_size-1);
-
- runtime_SysMap(h->arena_start - n, n - h->bitmap_mapped, &mstats.gc_sys);
+ runtime_SysMap(h->arena_start - n, n - h->bitmap_mapped, h->arena_reserved, &mstats.gc_sys);
h->bitmap_mapped = n;
}
diff --git a/libgo/runtime/mgc0.h b/libgo/runtime/mgc0.h
index f8abe6c9c1..16000d1ae2 100644
--- a/libgo/runtime/mgc0.h
+++ b/libgo/runtime/mgc0.h
@@ -44,3 +44,44 @@ enum {
// - at most GC_STACK_CAPACITY allocations because of GC_ARRAY_START
GC_STACK_CAPACITY = 8,
};
+
+enum {
+ ScanStackByFrames = 1,
+ IgnorePreciseGC = 0,
+
+ // Four bits per word (see #defines below).
+ wordsPerBitmapWord = sizeof(void*)*8/4,
+ bitShift = sizeof(void*)*8/4,
+};
+
+// Bits in per-word bitmap.
+// #defines because enum might not be able to hold the values.
+//
+// Each word in the bitmap describes wordsPerBitmapWord words
+// of heap memory. There are 4 bitmap bits dedicated to each heap word,
+// so on a 64-bit system there is one bitmap word per 16 heap words.
+// The bits in the word are packed together by type first, then by
+// heap location, so each 64-bit bitmap word consists of, from top to bottom,
+// the 16 bitMarked bits for the corresponding heap words,
+// then the 16 bitScan/bitBlockBoundary bits, then the 16 bitAllocated bits.
+// This layout makes it easier to iterate over the bits of a given type.
+//
+// The bitmap starts at mheap.arena_start and extends *backward* from
+// there. On a 64-bit system the off'th word in the arena is tracked by
+// the off/16+1'th word before mheap.arena_start. (On a 32-bit system,
+// the only difference is that the divisor is 8.)
+//
+// To pull out the bits corresponding to a given pointer p, we use:
+//
+// off = p - (uintptr*)mheap.arena_start; // word offset
+// b = (uintptr*)mheap.arena_start - off/wordsPerBitmapWord - 1;
+// shift = off % wordsPerBitmapWord
+// bits = *b >> shift;
+// /* then test bits & bitAllocated, bits & bitMarked, etc. */
+//
+#define bitAllocated ((uintptr)1<<(bitShift*0)) /* block start; eligible for garbage collection */
+#define bitScan ((uintptr)1<<(bitShift*1)) /* when bitAllocated is set */
+#define bitMarked ((uintptr)1<<(bitShift*2)) /* when bitAllocated is set */
+#define bitBlockBoundary ((uintptr)1<<(bitShift*1)) /* when bitAllocated is NOT set - mark for FlagNoGC objects */
+
+#define bitMask (bitAllocated | bitScan | bitMarked)
diff --git a/libgo/runtime/mheap.c b/libgo/runtime/mheap.c
index 1b8ab79160..793915ef44 100644
--- a/libgo/runtime/mheap.c
+++ b/libgo/runtime/mheap.c
@@ -41,7 +41,10 @@ RecordSpan(void *vh, byte *p)
runtime_throw("runtime: cannot allocate memory");
if(h->allspans) {
runtime_memmove(all, h->allspans, h->nspancap*sizeof(all[0]));
- runtime_SysFree(h->allspans, h->nspancap*sizeof(all[0]), &mstats.other_sys);
+ // Don't free the old array if it's referenced by sweep.
+ // See the comment in mgc0.c.
+ if(h->allspans != runtime_mheap.sweepspans)
+ runtime_SysFree(h->allspans, h->nspancap*sizeof(all[0]), &mstats.other_sys);
}
h->allspans = all;
h->nspancap = cap;
@@ -57,10 +60,15 @@ runtime_MHeap_Init(MHeap *h)
runtime_FixAlloc_Init(&h->spanalloc, sizeof(MSpan), RecordSpan, h, &mstats.mspan_sys);
runtime_FixAlloc_Init(&h->cachealloc, sizeof(MCache), nil, nil, &mstats.mcache_sys);
+ runtime_FixAlloc_Init(&h->specialfinalizeralloc, sizeof(SpecialFinalizer), nil, nil, &mstats.other_sys);
+ runtime_FixAlloc_Init(&h->specialprofilealloc, sizeof(SpecialProfile), nil, nil, &mstats.other_sys);
// h->mapcache needs no init
- for(i=0; i<nelem(h->free); i++)
+ for(i=0; i<nelem(h->free); i++) {
runtime_MSpanList_Init(&h->free[i]);
- runtime_MSpanList_Init(&h->large);
+ runtime_MSpanList_Init(&h->busy[i]);
+ }
+ runtime_MSpanList_Init(&h->freelarge);
+ runtime_MSpanList_Init(&h->busylarge);
for(i=0; i<nelem(h->central); i++)
runtime_MCentral_Init(&h->central[i], i);
}
@@ -80,14 +88,90 @@ runtime_MHeap_MapSpans(MHeap *h)
n = ROUND(n, pagesize);
if(h->spans_mapped >= n)
return;
- runtime_SysMap((byte*)h->spans + h->spans_mapped, n - h->spans_mapped, &mstats.other_sys);
+ runtime_SysMap((byte*)h->spans + h->spans_mapped, n - h->spans_mapped, h->arena_reserved, &mstats.other_sys);
h->spans_mapped = n;
}
+// Sweeps spans in list until reclaims at least npages into heap.
+// Returns the actual number of pages reclaimed.
+static uintptr
+MHeap_ReclaimList(MHeap *h, MSpan *list, uintptr npages)
+{
+ MSpan *s;
+ uintptr n;
+ uint32 sg;
+
+ n = 0;
+ sg = runtime_mheap.sweepgen;
+retry:
+ for(s = list->next; s != list; s = s->next) {
+ if(s->sweepgen == sg-2 && runtime_cas(&s->sweepgen, sg-2, sg-1)) {
+ runtime_MSpanList_Remove(s);
+ // swept spans are at the end of the list
+ runtime_MSpanList_InsertBack(list, s);
+ runtime_unlock(h);
+ n += runtime_MSpan_Sweep(s);
+ runtime_lock(h);
+ if(n >= npages)
+ return n;
+ // the span could have been moved elsewhere
+ goto retry;
+ }
+ if(s->sweepgen == sg-1) {
+ // the span is being sweept by background sweeper, skip
+ continue;
+ }
+ // already swept empty span,
+ // all subsequent ones must also be either swept or in process of sweeping
+ break;
+ }
+ return n;
+}
+
+// Sweeps and reclaims at least npage pages into heap.
+// Called before allocating npage pages.
+static void
+MHeap_Reclaim(MHeap *h, uintptr npage)
+{
+ uintptr reclaimed, n;
+
+ // First try to sweep busy spans with large objects of size >= npage,
+ // this has good chances of reclaiming the necessary space.
+ for(n=npage; n < nelem(h->busy); n++) {
+ if(MHeap_ReclaimList(h, &h->busy[n], npage))
+ return; // Bingo!
+ }
+
+ // Then -- even larger objects.
+ if(MHeap_ReclaimList(h, &h->busylarge, npage))
+ return; // Bingo!
+
+ // Now try smaller objects.
+ // One such object is not enough, so we need to reclaim several of them.
+ reclaimed = 0;
+ for(n=0; n < npage && n < nelem(h->busy); n++) {
+ reclaimed += MHeap_ReclaimList(h, &h->busy[n], npage-reclaimed);
+ if(reclaimed >= npage)
+ return;
+ }
+
+ // Now sweep everything that is not yet swept.
+ runtime_unlock(h);
+ for(;;) {
+ n = runtime_sweepone();
+ if(n == (uintptr)-1) // all spans are swept
+ break;
+ reclaimed += n;
+ if(reclaimed >= npage)
+ break;
+ }
+ runtime_lock(h);
+}
+
// Allocate a new span of npage pages from the heap
// and record its size class in the HeapMap and HeapMapCache.
MSpan*
-runtime_MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, int32 acct, int32 zeroed)
+runtime_MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, bool large, bool needzero)
{
MSpan *s;
@@ -97,14 +181,22 @@ runtime_MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, int32 acct, int32
s = MHeap_AllocLocked(h, npage, sizeclass);
if(s != nil) {
mstats.heap_inuse += npage<<PageShift;
- if(acct) {
+ if(large) {
mstats.heap_objects++;
mstats.heap_alloc += npage<<PageShift;
+ // Swept spans are at the end of lists.
+ if(s->npages < nelem(h->free))
+ runtime_MSpanList_InsertBack(&h->busy[s->npages], s);
+ else
+ runtime_MSpanList_InsertBack(&h->busylarge, s);
}
}
runtime_unlock(h);
- if(s != nil && *(uintptr*)(s->start<<PageShift) != 0 && zeroed)
- runtime_memclr((byte*)(s->start<<PageShift), s->npages<<PageShift);
+ if(s != nil) {
+ if(needzero && s->needzero)
+ runtime_memclr((byte*)(s->start<<PageShift), s->npages<<PageShift);
+ s->needzero = 0;
+ }
return s;
}
@@ -115,6 +207,11 @@ MHeap_AllocLocked(MHeap *h, uintptr npage, int32 sizeclass)
MSpan *s, *t;
PageID p;
+ // To prevent excessive heap growth, before allocating n pages
+ // we need to sweep and reclaim at least n pages.
+ if(!h->sweepdone)
+ MHeap_Reclaim(h, npage);
+
// Try in fixed-size lists up to max.
for(n=npage; n < nelem(h->free); n++) {
if(!runtime_MSpanList_IsEmpty(&h->free[n])) {
@@ -138,29 +235,12 @@ HaveSpan:
if(s->npages < npage)
runtime_throw("MHeap_AllocLocked - bad npages");
runtime_MSpanList_Remove(s);
+ runtime_atomicstore(&s->sweepgen, h->sweepgen);
s->state = MSpanInUse;
mstats.heap_idle -= s->npages<<PageShift;
mstats.heap_released -= s->npreleased<<PageShift;
- if(s->npreleased > 0) {
- // We have called runtime_SysUnused with these pages, and on
- // Unix systems it called madvise. At this point at least
- // some BSD-based kernels will return these pages either as
- // zeros or with the old data. For our caller, the first word
- // in the page indicates whether the span contains zeros or
- // not (this word was set when the span was freed by
- // MCentral_Free or runtime_MCentral_FreeSpan). If the first
- // page in the span is returned as zeros, and some subsequent
- // page is returned with the old data, then we will be
- // returning a span that is assumed to be all zeros, but the
- // actual data will not be all zeros. Avoid that problem by
- // explicitly marking the span as not being zeroed, just in
- // case. The beadbead constant we use here means nothing, it
- // is just a unique constant not seen elsewhere in the
- // runtime, as a clue in case it turns up unexpectedly in
- // memory or in a stack trace.
+ if(s->npreleased > 0)
runtime_SysUsed((void*)(s->start<<PageShift), s->npages<<PageShift);
- *(uintptr*)(s->start<<PageShift) = (uintptr)0xbeadbeadbeadbeadULL;
- }
s->npreleased = 0;
if(s->npages > npage) {
@@ -174,7 +254,8 @@ HaveSpan:
h->spans[p-1] = s;
h->spans[p] = t;
h->spans[p+t->npages-1] = t;
- *(uintptr*)(t->start<<PageShift) = *(uintptr*)(s->start<<PageShift); // copy "needs zeroing" mark
+ t->needzero = s->needzero;
+ runtime_atomicstore(&t->sweepgen, h->sweepgen);
t->state = MSpanInUse;
MHeap_FreeLocked(h, t);
t->unusedsince = s->unusedsince; // preserve age
@@ -197,7 +278,7 @@ HaveSpan:
static MSpan*
MHeap_AllocLarge(MHeap *h, uintptr npage)
{
- return BestFit(&h->large, npage, nil);
+ return BestFit(&h->freelarge, npage, nil);
}
// Search list for smallest span with >= npage pages.
@@ -258,6 +339,7 @@ MHeap_Grow(MHeap *h, uintptr npage)
p -= ((uintptr)h->arena_start>>PageShift);
h->spans[p] = s;
h->spans[p + s->npages - 1] = s;
+ runtime_atomicstore(&s->sweepgen, h->sweepgen);
s->state = MSpanInUse;
MHeap_FreeLocked(h, s);
return true;
@@ -319,20 +401,19 @@ runtime_MHeap_Free(MHeap *h, MSpan *s, int32 acct)
static void
MHeap_FreeLocked(MHeap *h, MSpan *s)
{
- uintptr *sp, *tp;
MSpan *t;
PageID p;
s->types.compression = MTypes_Empty;
- if(s->state != MSpanInUse || s->ref != 0) {
- runtime_printf("MHeap_FreeLocked - span %p ptr %p state %d ref %d\n", s, s->start<<PageShift, s->state, s->ref);
+ if(s->state != MSpanInUse || s->ref != 0 || s->sweepgen != h->sweepgen) {
+ runtime_printf("MHeap_FreeLocked - span %p ptr %p state %d ref %d sweepgen %d/%d\n",
+ s, s->start<<PageShift, s->state, s->ref, s->sweepgen, h->sweepgen);
runtime_throw("MHeap_FreeLocked - invalid free");
}
mstats.heap_idle += s->npages<<PageShift;
s->state = MSpanFree;
runtime_MSpanList_Remove(s);
- sp = (uintptr*)(s->start<<PageShift);
// Stamp newly unused spans. The scavenger will use that
// info to potentially give back some pages to the OS.
s->unusedsince = runtime_nanotime();
@@ -342,13 +423,10 @@ MHeap_FreeLocked(MHeap *h, MSpan *s)
p = s->start;
p -= (uintptr)h->arena_start >> PageShift;
if(p > 0 && (t = h->spans[p-1]) != nil && t->state != MSpanInUse) {
- if(t->npreleased == 0) { // cant't touch this otherwise
- tp = (uintptr*)(t->start<<PageShift);
- *tp |= *sp; // propagate "needs zeroing" mark
- }
s->start = t->start;
s->npages += t->npages;
s->npreleased = t->npreleased; // absorb released pages
+ s->needzero |= t->needzero;
p -= t->npages;
h->spans[p] = s;
runtime_MSpanList_Remove(t);
@@ -356,12 +434,9 @@ MHeap_FreeLocked(MHeap *h, MSpan *s)
runtime_FixAlloc_Free(&h->spanalloc, t);
}
if((p+s->npages)*sizeof(h->spans[0]) < h->spans_mapped && (t = h->spans[p+s->npages]) != nil && t->state != MSpanInUse) {
- if(t->npreleased == 0) { // cant't touch this otherwise
- tp = (uintptr*)(t->start<<PageShift);
- *sp |= *tp; // propagate "needs zeroing" mark
- }
s->npages += t->npages;
s->npreleased += t->npreleased;
+ s->needzero |= t->needzero;
h->spans[p + s->npages - 1] = s;
runtime_MSpanList_Remove(t);
t->state = MSpanDead;
@@ -372,7 +447,7 @@ MHeap_FreeLocked(MHeap *h, MSpan *s)
if(s->npages < nelem(h->free))
runtime_MSpanList_Insert(&h->free[s->npages], s);
else
- runtime_MSpanList_Insert(&h->large, s);
+ runtime_MSpanList_Insert(&h->freelarge, s);
}
static void
@@ -427,7 +502,7 @@ scavenge(int32 k, uint64 now, uint64 limit)
sumreleased = 0;
for(i=0; i < nelem(h->free); i++)
sumreleased += scavengelist(&h->free[i], now, limit);
- sumreleased += scavengelist(&h->large, now, limit);
+ sumreleased += scavengelist(&h->freelarge, now, limit);
if(runtime_debug.gctrace > 0) {
if(sumreleased > 0)
@@ -447,6 +522,7 @@ runtime_MHeap_Scavenger(void* dummy)
G *g;
MHeap *h;
uint64 tick, now, forcegc, limit;
+ int64 unixnow;
uint32 k;
Note note, *notep;
@@ -473,8 +549,8 @@ runtime_MHeap_Scavenger(void* dummy)
runtime_notetsleepg(&note, tick);
runtime_lock(h);
- now = runtime_nanotime();
- if(now - mstats.last_gc > forcegc) {
+ unixnow = runtime_unixnanotime();
+ if(unixnow - mstats.last_gc > forcegc) {
runtime_unlock(h);
// The scavenger can not block other goroutines,
// otherwise deadlock detector can fire spuriously.
@@ -486,8 +562,8 @@ runtime_MHeap_Scavenger(void* dummy)
if(runtime_debug.gctrace > 0)
runtime_printf("scvg%d: GC forced\n", k);
runtime_lock(h);
- now = runtime_nanotime();
}
+ now = runtime_nanotime();
scavenge(k, now, limit);
runtime_unlock(h);
}
@@ -498,7 +574,7 @@ void runtime_debug_freeOSMemory(void) __asm__("runtime_debug.freeOSMemory");
void
runtime_debug_freeOSMemory(void)
{
- runtime_gc(1);
+ runtime_gc(2); // force GC and do eager sweep
runtime_lock(&runtime_mheap);
scavenge(-1, ~(uintptr)0, 0);
runtime_unlock(&runtime_mheap);
@@ -515,11 +591,16 @@ runtime_MSpan_Init(MSpan *span, PageID start, uintptr npages)
span->freelist = nil;
span->ref = 0;
span->sizeclass = 0;
+ span->incache = false;
span->elemsize = 0;
- span->state = 0;
+ span->state = MSpanDead;
span->unusedsince = 0;
span->npreleased = 0;
span->types.compression = MTypes_Empty;
+ span->specialLock.key = 0;
+ span->specials = nil;
+ span->needzero = 0;
+ span->freebuf = nil;
}
// Initialize an empty doubly-linked list.
@@ -561,4 +642,309 @@ runtime_MSpanList_Insert(MSpan *list, MSpan *span)
span->prev->next = span;
}
+void
+runtime_MSpanList_InsertBack(MSpan *list, MSpan *span)
+{
+ if(span->next != nil || span->prev != nil) {
+ runtime_printf("failed MSpanList_Insert %p %p %p\n", span, span->next, span->prev);
+ runtime_throw("MSpanList_Insert");
+ }
+ span->next = list;
+ span->prev = list->prev;
+ span->next->prev = span;
+ span->prev->next = span;
+}
+
+// Adds the special record s to the list of special records for
+// the object p. All fields of s should be filled in except for
+// offset & next, which this routine will fill in.
+// Returns true if the special was successfully added, false otherwise.
+// (The add will fail only if a record with the same p and s->kind
+// already exists.)
+static bool
+addspecial(void *p, Special *s)
+{
+ MSpan *span;
+ Special **t, *x;
+ uintptr offset;
+ byte kind;
+
+ span = runtime_MHeap_LookupMaybe(&runtime_mheap, p);
+ if(span == nil)
+ runtime_throw("addspecial on invalid pointer");
+
+ // Ensure that the span is swept.
+ // GC accesses specials list w/o locks. And it's just much safer.
+ runtime_m()->locks++;
+ runtime_MSpan_EnsureSwept(span);
+
+ offset = (uintptr)p - (span->start << PageShift);
+ kind = s->kind;
+
+ runtime_lock(&span->specialLock);
+
+ // Find splice point, check for existing record.
+ t = &span->specials;
+ while((x = *t) != nil) {
+ if(offset == x->offset && kind == x->kind) {
+ runtime_unlock(&span->specialLock);
+ runtime_m()->locks--;
+ return false; // already exists
+ }
+ if(offset < x->offset || (offset == x->offset && kind < x->kind))
+ break;
+ t = &x->next;
+ }
+ // Splice in record, fill in offset.
+ s->offset = offset;
+ s->next = x;
+ *t = s;
+ runtime_unlock(&span->specialLock);
+ runtime_m()->locks--;
+ return true;
+}
+// Removes the Special record of the given kind for the object p.
+// Returns the record if the record existed, nil otherwise.
+// The caller must FixAlloc_Free the result.
+static Special*
+removespecial(void *p, byte kind)
+{
+ MSpan *span;
+ Special *s, **t;
+ uintptr offset;
+
+ span = runtime_MHeap_LookupMaybe(&runtime_mheap, p);
+ if(span == nil)
+ runtime_throw("removespecial on invalid pointer");
+
+ // Ensure that the span is swept.
+ // GC accesses specials list w/o locks. And it's just much safer.
+ runtime_m()->locks++;
+ runtime_MSpan_EnsureSwept(span);
+
+ offset = (uintptr)p - (span->start << PageShift);
+
+ runtime_lock(&span->specialLock);
+ t = &span->specials;
+ while((s = *t) != nil) {
+ // This function is used for finalizers only, so we don't check for
+ // "interior" specials (p must be exactly equal to s->offset).
+ if(offset == s->offset && kind == s->kind) {
+ *t = s->next;
+ runtime_unlock(&span->specialLock);
+ runtime_m()->locks--;
+ return s;
+ }
+ t = &s->next;
+ }
+ runtime_unlock(&span->specialLock);
+ runtime_m()->locks--;
+ return nil;
+}
+
+// Adds a finalizer to the object p. Returns true if it succeeded.
+bool
+runtime_addfinalizer(void *p, FuncVal *f, const FuncType *ft, const PtrType *ot)
+{
+ SpecialFinalizer *s;
+
+ runtime_lock(&runtime_mheap.speciallock);
+ s = runtime_FixAlloc_Alloc(&runtime_mheap.specialfinalizeralloc);
+ runtime_unlock(&runtime_mheap.speciallock);
+ s->kind = KindSpecialFinalizer;
+ s->fn = f;
+ s->ft = ft;
+ s->ot = ot;
+ if(addspecial(p, s))
+ return true;
+
+ // There was an old finalizer
+ runtime_lock(&runtime_mheap.speciallock);
+ runtime_FixAlloc_Free(&runtime_mheap.specialfinalizeralloc, s);
+ runtime_unlock(&runtime_mheap.speciallock);
+ return false;
+}
+
+// Removes the finalizer (if any) from the object p.
+void
+runtime_removefinalizer(void *p)
+{
+ SpecialFinalizer *s;
+
+ s = (SpecialFinalizer*)removespecial(p, KindSpecialFinalizer);
+ if(s == nil)
+ return; // there wasn't a finalizer to remove
+ runtime_lock(&runtime_mheap.speciallock);
+ runtime_FixAlloc_Free(&runtime_mheap.specialfinalizeralloc, s);
+ runtime_unlock(&runtime_mheap.speciallock);
+}
+
+// Set the heap profile bucket associated with addr to b.
+void
+runtime_setprofilebucket(void *p, Bucket *b)
+{
+ SpecialProfile *s;
+
+ runtime_lock(&runtime_mheap.speciallock);
+ s = runtime_FixAlloc_Alloc(&runtime_mheap.specialprofilealloc);
+ runtime_unlock(&runtime_mheap.speciallock);
+ s->kind = KindSpecialProfile;
+ s->b = b;
+ if(!addspecial(p, s))
+ runtime_throw("setprofilebucket: profile already set");
+}
+
+// Do whatever cleanup needs to be done to deallocate s. It has
+// already been unlinked from the MSpan specials list.
+// Returns true if we should keep working on deallocating p.
+bool
+runtime_freespecial(Special *s, void *p, uintptr size, bool freed)
+{
+ SpecialFinalizer *sf;
+ SpecialProfile *sp;
+
+ switch(s->kind) {
+ case KindSpecialFinalizer:
+ sf = (SpecialFinalizer*)s;
+ runtime_queuefinalizer(p, sf->fn, sf->ft, sf->ot);
+ runtime_lock(&runtime_mheap.speciallock);
+ runtime_FixAlloc_Free(&runtime_mheap.specialfinalizeralloc, sf);
+ runtime_unlock(&runtime_mheap.speciallock);
+ return false; // don't free p until finalizer is done
+ case KindSpecialProfile:
+ sp = (SpecialProfile*)s;
+ runtime_MProf_Free(sp->b, size, freed);
+ runtime_lock(&runtime_mheap.speciallock);
+ runtime_FixAlloc_Free(&runtime_mheap.specialprofilealloc, sp);
+ runtime_unlock(&runtime_mheap.speciallock);
+ return true;
+ default:
+ runtime_throw("bad special kind");
+ return true;
+ }
+}
+
+// Free all special records for p.
+void
+runtime_freeallspecials(MSpan *span, void *p, uintptr size)
+{
+ Special *s, **t, *list;
+ uintptr offset;
+
+ if(span->sweepgen != runtime_mheap.sweepgen)
+ runtime_throw("runtime: freeallspecials: unswept span");
+ // first, collect all specials into the list; then, free them
+ // this is required to not cause deadlock between span->specialLock and proflock
+ list = nil;
+ offset = (uintptr)p - (span->start << PageShift);
+ runtime_lock(&span->specialLock);
+ t = &span->specials;
+ while((s = *t) != nil) {
+ if(offset + size <= s->offset)
+ break;
+ if(offset <= s->offset) {
+ *t = s->next;
+ s->next = list;
+ list = s;
+ } else
+ t = &s->next;
+ }
+ runtime_unlock(&span->specialLock);
+
+ while(list != nil) {
+ s = list;
+ list = s->next;
+ if(!runtime_freespecial(s, p, size, true))
+ runtime_throw("can't explicitly free an object with a finalizer");
+ }
+}
+
+// Split an allocated span into two equal parts.
+void
+runtime_MHeap_SplitSpan(MHeap *h, MSpan *s)
+{
+ MSpan *t;
+ MCentral *c;
+ uintptr i;
+ uintptr npages;
+ PageID p;
+
+ if(s->state != MSpanInUse)
+ runtime_throw("MHeap_SplitSpan on a free span");
+ if(s->sizeclass != 0 && s->ref != 1)
+ runtime_throw("MHeap_SplitSpan doesn't have an allocated object");
+ npages = s->npages;
+
+ // remove the span from whatever list it is in now
+ if(s->sizeclass > 0) {
+ // must be in h->central[x].empty
+ c = &h->central[s->sizeclass];
+ runtime_lock(c);
+ runtime_MSpanList_Remove(s);
+ runtime_unlock(c);
+ runtime_lock(h);
+ } else {
+ // must be in h->busy/busylarge
+ runtime_lock(h);
+ runtime_MSpanList_Remove(s);
+ }
+ // heap is locked now
+
+ if(npages == 1) {
+ // convert span of 1 PageSize object to a span of 2 PageSize/2 objects.
+ s->ref = 2;
+ s->sizeclass = runtime_SizeToClass(PageSize/2);
+ s->elemsize = PageSize/2;
+ } else {
+ // convert span of n>1 pages into two spans of n/2 pages each.
+ if((s->npages & 1) != 0)
+ runtime_throw("MHeap_SplitSpan on an odd size span");
+
+ // compute position in h->spans
+ p = s->start;
+ p -= (uintptr)h->arena_start >> PageShift;
+
+ // Allocate a new span for the first half.
+ t = runtime_FixAlloc_Alloc(&h->spanalloc);
+ runtime_MSpan_Init(t, s->start, npages/2);
+ t->limit = (byte*)((t->start + npages/2) << PageShift);
+ t->state = MSpanInUse;
+ t->elemsize = npages << (PageShift - 1);
+ t->sweepgen = s->sweepgen;
+ if(t->elemsize <= MaxSmallSize) {
+ t->sizeclass = runtime_SizeToClass(t->elemsize);
+ t->ref = 1;
+ }
+
+ // the old span holds the second half.
+ s->start += npages/2;
+ s->npages = npages/2;
+ s->elemsize = npages << (PageShift - 1);
+ if(s->elemsize <= MaxSmallSize) {
+ s->sizeclass = runtime_SizeToClass(s->elemsize);
+ s->ref = 1;
+ }
+
+ // update span lookup table
+ for(i = p; i < p + npages/2; i++)
+ h->spans[i] = t;
+ }
+
+ // place the span into a new list
+ if(s->sizeclass > 0) {
+ runtime_unlock(h);
+ c = &h->central[s->sizeclass];
+ runtime_lock(c);
+ // swept spans are at the end of the list
+ runtime_MSpanList_InsertBack(&c->empty, s);
+ runtime_unlock(c);
+ } else {
+ // Swept spans are at the end of lists.
+ if(s->npages < nelem(h->free))
+ runtime_MSpanList_InsertBack(&h->busy[s->npages], s);
+ else
+ runtime_MSpanList_InsertBack(&h->busylarge, s);
+ runtime_unlock(h);
+ }
+}
diff --git a/libgo/runtime/mprof.goc b/libgo/runtime/mprof.goc
index 7507dfc917..d9c220bca2 100644
--- a/libgo/runtime/mprof.goc
+++ b/libgo/runtime/mprof.goc
@@ -23,7 +23,6 @@ enum { MProf, BProf }; // profile types
// Per-call-stack profiling information.
// Lookup by hashing call stack into a linked-list hash table.
-typedef struct Bucket Bucket;
struct Bucket
{
Bucket *next; // next in hash list
@@ -35,14 +34,33 @@ struct Bucket
{
struct // typ == MProf
{
+ // 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.
uintptr allocs;
uintptr frees;
uintptr alloc_bytes;
uintptr free_bytes;
- uintptr recent_allocs; // since last gc
+
+ uintptr prev_allocs; // since last but one till last gc
+ uintptr prev_frees;
+ uintptr prev_alloc_bytes;
+ uintptr prev_free_bytes;
+
+ uintptr recent_allocs; // since last gc till now
uintptr recent_frees;
uintptr recent_alloc_bytes;
uintptr recent_free_bytes;
+
};
struct // typ == BProf
{
@@ -50,7 +68,8 @@ struct Bucket
int64 cycles;
};
};
- uintptr hash;
+ uintptr hash; // hash of size + stk
+ uintptr size;
uintptr nstk;
Location stk[1];
};
@@ -64,7 +83,7 @@ static uintptr bucketmem;
// Return the bucket for stk[0:nstk], allocating new bucket if needed.
static Bucket*
-stkbucket(int32 typ, Location *stk, int32 nstk, bool alloc)
+stkbucket(int32 typ, uintptr size, Location *stk, int32 nstk, bool alloc)
{
int32 i, j;
uintptr h;
@@ -83,12 +102,17 @@ stkbucket(int32 typ, Location *stk, int32 nstk, bool alloc)
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 = h%BuckHashSize;
for(b = buckhash[i]; b; b=b->next) {
- if(b->typ == typ && b->hash == h && b->nstk == (uintptr)nstk) {
+ if(b->typ == typ && b->hash == h && b->size == size && b->nstk == (uintptr)nstk) {
for(j = 0; j < nstk; j++) {
if(b->stk[j].pc != stk[j].pc ||
b->stk[j].lineno != stk[j].lineno ||
@@ -108,6 +132,7 @@ stkbucket(int32 typ, Location *stk, int32 nstk, bool alloc)
runtime_memmove(b->stk, stk, nstk*sizeof stk[0]);
b->typ = typ;
b->hash = h;
+ b->size = size;
b->nstk = nstk;
b->next = buckhash[i];
buckhash[i] = b;
@@ -127,10 +152,16 @@ MProf_GC(void)
Bucket *b;
for(b=mbuckets; b; b=b->allnext) {
- b->allocs += b->recent_allocs;
- b->frees += b->recent_frees;
- b->alloc_bytes += b->recent_alloc_bytes;
- b->free_bytes += b->recent_free_bytes;
+ b->allocs += b->prev_allocs;
+ b->frees += b->prev_frees;
+ b->alloc_bytes += b->prev_alloc_bytes;
+ b->free_bytes += b->prev_free_bytes;
+
+ b->prev_allocs = b->recent_allocs;
+ b->prev_frees = b->recent_frees;
+ b->prev_alloc_bytes = b->recent_alloc_bytes;
+ b->prev_free_bytes = b->recent_free_bytes;
+
b->recent_allocs = 0;
b->recent_frees = 0;
b->recent_alloc_bytes = 0;
@@ -147,143 +178,39 @@ runtime_MProf_GC(void)
runtime_unlock(&proflock);
}
-// Map from pointer to Bucket* that allocated it.
-// Three levels:
-// Linked-list hash table for top N-AddrHashShift bits.
-// Array index for next AddrDenseBits bits.
-// Linked list for next AddrHashShift-AddrDenseBits bits.
-// This is more efficient than using a general map,
-// because of the typical clustering of the pointer keys.
-
-typedef struct AddrHash AddrHash;
-typedef struct AddrEntry AddrEntry;
-
-enum {
- AddrHashBits = 12, // good for 4GB of used address space
- AddrHashShift = 20, // each AddrHash knows about 1MB of address space
- AddrDenseBits = 8, // good for a profiling rate of 4096 bytes
-};
-
-struct AddrHash
-{
- AddrHash *next; // next in top-level hash table linked list
- uintptr addr; // addr>>20
- AddrEntry *dense[1<<AddrDenseBits];
-};
-
-struct AddrEntry
-{
- AddrEntry *next; // next in bottom-level linked list
- uint32 addr;
- Bucket *b;
-};
-
-static AddrHash **addrhash; // points to (AddrHash*)[1<<AddrHashBits]
-static AddrEntry *addrfree;
-static uintptr addrmem;
-
-// Multiplicative hash function:
-// hashMultiplier is the bottom 32 bits of int((sqrt(5)-1)/2 * (1<<32)).
-// This is a good multiplier as suggested in CLR, Knuth. The hash
-// value is taken to be the top AddrHashBits bits of the bottom 32 bits
-// of the multiplied value.
-enum {
- HashMultiplier = 2654435769U
-};
-
-// Set the bucket associated with addr to b.
-static void
-setaddrbucket(uintptr addr, Bucket *b)
-{
- int32 i;
- uint32 h;
- AddrHash *ah;
- AddrEntry *e;
-
- h = (uint32)((addr>>AddrHashShift)*HashMultiplier) >> (32-AddrHashBits);
- for(ah=addrhash[h]; ah; ah=ah->next)
- if(ah->addr == (addr>>AddrHashShift))
- goto found;
-
- ah = runtime_persistentalloc(sizeof *ah, 0, &mstats.buckhash_sys);
- addrmem += sizeof *ah;
- ah->next = addrhash[h];
- ah->addr = addr>>AddrHashShift;
- addrhash[h] = ah;
-
-found:
- if((e = addrfree) == nil) {
- e = runtime_persistentalloc(64*sizeof *e, 0, &mstats.buckhash_sys);
- addrmem += 64*sizeof *e;
- for(i=0; i+1<64; i++)
- e[i].next = &e[i+1];
- e[63].next = nil;
- }
- addrfree = e->next;
- e->addr = (uint32)~(addr & ((1<<AddrHashShift)-1));
- e->b = b;
- h = (addr>>(AddrHashShift-AddrDenseBits))&(nelem(ah->dense)-1); // entry in dense is top 8 bits of low 20.
- e->next = ah->dense[h];
- ah->dense[h] = e;
-}
-
-// Get the bucket associated with addr and clear the association.
-static Bucket*
-getaddrbucket(uintptr addr)
-{
- uint32 h;
- AddrHash *ah;
- AddrEntry *e, **l;
- Bucket *b;
-
- h = (uint32)((addr>>AddrHashShift)*HashMultiplier) >> (32-AddrHashBits);
- for(ah=addrhash[h]; ah; ah=ah->next)
- if(ah->addr == (addr>>AddrHashShift))
- goto found;
- return nil;
-
-found:
- h = (addr>>(AddrHashShift-AddrDenseBits))&(nelem(ah->dense)-1); // entry in dense is top 8 bits of low 20.
- for(l=&ah->dense[h]; (e=*l) != nil; l=&e->next) {
- if(e->addr == (uint32)~(addr & ((1<<AddrHashShift)-1))) {
- *l = e->next;
- b = e->b;
- e->next = addrfree;
- addrfree = e;
- return b;
- }
- }
- return nil;
-}
-
// Called by malloc to record a profiled block.
void
runtime_MProf_Malloc(void *p, uintptr size)
{
- int32 nstk;
Location stk[32];
Bucket *b;
+ int32 nstk;
- nstk = runtime_callers(1, stk, 32);
+ nstk = runtime_callers(1, stk, nelem(stk), false);
runtime_lock(&proflock);
- b = stkbucket(MProf, stk, nstk, true);
+ b = stkbucket(MProf, size, stk, nstk, true);
b->recent_allocs++;
b->recent_alloc_bytes += size;
- setaddrbucket((uintptr)p, b);
runtime_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.
+ runtime_setprofilebucket(p, b);
}
// Called when freeing a profiled block.
void
-runtime_MProf_Free(void *p, uintptr size)
+runtime_MProf_Free(Bucket *b, uintptr size, bool freed)
{
- Bucket *b;
-
runtime_lock(&proflock);
- b = getaddrbucket((uintptr)p);
- if(b != nil) {
+ if(freed) {
b->recent_frees++;
b->recent_free_bytes += size;
+ } else {
+ b->prev_frees++;
+ b->prev_free_bytes += size;
}
runtime_unlock(&proflock);
}
@@ -322,9 +249,9 @@ runtime_blockevent(int64 cycles, int32 skip)
if(rate <= 0 || (rate > cycles && runtime_fastrand1()%rate > cycles))
return;
- nstk = runtime_callers(skip, stk, 32);
+ nstk = runtime_callers(skip, stk, nelem(stk), false);
runtime_lock(&proflock);
- b = stkbucket(BProf, stk, nstk, true);
+ b = stkbucket(BProf, 0, stk, nstk, true);
b->count++;
b->cycles += cycles;
runtime_unlock(&proflock);
@@ -376,6 +303,7 @@ func MemProfile(p Slice, include_inuse_zero bool) (n int, ok bool) {
// 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; b=b->allnext)
if(include_inuse_zero || b->alloc_bytes != b->free_bytes)
@@ -393,13 +321,23 @@ func MemProfile(p Slice, include_inuse_zero bool) (n int, ok bool) {
}
void
-runtime_MProf_Mark(void (*addroot)(Obj))
+runtime_MProf_Mark(struct Workbuf **wbufp, void (*enqueue1)(struct Workbuf**, Obj))
{
// buckhash is not allocated via mallocgc.
- addroot((Obj){(byte*)&mbuckets, sizeof mbuckets, 0});
- addroot((Obj){(byte*)&bbuckets, sizeof bbuckets, 0});
- addroot((Obj){(byte*)&addrhash, sizeof addrhash, 0});
- addroot((Obj){(byte*)&addrfree, sizeof addrfree, 0});
+ enqueue1(wbufp, (Obj){(byte*)&mbuckets, sizeof mbuckets, 0});
+ enqueue1(wbufp, (Obj){(byte*)&bbuckets, sizeof bbuckets, 0});
+}
+
+void
+runtime_iterate_memprof(void (*callback)(Bucket*, uintptr, Location*, uintptr, uintptr, uintptr))
+{
+ Bucket *b;
+
+ runtime_lock(&proflock);
+ for(b=mbuckets; b; b=b->allnext) {
+ callback(b, b->nstk, b->stk, b->size, b->allocs, b->frees);
+ }
+ runtime_unlock(&proflock);
}
// Must match BlockProfileRecord in debug.go.
@@ -511,7 +449,7 @@ saveg(G *gp, TRecord *r)
Location locstk[nelem(r->stk)];
if(gp == runtime_g()) {
- n = runtime_callers(0, locstk, nelem(r->stk));
+ n = runtime_callers(0, locstk, nelem(r->stk), false);
for(i = 0; i < n; i++)
r->stk[i] = locstk[i].pc;
}
@@ -524,6 +462,7 @@ saveg(G *gp, TRecord *r)
}
func GoroutineProfile(b Slice) (n int, ok bool) {
+ uintptr i;
TRecord *r;
G *gp;
@@ -540,7 +479,8 @@ func GoroutineProfile(b Slice) (n int, ok bool) {
ok = true;
r = (TRecord*)b.__values;
saveg(g, r++);
- for(gp = runtime_allg; gp != nil; gp = gp->alllink) {
+ for(i = 0; i < runtime_allglen; i++) {
+ gp = runtime_allg[i];
if(gp == g || gp->status == Gdead)
continue;
saveg(gp, r++);
@@ -553,8 +493,72 @@ func GoroutineProfile(b Slice) (n int, ok bool) {
}
}
+// Tracing of alloc/free/gc.
+
+static Lock tracelock;
+
+static const char*
+typeinfoname(int32 typeinfo)
+{
+ if(typeinfo == TypeInfo_SingleObject)
+ return "single object";
+ else if(typeinfo == TypeInfo_Array)
+ return "array";
+ else if(typeinfo == TypeInfo_Chan)
+ return "channel";
+ runtime_throw("typinfoname: unknown type info");
+ return nil;
+}
+
+void
+runtime_tracealloc(void *p, uintptr size, uintptr typ)
+{
+ const char *name;
+ Type *type;
+
+ runtime_lock(&tracelock);
+ runtime_m()->traceback = 2;
+ type = (Type*)(typ & ~3);
+ name = typeinfoname(typ & 3);
+ if(type == nil)
+ runtime_printf("tracealloc(%p, %p, %s)\n", p, size, name);
+ else
+ runtime_printf("tracealloc(%p, %p, %s of %S)\n", p, size, name, *type->__reflection);
+ if(runtime_m()->curg == nil || runtime_g() == runtime_m()->curg) {
+ runtime_goroutineheader(runtime_g());
+ runtime_traceback();
+ } else {
+ runtime_goroutineheader(runtime_m()->curg);
+ runtime_traceback();
+ }
+ runtime_printf("\n");
+ runtime_m()->traceback = 0;
+ runtime_unlock(&tracelock);
+}
+
+void
+runtime_tracefree(void *p, uintptr size)
+{
+ runtime_lock(&tracelock);
+ runtime_m()->traceback = 2;
+ runtime_printf("tracefree(%p, %p)\n", p, size);
+ runtime_goroutineheader(runtime_g());
+ runtime_traceback();
+ runtime_printf("\n");
+ runtime_m()->traceback = 0;
+ runtime_unlock(&tracelock);
+}
+
void
-runtime_mprofinit(void)
+runtime_tracegc(void)
{
- addrhash = runtime_persistentalloc((1<<AddrHashBits)*sizeof *addrhash, 0, &mstats.buckhash_sys);
+ runtime_lock(&tracelock);
+ runtime_m()->traceback = 2;
+ runtime_printf("tracegc()\n");
+ // running on m->g0 stack; show all non-g0 goroutines
+ runtime_tracebackothers(runtime_g());
+ runtime_printf("end tracegc\n");
+ runtime_printf("\n");
+ runtime_m()->traceback = 0;
+ runtime_unlock(&tracelock);
}
diff --git a/libgo/runtime/msize.c b/libgo/runtime/msize.c
index 745a76958c..34509d0456 100644
--- a/libgo/runtime/msize.c
+++ b/libgo/runtime/msize.c
@@ -44,8 +44,8 @@ int32 runtime_class_to_allocnpages[NumSizeClasses];
int8 runtime_size_to_class8[1024/8 + 1];
int8 runtime_size_to_class128[(MaxSmallSize-1024)/128 + 1];
-static int32
-SizeToClass(int32 size)
+int32
+runtime_SizeToClass(int32 size)
{
if(size > MaxSmallSize)
runtime_throw("SizeToClass - invalid size");
@@ -90,9 +90,9 @@ runtime_InitSizes(void)
// objects into the page, we might as well
// use just this size instead of having two
// different sizes.
- if(sizeclass > 1
- && (int32)npages == runtime_class_to_allocnpages[sizeclass-1]
- && allocsize/size == allocsize/runtime_class_to_size[sizeclass-1]) {
+ if(sizeclass > 1 &&
+ (int32)npages == runtime_class_to_allocnpages[sizeclass-1] &&
+ allocsize/size == allocsize/runtime_class_to_size[sizeclass-1]) {
runtime_class_to_size[sizeclass-1] = size;
continue;
}
@@ -119,7 +119,7 @@ runtime_InitSizes(void)
// Double-check SizeToClass.
if(0) {
for(n=0; n < MaxSmallSize; n++) {
- sizeclass = SizeToClass(n);
+ sizeclass = runtime_SizeToClass(n);
if(sizeclass < 1 || sizeclass >= NumSizeClasses || runtime_class_to_size[sizeclass] < n) {
runtime_printf("size=%d sizeclass=%d runtime_class_to_size=%d\n", n, sizeclass, runtime_class_to_size[sizeclass]);
runtime_printf("incorrect SizeToClass");
@@ -158,3 +158,18 @@ dump:
}
runtime_throw("InitSizes failed");
}
+
+// Returns size of the memory block that mallocgc will allocate if you ask for the size.
+uintptr
+runtime_roundupsize(uintptr size)
+{
+ if(size < MaxSmallSize) {
+ if(size <= 1024-8)
+ return runtime_class_to_size[runtime_size_to_class8[(size+7)>>3]];
+ else
+ return runtime_class_to_size[runtime_size_to_class128[(size-1024+127) >> 7]];
+ }
+ if(size + PageSize < size)
+ return size;
+ return ROUND(size, PageSize);
+}
diff --git a/libgo/runtime/netpoll.goc b/libgo/runtime/netpoll.goc
index 02705734dd..2f3fa455f3 100644
--- a/libgo/runtime/netpoll.goc
+++ b/libgo/runtime/netpoll.goc
@@ -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 netbsd openbsd windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
package net
@@ -24,21 +24,46 @@ package net
// An implementation must call the following function to denote that the pd is ready.
// void runtime_netpollready(G **gpp, PollDesc *pd, int32 mode);
+// PollDesc contains 2 binary semaphores, rg and wg, to park reader and writer
+// goroutines respectively. The semaphore can be in the following states:
+// READY - io readiness notification is pending;
+// a goroutine consumes the notification by changing the state to nil.
+// WAIT - 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.
#define READY ((G*)1)
+#define WAIT ((G*)2)
+
+enum
+{
+ PollBlockSize = 4*1024,
+};
struct PollDesc
{
PollDesc* link; // 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 rediness notification)
+ // proceed w/o taking the lock. So closing, rg, rd, wg and wd are manipulated
+ // in a lock-free way by all operations.
Lock; // protectes the following fields
uintptr fd;
bool closing;
uintptr seq; // protects from stale timers and ready notifications
- G* rg; // G waiting for read or READY (binary semaphore)
+ G* rg; // READY, WAIT, G waiting for read or nil
Timer rt; // read deadline timer (set if rt.fv != nil)
int64 rd; // read deadline
- G* wg; // the same for writes
- Timer wt;
- int64 wd;
+ G* wg; // READY, WAIT, G waiting for write or nil
+ Timer wt; // write deadline timer
+ int64 wd; // write deadline
+ void* user; // user settable cookie
};
static struct
@@ -52,11 +77,11 @@ static struct
// seq is incremented when deadlines are changed or descriptor is reused.
} pollcache;
-static bool netpollblock(PollDesc*, int32);
+static bool netpollblock(PollDesc*, int32, bool);
static G* netpollunblock(PollDesc*, int32, bool);
-static void deadline(int64, Eface);
-static void readDeadline(int64, Eface);
-static void writeDeadline(int64, Eface);
+static void deadline(Eface, uintptr);
+static void readDeadline(Eface, uintptr);
+static void writeDeadline(Eface, uintptr);
static PollDesc* allocPollDesc(void);
static intgo checkerr(PollDesc *pd, int32 mode);
@@ -64,6 +89,11 @@ static FuncVal deadlineFn = {(void(*)(void))deadline};
static FuncVal readDeadlineFn = {(void(*)(void))readDeadline};
static FuncVal writeDeadlineFn = {(void(*)(void))writeDeadline};
+// runtimeNano returns the current value of the runtime clock in nanoseconds.
+func runtimeNano() (ns int64) {
+ ns = runtime_nanotime();
+}
+
func runtime_pollServerInit() {
runtime_netpollinit();
}
@@ -102,7 +132,6 @@ func runtime_pollClose(pd *PollDesc) {
}
func runtime_pollReset(pd *PollDesc, mode int) (err int) {
- runtime_lock(pd);
err = checkerr(pd, mode);
if(err)
goto ret;
@@ -111,14 +140,15 @@ func runtime_pollReset(pd *PollDesc, mode int) (err int) {
else if(mode == 'w')
pd->wg = nil;
ret:
- runtime_unlock(pd);
}
func runtime_pollWait(pd *PollDesc, mode int) (err int) {
- runtime_lock(pd);
err = checkerr(pd, mode);
if(err == 0) {
- while(!netpollblock(pd, mode)) {
+ // As for now only Solaris uses level-triggered IO.
+ if(Solaris)
+ runtime_netpollarm(pd, mode);
+ while(!netpollblock(pd, mode, false)) {
err = checkerr(pd, mode);
if(err != 0)
break;
@@ -127,15 +157,13 @@ func runtime_pollWait(pd *PollDesc, mode int) (err int) {
// Pretend it has not happened and retry.
}
}
- runtime_unlock(pd);
}
func runtime_pollWaitCanceled(pd *PollDesc, mode int) {
- runtime_lock(pd);
- // wait for ioready, ignore closing or timeouts.
- while(!netpollblock(pd, mode))
+ // 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.
+ while(!netpollblock(pd, mode, true))
;
- runtime_unlock(pd);
}
func runtime_pollSetDeadline(pd *PollDesc, d int64, mode int) {
@@ -169,28 +197,31 @@ func runtime_pollSetDeadline(pd *PollDesc, d int64, mode int) {
// 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.type = (Type*)pd->seq;
+ pd->rt.arg.type = nil; // should be *pollDesc type descriptor.
pd->rt.arg.data = pd;
+ pd->rt.seq = pd->seq;
runtime_addtimer(&pd->rt);
} else {
if(pd->rd > 0) {
pd->rt.fv = &readDeadlineFn;
pd->rt.when = pd->rd;
- pd->rt.arg.type = (Type*)pd->seq;
+ pd->rt.arg.type = nil; // should be *pollDesc type descriptor.
pd->rt.arg.data = pd;
+ pd->rt.seq = pd->seq;
runtime_addtimer(&pd->rt);
}
if(pd->wd > 0) {
pd->wt.fv = &writeDeadlineFn;
pd->wt.when = pd->wd;
- pd->wt.arg.type = (Type*)pd->seq;
+ pd->wt.arg.type = nil; // should be *pollDesc type descriptor.
pd->wt.arg.data = pd;
+ pd->wt.seq = pd->seq;
runtime_addtimer(&pd->wt);
}
}
// If we set the new deadline in the past, unblock currently pending IO if any.
rg = nil;
- wg = nil;
+ runtime_atomicstorep(&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)
@@ -210,6 +241,7 @@ func runtime_pollUnblock(pd *PollDesc) {
runtime_throw("runtime_pollUnblock: already closing");
pd->closing = true;
pd->seq++;
+ runtime_atomicstorep(&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.fv) {
@@ -233,6 +265,30 @@ runtime_netpollfd(PollDesc *pd)
return pd->fd;
}
+void**
+runtime_netpolluser(PollDesc *pd)
+{
+ return &pd->user;
+}
+
+bool
+runtime_netpollclosing(PollDesc *pd)
+{
+ return pd->closing;
+}
+
+void
+runtime_netpolllock(PollDesc *pd)
+{
+ runtime_lock(pd);
+}
+
+void
+runtime_netpollunlock(PollDesc *pd)
+{
+ runtime_unlock(pd);
+}
+
// make pd ready, newly runnable goroutines (if any) are enqueued info gpp list
void
runtime_netpollready(G **gpp, PollDesc *pd, int32 mode)
@@ -240,12 +296,10 @@ runtime_netpollready(G **gpp, PollDesc *pd, int32 mode)
G *rg, *wg;
rg = wg = nil;
- runtime_lock(pd);
if(mode == 'r' || mode == 'r'+'w')
rg = netpollunblock(pd, 'r', true);
if(mode == 'w' || mode == 'r'+'w')
wg = netpollunblock(pd, 'w', true);
- runtime_unlock(pd);
if(rg) {
rg->schedlink = *gpp;
*gpp = rg;
@@ -266,67 +320,88 @@ checkerr(PollDesc *pd, int32 mode)
return 0;
}
+static bool
+blockcommit(G *gp, G **gpp)
+{
+ return runtime_casp(gpp, WAIT, gp);
+}
+
// returns true if IO is ready, or false if timedout or closed
+// waitio - wait only for completed IO, ignore errors
static bool
-netpollblock(PollDesc *pd, int32 mode)
+netpollblock(PollDesc *pd, int32 mode, bool waitio)
{
- G **gpp;
+ G **gpp, *old;
gpp = &pd->rg;
if(mode == 'w')
gpp = &pd->wg;
- if(*gpp == READY) {
- *gpp = nil;
- return true;
+
+ // set the gpp semaphore to WAIT
+ for(;;) {
+ old = *gpp;
+ if(old == READY) {
+ *gpp = nil;
+ return true;
+ }
+ if(old != nil)
+ runtime_throw("netpollblock: double wait");
+ if(runtime_casp(gpp, nil, WAIT))
+ break;
}
- if(*gpp != nil)
- runtime_throw("netpollblock: double wait");
- *gpp = runtime_g();
- runtime_park(runtime_unlock, &pd->Lock, "IO wait");
- runtime_lock(pd);
- if(runtime_g()->param)
- return true;
- return false;
+
+ // 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 || checkerr(pd, mode) == 0)
+ runtime_park((bool(*)(G*, void*))blockcommit, gpp, "IO wait");
+ // be careful to not lose concurrent READY notification
+ old = runtime_xchgp(gpp, nil);
+ if(old > WAIT)
+ runtime_throw("netpollblock: corrupted state");
+ return old == READY;
}
static G*
netpollunblock(PollDesc *pd, int32 mode, bool ioready)
{
- G **gpp, *old;
+ G **gpp, *old, *new;
gpp = &pd->rg;
if(mode == 'w')
gpp = &pd->wg;
- if(*gpp == READY)
- return nil;
- if(*gpp == nil) {
- // Only set READY for ioready. runtime_pollWait
- // will check for timeout/cancel before waiting.
+
+ for(;;) {
+ old = *gpp;
+ if(old == READY)
+ return nil;
+ if(old == nil && !ioready) {
+ // Only set READY for ioready. runtime_pollWait
+ // will check for timeout/cancel before waiting.
+ return nil;
+ }
+ new = nil;
if(ioready)
- *gpp = READY;
- return nil;
+ new = READY;
+ if(runtime_casp(gpp, old, new))
+ break;
}
- old = *gpp;
- // pass unblock reason onto blocked g
- old->param = (void*)(uintptr)ioready;
- *gpp = nil;
- return old;
+ if(old > WAIT)
+ return old; // must be G*
+ return nil;
}
static void
-deadlineimpl(int64 now, Eface arg, bool read, bool write)
+deadlineimpl(Eface arg, uintptr seq, bool read, bool write)
{
PollDesc *pd;
- uint32 seq;
G *rg, *wg;
- USED(now);
pd = (PollDesc*)arg.data;
- // This is the seq when the timer was set.
- // If it's stale, ignore the timer event.
- seq = (uintptr)arg.type;
rg = wg = nil;
runtime_lock(pd);
+ // 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.
runtime_unlock(pd);
@@ -336,14 +411,14 @@ deadlineimpl(int64 now, Eface arg, bool read, bool write)
if(pd->rd <= 0 || pd->rt.fv == nil)
runtime_throw("deadlineimpl: inconsistent read deadline");
pd->rd = -1;
- pd->rt.fv = nil;
+ runtime_atomicstorep(&pd->rt.fv, nil); // full memory barrier between store to rd and load of rg in netpollunblock
rg = netpollunblock(pd, 'r', false);
}
if(write) {
if(pd->wd <= 0 || (pd->wt.fv == nil && !read))
runtime_throw("deadlineimpl: inconsistent write deadline");
pd->wd = -1;
- pd->wt.fv = nil;
+ runtime_atomicstorep(&pd->wt.fv, nil); // full memory barrier between store to wd and load of wg in netpollunblock
wg = netpollunblock(pd, 'w', false);
}
runtime_unlock(pd);
@@ -354,21 +429,21 @@ deadlineimpl(int64 now, Eface arg, bool read, bool write)
}
static void
-deadline(int64 now, Eface arg)
+deadline(Eface arg, uintptr seq)
{
- deadlineimpl(now, arg, true, true);
+ deadlineimpl(arg, seq, true, true);
}
static void
-readDeadline(int64 now, Eface arg)
+readDeadline(Eface arg, uintptr seq)
{
- deadlineimpl(now, arg, true, false);
+ deadlineimpl(arg, seq, true, false);
}
static void
-writeDeadline(int64 now, Eface arg)
+writeDeadline(Eface arg, uintptr seq)
{
- deadlineimpl(now, arg, false, true);
+ deadlineimpl(arg, seq, false, true);
}
static PollDesc*
@@ -379,7 +454,7 @@ allocPollDesc(void)
runtime_lock(&pollcache);
if(pollcache.first == nil) {
- n = PageSize/sizeof(*pd);
+ n = PollBlockSize/sizeof(*pd);
if(n == 0)
n = 1;
// Must be in non-GC memory because can be referenced
diff --git a/libgo/runtime/netpoll_epoll.c b/libgo/runtime/netpoll_epoll.c
index 2acbca3232..1281f45b08 100644
--- a/libgo/runtime/netpoll_epoll.c
+++ b/libgo/runtime/netpoll_epoll.c
@@ -116,6 +116,14 @@ runtime_netpollclose(uintptr fd)
return -res;
}
+void
+runtime_netpollarm(PollDesc* pd, int32 mode)
+{
+ USED(pd);
+ USED(mode);
+ runtime_throw("unused");
+}
+
// polls for ready network connections
// returns list of goroutines that become runnable
G*
@@ -159,7 +167,8 @@ retry:
}
void
-runtime_netpoll_scan(void (*addroot)(Obj))
+runtime_netpoll_scan(struct Workbuf** wbufp, void (*enqueue1)(struct Workbuf**, Obj))
{
- USED(addroot);
+ USED(wbufp);
+ USED(enqueue1);
}
diff --git a/libgo/runtime/netpoll_kqueue.c b/libgo/runtime/netpoll_kqueue.c
index 5d3f85617b..5144a870fb 100644
--- a/libgo/runtime/netpoll_kqueue.c
+++ b/libgo/runtime/netpoll_kqueue.c
@@ -59,6 +59,13 @@ runtime_netpollclose(uintptr fd)
return 0;
}
+void
+runtime_netpollarm(PollDesc* pd, int32 mode)
+{
+ USED(pd, mode);
+ runtime_throw("unused");
+}
+
// Polls for ready network connections.
// Returns list of goroutines that become runnable.
G*
@@ -104,7 +111,8 @@ retry:
}
void
-runtime_netpoll_scan(void (*addroot)(Obj))
+runtime_netpoll_scan(struct Workbuf** wbufp, void (*enqueue1)(struct Workbuf**, Obj))
{
- USED(addroot);
+ USED(wbufp);
+ USED(enqueue1);
}
diff --git a/libgo/runtime/netpoll_select.c b/libgo/runtime/netpoll_select.c
index 788d19f619..b461335911 100644
--- a/libgo/runtime/netpoll_select.c
+++ b/libgo/runtime/netpoll_select.c
@@ -246,7 +246,7 @@ runtime_netpoll(bool block)
}
void
-runtime_netpoll_scan(void (*addroot)(Obj))
+runtime_netpoll_scan(struct Workbuf** wbufp, void (*enqueue1)(struct Workbuf**, Obj))
{
- addroot((Obj){(byte*)&data, sizeof data, 0});
+ enqueue1(wbufp, (Obj){(byte*)&data, sizeof data, 0});
}
diff --git a/libgo/runtime/netpoll_stub.c b/libgo/runtime/netpoll_stub.c
index a88c9f5b9c..468a610f6f 100644
--- a/libgo/runtime/netpoll_stub.c
+++ b/libgo/runtime/netpoll_stub.c
@@ -19,7 +19,8 @@ runtime_netpoll(bool block)
}
void
-runtime_netpoll_scan(void (*addroot)(Obj))
+runtime_netpoll_scan(struct Workbuf** wbufp, void (*enqueue1)(struct Workbuf**, Obj))
{
+ USED(wbufp);
USED(addroot);
}
diff --git a/libgo/runtime/panic.c b/libgo/runtime/panic.c
index 8fe321f6af..de000db988 100644
--- a/libgo/runtime/panic.c
+++ b/libgo/runtime/panic.c
@@ -12,9 +12,47 @@
uint32 runtime_panicking;
static Lock paniclk;
+// Allocate a Defer, usually using per-P pool.
+// Each defer must be released with freedefer.
+Defer*
+runtime_newdefer()
+{
+ Defer *d;
+ P *p;
+
+ d = nil;
+ p = runtime_m()->p;
+ d = p->deferpool;
+ if(d)
+ p->deferpool = d->__next;
+ if(d == nil) {
+ // deferpool is empty
+ d = runtime_malloc(sizeof(Defer));
+ }
+ return d;
+}
+
+// Free the given defer.
+// The defer cannot be used after this call.
+void
+runtime_freedefer(Defer *d)
+{
+ P *p;
+
+ if(d->__special)
+ return;
+ p = runtime_m()->p;
+ d->__next = p->deferpool;
+ p->deferpool = d;
+ // No need to wipe out pointers in argp/pc/fn/args,
+ // because we empty the pool before GC.
+}
+
// Run all deferred functions for the current goroutine.
+// This is noinline for go_can_recover.
+static void __go_rundefer (void) __attribute__ ((noinline));
static void
-rundefer(void)
+__go_rundefer(void)
{
G *g;
Defer *d;
@@ -28,8 +66,7 @@ rundefer(void)
d->__pfn = nil;
if (pfn != nil)
(*pfn)(d->__arg);
- if (d->__free)
- runtime_free(d);
+ runtime_freedefer(d);
}
}
@@ -44,18 +81,34 @@ runtime_startpanic(void)
m->mallocing = 1; // tell rest of panic not to try to malloc
} else if(m->mcache == nil) // can happen if called from signal handler or throw
m->mcache = runtime_allocmcache();
- if(m->dying) {
+ switch(m->dying) {
+ case 0:
+ m->dying = 1;
+ if(runtime_g() != nil)
+ runtime_g()->writebuf = nil;
+ runtime_xadd(&runtime_panicking, 1);
+ runtime_lock(&paniclk);
+ if(runtime_debug.schedtrace > 0 || runtime_debug.scheddetail > 0)
+ runtime_schedtrace(true);
+ runtime_freezetheworld();
+ return;
+ case 1:
+ // Something failed while panicing, probably the print of the
+ // argument to panic(). Just print a stack trace and exit.
+ m->dying = 2;
runtime_printf("panic during panic\n");
+ runtime_dopanic(0);
runtime_exit(3);
+ case 2:
+ // This is a genuine bug in the runtime, we couldn't even
+ // print the stack trace successfully.
+ m->dying = 3;
+ runtime_printf("stack trace unavailable\n");
+ runtime_exit(4);
+ default:
+ // Can't even print! Just exit.
+ runtime_exit(5);
}
- m->dying = 1;
- if(runtime_g() != nil)
- runtime_g()->writebuf = nil;
- runtime_xadd(&runtime_panicking, 1);
- runtime_lock(&paniclk);
- if(runtime_debug.schedtrace > 0 || runtime_debug.scheddetail > 0)
- runtime_schedtrace(true);
- runtime_freezetheworld();
}
void
@@ -103,6 +156,30 @@ runtime_dopanic(int32 unused __attribute__ ((unused)))
runtime_exit(2);
}
+bool
+runtime_canpanic(G *gp)
+{
+ M *m = runtime_m();
+ byte g;
+
+ USED(&g); // don't use global g, it points to gsignal
+
+ // Is it okay for gp to panic instead of crashing the program?
+ // Yes, as long as it is running Go code, not runtime code,
+ // and not stuck in a system call.
+ if(gp == nil || gp != m->curg)
+ return false;
+ if(m->locks-m->softfloat != 0 || m->mallocing != 0 || m->throwing != 0 || m->gcing != 0 || m->dying != 0)
+ return false;
+ if(gp->status != Grunning)
+ return false;
+#ifdef GOOS_windows
+ if(m->libcallsp != 0)
+ return false;
+#endif
+ return true;
+}
+
void
runtime_throw(const char *s)
{
@@ -131,6 +208,10 @@ runtime_panicstring(const char *s)
runtime_printf("panic: %s\n", s);
runtime_throw("panic during gc");
}
+ if(runtime_m()->locks) {
+ runtime_printf("panic: %s\n", s);
+ runtime_throw("panic holding locks");
+ }
runtime_newErrorCString(s, &err);
runtime_panic(err);
}
@@ -140,6 +221,12 @@ void runtime_Goexit (void) __asm__ (GOSYM_PREFIX "runtime.Goexit");
void
runtime_Goexit(void)
{
- rundefer();
+ __go_rundefer();
runtime_goexit();
}
+
+void
+runtime_panicdivide(void)
+{
+ runtime_panicstring("integer divide by zero");
+}
diff --git a/libgo/runtime/parfor.c b/libgo/runtime/parfor.c
index 9489d8dc2e..386faea512 100644
--- a/libgo/runtime/parfor.c
+++ b/libgo/runtime/parfor.c
@@ -33,18 +33,6 @@ runtime_parforalloc(uint32 nthrmax)
return desc;
}
-// For testing from Go
-// func parforalloc2(nthrmax uint32) *ParFor
-
-ParFor *runtime_parforalloc2(uint32)
- __asm__ (GOSYM_PREFIX "runtime.parforalloc2");
-
-ParFor *
-runtime_parforalloc2(uint32 nthrmax)
-{
- return runtime_parforalloc(nthrmax);
-}
-
void
runtime_parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait, void (*body)(ParFor*, uint32))
{
@@ -78,18 +66,6 @@ runtime_parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait, v
}
}
-// For testing from Go
-// func parforsetup2(desc *ParFor, nthr, n uint32, ctx *byte, wait bool, body func(*ParFor, uint32))
-
-void runtime_parforsetup2(ParFor *, uint32, uint32, void *, bool, void *)
- __asm__ (GOSYM_PREFIX "runtime.parforsetup2");
-
-void
-runtime_parforsetup2(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait, void *body)
-{
- runtime_parforsetup(desc, nthr, n, ctx, wait, *(void(**)(ParFor*, uint32))body);
-}
-
void
runtime_parfordo(ParFor *desc)
{
@@ -214,23 +190,10 @@ exit:
me->nsleep = 0;
}
-// For testing from Go
-// func parforiters(desc *ParFor, tid uintptr) (uintptr, uintptr)
-
-struct parforiters_ret {
- uintptr start;
- uintptr end;
-};
-
-struct parforiters_ret runtime_parforiters(ParFor *, uintptr)
- __asm__ (GOSYM_PREFIX "runtime.parforiters");
-
-struct parforiters_ret
-runtime_parforiters(ParFor *desc, uintptr tid)
+// For testing from Go.
+void
+runtime_parforiters(ParFor *desc, uintptr tid, uintptr *start, uintptr *end)
{
- struct parforiters_ret ret;
-
- ret.start = (uint32)desc->thr[tid].pos;
- ret.end = (uint32)(desc->thr[tid].pos>>32);
- return ret;
+ *start = (uint32)desc->thr[tid].pos;
+ *end = (uint32)(desc->thr[tid].pos>>32);
}
diff --git a/libgo/runtime/print.c b/libgo/runtime/print.c
index 766ddbdc49..69b1f81fb4 100644
--- a/libgo/runtime/print.c
+++ b/libgo/runtime/print.c
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <complex.h>
+#include <math.h>
#include <stdarg.h>
#include "runtime.h"
#include "array.h"
@@ -9,7 +11,9 @@
//static Lock debuglock;
-static void go_vprintf(const char*, va_list);
+// Clang requires this function to not be inlined (see below).
+static void go_vprintf(const char*, va_list)
+__attribute__((noinline));
// write to goroutine-local buffer if diverting output,
// or else standard error.
@@ -59,14 +63,57 @@ runtime_prints(const char *s)
gwrite(s, runtime_findnull((const byte*)s));
}
+#if defined (__clang__) && (defined (__i386__) || defined (__x86_64__))
+// LLVM's code generator does not currently support split stacks for vararg
+// functions, so we disable the feature for this function under Clang. This
+// appears to be OK as long as:
+// - this function only calls non-inlined, internal-linkage (hence no dynamic
+// loader) functions compiled with split stacks (i.e. go_vprintf), which can
+// allocate more stack space as required;
+// - this function itself does not occupy more than BACKOFF bytes of stack space
+// (see libgcc/config/i386/morestack.S).
+// These conditions are currently known to be satisfied by Clang on x86-32 and
+// x86-64. Note that signal handlers receive slightly less stack space than they
+// would normally do if they happen to be called while this function is being
+// run. If this turns out to be a problem we could consider increasing BACKOFF.
+
void
runtime_printf(const char *s, ...)
+__attribute__((no_split_stack));
+
+int32
+runtime_snprintf(byte *buf, int32 n, const char *s, ...)
+__attribute__((no_split_stack));
+
+#endif
+
+void
+runtime_printf(const char *s, ...)
+{
+ va_list va;
+
+ va_start(va, s);
+ go_vprintf(s, va);
+ va_end(va);
+}
+
+int32
+runtime_snprintf(byte *buf, int32 n, const char *s, ...)
{
+ G *g = runtime_g();
va_list va;
+ int32 m;
+ g->writebuf = buf;
+ g->writenbuf = n-1;
va_start(va, s);
go_vprintf(s, va);
va_end(va);
+ *g->writebuf = '\0';
+ m = g->writebuf - buf;
+ g->writenbuf = 0;
+ g->writebuf = nil;
+ return m;
}
// Very simple printf. Only for debugging prints.
@@ -105,7 +152,7 @@ go_vprintf(const char *s, va_list va)
runtime_printfloat(va_arg(va, float64));
break;
case 'C':
- runtime_printcomplex(va_arg(va, __complex double));
+ runtime_printcomplex(va_arg(va, complex double));
break;
case 'i':
runtime_printiface(va_arg(va, Iface));
@@ -174,20 +221,22 @@ runtime_printfloat(double v)
gwrite("NaN", 3);
return;
}
- i = __builtin_isinf_sign(v);
- if(i > 0) {
- gwrite("+Inf", 4);
- return;
- }
- if(i < 0) {
- gwrite("-Inf", 4);
+ if(isinf(v)) {
+ if(signbit(v)) {
+ gwrite("-Inf", 4);
+ } else {
+ gwrite("+Inf", 4);
+ }
return;
}
n = 7; // digits printed
e = 0; // exp
s = 0; // sign
- if(v != 0) {
+ if(v == 0) {
+ if(isinf(1/v) && 1/v < 0)
+ s = 1;
+ } else {
// sign
if(v < 0) {
v = -v;
@@ -243,11 +292,11 @@ runtime_printfloat(double v)
}
void
-runtime_printcomplex(__complex double v)
+runtime_printcomplex(complex double v)
{
gwrite("(", 1);
- runtime_printfloat(__builtin_creal(v));
- runtime_printfloat(__builtin_cimag(v));
+ runtime_printfloat(creal(v));
+ runtime_printfloat(cimag(v));
gwrite("i)", 2);
}
@@ -296,7 +345,7 @@ runtime_printhex(uint64 v)
void
runtime_printpointer(void *p)
{
- runtime_printhex((uint64)(uintptr)p);
+ runtime_printhex((uintptr)p);
}
void
diff --git a/libgo/runtime/proc.c b/libgo/runtime/proc.c
index 30516ad7d7..da0f2ed3a7 100644
--- a/libgo/runtime/proc.c
+++ b/libgo/runtime/proc.c
@@ -18,7 +18,6 @@
#include "arch.h"
#include "defs.h"
#include "malloc.h"
-#include "race.h"
#include "go-type.h"
#include "go-defer.h"
@@ -51,7 +50,7 @@ extern void __splitstack_block_signals_context (void *context[10], int *,
#if defined(USING_SPLIT_STACK) && defined(LINKER_SUPPORTS_SPLIT_STACK)
# define StackMin PTHREAD_STACK_MIN
#else
-# define StackMin 2 * 1024 * 1024
+# define StackMin ((sizeof(char *) < 8) ? 2 * 1024 * 1024 : 4 * 1024 * 1024)
#endif
uintptr runtime_stacks_sys;
@@ -127,6 +126,30 @@ fixcontext(ucontext_t* c)
c->uc_mcontext._mc_tlsbase = tlsbase;
}
+# elif defined(__sparc__)
+
+static inline void
+initcontext(void)
+{
+}
+
+static inline void
+fixcontext(ucontext_t *c)
+{
+ /* ??? Using
+ register unsigned long thread __asm__("%g7");
+ c->uc_mcontext.gregs[REG_G7] = thread;
+ results in
+ error: variable ‘thread’ might be clobbered by \
+ ‘longjmp’ or ‘vfork’ [-Werror=clobbered]
+ which ought to be false, as %g7 is a fixed register. */
+
+ if (sizeof (c->uc_mcontext.gregs[REG_G7]) == 8)
+ asm ("stx %%g7, %0" : "=m"(c->uc_mcontext.gregs[REG_G7]));
+ else
+ asm ("st %%g7, %0" : "=m"(c->uc_mcontext.gregs[REG_G7]));
+}
+
# else
# error unknown case for SETCONTEXT_CLOBBERS_TLS
@@ -167,15 +190,11 @@ runtime_setmg(M* mp, G* gp)
g = gp;
}
-// The static TLS size. See runtime_newm.
-static int tlssize;
-
// Start a new thread.
static void
runtime_newosproc(M *mp)
{
pthread_attr_t attr;
- size_t stacksize;
sigset_t clear, old;
pthread_t tid;
int ret;
@@ -185,19 +204,6 @@ runtime_newosproc(M *mp)
if(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0)
runtime_throw("pthread_attr_setdetachstate");
- stacksize = PTHREAD_STACK_MIN;
-
- // With glibc before version 2.16 the static TLS size is taken
- // out of the stack size, and we get an error or a crash if
- // there is not enough stack space left. Add it back in if we
- // can, in case the program uses a lot of TLS space. FIXME:
- // This can be disabled in glibc 2.16 and later, if the bug is
- // indeed fixed then.
- stacksize += tlssize;
-
- if(pthread_attr_setstacksize(&attr, stacksize) != 0)
- runtime_throw("pthread_attr_setstacksize");
-
// Block signals during pthread_create so that the new thread
// starts with signals disabled. It will enable them in minit.
sigfillset(&clear);
@@ -255,9 +261,6 @@ runtime_mcall(void (*pfn)(G*))
{
M *mp;
G *gp;
-#ifndef USING_SPLIT_STACK
- int i;
-#endif
// Ensure that all registers are on the stack for the garbage
// collector.
@@ -273,7 +276,7 @@ runtime_mcall(void (*pfn)(G*))
#ifdef USING_SPLIT_STACK
__splitstack_getcontext(&g->stack_context[0]);
#else
- gp->gcnext_sp = &i;
+ gp->gcnext_sp = &pfn;
#endif
gp->fromgogo = false;
getcontext(&gp->context);
@@ -309,43 +312,6 @@ runtime_mcall(void (*pfn)(G*))
}
}
-#ifdef HAVE_DL_ITERATE_PHDR
-
-// Called via dl_iterate_phdr.
-
-static int
-addtls(struct dl_phdr_info* info, size_t size __attribute__ ((unused)), void *data)
-{
- size_t *total = (size_t *)data;
- unsigned int i;
-
- for(i = 0; i < info->dlpi_phnum; ++i) {
- if(info->dlpi_phdr[i].p_type == PT_TLS)
- *total += info->dlpi_phdr[i].p_memsz;
- }
- return 0;
-}
-
-// Set the total TLS size.
-
-static void
-inittlssize()
-{
- size_t total = 0;
-
- dl_iterate_phdr(addtls, (void *)&total);
- tlssize = total;
-}
-
-#else
-
-static void
-inittlssize()
-{
-}
-
-#endif
-
// Goroutine scheduler
// The scheduler's job is to distribute ready-to-run goroutines over worker threads.
//
@@ -392,17 +358,23 @@ struct Sched {
int32 profilehz; // cpu profiling rate
};
-// The max value of GOMAXPROCS.
-// There are no fundamental restrictions on the value.
-enum { MaxGomaxprocs = 1<<8 };
+enum
+{
+ // The max value of GOMAXPROCS.
+ // There are no fundamental restrictions on the value.
+ MaxGomaxprocs = 1<<8,
+
+ // Number of goroutine ids to grab from runtime_sched.goidgen to local per-P cache at once.
+ // 16 seems to provide enough amortization, but other than that it's mostly arbitrary number.
+ GoidCacheBatch = 16,
+};
Sched runtime_sched;
int32 runtime_gomaxprocs;
uint32 runtime_needextram = 1;
bool runtime_iscgo = true;
M runtime_m0;
-G runtime_g0; // idle goroutine for m0
-G* runtime_allg;
+G runtime_g0; // idle goroutine for m0
G* runtime_lastg;
M* runtime_allm;
P** runtime_allp;
@@ -412,10 +384,15 @@ int32 runtime_ncpu;
bool runtime_precisestack;
static int32 newprocs;
+static Lock allglock; // the following vars are protected by this lock or by stoptheworld
+G** runtime_allg;
+uintptr runtime_allglen;
+static uintptr allgcap;
+
void* runtime_mstart(void*);
static void runqput(P*, G*);
static G* runqget(P*);
-static void runqgrow(P*);
+static bool runqputslow(P*, G*, uint32, uint32);
static G* runqsteal(P*, P*);
static void mput(M*);
static M* mget(void);
@@ -442,12 +419,14 @@ static void gfput(P*, G*);
static G* gfget(P*);
static void gfpurge(P*);
static void globrunqput(G*);
+static void globrunqputbatch(G*, G*, int32);
static G* globrunqget(P*, int32);
static P* pidleget(void);
static void pidleput(P*);
static void injectglist(G*);
static bool preemptall(void);
static bool exitsyscallfast(void);
+static void allgadd(G*);
// The bootstrap sequence is:
//
@@ -471,12 +450,11 @@ runtime_schedinit(void)
g->m = m;
initcontext();
- inittlssize();
runtime_sched.maxmcount = 10000;
runtime_precisestack = 0;
- runtime_mprofinit();
+ // runtime_symtabinit();
runtime_mallocinit();
mcommoninit(m);
@@ -485,6 +463,10 @@ runtime_schedinit(void)
// in a fault during a garbage collection, it will not
// need to allocated memory.
runtime_newErrorCString(0, &i);
+
+ // Initialize the cached gotraceback value, since
+ // gotraceback calls getenv, which mallocs on Plan 9.
+ runtime_gotraceback(nil);
runtime_goargs();
runtime_goenvs();
@@ -503,9 +485,6 @@ runtime_schedinit(void)
// Can not enable GC until all roots are registered.
// mstats.enablegc = 1;
-
- // if(raceenabled)
- // g->racectx = runtime_raceinit();
}
extern void main_init(void) __asm__ (GOSYM_PREFIX "__go_init_main");
@@ -517,6 +496,15 @@ initDone(void *arg __attribute__ ((unused))) {
};
// The main goroutine.
+// Note: C frames in general are not copyable during stack growth, for two reasons:
+// 1) We don't know where in a frame to find pointers to other stack locations.
+// 2) There's no guarantee that globals or heap values do not point into the frame.
+//
+// The C frame for runtime.main is copyable, because:
+// 1) There are no pointers to other stack locations in the frame
+// (d.fn points at a global, d.link is nil, d.argp is -1).
+// 2) The only pointer into this frame is from the defer chain,
+// which is explicitly handled during stack copying.
void
runtime_main(void* dummy __attribute__((unused)))
{
@@ -541,7 +529,7 @@ runtime_main(void* dummy __attribute__((unused)))
d.__retaddr = nil;
d.__makefunc_can_recover = 0;
d.__frame = &frame;
- d.__free = 0;
+ d.__special = true;
g->defer = &d;
if(m != &runtime_m0)
@@ -560,8 +548,6 @@ runtime_main(void* dummy __attribute__((unused)))
mstats.enablegc = 1;
main_main();
- if(raceenabled)
- runtime_racefini();
// Make racy client program work: if panicking on
// another goroutine at the same time as main returns,
@@ -579,6 +565,7 @@ void
runtime_goroutineheader(G *gp)
{
const char *status;
+ int64 waitfor;
switch(gp->status) {
case Gidle:
@@ -603,7 +590,16 @@ runtime_goroutineheader(G *gp)
status = "???";
break;
}
- runtime_printf("goroutine %D [%s]:\n", gp->goid, status);
+
+ // approx time the G is blocked, in minutes
+ waitfor = 0;
+ if((gp->status == Gwaiting || gp->status == Gsyscall) && gp->waitsince != 0)
+ waitfor = (runtime_nanotime() - gp->waitsince) / (60LL*1000*1000*1000);
+
+ if(waitfor < 1)
+ runtime_printf("goroutine %D [%s]:\n", gp->goid, status);
+ else
+ runtime_printf("goroutine %D [%s, %D minutes]:\n", gp->goid, status, waitfor);
}
void
@@ -624,7 +620,7 @@ runtime_printcreatedby(G *g)
struct Traceback
{
G* gp;
- Location locbuf[100];
+ Location locbuf[TracebackMaxFrames];
int32 c;
};
@@ -634,6 +630,7 @@ runtime_tracebackothers(G * volatile me)
G * volatile gp;
Traceback tb;
int32 traceback;
+ volatile uintptr i;
tb.gp = me;
traceback = runtime_gotraceback(nil);
@@ -657,7 +654,9 @@ runtime_tracebackothers(G * volatile me)
runtime_printcreatedby(gp);
}
- for(gp = runtime_allg; gp != nil; gp = gp->alllink) {
+ runtime_lock(&allglock);
+ for(i = 0; i < runtime_allglen; i++) {
+ gp = runtime_allg[i];
if(gp == me || gp == m->curg || gp->status == Gdead)
continue;
if(gp->issystem && traceback < 2)
@@ -696,6 +695,7 @@ runtime_tracebackothers(G * volatile me)
runtime_printcreatedby(gp);
}
}
+ runtime_unlock(&allglock);
}
static void
@@ -719,7 +719,7 @@ gtraceback(G* gp)
traceback = gp->traceback;
gp->traceback = nil;
traceback->c = runtime_callers(1, traceback->locbuf,
- sizeof traceback->locbuf / sizeof traceback->locbuf[0]);
+ sizeof traceback->locbuf / sizeof traceback->locbuf[0], false);
runtime_gogo(traceback->gp);
}
@@ -729,7 +729,7 @@ mcommoninit(M *mp)
// If there is no mcache runtime_callers() will crash,
// and we are most likely in sysmon thread so the stack is senseless anyway.
if(m->mcache)
- runtime_callers(1, mp->createstack, nelem(mp->createstack));
+ runtime_callers(1, mp->createstack, nelem(mp->createstack), false);
mp->fastrand = 0x49f6428aUL + mp->id + runtime_cputicks();
@@ -1038,6 +1038,7 @@ struct CgoThreadStart
{
M *m;
G *g;
+ uintptr *tls;
void (*fn)(void);
};
@@ -1070,6 +1071,22 @@ runtime_allocm(P *p, int32 stacksize, byte** ret_g0_stack, size_t* ret_g0_stacks
return mp;
}
+static G*
+allocg(void)
+{
+ G *gp;
+ // static Type *gtype;
+
+ // if(gtype == nil) {
+ // Eface e;
+ // runtime_gc_g_ptr(&e);
+ // gtype = ((PtrType*)e.__type_descriptor)->__element_type;
+ // }
+ // gp = runtime_cnew(gtype);
+ gp = runtime_malloc(sizeof(G));
+ return gp;
+}
+
static M* lockextra(bool nilokay);
static void unlockextra(M*);
@@ -1151,6 +1168,7 @@ runtime_needm(void)
__splitstack_getcontext(&g->stack_context[0]);
#else
g->gcinitial_sp = &mp;
+ g->gcstack = nil;
g->gcstack_size = 0;
g->gcnext_sp = &mp;
#endif
@@ -1200,22 +1218,12 @@ runtime_newextram(void)
gp->lockedm = mp;
gp->goid = runtime_xadd64(&runtime_sched.goidgen, 1);
// put on allg for garbage collector
- runtime_lock(&runtime_sched);
- if(runtime_lastg == nil)
- runtime_allg = gp;
- else
- runtime_lastg->alllink = gp;
- runtime_lastg = gp;
- runtime_unlock(&runtime_sched);
- gp->goid = runtime_xadd64(&runtime_sched.goidgen, 1);
+ allgadd(gp);
// The context for gp will be set up in runtime_needm. But
// here we need to set up the context for g0.
getcontext(&mp->g0->context);
mp->g0->context.uc_stack.ss_sp = g0_sp;
-#ifdef MAKECONTEXT_STACK_TOP
- mp->g0->context.uc_stack.ss_sp += g0_spsize;
-#endif
mp->g0->context.uc_stack.ss_size = g0_spsize;
makecontext(&mp->g0->context, kickoff, 0);
@@ -1262,6 +1270,8 @@ runtime_dropm(void)
runtime_setmg(nil, nil);
mp->curg->status = Gdead;
+ mp->curg->gcstack = nil;
+ mp->curg->gcnext_sp = nil;
mnext = lockextra(true);
mp->schedlink = mnext;
@@ -1382,7 +1392,7 @@ mspinning(void)
}
// Schedules some M to run the p (creates an M if necessary).
-// If p==nil, tries to get an idle P, if no idle P's returns false.
+// If p==nil, tries to get an idle P, if no idle P's does nothing.
static void
startm(P *p, bool spinning)
{
@@ -1546,6 +1556,7 @@ execute(G *gp)
runtime_throw("execute: bad g status");
}
gp->status = Grunning;
+ gp->waitsince = 0;
m->p->schedtick++;
m->curg = gp;
gp->m = m;
@@ -1572,6 +1583,8 @@ top:
gcstopm();
goto top;
}
+ if(runtime_fingwait && runtime_fingwake && (gp = runtime_wakefing()) != nil)
+ runtime_ready(gp);
// local runq
gp = runqget(m->p);
if(gp)
@@ -1763,28 +1776,52 @@ top:
execute(gp);
}
-// Puts the current goroutine into a waiting state and unlocks the lock.
-// The goroutine can be made runnable again by calling runtime_ready(gp).
+// Puts the current goroutine into a waiting state and calls unlockf.
+// If unlockf returns false, the goroutine is resumed.
void
-runtime_park(void(*unlockf)(Lock*), Lock *lock, const char *reason)
+runtime_park(bool(*unlockf)(G*, void*), void *lock, const char *reason)
{
+ if(g->status != Grunning)
+ runtime_throw("bad g status");
m->waitlock = lock;
m->waitunlockf = unlockf;
g->waitreason = reason;
runtime_mcall(park0);
}
+static bool
+parkunlock(G *gp, void *lock)
+{
+ USED(gp);
+ runtime_unlock(lock);
+ return true;
+}
+
+// Puts the current goroutine into a waiting state and unlocks the lock.
+// The goroutine can be made runnable again by calling runtime_ready(gp).
+void
+runtime_parkunlock(Lock *lock, const char *reason)
+{
+ runtime_park(parkunlock, lock, reason);
+}
+
// runtime_park continuation on g0.
static void
park0(G *gp)
{
+ bool ok;
+
gp->status = Gwaiting;
gp->m = nil;
m->curg = nil;
if(m->waitunlockf) {
- m->waitunlockf(m->waitlock);
+ ok = m->waitunlockf(gp, m->waitlock);
m->waitunlockf = nil;
m->waitlock = nil;
+ if(!ok) {
+ gp->status = Grunnable;
+ execute(gp); // Schedule it back, never returns.
+ }
}
if(m->lockedg) {
stoplockedm();
@@ -1797,6 +1834,8 @@ park0(G *gp)
void
runtime_gosched(void)
{
+ if(g->status != Grunning)
+ runtime_throw("bad g status");
runtime_mcall(runtime_gosched0);
}
@@ -1821,11 +1860,12 @@ runtime_gosched0(G *gp)
// Need to mark it as nosplit, because it runs with sp > stackbase (as runtime_lessstack).
// Since it does not return it does not matter. But if it is preempted
// at the split stack check, GC will complain about inconsistent sp.
+void runtime_goexit(void) __attribute__ ((noinline));
void
runtime_goexit(void)
{
- if(raceenabled)
- runtime_racegoend();
+ if(g->status != Grunning)
+ runtime_throw("bad g status");
runtime_mcall(goexit0);
}
@@ -1837,6 +1877,13 @@ goexit0(G *gp)
gp->entry = nil;
gp->m = nil;
gp->lockedm = nil;
+ gp->paniconfault = 0;
+ gp->defer = nil; // should be true already but just in case.
+ gp->panic = nil; // non-nil for Goexit during panic. points at stack-allocated data.
+ gp->writenbuf = 0;
+ gp->writebuf = nil;
+ gp->waitreason = nil;
+ gp->param = nil;
m->curg = nil;
m->lockedg = nil;
if(m->locked & ~LockExternal) {
@@ -1893,7 +1940,7 @@ doentersyscall()
&g->gcinitial_sp);
#else
{
- uint32 v;
+ void *v;
g->gcnext_sp = (byte *) &v;
}
@@ -1971,6 +2018,7 @@ runtime_exitsyscall(void)
if(gp->isbackground) // do not consider blocked scavenger for deadlock detection
incidlelocked(-1);
+ g->waitsince = 0;
if(exitsyscallfast()) {
// There's a cpu for us, so we can run.
m->p->syscalltick++;
@@ -2084,8 +2132,8 @@ syscall_runtime_BeforeFork(void)
{
// Fork can hang if preempted with signals frequently enough (see issue 5517).
// Ensure that we stay on the same M where we disable profiling.
- m->locks++;
- if(m->profilehz != 0)
+ runtime_m()->locks++;
+ if(runtime_m()->profilehz != 0)
runtime_resetcpuprofiler(0);
}
@@ -2100,7 +2148,7 @@ syscall_runtime_AfterFork(void)
hz = runtime_sched.profilehz;
if(hz != 0)
runtime_resetcpuprofiler(hz);
- m->locks--;
+ runtime_m()->locks--;
}
// Allocate a new g, with a stack big enough for stacksize bytes.
@@ -2109,7 +2157,7 @@ runtime_malg(int32 stacksize, byte** ret_stack, size_t* ret_stacksize)
{
G *newg;
- newg = runtime_malloc(sizeof(G));
+ newg = allocg();
if(stacksize >= 0) {
#if USING_SPLIT_STACK
int dont_block_signals = 0;
@@ -2163,11 +2211,17 @@ __go_go(void (*fn)(void*), void* arg)
byte *sp;
size_t spsize;
G *newg;
+ P *p;
//runtime_printf("newproc1 %p %p narg=%d nret=%d\n", fn->fn, argp, narg, nret);
+ if(fn == nil) {
+ m->throwing = -1; // do not dump full stacks
+ runtime_throw("go of nil func value");
+ }
m->locks++; // disable preemption because it can be holding p in a local var
- if((newg = gfget(m->p)) != nil) {
+ p = m->p;
+ if((newg = gfget(p)) != nil) {
#ifdef USING_SPLIT_STACK
int dont_block_signals = 0;
@@ -2184,20 +2238,18 @@ __go_go(void (*fn)(void*), void* arg)
#endif
} else {
newg = runtime_malg(StackMin, &sp, &spsize);
- runtime_lock(&runtime_sched);
- if(runtime_lastg == nil)
- runtime_allg = newg;
- else
- runtime_lastg->alllink = newg;
- runtime_lastg = newg;
- runtime_unlock(&runtime_sched);
+ allgadd(newg);
}
newg->entry = (byte*)fn;
newg->param = arg;
newg->gopc = (uintptr)__builtin_return_address(0);
newg->status = Grunnable;
- newg->goid = runtime_xadd64(&runtime_sched.goidgen, 1);
+ if(p->goidcache == p->goidcacheend) {
+ p->goidcache = runtime_xadd64(&runtime_sched.goidgen, GoidCacheBatch);
+ p->goidcacheend = p->goidcache + GoidCacheBatch;
+ }
+ newg->goid = p->goidcache++;
{
// Avoid warnings about variables clobbered by
@@ -2214,7 +2266,7 @@ __go_go(void (*fn)(void*), void* arg)
vnewg->context.uc_stack.ss_size = vspsize;
makecontext(&vnewg->context, kickoff, 0);
- runqput(m->p, vnewg);
+ runqput(p, vnewg);
if(runtime_atomicload(&runtime_sched.npidle) != 0 && runtime_atomicload(&runtime_sched.nmspinning) == 0 && fn != runtime_main) // TODO: fast atomic
wakep();
@@ -2223,6 +2275,31 @@ __go_go(void (*fn)(void*), void* arg)
}
}
+static void
+allgadd(G *gp)
+{
+ G **new;
+ uintptr cap;
+
+ runtime_lock(&allglock);
+ if(runtime_allglen >= allgcap) {
+ cap = 4096/sizeof(new[0]);
+ if(cap < 2*allgcap)
+ cap = 2*allgcap;
+ new = runtime_malloc(cap*sizeof(new[0]));
+ if(new == nil)
+ runtime_throw("runtime: cannot allocate memory");
+ if(runtime_allg != nil) {
+ runtime_memmove(new, runtime_allg, runtime_allglen*sizeof(new[0]));
+ runtime_free(runtime_allg);
+ }
+ runtime_allg = new;
+ allgcap = cap;
+ }
+ runtime_allg[runtime_allglen++] = gp;
+ runtime_unlock(&allglock);
+}
+
// Put on gfree list.
// If local list is too long, transfer a batch to the global list.
static void
@@ -2393,44 +2470,26 @@ runtime_lockedOSThread(void)
return g->lockedm != nil && m->lockedg != nil;
}
-// for testing of callbacks
-
-_Bool runtime_golockedOSThread(void)
- __asm__ (GOSYM_PREFIX "runtime.golockedOSThread");
-
-_Bool
-runtime_golockedOSThread(void)
-{
- return runtime_lockedOSThread();
-}
-
-intgo runtime_NumGoroutine (void)
- __asm__ (GOSYM_PREFIX "runtime.NumGoroutine");
-
-intgo
-runtime_NumGoroutine()
-{
- return runtime_gcount();
-}
-
int32
runtime_gcount(void)
{
G *gp;
int32 n, s;
+ uintptr i;
n = 0;
- runtime_lock(&runtime_sched);
+ runtime_lock(&allglock);
// TODO(dvyukov): runtime.NumGoroutine() is O(N).
// We do not want to increment/decrement centralized counter in newproc/goexit,
// just to make runtime.NumGoroutine() faster.
// Compromise solution is to introduce per-P counters of active goroutines.
- for(gp = runtime_allg; gp; gp = gp->alllink) {
+ for(i = 0; i < runtime_allglen; i++) {
+ gp = runtime_allg[i];
s = gp->status;
if(s == Grunnable || s == Grunning || s == Gsyscall || s == Gwaiting)
n++;
}
- runtime_unlock(&runtime_sched);
+ runtime_unlock(&allglock);
return n;
}
@@ -2444,32 +2503,39 @@ static struct {
Lock;
void (*fn)(uintptr*, int32);
int32 hz;
- uintptr pcbuf[100];
- Location locbuf[100];
+ uintptr pcbuf[TracebackMaxFrames];
+ Location locbuf[TracebackMaxFrames];
} prof;
-static void
-System(void)
-{
-}
+static void System(void) {}
+static void GC(void) {}
// Called if we receive a SIGPROF signal.
void
runtime_sigprof()
{
+ M *mp = m;
int32 n, i;
bool traceback;
if(prof.fn == nil || prof.hz == 0)
return;
+
+ if(mp == nil)
+ return;
+
+ // Profiling runs concurrently with GC, so it must not allocate.
+ mp->mallocing++;
+
traceback = true;
- // Windows does profiling in a dedicated thread w/o m.
- if(!Windows && (m == nil || m->mcache == nil))
+
+ if(mp->mcache == nil)
traceback = false;
-
+
runtime_lock(&prof);
if(prof.fn == nil) {
runtime_unlock(&prof);
+ mp->mallocing--;
return;
}
n = 0;
@@ -2483,17 +2549,21 @@ runtime_sigprof()
}
if(traceback) {
- n = runtime_callers(0, prof.locbuf, nelem(prof.locbuf));
+ n = runtime_callers(0, prof.locbuf, nelem(prof.locbuf), false);
for(i = 0; i < n; i++)
prof.pcbuf[i] = prof.locbuf[i].pc;
}
- if (!traceback || n <= 0) {
+ if(!traceback || n <= 0) {
n = 2;
prof.pcbuf[0] = (uintptr)runtime_getcallerpc(&n);
- prof.pcbuf[1] = (uintptr)System + 1;
+ if(mp->gcing || mp->helpgc)
+ prof.pcbuf[1] = (uintptr)GC;
+ else
+ prof.pcbuf[1] = (uintptr)System;
}
prof.fn(prof.pcbuf, n);
runtime_unlock(&prof);
+ mp->mallocing--;
}
// Arrange to call fn with a traceback hz times a second.
@@ -2536,6 +2606,7 @@ static void
procresize(int32 new)
{
int32 i, old;
+ bool empty;
G *gp;
P *p;
@@ -2557,27 +2628,42 @@ procresize(int32 new)
else
p->mcache = runtime_allocmcache();
}
- if(p->runq == nil) {
- p->runqsize = 128;
- p->runq = (G**)runtime_mallocgc(p->runqsize*sizeof(G*), 0, FlagNoInvokeGC);
- }
}
// redistribute runnable G's evenly
- for(i = 0; i < old; i++) {
- p = runtime_allp[i];
- while((gp = runqget(p)) != nil)
- globrunqput(gp);
+ // collect all runnable goroutines in global queue preserving FIFO order
+ // FIFO order is required to ensure fairness even during frequent GCs
+ // see http://golang.org/issue/7126
+ empty = false;
+ while(!empty) {
+ empty = true;
+ for(i = 0; i < old; i++) {
+ p = runtime_allp[i];
+ if(p->runqhead == p->runqtail)
+ continue;
+ empty = false;
+ // pop from tail of local queue
+ p->runqtail--;
+ gp = p->runq[p->runqtail%nelem(p->runq)];
+ // push onto head of global queue
+ gp->schedlink = runtime_sched.runqhead;
+ runtime_sched.runqhead = gp;
+ if(runtime_sched.runqtail == nil)
+ runtime_sched.runqtail = gp;
+ runtime_sched.runqsize++;
+ }
}
+ // fill local queues with at most nelem(p->runq)/2 goroutines
// start at 1 because current M already executes some G and will acquire allp[0] below,
// so if we have a spare G we want to put it into allp[1].
- for(i = 1; runtime_sched.runqhead; i++) {
+ for(i = 1; (uint32)i < (uint32)new * nelem(p->runq)/2 && runtime_sched.runqsize > 0; i++) {
gp = runtime_sched.runqhead;
runtime_sched.runqhead = gp->schedlink;
+ if(runtime_sched.runqhead == nil)
+ runtime_sched.runqtail = nil;
+ runtime_sched.runqsize--;
runqput(runtime_allp[i%new], gp);
}
- runtime_sched.runqtail = nil;
- runtime_sched.runqsize = 0;
// free unused P's
for(i = new; i < old; i++) {
@@ -2659,30 +2745,41 @@ checkdead(void)
{
G *gp;
int32 run, grunning, s;
+ uintptr i;
// -1 for sysmon
run = runtime_sched.mcount - runtime_sched.nmidle - runtime_sched.nmidlelocked - 1 - countextra();
if(run > 0)
return;
+ // If we are dying because of a signal caught on an already idle thread,
+ // freezetheworld will cause all running threads to block.
+ // And runtime will essentially enter into deadlock state,
+ // except that there is a thread that will call runtime_exit soon.
+ if(runtime_panicking > 0)
+ return;
if(run < 0) {
- runtime_printf("checkdead: nmidle=%d nmidlelocked=%d mcount=%d\n",
+ runtime_printf("runtime: checkdead: nmidle=%d nmidlelocked=%d mcount=%d\n",
runtime_sched.nmidle, runtime_sched.nmidlelocked, runtime_sched.mcount);
runtime_throw("checkdead: inconsistent counts");
}
grunning = 0;
- for(gp = runtime_allg; gp; gp = gp->alllink) {
+ runtime_lock(&allglock);
+ for(i = 0; i < runtime_allglen; i++) {
+ gp = runtime_allg[i];
if(gp->isbackground)
continue;
s = gp->status;
if(s == Gwaiting)
grunning++;
else if(s == Grunnable || s == Grunning || s == Gsyscall) {
- runtime_printf("checkdead: find g %D in status %d\n", gp->goid, s);
+ runtime_unlock(&allglock);
+ runtime_printf("runtime: checkdead: find g %D in status %d\n", gp->goid, s);
runtime_throw("checkdead: runnable g");
}
}
+ runtime_unlock(&allglock);
if(grunning == 0) // possible if main goroutine calls runtime_Goexit()
- runtime_exit(0);
+ runtime_throw("no goroutines (main called runtime.Goexit) - deadlock!");
m->throwing = -1; // do not dump full stacks
runtime_throw("all goroutines are asleep - deadlock!");
}
@@ -2777,16 +2874,19 @@ retake(int64 now)
pd = &pdesc[i];
s = p->status;
if(s == Psyscall) {
- // Retake P from syscall if it's there for more than 1 sysmon tick (20us).
- // But only if there is other work to do.
+ // Retake P from syscall if it's there for more than 1 sysmon tick (at least 20us).
t = p->syscalltick;
if(pd->syscalltick != t) {
pd->syscalltick = t;
pd->syscallwhen = now;
continue;
}
+ // On the one hand we don't want to retake Ps if there is no other work to do,
+ // but on the other hand we want to retake them eventually
+ // because they can prevent the sysmon thread from deep sleep.
if(p->runqhead == p->runqtail &&
- runtime_atomicload(&runtime_sched.nmspinning) + runtime_atomicload(&runtime_sched.npidle) > 0)
+ runtime_atomicload(&runtime_sched.nmspinning) + runtime_atomicload(&runtime_sched.npidle) > 0 &&
+ pd->syscallwhen + 10*1000*1000 > now)
continue;
// Need to decrement number of idle locked M's
// (pretending that one more is running) before the CAS.
@@ -2831,7 +2931,8 @@ runtime_schedtrace(bool detailed)
static int64 starttime;
int64 now;
int64 id1, id2, id3;
- int32 i, q, t, h, s;
+ int32 i, t, h;
+ uintptr gi;
const char *fmt;
M *mp, *lockedm;
G *gp, *lockedg;
@@ -2858,15 +2959,11 @@ runtime_schedtrace(bool detailed)
if(p == nil)
continue;
mp = p->m;
- t = p->runqtail;
- h = p->runqhead;
- s = p->runqsize;
- q = t - h;
- if(q < 0)
- q += s;
+ h = runtime_atomicload(&p->runqhead);
+ t = runtime_atomicload(&p->runqtail);
if(detailed)
- runtime_printf(" P%d: status=%d schedtick=%d syscalltick=%d m=%d runqsize=%d/%d gfreecnt=%d\n",
- i, p->status, p->schedtick, p->syscalltick, mp ? mp->id : -1, q, s, p->gfreecnt);
+ runtime_printf(" P%d: status=%d schedtick=%d syscalltick=%d m=%d runqsize=%d gfreecnt=%d\n",
+ i, p->status, p->schedtick, p->syscalltick, mp ? mp->id : -1, t-h, p->gfreecnt);
else {
// In non-detailed mode format lengths of per-P run queues as:
// [len1 len2 len3 len4]
@@ -2877,7 +2974,7 @@ runtime_schedtrace(bool detailed)
fmt = " [%d";
else if(i == runtime_gomaxprocs-1)
fmt = " %d]\n";
- runtime_printf(fmt, q);
+ runtime_printf(fmt, t-h);
}
}
if(!detailed) {
@@ -2898,18 +2995,21 @@ runtime_schedtrace(bool detailed)
if(lockedg)
id3 = lockedg->goid;
runtime_printf(" M%d: p=%D curg=%D mallocing=%d throwing=%d gcing=%d"
- " locks=%d dying=%d helpgc=%d spinning=%d lockedg=%D\n",
+ " locks=%d dying=%d helpgc=%d spinning=%d blocked=%d lockedg=%D\n",
mp->id, id1, id2,
mp->mallocing, mp->throwing, mp->gcing, mp->locks, mp->dying, mp->helpgc,
- mp->spinning, id3);
+ mp->spinning, m->blocked, id3);
}
- for(gp = runtime_allg; gp; gp = gp->alllink) {
+ runtime_lock(&allglock);
+ for(gi = 0; gi < runtime_allglen; gi++) {
+ gp = runtime_allg[gi];
mp = gp->m;
lockedm = gp->lockedm;
runtime_printf(" G%D: status=%d(%s) m=%d lockedm=%d\n",
gp->goid, gp->status, gp->waitreason, mp ? mp->id : -1,
lockedm ? lockedm->id : -1);
}
+ runtime_unlock(&allglock);
runtime_unlock(&runtime_sched);
}
@@ -2952,6 +3052,20 @@ globrunqput(G *gp)
runtime_sched.runqsize++;
}
+// Put a batch of runnable goroutines on the global runnable queue.
+// Sched must be locked.
+static void
+globrunqputbatch(G *ghead, G *gtail, int32 n)
+{
+ gtail->schedlink = nil;
+ if(runtime_sched.runqtail)
+ runtime_sched.runqtail->schedlink = ghead;
+ else
+ runtime_sched.runqhead = ghead;
+ runtime_sched.runqtail = gtail;
+ runtime_sched.runqsize += n;
+}
+
// Try get a batch of G's from the global runnable queue.
// Sched must be locked.
static G*
@@ -2967,6 +3081,8 @@ globrunqget(P *p, int32 max)
n = runtime_sched.runqsize;
if(max > 0 && n > max)
n = max;
+ if((uint32)n > nelem(p->runq)/2)
+ n = nelem(p->runq)/2;
runtime_sched.runqsize -= n;
if(runtime_sched.runqsize == 0)
runtime_sched.runqtail = nil;
@@ -3006,78 +3122,98 @@ pidleget(void)
return p;
}
-// Put g on local runnable queue.
-// TODO(dvyukov): consider using lock-free queue.
+// Try to put g on local runnable queue.
+// If it's full, put onto global queue.
+// Executed only by the owner P.
static void
runqput(P *p, G *gp)
{
- int32 h, t, s;
+ uint32 h, t;
- runtime_lock(p);
retry:
- h = p->runqhead;
+ h = runtime_atomicload(&p->runqhead); // load-acquire, synchronize with consumers
t = p->runqtail;
- s = p->runqsize;
- if(t == h-1 || (h == 0 && t == s-1)) {
- runqgrow(p);
- goto retry;
+ if(t - h < nelem(p->runq)) {
+ p->runq[t%nelem(p->runq)] = gp;
+ runtime_atomicstore(&p->runqtail, t+1); // store-release, makes the item available for consumption
+ return;
}
- p->runq[t++] = gp;
- if(t == s)
- t = 0;
- p->runqtail = t;
- runtime_unlock(p);
+ if(runqputslow(p, gp, h, t))
+ return;
+ // the queue is not full, now the put above must suceed
+ goto retry;
+}
+
+// Put g and a batch of work from local runnable queue on global queue.
+// Executed only by the owner P.
+static bool
+runqputslow(P *p, G *gp, uint32 h, uint32 t)
+{
+ G *batch[nelem(p->runq)/2+1];
+ uint32 n, i;
+
+ // First, grab a batch from local queue.
+ n = t-h;
+ n = n/2;
+ if(n != nelem(p->runq)/2)
+ runtime_throw("runqputslow: queue is not full");
+ for(i=0; i<n; i++)
+ batch[i] = p->runq[(h+i)%nelem(p->runq)];
+ if(!runtime_cas(&p->runqhead, h, h+n)) // cas-release, commits consume
+ return false;
+ batch[n] = gp;
+ // Link the goroutines.
+ for(i=0; i<n; i++)
+ batch[i]->schedlink = batch[i+1];
+ // Now put the batch on global queue.
+ runtime_lock(&runtime_sched);
+ globrunqputbatch(batch[0], batch[n], n+1);
+ runtime_unlock(&runtime_sched);
+ return true;
}
// Get g from local runnable queue.
+// Executed only by the owner P.
static G*
runqget(P *p)
{
G *gp;
- int32 t, h, s;
+ uint32 t, h;
- if(p->runqhead == p->runqtail)
- return nil;
- runtime_lock(p);
- h = p->runqhead;
- t = p->runqtail;
- s = p->runqsize;
- if(t == h) {
- runtime_unlock(p);
- return nil;
+ for(;;) {
+ h = runtime_atomicload(&p->runqhead); // load-acquire, synchronize with other consumers
+ t = p->runqtail;
+ if(t == h)
+ return nil;
+ gp = p->runq[h%nelem(p->runq)];
+ if(runtime_cas(&p->runqhead, h, h+1)) // cas-release, commits consume
+ return gp;
}
- gp = p->runq[h++];
- if(h == s)
- h = 0;
- p->runqhead = h;
- runtime_unlock(p);
- return gp;
}
-// Grow local runnable queue.
-// TODO(dvyukov): consider using fixed-size array
-// and transfer excess to the global list (local queue can grow way too big).
-static void
-runqgrow(P *p)
+// Grabs a batch of goroutines from local runnable queue.
+// batch array must be of size nelem(p->runq)/2. Returns number of grabbed goroutines.
+// Can be executed by any P.
+static uint32
+runqgrab(P *p, G **batch)
{
- G **q;
- int32 s, t, h, t2;
+ uint32 t, h, n, i;
- h = p->runqhead;
- t = p->runqtail;
- s = p->runqsize;
- t2 = 0;
- q = runtime_malloc(2*s*sizeof(*q));
- while(t != h) {
- q[t2++] = p->runq[h++];
- if(h == s)
- h = 0;
+ for(;;) {
+ h = runtime_atomicload(&p->runqhead); // load-acquire, synchronize with other consumers
+ t = runtime_atomicload(&p->runqtail); // load-acquire, synchronize with the producer
+ n = t-h;
+ n = n - n/2;
+ if(n == 0)
+ break;
+ if(n > nelem(p->runq)/2) // read inconsistent h and t
+ continue;
+ for(i=0; i<n; i++)
+ batch[i] = p->runq[(h+i)%nelem(p->runq)];
+ if(runtime_cas(&p->runqhead, h, h+n)) // cas-release, commits consume
+ break;
}
- runtime_free(p->runq);
- p->runq = q;
- p->runqhead = 0;
- p->runqtail = t2;
- p->runqsize = 2*s;
+ return n;
}
// Steal half of elements from local runnable queue of p2
@@ -3086,57 +3222,24 @@ runqgrow(P *p)
static G*
runqsteal(P *p, P *p2)
{
- G *gp, *gp1;
- int32 t, h, s, t2, h2, s2, c, i;
+ G *gp;
+ G *batch[nelem(p->runq)/2];
+ uint32 t, h, n, i;
- if(p2->runqhead == p2->runqtail)
- return nil;
- // sort locks to prevent deadlocks
- if(p < p2)
- runtime_lock(p);
- runtime_lock(p2);
- if(p2->runqhead == p2->runqtail) {
- runtime_unlock(p2);
- if(p < p2)
- runtime_unlock(p);
+ n = runqgrab(p2, batch);
+ if(n == 0)
return nil;
- }
- if(p >= p2)
- runtime_lock(p);
- // now we've locked both queues and know the victim is not empty
- h = p->runqhead;
+ n--;
+ gp = batch[n];
+ if(n == 0)
+ return gp;
+ h = runtime_atomicload(&p->runqhead); // load-acquire, synchronize with consumers
t = p->runqtail;
- s = p->runqsize;
- h2 = p2->runqhead;
- t2 = p2->runqtail;
- s2 = p2->runqsize;
- gp = p2->runq[h2++]; // return value
- if(h2 == s2)
- h2 = 0;
- // steal roughly half
- if(t2 > h2)
- c = (t2 - h2) / 2;
- else
- c = (s2 - h2 + t2) / 2;
- // copy
- for(i = 0; i != c; i++) {
- // the target queue is full?
- if(t == h-1 || (h == 0 && t == s-1))
- break;
- // the victim queue is empty?
- if(t2 == h2)
- break;
- gp1 = p2->runq[h2++];
- if(h2 == s2)
- h2 = 0;
- p->runq[t++] = gp1;
- if(t == s)
- t = 0;
- }
- p->runqtail = t;
- p2->runqhead = h2;
- runtime_unlock(p2);
- runtime_unlock(p);
+ if(t - h + n >= nelem(p->runq))
+ runtime_throw("runqsteal: runq overflow");
+ for(i=0; i<n; i++, t++)
+ p->runq[t%nelem(p->runq)] = batch[i];
+ runtime_atomicstore(&p->runqtail, t); // store-release, makes the item available for consumption
return gp;
}
@@ -3147,14 +3250,10 @@ void
runtime_testSchedLocalQueue(void)
{
P p;
- G gs[1000];
+ G gs[nelem(p.runq)];
int32 i, j;
runtime_memclr((byte*)&p, sizeof(p));
- p.runqsize = 1;
- p.runqhead = 0;
- p.runqtail = 0;
- p.runq = runtime_malloc(p.runqsize*sizeof(*p.runq));
for(i = 0; i < (int32)nelem(gs); i++) {
if(runqget(&p) != nil)
@@ -3179,20 +3278,11 @@ void
runtime_testSchedLocalQueueSteal(void)
{
P p1, p2;
- G gs[1000], *gp;
+ G gs[nelem(p1.runq)], *gp;
int32 i, j, s;
runtime_memclr((byte*)&p1, sizeof(p1));
- p1.runqsize = 1;
- p1.runqhead = 0;
- p1.runqtail = 0;
- p1.runq = runtime_malloc(p1.runqsize*sizeof(*p1.runq));
-
runtime_memclr((byte*)&p2, sizeof(p2));
- p2.runqsize = nelem(gs);
- p2.runqhead = 0;
- p2.runqtail = 0;
- p2.runq = runtime_malloc(p2.runqsize*sizeof(*p2.runq));
for(i = 0; i < (int32)nelem(gs); i++) {
for(j = 0; j < i; j++) {
@@ -3225,13 +3315,10 @@ runtime_testSchedLocalQueueSteal(void)
}
}
-intgo runtime_debug_setMaxThreads(intgo)
- __asm__(GOSYM_PREFIX "runtime_debug.setMaxThreads");
-
-intgo
-runtime_debug_setMaxThreads(intgo in)
+int32
+runtime_setmaxthreads(int32 in)
{
- intgo out;
+ int32 out;
runtime_lock(&runtime_sched);
out = runtime_sched.maxmcount;
@@ -3242,29 +3329,9 @@ runtime_debug_setMaxThreads(intgo in)
}
void
-runtime_proc_scan(void (*addroot)(Obj))
-{
- addroot((Obj){(byte*)&runtime_sched, sizeof runtime_sched, 0});
-}
-
-// When a function calls a closure, it passes the closure value to
-// __go_set_closure immediately before the function call. When a
-// function uses a closure, it calls __go_get_closure immediately on
-// function entry. This is a hack, but it will work on any system.
-// It would be better to use the static chain register when there is
-// one. It is also worth considering expanding these functions
-// directly in the compiler.
-
-void
-__go_set_closure(void* v)
-{
- g->closure = v;
-}
-
-void *
-__go_get_closure(void)
+runtime_proc_scan(struct Workbuf** wbufp, void (*enqueue1)(struct Workbuf**, Obj))
{
- return g->closure;
+ enqueue1(wbufp, (Obj){(byte*)&runtime_sched, sizeof runtime_sched, 0});
}
// Return whether we are waiting for a GC. This gc toolchain uses
diff --git a/libgo/runtime/race.h b/libgo/runtime/race.h
deleted file mode 100644
index 884245ceda..0000000000
--- a/libgo/runtime/race.h
+++ /dev/null
@@ -1,33 +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.
-
-// Definitions related to data race detection.
-
-#ifdef RACE
-enum { raceenabled = 1 };
-#else
-enum { raceenabled = 0 };
-#endif
-
-// Initialize race detection subsystem.
-uintptr runtime_raceinit(void);
-// Finalize race detection subsystem, does not return.
-void runtime_racefini(void);
-
-void runtime_racemapshadow(void *addr, uintptr size);
-void runtime_racemalloc(void *p, uintptr sz);
-void runtime_racefree(void *p);
-uintptr runtime_racegostart(void *pc);
-void runtime_racegoend(void);
-void runtime_racewritepc(void *addr, void *callpc, void *pc);
-void runtime_racereadpc(void *addr, void *callpc, void *pc);
-void runtime_racewriterangepc(void *addr, uintptr sz, void *callpc, void *pc);
-void runtime_racereadrangepc(void *addr, uintptr sz, void *callpc, void *pc);
-void runtime_racefingo(void);
-void runtime_raceacquire(void *addr);
-void runtime_raceacquireg(G *gp, void *addr);
-void runtime_racerelease(void *addr);
-void runtime_racereleaseg(G *gp, void *addr);
-void runtime_racereleasemerge(void *addr);
-void runtime_racereleasemergeg(G *gp, void *addr);
diff --git a/libgo/runtime/rdebug.goc b/libgo/runtime/rdebug.goc
new file mode 100644
index 0000000000..63eb4dd457
--- /dev/null
+++ b/libgo/runtime/rdebug.goc
@@ -0,0 +1,26 @@
+// 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_debug
+#include "runtime.h"
+#include "arch.h"
+#include "malloc.h"
+
+func setMaxStack(in int) (out int) {
+ out = runtime_maxstacksize;
+ runtime_maxstacksize = in;
+}
+
+func setGCPercent(in int) (out int) {
+ out = runtime_setgcpercent(in);
+}
+
+func setMaxThreads(in int) (out int) {
+ out = runtime_setmaxthreads(in);
+}
+
+func SetPanicOnFault(enabled bool) (old bool) {
+ old = runtime_g()->paniconfault;
+ runtime_g()->paniconfault = enabled;
+}
diff --git a/libgo/runtime/reflect.goc b/libgo/runtime/reflect.goc
index c798b269e0..4e493ee810 100644
--- a/libgo/runtime/reflect.goc
+++ b/libgo/runtime/reflect.goc
@@ -12,8 +12,6 @@ func ifaceE2I(inter *Type, e Eface, ret *Iface) {
const Type *t;
Eface err;
- if(((uintptr)e.__type_descriptor&reflectFlags) != 0)
- runtime_throw("invalid interface value");
t = e.__type_descriptor;
if(t == nil) {
// explicit conversions require non-nil interface value.
diff --git a/libgo/runtime/runtime.c b/libgo/runtime/runtime.c
index 1a7c3c7219..e3320356c4 100644
--- a/libgo/runtime/runtime.c
+++ b/libgo/runtime/runtime.c
@@ -8,8 +8,23 @@
#include "config.h"
#include "runtime.h"
+#include "arch.h"
#include "array.h"
-#include "go-panic.h"
+
+enum {
+ maxround = sizeof(uintptr),
+};
+
+// Keep a cached value to make gotraceback fast,
+// since we call it on every call to gentraceback.
+// The cached value is a uint32 in which the low bit
+// is the "crash" setting and the top 31 bits are the
+// gotraceback value.
+static uint32 traceback_cache = ~(uint32)0;
+
+extern volatile intgo runtime_MemProfileRate
+ __asm__ (GOSYM_PREFIX "runtime.MemProfileRate");
+
// The GOTRACEBACK environment variable controls the
// behavior of a Go program that is crashing and exiting.
@@ -21,25 +36,35 @@ int32
runtime_gotraceback(bool *crash)
{
const byte *p;
+ uint32 x;
if(crash != nil)
*crash = false;
- p = runtime_getenv("GOTRACEBACK");
- if(p == nil || p[0] == '\0')
- return 1; // default is on
- if(runtime_strcmp((const char *)p, "crash") == 0) {
- if(crash != nil)
- *crash = true;
- return 2; // extra information
+ if(runtime_m()->traceback != 0)
+ 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')
+ x = 1<<1;
+ else if(runtime_strcmp((const char *)p, "crash") == 0)
+ x = (2<<1) | 1;
+ else
+ x = runtime_atoi(p)<<1;
+ runtime_atomicstore(&traceback_cache, x);
}
- return runtime_atoi(p);
+ if(crash != nil)
+ *crash = x&1;
+ return x>>1;
}
static int32 argc;
static byte** argv;
-extern Slice os_Args __asm__ (GOSYM_PREFIX "os.Args");
-extern Slice syscall_Envs __asm__ (GOSYM_PREFIX "syscall.Envs");
+static Slice args;
+Slice envs;
void (*runtime_sysargs)(int32, uint8**);
@@ -71,9 +96,9 @@ runtime_goargs(void)
s = runtime_malloc(argc*sizeof s[0]);
for(i=0; i<argc; i++)
s[i] = runtime_gostringnocopy((const byte*)argv[i]);
- os_Args.__values = (void*)s;
- os_Args.__count = argc;
- os_Args.__capacity = argc;
+ args.__values = (void*)s;
+ args.__count = argc;
+ args.__capacity = argc;
}
void
@@ -88,9 +113,26 @@ runtime_goenvs_unix(void)
s = runtime_malloc(n*sizeof s[0]);
for(i=0; i<n; i++)
s[i] = runtime_gostringnocopy(argv[argc+1+i]);
- syscall_Envs.__values = (void*)s;
- syscall_Envs.__count = n;
- syscall_Envs.__capacity = n;
+ envs.__values = (void*)s;
+ envs.__count = n;
+ envs.__capacity = n;
+}
+
+// Called from the syscall package.
+Slice runtime_envs(void) __asm__ (GOSYM_PREFIX "syscall.runtime_envs");
+
+Slice
+runtime_envs()
+{
+ return envs;
+}
+
+Slice os_runtime_args(void) __asm__ (GOSYM_PREFIX "os.runtime_args");
+
+Slice
+os_runtime_args()
+{
+ return args;
}
int32
@@ -106,8 +148,8 @@ runtime_atoi(const byte *p)
static struct root_list runtime_roots =
{ nil,
- { { &syscall_Envs, sizeof syscall_Envs },
- { &os_Args, sizeof os_Args },
+ { { &envs, sizeof envs },
+ { &args, sizeof args },
{ nil, 0 } },
};
@@ -173,6 +215,14 @@ runtime_cputicks(void)
uint32 low, high;
asm("rdtsc" : "=a" (low), "=d" (high));
return (int64)(((uint64)high << 32) | (uint64)low);
+#elif defined (__s390__) || defined (__s390x__)
+ uint64 clock = 0;
+ /* stckf may not write the return variable in case of a clock error, so make
+ it read-write to prevent that the initialisation is optimised out.
+ Note: Targets below z9-109 will crash when executing store clock fast, i.e.
+ we don't support Go for machines older than that. */
+ asm volatile(".insn s,0xb27c0000,%0" /* stckf */ : "+Q" (clock) : : "cc" );
+ return (int64)clock;
#else
// FIXME: implement for other processors.
return 0;
@@ -221,15 +271,6 @@ runtime_tickspersecond(void)
return res;
}
-int64 runtime_pprof_runtime_cyclesPerSecond(void)
- __asm__ (GOSYM_PREFIX "runtime_pprof.runtime_cyclesPerSecond");
-
-int64
-runtime_pprof_runtime_cyclesPerSecond(void)
-{
- return runtime_tickspersecond();
-}
-
// Called to initialize a new m (including the bootstrap m).
// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
void
@@ -278,13 +319,21 @@ runtime_signalstack(byte *p, int32 n)
DebugVars runtime_debug;
+// Holds variables parsed from GODEBUG env var,
+// except for "memprofilerate" since there is an
+// existing var for that value which is int
+// instead of in32 and might have an
+// initial value.
static struct {
const char* name;
int32* value;
} dbgvar[] = {
+ {"allocfreetrace", &runtime_debug.allocfreetrace},
+ {"efence", &runtime_debug.efence},
{"gctrace", &runtime_debug.gctrace},
- {"schedtrace", &runtime_debug.schedtrace},
+ {"gcdead", &runtime_debug.gcdead},
{"scheddetail", &runtime_debug.scheddetail},
+ {"schedtrace", &runtime_debug.schedtrace},
};
void
@@ -292,6 +341,16 @@ runtime_parsedebugvars(void)
{
const byte *p;
intgo i, n;
+ bool tmp;
+
+ // gotraceback caches the GOTRACEBACK setting in traceback_cache.
+ // gotraceback can be called before the environment is available.
+ // traceback_cache must be reset after the environment is made
+ // available, in order for the environment variable to take effect.
+ // The code is fixed differently in Go 1.4.
+ // This is a limited fix for Go 1.3.3.
+ traceback_cache = ~(uint32)0;
+ runtime_gotraceback(&tmp);
p = runtime_getenv("GODEBUG");
if(p == nil)
@@ -299,7 +358,12 @@ runtime_parsedebugvars(void)
for(;;) {
for(i=0; i<(intgo)nelem(dbgvar); i++) {
n = runtime_findnull((const byte*)dbgvar[i].name);
- if(runtime_mcmp(p, dbgvar[i].name, n) == 0 && p[n] == '=')
+ if(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);
}
p = (const byte *)runtime_strstr((const char *)p, ",");
@@ -339,15 +403,11 @@ runtime_timediv(int64 v, int32 div, int32 *rem)
uintptr runtime_maxstacksize = 1<<20; // enough until runtime.main sets it for real
-intgo runtime_debug_setMaxStack(intgo)
- __asm__ (GOSYM_PREFIX "runtime_debug.setMaxStack");
+void memclrBytes(Slice)
+ __asm__ (GOSYM_PREFIX "runtime.memclrBytes");
-intgo
-runtime_debug_setMaxStack(intgo in)
+void
+memclrBytes(Slice s)
{
- intgo out;
-
- out = runtime_maxstacksize;
- runtime_maxstacksize = in;
- return out;
+ runtime_memclr(s.__values, s.__count);
}
diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h
index da2416335e..515ae58ff8 100644
--- a/libgo/runtime/runtime.h
+++ b/libgo/runtime/runtime.h
@@ -5,6 +5,7 @@
#include "config.h"
#include "go-assert.h"
+#include <complex.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
@@ -48,6 +49,8 @@ typedef unsigned int uintptr __attribute__ ((mode (pointer)));
typedef intptr intgo; // Go's int
typedef uintptr uintgo; // Go's uint
+typedef uintptr uintreg;
+
/* Defined types. */
typedef uint8 bool;
@@ -192,7 +195,6 @@ struct Location
struct G
{
- void* closure; // Closure value.
Defer* defer;
Panic* panic;
void* exception; // current exception being thrown
@@ -204,24 +206,23 @@ struct G
void* gcinitial_sp;
ucontext_t gcregs;
byte* entry; // initial function
- G* alllink; // on allg
void* param; // passed parameter on wakeup
bool fromgogo; // reached from gogo
int16 status;
uint32 selgen; // valid sudog pointer
int64 goid;
+ int64 waitsince; // approx time when the G become blocked
const char* waitreason; // if status==Gwaiting
G* schedlink;
bool ispanic;
bool issystem; // do not output in stack dump
bool isbackground; // ignore in deadlock detector
+ bool paniconfault; // panic (instead of crash) on unexpected fault address
M* m; // for debuggers, but offset not hard-coded
M* lockedm;
int32 sig;
int32 writenbuf;
byte* writebuf;
- // DeferChunk* dchunk;
- // DeferChunk* dchunknext;
uintptr sigcode0;
uintptr sigcode1;
// uintptr sigpc;
@@ -252,10 +253,12 @@ struct M
int32 throwing;
int32 gcing;
int32 locks;
+ int32 softfloat;
int32 dying;
int32 profilehz;
int32 helpgc;
- bool spinning;
+ bool spinning; // M is out of work and is actively looking for work
+ bool blocked; // M is blocked on a Note
uint32 fastrand;
uint64 ncgocall; // number of cgo calls in total
int32 ncgo; // number of cgo calls currently in progress
@@ -272,16 +275,11 @@ struct M
uint32 waitsemacount;
uint32 waitsemalock;
GCStats gcstats;
- bool racecall;
bool needextram;
bool dropextram; // for gccgo: drop after call is done.
- void* racepc;
- void (*waitunlockf)(Lock*);
+ uint8 traceback;
+ bool (*waitunlockf)(G*, void*);
void* waitlock;
-
- uintptr settype_buf[1024];
- uintptr settype_bufsize;
-
uintptr end[];
};
@@ -296,12 +294,16 @@ struct P
uint32 syscalltick; // incremented on every system call
M* m; // back-link to associated M (nil if idle)
MCache* mcache;
+ Defer* deferpool; // pool of available Defer structs (see panic.c)
+
+ // Cache of goroutine ids, amortizes accesses to runtime_sched.goidgen.
+ uint64 goidcache;
+ uint64 goidcacheend;
// Queue of runnable goroutines.
- G** runq;
- int32 runqhead;
- int32 runqtail;
- int32 runqsize;
+ uint32 runqhead;
+ uint32 runqtail;
+ G* runq[256];
// Available G's (status == Gdead)
G* gfree;
@@ -337,6 +339,7 @@ enum
SigDefault = 1<<4, // if the signal isn't explicitly requested, don't monitor it
SigHandling = 1<<5, // our signal handler is registered
SigIgnored = 1<<6, // the signal was ignored before we registered for it
+ SigGoExit = 1<<7, // cause all runtime procs to exit (only used on Plan 9).
};
// Layout of in-memory per-function information prepared by linker
@@ -349,6 +352,16 @@ struct Func
uintptr entry; // entry pc
};
+#ifdef GOOS_nacl
+enum {
+ NaCl = 1,
+};
+#else
+enum {
+ NaCl = 0,
+};
+#endif
+
#ifdef GOOS_windows
enum {
Windows = 1
@@ -358,6 +371,15 @@ enum {
Windows = 0
};
#endif
+#ifdef GOOS_solaris
+enum {
+ Solaris = 1
+};
+#else
+enum {
+ Solaris = 0
+};
+#endif
struct Timers
{
@@ -373,9 +395,11 @@ struct Timers
// 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.
struct Timer
{
- int32 i; // heap index
+ intgo i; // 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
@@ -384,6 +408,7 @@ struct Timer
int64 period;
FuncVal *fv;
Eface arg;
+ uintptr seq;
};
// Lock-free stack node.
@@ -426,12 +451,16 @@ struct CgoMal
// Holds variables parsed from GODEBUG env var.
struct DebugVars
{
+ int32 allocfreetrace;
+ int32 efence;
int32 gctrace;
- int32 schedtrace;
+ int32 gcdead;
int32 scheddetail;
+ int32 schedtrace;
};
extern bool runtime_precisestack;
+extern bool runtime_copystack;
/*
* defined macros
@@ -441,7 +470,7 @@ extern bool runtime_precisestack;
#define nelem(x) (sizeof(x)/sizeof((x)[0]))
#define nil ((void*)0)
#define USED(v) ((void) v)
-#define ROUND(x, n) (((x)+(n)-1)&~((n)-1)) /* all-caps to mark as macro: it evaluates n twice */
+#define ROUND(x, n) (((x)+(n)-1)&~(uintptr)((n)-1)) /* all-caps to mark as macro: it evaluates n twice */
byte* runtime_startup_random_data;
uint32 runtime_startup_random_data_len;
@@ -455,12 +484,18 @@ void runtime_hashinit(void);
void runtime_traceback(void);
void runtime_tracebackothers(G*);
+enum
+{
+ // The maximum number of frames we print for a traceback
+ TracebackMaxFrames = 100,
+};
/*
* external data
*/
extern uintptr runtime_zerobase;
-extern G* runtime_allg;
+extern G** runtime_allg;
+extern uintptr runtime_allglen;
extern G* runtime_lastg;
extern M* runtime_allm;
extern P** runtime_allp;
@@ -470,20 +505,20 @@ extern uint32 runtime_panicking;
extern int8* runtime_goos;
extern int32 runtime_ncpu;
extern void (*runtime_sysargs)(int32, uint8**);
+extern uint32 runtime_Hchansize;
extern DebugVars runtime_debug;
+extern uintptr runtime_maxstacksize;
/*
* common functions and data
*/
#define runtime_strcmp(s1, s2) __builtin_strcmp((s1), (s2))
+#define runtime_strncmp(s1, s2, n) __builtin_strncmp((s1), (s2), (n))
#define runtime_strstr(s1, s2) __builtin_strstr((s1), (s2))
intgo runtime_findnull(const byte*);
intgo runtime_findnullw(const uint16*);
void runtime_dump(byte*, int32);
-/*
- * very low level c-called
- */
void runtime_gogo(G*);
struct __go_func_type;
void runtime_args(int32, byte**);
@@ -493,8 +528,10 @@ void runtime_goenvs(void);
void runtime_goenvs_unix(void);
void runtime_throw(const char*) __attribute__ ((noreturn));
void runtime_panicstring(const char*) __attribute__ ((noreturn));
+bool runtime_canpanic(G*);
void runtime_prints(const char*);
void runtime_printf(const char*, ...);
+int32 runtime_snprintf(byte*, int32, const char*, ...);
#define runtime_mcmp(a, b, s) __builtin_memcmp((a), (b), (s))
#define runtime_memmove(a, b, s) __builtin_memmove((a), (b), (s))
void* runtime_mal(uintptr);
@@ -511,21 +548,6 @@ void runtime_printtrace(Location*, int32, bool);
#define runtime_read(d, v, n) read((d), (v), (n))
#define runtime_write(d, v, n) write((d), (v), (n))
#define runtime_close(d) close(d)
-#define runtime_cas(pval, old, new) __sync_bool_compare_and_swap (pval, old, new)
-#define runtime_cas64(pval, old, new) __sync_bool_compare_and_swap (pval, old, new)
-#define runtime_casp(pval, old, new) __sync_bool_compare_and_swap (pval, old, new)
-// Don't confuse with XADD x86 instruction,
-// this one is actually 'addx', that is, add-and-fetch.
-#define runtime_xadd(p, v) __sync_add_and_fetch (p, v)
-#define runtime_xadd64(p, v) __sync_add_and_fetch (p, v)
-#define runtime_xchg(p, v) __atomic_exchange_n (p, v, __ATOMIC_SEQ_CST)
-#define runtime_xchg64(p, v) __atomic_exchange_n (p, v, __ATOMIC_SEQ_CST)
-#define runtime_atomicload(p) __atomic_load_n (p, __ATOMIC_SEQ_CST)
-#define runtime_atomicstore(p, v) __atomic_store_n (p, v, __ATOMIC_SEQ_CST)
-#define runtime_atomicstore64(p, v) __atomic_store_n (p, v, __ATOMIC_SEQ_CST)
-#define runtime_atomicload64(p) __atomic_load_n (p, __ATOMIC_SEQ_CST)
-#define runtime_atomicloadp(p) __atomic_load_n (p, __ATOMIC_SEQ_CST)
-#define runtime_atomicstorep(p, v) __atomic_store_n (p, v, __ATOMIC_SEQ_CST)
void runtime_ready(G*);
const byte* runtime_getenv(const char*);
int32 runtime_atoi(const byte*);
@@ -543,13 +565,31 @@ void runtime_mallocinit(void);
void runtime_mprofinit(void);
#define runtime_malloc(s) __go_alloc(s)
#define runtime_free(p) __go_free(p)
-bool runtime_addfinalizer(void*, FuncVal *fn, const struct __go_func_type *, const struct __go_ptr_type *);
#define runtime_getcallersp(p) __builtin_frame_address(1)
int32 runtime_mcount(void);
int32 runtime_gcount(void);
void runtime_mcall(void(*)(G*));
uint32 runtime_fastrand1(void);
int32 runtime_timediv(int64, int32, int32*);
+int32 runtime_round2(int32 x); // round x up to a power of 2.
+
+// atomic operations
+#define runtime_cas(pval, old, new) __sync_bool_compare_and_swap (pval, old, new)
+#define runtime_cas64(pval, old, new) __sync_bool_compare_and_swap (pval, old, new)
+#define runtime_casp(pval, old, new) __sync_bool_compare_and_swap (pval, old, new)
+// Don't confuse with XADD x86 instruction,
+// this one is actually 'addx', that is, add-and-fetch.
+#define runtime_xadd(p, v) __sync_add_and_fetch (p, v)
+#define runtime_xadd64(p, v) __sync_add_and_fetch (p, v)
+#define runtime_xchg(p, v) __atomic_exchange_n (p, v, __ATOMIC_SEQ_CST)
+#define runtime_xchg64(p, v) __atomic_exchange_n (p, v, __ATOMIC_SEQ_CST)
+#define runtime_xchgp(p, v) __atomic_exchange_n (p, v, __ATOMIC_SEQ_CST)
+#define runtime_atomicload(p) __atomic_load_n (p, __ATOMIC_SEQ_CST)
+#define runtime_atomicstore(p, v) __atomic_store_n (p, v, __ATOMIC_SEQ_CST)
+#define runtime_atomicstore64(p, v) __atomic_store_n (p, v, __ATOMIC_SEQ_CST)
+#define runtime_atomicload64(p) __atomic_load_n (p, __ATOMIC_SEQ_CST)
+#define runtime_atomicloadp(p) __atomic_load_n (p, __ATOMIC_SEQ_CST)
+#define runtime_atomicstorep(p, v) __atomic_store_n (p, v, __ATOMIC_SEQ_CST)
void runtime_setmg(M*, G*);
void runtime_newextram(void);
@@ -558,7 +598,8 @@ void runtime_newextram(void);
void runtime_gosched(void);
void runtime_gosched0(G*);
void runtime_schedtrace(bool);
-void runtime_park(void(*)(Lock*), Lock*, const char*);
+void runtime_park(bool(*)(G*, void*), void*, const char*);
+void runtime_parkunlock(Lock*, const char*);
void runtime_tsleep(int64, const char*);
M* runtime_newm(void);
void runtime_goexit(void);
@@ -568,8 +609,9 @@ void runtime_exitsyscall(void) __asm__ (GOSYM_PREFIX "syscall.Exitsyscall");
G* __go_go(void (*pfn)(void*), void*);
void siginit(void);
bool __go_sigsend(int32 sig);
-int32 runtime_callers(int32, Location*, int32);
-int64 runtime_nanotime(void);
+int32 runtime_callers(int32, Location*, int32, bool keep_callers);
+int64 runtime_nanotime(void); // monotonic time
+int64 runtime_unixnanotime(void); // real time, can skip
void runtime_dopanic(int32) __attribute__ ((noreturn));
void runtime_startpanic(void);
void runtime_freezetheworld(void);
@@ -590,10 +632,18 @@ int32 runtime_netpollopen(uintptr, PollDesc*);
int32 runtime_netpollclose(uintptr);
void runtime_netpollready(G**, PollDesc*, int32);
uintptr runtime_netpollfd(PollDesc*);
+void runtime_netpollarm(PollDesc*, int32);
+void** runtime_netpolluser(PollDesc*);
+bool runtime_netpollclosing(PollDesc*);
+void runtime_netpolllock(PollDesc*);
+void runtime_netpollunlock(PollDesc*);
void runtime_crash(void);
void runtime_parsedebugvars(void);
void _rt0_go(void);
void* runtime_funcdata(Func*, int32);
+int32 runtime_setmaxthreads(int32);
+G* runtime_timejump(void);
+void runtime_iterate_finq(void (*callback)(FuncVal*, void*, const FuncType*, const PtrType*));
void runtime_stoptheworld(void);
void runtime_starttheworld(void);
@@ -666,7 +716,8 @@ LFNode* runtime_lfstackpop(uint64 *head);
*/
ParFor* runtime_parforalloc(uint32 nthrmax);
void runtime_parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait, void (*body)(ParFor*, uint32));
-void runtime_parfordo(ParFor *desc) __asm__ (GOSYM_PREFIX "runtime.parfordo");
+void runtime_parfordo(ParFor *desc);
+void runtime_parforiters(ParFor*, uintptr, uintptr*, uintptr*);
/*
* low level C-called
@@ -710,7 +761,7 @@ void runtime_printpointer(void*);
void runtime_printuint(uint64);
void runtime_printhex(uint64);
void runtime_printslice(Slice);
-void runtime_printcomplex(__complex double);
+void runtime_printcomplex(complex double);
void reflect_call(const struct __go_func_type *, FuncVal *, _Bool, _Bool,
void **, void **)
__asm__ (GOSYM_PREFIX "reflect.call");
@@ -723,8 +774,6 @@ void runtime_printany(Eface)
__asm__ (GOSYM_PREFIX "runtime.Printany");
void runtime_newTypeAssertionError(const String*, const String*, const String*, const String*, Eface*)
__asm__ (GOSYM_PREFIX "runtime.NewTypeAssertionError");
-void runtime_newErrorString(String, Eface*)
- __asm__ (GOSYM_PREFIX "runtime.NewErrorString");
void runtime_newErrorCString(const char*, Eface*)
__asm__ (GOSYM_PREFIX "runtime.NewErrorCString");
@@ -738,6 +787,7 @@ void runtime_procyield(uint32);
void runtime_osyield(void);
void runtime_lockOSThread(void);
void runtime_unlockOSThread(void);
+bool runtime_lockedOSThread(void);
bool runtime_showframe(String, bool);
void runtime_printcreatedby(G*);
@@ -748,7 +798,7 @@ uintptr runtime_memlimit(void);
enum
{
- UseSpanType = 0,
+ UseSpanType = 1,
};
#define runtime_setitimer setitimer
@@ -782,8 +832,16 @@ int32 getproccount(void);
#define PREFETCH(p) __builtin_prefetch(p)
-void __go_set_closure(void*);
-void* __go_get_closure(void);
-
bool runtime_gcwaiting(void);
void runtime_badsignal(int);
+Defer* runtime_newdefer(void);
+void runtime_freedefer(Defer*);
+
+struct time_now_ret
+{
+ int64_t sec;
+ int32_t nsec;
+};
+
+struct time_now_ret now() __asm__ (GOSYM_PREFIX "time.now")
+ __attribute__ ((no_split_stack));
diff --git a/libgo/runtime/runtime1.goc b/libgo/runtime/runtime1.goc
index 9ce83000b8..6d8f09a6c5 100644
--- a/libgo/runtime/runtime1.goc
+++ b/libgo/runtime/runtime1.goc
@@ -4,6 +4,8 @@
package runtime
#include "runtime.h"
+#include "arch.h"
+#include "go-type.h"
func GOMAXPROCS(n int) (ret int) {
ret = runtime_gomaxprocsfunc(n);
@@ -12,3 +14,76 @@ func GOMAXPROCS(n int) (ret int) {
func NumCPU() (ret int) {
ret = runtime_ncpu;
}
+
+func NumCgoCall() (ret int64) {
+ M *mp;
+
+ ret = 0;
+ for(mp=runtime_atomicloadp(&runtime_allm); mp; mp=mp->alllink)
+ ret += mp->ncgocall;
+}
+
+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 parForDo(desc *ParFor) {
+ runtime_parfordo(desc);
+}
+
+func parForIters(desc *ParFor, tid uintptr) (start uintptr, end uintptr) {
+ runtime_parforiters(desc, tid, &start, &end);
+}
+
+func typestring(e Eface) (s String) {
+ s = *e.__type_descriptor->__reflection;
+}
+
+func golockedOSThread() (ret bool) {
+ ret = runtime_lockedOSThread();
+}
+
+func NumGoroutine() (ret int) {
+ ret = runtime_gcount();
+}
+
+func getgoroot() (out String) {
+ const byte *p;
+
+ p = runtime_getenv("GOROOT");
+ out = runtime_gostringnocopy(p);
+}
+
+func runtime_pprof.runtime_cyclesPerSecond() (res int64) {
+ res = runtime_tickspersecond();
+}
+
+func sync.runtime_procPin() (p int) {
+ M *mp;
+
+ mp = runtime_m();
+ // Disable preemption.
+ mp->locks++;
+ p = mp->p->id;
+}
+
+func sync.runtime_procUnpin() {
+ runtime_m()->locks--;
+}
+
+func sync_atomic.runtime_procPin() (p int) {
+ M *mp;
+
+ mp = runtime_m();
+ // Disable preemption.
+ mp->locks++;
+ p = mp->p->id;
+}
+
+func sync_atomic.runtime_procUnpin() {
+ runtime_m()->locks--;
+}
diff --git a/libgo/runtime/sema.goc b/libgo/runtime/sema.goc
index f5d5bc89e3..50f0e973d7 100644
--- a/libgo/runtime/sema.goc
+++ b/libgo/runtime/sema.goc
@@ -136,7 +136,7 @@ runtime_semacquire(uint32 volatile *addr, bool profile)
// Any semrelease after the cansemacquire knows we're waiting
// (we set nwait above), so go to sleep.
semqueue(root, addr, &s);
- runtime_park(runtime_unlock, root, "semacquire");
+ runtime_parkunlock(root, "semacquire");
if(cansemacquire(addr)) {
if(t0)
runtime_blockevent(s.releasetime - t0, 3);
@@ -259,7 +259,7 @@ func runtime_Syncsemacquire(s *SyncSema) {
else
s->tail->next = &w;
s->tail = &w;
- runtime_park(runtime_unlock, s, "semacquire");
+ runtime_parkunlock(s, "semacquire");
if(t0)
runtime_blockevent(w.releasetime - t0, 2);
}
@@ -293,7 +293,7 @@ func runtime_Syncsemrelease(s *SyncSema, n uint32) {
else
s->tail->next = &w;
s->tail = &w;
- runtime_park(runtime_unlock, s, "semarelease");
+ runtime_parkunlock(s, "semarelease");
} else
runtime_unlock(s);
}
diff --git a/libgo/runtime/signal_unix.c b/libgo/runtime/signal_unix.c
index ea0a58f2ea..66638dec56 100644
--- a/libgo/runtime/signal_unix.c
+++ b/libgo/runtime/signal_unix.c
@@ -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 openbsd netbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
#include <sys/time.h>
@@ -122,6 +122,14 @@ os_sigpipe(void)
}
void
+runtime_unblocksignals(void)
+{
+ sigset_t sigset_none;
+ sigemptyset(&sigset_none);
+ pthread_sigmask(SIG_SETMASK, &sigset_none, nil);
+}
+
+void
runtime_crash(void)
{
int32 i;
@@ -137,6 +145,7 @@ runtime_crash(void)
return;
#endif
+ runtime_unblocksignals();
for(i = 0; runtime_sigtab[i].sig != -1; i++)
if(runtime_sigtab[i].sig == SIGABRT)
break;
diff --git a/libgo/runtime/string.goc b/libgo/runtime/string.goc
index a7446e93c4..0ad180b983 100644
--- a/libgo/runtime/string.goc
+++ b/libgo/runtime/string.goc
@@ -7,7 +7,6 @@ package runtime
#include "arch.h"
#include "malloc.h"
#include "go-string.h"
-#include "race.h"
#define charntorune(pv, str, len) __go_get_rune(str, len, pv)
@@ -43,11 +42,9 @@ gostringsize(intgo l, byte** pmem)
*pmem = nil;
return runtime_emptystring;
}
- // leave room for NUL for C runtime (e.g., callers of getenv)
- mem = runtime_mallocgc(l+1, 0, FlagNoScan|FlagNoZero);
+ mem = runtime_mallocgc(l, 0, FlagNoScan|FlagNoZero);
s.str = mem;
s.len = l;
- mem[l] = 0;
*pmem = mem;
return s;
}
@@ -75,13 +72,8 @@ runtime_gostringnocopy(const byte *str)
return s;
}
-String runtime_cstringToGo(byte*)
- __asm__ (GOSYM_PREFIX "runtime.cstringToGo");
-
-String
-runtime_cstringToGo(byte *str)
-{
- return runtime_gostringnocopy(str);
+func cstringToGo(str *byte) (s String) {
+ s = runtime_gostringnocopy(str);
}
enum
diff --git a/libgo/runtime/time.goc b/libgo/runtime/time.goc
index e4e35ec084..b77ad3333d 100644
--- a/libgo/runtime/time.goc
+++ b/libgo/runtime/time.goc
@@ -6,11 +6,12 @@
package time
+#include <sys/time.h>
+
#include "runtime.h"
#include "defs.h"
#include "arch.h"
#include "malloc.h"
-#include "race.h"
enum {
debug = 0,
@@ -20,11 +21,19 @@ static Timers timers;
static void addtimer(Timer*);
static void dumptimers(const char*);
+// nacl fake time support.
+int64 runtime_timens;
+
// Package time APIs.
// Godoc uses the comments in package time, not these.
// time.now is implemented in assembly.
+// runtimeNano returns the current value of the runtime clock in nanoseconds.
+func runtimeNano() (ns int64) {
+ ns = runtime_nanotime();
+}
+
// Sleep puts the current goroutine to sleep for at least ns nanoseconds.
func Sleep(ns int64) {
runtime_tsleep(ns, "sleep");
@@ -32,8 +41,6 @@ func Sleep(ns int64) {
// startTimer adds t to the timer heap.
func startTimer(t *Timer) {
- if(raceenabled)
- runtime_racerelease(t);
runtime_addtimer(t);
}
@@ -45,15 +52,23 @@ func stopTimer(t *Timer) (stopped bool) {
// C runtime.
+int64 runtime_unixnanotime(void)
+{
+ struct time_now_ret r;
+
+ r = now();
+ return r.sec*1000000000 + r.nsec;
+}
+
static void timerproc(void*);
static void siftup(int32);
static void siftdown(int32);
// Ready the goroutine e.data.
static void
-ready(int64 now, Eface e)
+ready(Eface e, uintptr seq)
{
- USED(now);
+ USED(seq);
runtime_ready(e.__object);
}
@@ -76,9 +91,10 @@ runtime_tsleep(int64 ns, const char *reason)
t.period = 0;
t.fv = &readyv;
t.arg.__object = g;
+ t.seq = 0;
runtime_lock(&timers);
addtimer(&t);
- runtime_park(runtime_unlock, &timers, reason);
+ runtime_parkunlock(&timers, reason);
}
void
@@ -187,8 +203,10 @@ timerproc(void* dummy __attribute__ ((unused)))
{
int64 delta, now;
Timer *t;
- void (*f)(int64, Eface);
+ FuncVal *fv;
+ void (*f)(Eface, uintptr);
Eface arg;
+ uintptr seq;
for(;;) {
runtime_lock(&timers);
@@ -214,19 +232,28 @@ timerproc(void* dummy __attribute__ ((unused)))
siftdown(0);
t->i = -1; // mark as removed
}
+ fv = t->fv;
f = (void*)t->fv->fn;
arg = t->arg;
+ seq = t->seq;
runtime_unlock(&timers);
- if(raceenabled)
- runtime_raceacquire(t);
- __go_set_closure(t->fv);
- f(now, arg);
+ __builtin_call_with_static_chain(f(arg, seq), fv);
+
+ // clear f and arg to avoid leak while sleeping for next timer
+ f = nil;
+ USED(f);
+ arg.__type_descriptor = nil;
+ arg.__object = nil;
+ USED(&arg);
+
runtime_lock(&timers);
}
if(delta < 0) {
// No timers left - put goroutine to sleep.
timers.rescheduling = true;
- runtime_park(runtime_unlock, &timers, "timer goroutine (idle)");
+ runtime_g()->isbackground = true;
+ runtime_parkunlock(&timers, "timer goroutine (idle)");
+ runtime_g()->isbackground = false;
continue;
}
// At least one timer pending. Sleep until then.
@@ -320,7 +347,7 @@ dumptimers(const char *msg)
}
void
-runtime_time_scan(void (*addroot)(Obj))
+runtime_time_scan(struct Workbuf** wbufp, void (*enqueue1)(struct Workbuf**, Obj))
{
- addroot((Obj){(byte*)&timers, sizeof timers, 0});
+ enqueue1(wbufp, (Obj){(byte*)&timers, sizeof timers, 0});
}
diff --git a/libgo/runtime/yield.c b/libgo/runtime/yield.c
index 5c47719d48..442d346db7 100644
--- a/libgo/runtime/yield.c
+++ b/libgo/runtime/yield.c
@@ -14,6 +14,10 @@
#include <sys/select.h>
#endif
+#if defined (__i386__) || defined (__x86_64__)
+#include <xmmintrin.h>
+#endif
+
#include "runtime.h"
/* Spin wait. */
@@ -26,7 +30,7 @@ runtime_procyield (uint32 cnt)
for (i = 0; i < cnt; ++i)
{
#if defined (__i386__) || defined (__x86_64__)
- __builtin_ia32_pause ();
+ _mm_pause ();
#endif
}
}
diff --git a/libgo/testsuite/Makefile.in b/libgo/testsuite/Makefile.in
index 8f0e2ad933..7f7fb74c58 100644
--- a/libgo/testsuite/Makefile.in
+++ b/libgo/testsuite/Makefile.in
@@ -96,6 +96,7 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LD = @LD@
LDFLAGS = @LDFLAGS@
+LIBATOMIC = @LIBATOMIC@
LIBFFI = @LIBFFI@
LIBFFIINCS = @LIBFFIINCS@
LIBOBJS = @LIBOBJS@
diff --git a/libgo/testsuite/gotest b/libgo/testsuite/gotest
index 155c7a8619..3596d727ff 100755
--- a/libgo/testsuite/gotest
+++ b/libgo/testsuite/gotest
@@ -36,6 +36,7 @@ dejagnu=no
GOARCH=""
timeout=240
testname=""
+bench=""
trace=false
while $loop; do
case "x$1" in
@@ -124,6 +125,15 @@ while $loop; do
testname=`echo $1 | sed -e 's/^--testname=//'`
shift
;;
+ x--bench)
+ bench=$2
+ shift
+ shift
+ ;;
+ x--bench=*)
+ bench=`echo $1 | sed -e 's/^--bench=//'`
+ shift
+ ;;
x--trace)
trace=true
shift
@@ -325,6 +335,15 @@ if [ "x$xgofiles" != "x" ]; then
havex=true
fi
+testmain=
+if $havex && fgrep 'func TestMain(' $xgofiles >/dev/null 2>&1; then
+ package=`grep '^package[ ]' $xgofiles | sed 1q | sed -e 's/.* //'`
+ testmain="${package}.TestMain"
+elif test -n "$gofiles" && fgrep 'func TestMain(' $gofiles >/dev/null 2>&1; then
+ package=`grep '^package[ ]' $gofiles | sed 1q | sed -e 's/.* //'`
+ testmain="${package}.TestMain"
+fi
+
set -e
package=`echo ${srcdir} | sed -e 's|^.*libgo/go/||'`
@@ -369,7 +388,7 @@ localname() {
{
text="T"
case "$GOARCH" in
- ppc64) text="[TD]" ;;
+ ppc64*) text="[TD]" ;;
esac
symtogo='sed -e s/_test/XXXtest/ -e s/.*_\([^_]*\.\)/\1/ -e s/XXXtest/_test/'
@@ -405,14 +424,19 @@ localname() {
fi
echo 'import "testing"'
echo 'import __regexp__ "regexp"' # rename in case tested package is called regexp
+ if ! test -n "$testmain"; then
+ echo 'import __os__ "os"'
+ fi
# test array
echo
echo 'var tests = []testing.InternalTest {'
for i in $tests
do
n=$(testname $i)
- j=$(localname $i)
- echo ' {"'$n'", '$j'},'
+ if test "$n" != "TestMain"; then
+ j=$(localname $i)
+ echo ' {"'$n'", '$j'},'
+ fi
done
echo '}'
@@ -457,8 +481,15 @@ func matchString(pat, str string) (result bool, err error) {
}
func main() {
- testing.Main(matchString, tests, benchmarks, examples)
-}'
+ m := testing.MainStart(matchString, tests, benchmarks, examples)
+'
+ if test -n "$testmain"; then
+ echo " ${testmain}(m)"
+ else
+ echo ' __os__.Exit(m.Run())'
+ fi
+
+ echo '}'
}>_testmain.go
case "x$dejagnu" in
@@ -473,20 +504,28 @@ xno)
fi
${GL} *.o ${GOLIBS}
- if test "$trace" = "true"; then
- echo ./a.out -test.short -test.timeout=${timeout}s "$@"
- fi
- ./a.out -test.short -test.timeout=${timeout}s "$@" &
- pid=$!
- (sleep `expr $timeout + 10`
- echo > gotest-timeout
- echo "timed out in gotest" 1>&2
- kill -9 $pid) &
- alarmpid=$!
- wait $pid
- status=$?
- if ! test -f gotest-timeout; then
- kill $alarmpid
+ if test "$bench" = ""; then
+ if test "$trace" = "true"; then
+ echo ./a.out -test.short -test.timeout=${timeout}s "$@"
+ fi
+ ./a.out -test.short -test.timeout=${timeout}s "$@" &
+ pid=$!
+ (sleep `expr $timeout + 10`
+ echo > gotest-timeout
+ echo "timed out in gotest" 1>&2
+ kill -9 $pid) &
+ alarmpid=$!
+ wait $pid
+ status=$?
+ if ! test -f gotest-timeout; then
+ kill $alarmpid
+ fi
+ else
+ if test "$trace" = "true"; then
+ echo ./a.out -test.run=^\$ -test.bench="${bench}" "$@"
+ fi
+ ./a.out -test.run=^\$ -test.bench="${bench}" "$@"
+ status=$?
fi
exit $status
;;
diff --git a/libgo/testsuite/lib/libgo.exp b/libgo/testsuite/lib/libgo.exp
index a8fe4e08ae..7031f635eb 100644
--- a/libgo/testsuite/lib/libgo.exp
+++ b/libgo/testsuite/lib/libgo.exp
@@ -42,6 +42,8 @@ proc load_gcc_lib { filename } {
load_gcc_lib prune.exp
load_gcc_lib target-libpath.exp
load_gcc_lib wrapper.exp
+load_gcc_lib target-supports.exp
+load_gcc_lib target-utils.exp
load_gcc_lib gcc-defs.exp
load_gcc_lib timeout.exp
load_gcc_lib go.exp