summaryrefslogtreecommitdiff
path: root/src/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg')
-rw-r--r--src/pkg/archive/tar/common.go3
-rw-r--r--src/pkg/archive/tar/reader.go465
-rw-r--r--src/pkg/archive/tar/reader_test.go368
-rw-r--r--src/pkg/archive/tar/stat_atim.go2
-rw-r--r--src/pkg/archive/tar/stat_unix.go2
-rw-r--r--src/pkg/archive/tar/tar_test.go4
-rw-r--r--src/pkg/archive/tar/testdata/sparse-formats.tarbin0 -> 17920 bytes
-rw-r--r--src/pkg/archive/tar/testdata/writer-big-long.tarbin0 -> 4096 bytes
-rw-r--r--src/pkg/archive/tar/testdata/xattrs.tarbin0 -> 5120 bytes
-rw-r--r--src/pkg/archive/tar/writer.go10
-rw-r--r--src/pkg/archive/tar/writer_test.go63
-rw-r--r--src/pkg/archive/zip/reader.go2
-rw-r--r--src/pkg/archive/zip/reader_test.go28
-rw-r--r--src/pkg/archive/zip/register.go41
-rw-r--r--src/pkg/archive/zip/struct.go4
-rw-r--r--src/pkg/archive/zip/testdata/zip64-2.zipbin0 -> 266 bytes
-rw-r--r--src/pkg/archive/zip/writer_test.go18
-rw-r--r--src/pkg/bufio/bufio.go147
-rw-r--r--src/pkg/bufio/bufio_test.go343
-rw-r--r--src/pkg/bufio/scan.go6
-rw-r--r--src/pkg/bufio/scan_test.go14
-rw-r--r--src/pkg/bytes/bytes.go10
-rw-r--r--src/pkg/bytes/bytes_test.go36
-rw-r--r--src/pkg/bytes/compare_test.go4
-rw-r--r--src/pkg/bytes/reader.go52
-rw-r--r--src/pkg/bytes/reader_test.go82
-rw-r--r--src/pkg/compress/bzip2/bzip2_test.go12
-rw-r--r--src/pkg/compress/bzip2/huffman.go32
-rw-r--r--src/pkg/compress/flate/fixedhuff.go4
-rw-r--r--src/pkg/compress/flate/flate_test.go2
-rw-r--r--src/pkg/compress/flate/inflate.go4
-rw-r--r--src/pkg/compress/flate/reader_test.go2
-rw-r--r--src/pkg/compress/gzip/gunzip.go15
-rw-r--r--src/pkg/compress/gzip/gunzip_test.go36
-rw-r--r--src/pkg/compress/gzip/gzip.go8
-rw-r--r--src/pkg/compress/gzip/gzip_test.go2
-rw-r--r--src/pkg/compress/lzw/reader.go4
-rw-r--r--src/pkg/compress/lzw/reader_test.go4
-rw-r--r--src/pkg/compress/lzw/writer.go4
-rw-r--r--src/pkg/compress/zlib/example_test.go2
-rw-r--r--src/pkg/compress/zlib/reader.go3
-rw-r--r--src/pkg/compress/zlib/reader_test.go2
-rw-r--r--src/pkg/compress/zlib/writer.go4
-rw-r--r--src/pkg/compress/zlib/writer_test.go2
-rw-r--r--src/pkg/container/heap/example_pq_test.go22
-rw-r--r--src/pkg/container/heap/heap.go4
-rw-r--r--src/pkg/container/list/example_test.go2
-rw-r--r--src/pkg/container/list/list.go10
-rw-r--r--src/pkg/container/list/list_test.go56
-rw-r--r--src/pkg/container/ring/ring_test.go8
-rw-r--r--src/pkg/crypto/aes/aes_test.go28
-rw-r--r--src/pkg/crypto/aes/cipher.go12
-rw-r--r--src/pkg/crypto/aes/cipher_asm.go2
-rw-r--r--src/pkg/crypto/cipher/benchmark_test.go139
-rw-r--r--src/pkg/crypto/cipher/cbc.go55
-rw-r--r--src/pkg/crypto/cipher/cbc_aes_test.go46
-rw-r--r--src/pkg/crypto/cipher/cfb.go60
-rw-r--r--src/pkg/crypto/cipher/cfb_test.go8
-rw-r--r--src/pkg/crypto/cipher/cipher.go10
-rw-r--r--src/pkg/crypto/cipher/ctr.go55
-rw-r--r--src/pkg/crypto/cipher/gcm.go27
-rw-r--r--src/pkg/crypto/cipher/gcm_test.go16
-rw-r--r--src/pkg/crypto/cipher/ofb.go42
-rw-r--r--src/pkg/crypto/cipher/xor.go84
-rw-r--r--src/pkg/crypto/cipher/xor_test.go28
-rw-r--r--src/pkg/crypto/dsa/dsa.go12
-rw-r--r--src/pkg/crypto/ecdsa/ecdsa.go12
-rw-r--r--src/pkg/crypto/hmac/hmac_test.go66
-rw-r--r--src/pkg/crypto/md5/example_test.go6
-rw-r--r--src/pkg/crypto/md5/gen.go9
-rw-r--r--src/pkg/crypto/md5/md5_test.go13
-rw-r--r--src/pkg/crypto/md5/md5block.go8
-rw-r--r--src/pkg/crypto/md5/md5block_amd64p32.s184
-rw-r--r--src/pkg/crypto/md5/md5block_decl.go2
-rw-r--r--src/pkg/crypto/md5/md5block_generic.go9
-rw-r--r--src/pkg/crypto/rand/rand_unix.go2
-rw-r--r--src/pkg/crypto/rand/util.go8
-rw-r--r--src/pkg/crypto/rand/util_test.go65
-rw-r--r--src/pkg/crypto/rc4/rc4.go17
-rw-r--r--src/pkg/crypto/rc4/rc4_amd64p32.s192
-rw-r--r--src/pkg/crypto/rc4/rc4_asm.go2
-rw-r--r--src/pkg/crypto/rc4/rc4_ref.go11
-rw-r--r--src/pkg/crypto/rc4/rc4_test.go19
-rw-r--r--src/pkg/crypto/rsa/pkcs1v15.go12
-rw-r--r--src/pkg/crypto/rsa/pkcs1v15_test.go22
-rw-r--r--src/pkg/crypto/rsa/pss.go6
-rw-r--r--src/pkg/crypto/rsa/rsa.go14
-rw-r--r--src/pkg/crypto/rsa/rsa_test.go2
-rw-r--r--src/pkg/crypto/sha1/example_test.go9
-rw-r--r--src/pkg/crypto/sha1/sha1.go10
-rw-r--r--src/pkg/crypto/sha1/sha1_test.go27
-rw-r--r--src/pkg/crypto/sha1/sha1block.go10
-rw-r--r--src/pkg/crypto/sha1/sha1block_386.s10
-rw-r--r--src/pkg/crypto/sha1/sha1block_amd64.s10
-rw-r--r--src/pkg/crypto/sha1/sha1block_amd64p32.s216
-rw-r--r--src/pkg/crypto/sha1/sha1block_arm.s217
-rw-r--r--src/pkg/crypto/sha1/sha1block_decl.go2
-rw-r--r--src/pkg/crypto/sha1/sha1block_generic.go9
-rw-r--r--src/pkg/crypto/sha256/sha256.go12
-rw-r--r--src/pkg/crypto/sha256/sha256_test.go18
-rw-r--r--src/pkg/crypto/sha256/sha256block.go2
-rw-r--r--src/pkg/crypto/sha256/sha256block_386.s283
-rw-r--r--src/pkg/crypto/sha256/sha256block_amd64.s256
-rw-r--r--src/pkg/crypto/sha256/sha256block_decl.go (renamed from src/pkg/runtime/export_test.c)16
-rw-r--r--src/pkg/crypto/sha512/sha512.go10
-rw-r--r--src/pkg/crypto/sha512/sha512_test.go18
-rw-r--r--src/pkg/crypto/sha512/sha512block.go2
-rw-r--r--src/pkg/crypto/sha512/sha512block_amd64.s273
-rw-r--r--src/pkg/crypto/sha512/sha512block_decl.go11
-rw-r--r--src/pkg/crypto/subtle/constant_time.go4
-rw-r--r--src/pkg/crypto/tls/common.go153
-rw-r--r--src/pkg/crypto/tls/conn.go169
-rw-r--r--src/pkg/crypto/tls/example_test.go57
-rw-r--r--src/pkg/crypto/tls/generate_cert.go13
-rw-r--r--src/pkg/crypto/tls/handshake_client.go362
-rw-r--r--src/pkg/crypto/tls/handshake_client_test.go3351
-rw-r--r--src/pkg/crypto/tls/handshake_messages.go115
-rw-r--r--src/pkg/crypto/tls/handshake_messages_test.go4
-rw-r--r--src/pkg/crypto/tls/handshake_server.go60
-rw-r--r--src/pkg/crypto/tls/handshake_server_test.go3838
-rw-r--r--src/pkg/crypto/tls/handshake_test.go167
-rw-r--r--src/pkg/crypto/tls/key_agreement.go79
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA129
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA125
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA128
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA124
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES87
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES97
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv10-RSA-RC483
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES89
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES99
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv11-RSA-RC483
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA134
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA127
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA133
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA126
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES89
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM84
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES99
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv12-RSA-RC483
-rw-r--r--src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-3DES83
-rw-r--r--src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-AES84
-rw-r--r--src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-RC479
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES84
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-3DES79
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-AES82
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-RC476
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv11-RSA-RC476
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA91
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA101
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven122
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven121
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven81
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES89
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv12-IssueTicket87
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-3DES83
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-AES87
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM93
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-RC479
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv12-Resume36
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv12-SNI76
-rw-r--r--src/pkg/crypto/tls/tls.go86
-rw-r--r--src/pkg/crypto/tls/tls_test.go130
-rw-r--r--src/pkg/crypto/x509/example_test.go91
-rw-r--r--src/pkg/crypto/x509/pkix/pkix.go7
-rw-r--r--src/pkg/crypto/x509/root_cgo_darwin.go79
-rw-r--r--src/pkg/crypto/x509/root_darwin.go78
-rw-r--r--src/pkg/crypto/x509/root_darwin_test.go50
-rw-r--r--src/pkg/crypto/x509/root_nocgo_darwin.go11
-rw-r--r--src/pkg/crypto/x509/root_stub.go14
-rw-r--r--src/pkg/crypto/x509/root_unix.go2
-rw-r--r--src/pkg/crypto/x509/verify.go3
-rw-r--r--src/pkg/crypto/x509/verify_test.go367
-rw-r--r--src/pkg/crypto/x509/x509.go602
-rw-r--r--src/pkg/crypto/x509/x509_test.go241
-rw-r--r--src/pkg/crypto/x509/x509_test_import.go53
-rw-r--r--src/pkg/database/sql/convert.go50
-rw-r--r--src/pkg/database/sql/convert_test.go56
-rw-r--r--src/pkg/database/sql/driver/driver.go2
-rw-r--r--src/pkg/database/sql/example_test.go1
-rw-r--r--src/pkg/database/sql/fakedb_test.go32
-rw-r--r--src/pkg/database/sql/sql.go166
-rw-r--r--src/pkg/database/sql/sql_test.go137
-rw-r--r--src/pkg/debug/dwarf/const.go35
-rw-r--r--src/pkg/debug/dwarf/entry.go16
-rw-r--r--src/pkg/debug/dwarf/open.go11
-rw-r--r--src/pkg/debug/dwarf/testdata/typedef.elf4bin0 -> 9496 bytes
-rw-r--r--src/pkg/debug/dwarf/type.go75
-rw-r--r--src/pkg/debug/dwarf/type_test.go2
-rw-r--r--src/pkg/debug/dwarf/typeunit.go166
-rw-r--r--src/pkg/debug/dwarf/unit.go2
-rw-r--r--src/pkg/debug/elf/elf.go2
-rw-r--r--src/pkg/debug/elf/elf_test.go2
-rw-r--r--src/pkg/debug/elf/file.go106
-rw-r--r--src/pkg/debug/elf/file_test.go6
-rw-r--r--src/pkg/debug/elf/testdata/go-relocation-test-clang-x86.objbin0 -> 1900 bytes
-rw-r--r--src/pkg/debug/elf/testdata/hello.c7
-rw-r--r--src/pkg/debug/gosym/pclntab.go27
-rw-r--r--src/pkg/debug/gosym/symtab.go7
-rw-r--r--src/pkg/debug/macho/fat.go146
-rw-r--r--src/pkg/debug/macho/file.go23
-rw-r--r--src/pkg/debug/macho/file_test.go43
-rw-r--r--src/pkg/debug/macho/macho.go23
-rw-r--r--src/pkg/debug/macho/testdata/fat-gcc-386-amd64-darwin-execbin0 -> 28992 bytes
-rw-r--r--src/pkg/debug/pe/file.go56
-rw-r--r--src/pkg/debug/pe/file_test.go139
-rw-r--r--src/pkg/debug/pe/pe.go72
-rw-r--r--src/pkg/debug/pe/testdata/gcc-amd64-mingw-execbin0 -> 37376 bytes
-rw-r--r--src/pkg/debug/pe/testdata/gcc-amd64-mingw-objbin0 -> 736 bytes
-rw-r--r--src/pkg/debug/plan9obj/file.go325
-rw-r--r--src/pkg/debug/plan9obj/file_test.go81
-rw-r--r--src/pkg/debug/plan9obj/plan9obj.go36
-rwxr-xr-xsrc/pkg/debug/plan9obj/testdata/386-plan9-execbin0 -> 37232 bytes
-rwxr-xr-xsrc/pkg/debug/plan9obj/testdata/amd64-plan9-execbin0 -> 34279 bytes
-rw-r--r--src/pkg/debug/plan9obj/testdata/hello.c8
-rw-r--r--src/pkg/encoding/ascii85/ascii85.go12
-rw-r--r--src/pkg/encoding/ascii85/ascii85_test.go21
-rw-r--r--src/pkg/encoding/asn1/asn1.go43
-rw-r--r--src/pkg/encoding/asn1/asn1_test.go75
-rw-r--r--src/pkg/encoding/asn1/marshal.go57
-rw-r--r--src/pkg/encoding/asn1/marshal_test.go9
-rw-r--r--src/pkg/encoding/base32/base32.go12
-rw-r--r--src/pkg/encoding/base32/base32_test.go8
-rw-r--r--src/pkg/encoding/base64/base64.go39
-rw-r--r--src/pkg/encoding/base64/base64_test.go27
-rw-r--r--src/pkg/encoding/binary/binary.go1
-rw-r--r--src/pkg/encoding/binary/binary_test.go28
-rw-r--r--src/pkg/encoding/binary/varint_test.go8
-rw-r--r--src/pkg/encoding/csv/reader.go6
-rw-r--r--src/pkg/encoding/csv/writer_test.go2
-rw-r--r--src/pkg/encoding/gob/codec_test.go56
-rw-r--r--src/pkg/encoding/gob/decode.go21
-rw-r--r--src/pkg/encoding/gob/decoder.go8
-rw-r--r--src/pkg/encoding/gob/encode.go2
-rw-r--r--src/pkg/encoding/gob/encoder_test.go4
-rw-r--r--src/pkg/encoding/gob/gobencdec_test.go19
-rw-r--r--src/pkg/encoding/hex/hex.go3
-rw-r--r--src/pkg/encoding/hex/hex_test.go6
-rw-r--r--src/pkg/encoding/json/decode.go16
-rw-r--r--src/pkg/encoding/json/decode_test.go42
-rw-r--r--src/pkg/encoding/json/encode.go41
-rw-r--r--src/pkg/encoding/json/encode_test.go31
-rw-r--r--src/pkg/encoding/json/example_test.go32
-rw-r--r--src/pkg/encoding/json/fold.go143
-rw-r--r--src/pkg/encoding/json/fold_test.go116
-rw-r--r--src/pkg/encoding/json/indent.go5
-rw-r--r--src/pkg/encoding/json/scanner_test.go22
-rw-r--r--src/pkg/encoding/json/stream.go5
-rw-r--r--src/pkg/encoding/xml/marshal.go11
-rw-r--r--src/pkg/encoding/xml/marshal_test.go115
-rw-r--r--src/pkg/encoding/xml/read.go11
-rw-r--r--src/pkg/encoding/xml/read_test.go27
-rw-r--r--src/pkg/encoding/xml/typeinfo.go3
-rw-r--r--src/pkg/encoding/xml/xml.go2
-rw-r--r--src/pkg/expvar/expvar.go62
-rw-r--r--src/pkg/expvar/expvar_test.go32
-rw-r--r--src/pkg/flag/flag.go6
-rw-r--r--src/pkg/fmt/doc.go58
-rw-r--r--src/pkg/fmt/fmt_test.go234
-rw-r--r--src/pkg/fmt/format.go139
-rw-r--r--src/pkg/fmt/print.go53
-rw-r--r--src/pkg/fmt/scan.go10
-rw-r--r--src/pkg/go/ast/commentmap.go2
-rw-r--r--src/pkg/go/ast/example_test.go74
-rw-r--r--src/pkg/go/build/build.go17
-rw-r--r--src/pkg/go/build/deps_test.go17
-rw-r--r--src/pkg/go/build/doc.go9
-rw-r--r--src/pkg/go/build/syslist.go4
-rw-r--r--src/pkg/go/doc/comment.go49
-rw-r--r--src/pkg/go/doc/comment_test.go106
-rw-r--r--src/pkg/go/doc/example.go15
-rw-r--r--src/pkg/go/parser/error_test.go21
-rw-r--r--src/pkg/go/parser/interface.go7
-rw-r--r--src/pkg/go/parser/parser.go75
-rw-r--r--src/pkg/go/parser/parser_test.go15
-rw-r--r--src/pkg/go/parser/short_test.go25
-rw-r--r--src/pkg/go/printer/nodes.go72
-rw-r--r--src/pkg/go/printer/printer.go125
-rw-r--r--src/pkg/go/printer/printer_test.go6
-rw-r--r--src/pkg/go/printer/testdata/comments.golden13
-rw-r--r--src/pkg/go/printer/testdata/comments.input12
-rw-r--r--src/pkg/go/printer/testdata/comments2.golden26
-rw-r--r--src/pkg/go/printer/testdata/comments2.input28
-rw-r--r--src/pkg/go/printer/testdata/declarations.golden18
-rw-r--r--src/pkg/go/printer/testdata/declarations.input21
-rw-r--r--src/pkg/go/scanner/scanner.go118
-rw-r--r--src/pkg/go/scanner/scanner_test.go103
-rw-r--r--src/pkg/hash/crc32/crc32_amd64p32.s64
-rw-r--r--src/pkg/hash/crc32/crc32_amd64x.go (renamed from src/pkg/hash/crc32/crc32_amd64.go)2
-rw-r--r--src/pkg/hash/fnv/fnv.go3
-rw-r--r--src/pkg/html/escape_test.go18
-rw-r--r--src/pkg/html/template/attr.go4
-rw-r--r--src/pkg/html/template/content.go3
-rw-r--r--src/pkg/html/template/context.go4
-rw-r--r--src/pkg/html/template/escape.go52
-rw-r--r--src/pkg/html/template/escape_test.go32
-rw-r--r--src/pkg/html/template/html.go4
-rw-r--r--src/pkg/html/template/js.go2
-rw-r--r--src/pkg/html/template/template.go8
-rw-r--r--src/pkg/image/color/palette/gen.go4
-rw-r--r--src/pkg/image/color/palette/palette.go4
-rw-r--r--src/pkg/image/gif/reader.go22
-rw-r--r--src/pkg/image/gif/reader_test.go4
-rw-r--r--src/pkg/image/jpeg/huffman.go6
-rw-r--r--src/pkg/image/jpeg/reader_test.go27
-rw-r--r--src/pkg/image/jpeg/scan.go21
-rw-r--r--src/pkg/image/png/reader.go10
-rw-r--r--src/pkg/image/testdata/video-001.separate.dc.progression.jpegbin0 -> 14288 bytes
-rw-r--r--src/pkg/image/testdata/video-001.separate.dc.progression.progressive.jpegbin0 -> 14312 bytes
-rw-r--r--src/pkg/io/io.go1
-rw-r--r--src/pkg/io/io_test.go20
-rw-r--r--src/pkg/io/ioutil/blackhole.go23
-rw-r--r--src/pkg/io/ioutil/ioutil.go14
-rw-r--r--src/pkg/io/multi.go11
-rw-r--r--src/pkg/io/multi_test.go27
-rw-r--r--src/pkg/log/example_test.go21
-rw-r--r--src/pkg/log/syslog/syslog.go5
-rw-r--r--src/pkg/log/syslog/syslog_test.go2
-rw-r--r--src/pkg/log/syslog/syslog_unix.go2
-rw-r--r--src/pkg/math/abs_amd64p32.s5
-rw-r--r--src/pkg/math/asin_amd64p32.s5
-rw-r--r--src/pkg/math/atan2_amd64p32.s5
-rw-r--r--src/pkg/math/atan_amd64p32.s5
-rw-r--r--src/pkg/math/big/arith.go14
-rw-r--r--src/pkg/math/big/arith_amd64p32.s41
-rw-r--r--src/pkg/math/big/arith_arm.s109
-rw-r--r--src/pkg/math/big/int.go37
-rw-r--r--src/pkg/math/big/int_test.go66
-rw-r--r--src/pkg/math/big/nat.go11
-rw-r--r--src/pkg/math/big/nat_test.go27
-rw-r--r--src/pkg/math/big/rat.go21
-rw-r--r--src/pkg/math/big/rat_test.go65
-rw-r--r--src/pkg/math/cmplx/cmath_test.go13
-rw-r--r--src/pkg/math/cmplx/pow.go18
-rw-r--r--src/pkg/math/cmplx/sqrt.go1
-rw-r--r--src/pkg/math/dim_amd64p32.s5
-rw-r--r--src/pkg/math/exp2_amd64p32.s5
-rw-r--r--src/pkg/math/exp_amd64p32.s5
-rw-r--r--src/pkg/math/expm1_amd64p32.s5
-rw-r--r--src/pkg/math/floor_amd64p32.s5
-rw-r--r--src/pkg/math/frexp_amd64p32.s5
-rw-r--r--src/pkg/math/hypot_amd64p32.s5
-rw-r--r--src/pkg/math/ldexp_amd64p32.s5
-rw-r--r--src/pkg/math/log10_amd64p32.s5
-rw-r--r--src/pkg/math/log1p_amd64p32.s5
-rw-r--r--src/pkg/math/log_amd64p32.s5
-rw-r--r--src/pkg/math/mod_amd64p32.s5
-rw-r--r--src/pkg/math/modf_amd64p32.s5
-rw-r--r--src/pkg/math/rand/rand.go52
-rw-r--r--src/pkg/math/rand/rand_test.go39
-rw-r--r--src/pkg/math/rand/regress_test.go355
-rw-r--r--src/pkg/math/remainder_amd64p32.s5
-rw-r--r--src/pkg/math/sin_amd64p32.s5
-rw-r--r--src/pkg/math/sincos_amd64p32.s5
-rw-r--r--src/pkg/math/sqrt_amd64p32.s5
-rw-r--r--src/pkg/math/tan_amd64p32.s5
-rw-r--r--src/pkg/mime/mediatype.go10
-rw-r--r--src/pkg/mime/mediatype_test.go1
-rw-r--r--src/pkg/mime/multipart/example_test.go53
-rw-r--r--src/pkg/mime/multipart/formdata_test.go3
-rw-r--r--src/pkg/mime/multipart/multipart.go10
-rw-r--r--src/pkg/mime/multipart/quotedprintable_test.go2
-rw-r--r--src/pkg/mime/type_unix.go2
-rw-r--r--src/pkg/net/cgo_bsd.go2
-rw-r--r--src/pkg/net/cgo_unix_test.go24
-rw-r--r--src/pkg/net/conn_test.go39
-rw-r--r--src/pkg/net/dial.go25
-rw-r--r--src/pkg/net/dial_test.go93
-rw-r--r--src/pkg/net/dialgoogle_test.go26
-rw-r--r--src/pkg/net/dnsclient.go4
-rw-r--r--src/pkg/net/dnsclient_test.go69
-rw-r--r--src/pkg/net/dnsclient_unix.go103
-rw-r--r--src/pkg/net/dnsclient_unix_test.go134
-rw-r--r--src/pkg/net/dnsconfig_unix.go9
-rw-r--r--src/pkg/net/dnsconfig_unix_test.go46
-rw-r--r--src/pkg/net/fd_mutex_test.go27
-rw-r--r--src/pkg/net/fd_plan9.go115
-rw-r--r--src/pkg/net/fd_poll_nacl.go94
-rw-r--r--src/pkg/net/fd_poll_runtime.go7
-rw-r--r--src/pkg/net/fd_unix.go58
-rw-r--r--src/pkg/net/fd_unix_test.go2
-rw-r--r--src/pkg/net/fd_windows.go14
-rw-r--r--src/pkg/net/file_plan9.go10
-rw-r--r--src/pkg/net/file_test.go8
-rw-r--r--src/pkg/net/file_unix.go4
-rw-r--r--src/pkg/net/hosts_test.go2
-rw-r--r--src/pkg/net/http/cgi/host.go27
-rw-r--r--src/pkg/net/http/cgi/matryoshka_test.go137
-rw-r--r--src/pkg/net/http/chunked.go58
-rw-r--r--src/pkg/net/http/chunked_test.go112
-rw-r--r--src/pkg/net/http/client.go111
-rw-r--r--src/pkg/net/http/client_test.go275
-rw-r--r--src/pkg/net/http/cookie.go58
-rw-r--r--src/pkg/net/http/cookie_test.go107
-rw-r--r--src/pkg/net/http/export_test.go18
-rw-r--r--src/pkg/net/http/fcgi/child.go19
-rw-r--r--src/pkg/net/http/fs.go18
-rw-r--r--src/pkg/net/http/fs_test.go70
-rw-r--r--src/pkg/net/http/header.go19
-rw-r--r--src/pkg/net/http/header_test.go9
-rw-r--r--src/pkg/net/http/httptest/server_test.go23
-rw-r--r--src/pkg/net/http/httputil/chunked.go74
-rw-r--r--src/pkg/net/http/httputil/chunked_test.go120
-rw-r--r--src/pkg/net/http/httputil/dump.go35
-rw-r--r--src/pkg/net/http/httputil/dump_test.go87
-rw-r--r--src/pkg/net/http/httputil/httputil.go32
-rw-r--r--src/pkg/net/http/httputil/persist.go21
-rw-r--r--src/pkg/net/http/httputil/reverseproxy.go4
-rw-r--r--src/pkg/net/http/httputil/reverseproxy_test.go16
-rw-r--r--src/pkg/net/http/proxy_test.go19
-rw-r--r--src/pkg/net/http/race.go11
-rw-r--r--src/pkg/net/http/request.go139
-rw-r--r--src/pkg/net/http/request_test.go133
-rw-r--r--src/pkg/net/http/requestwrite_test.go42
-rw-r--r--src/pkg/net/http/response.go68
-rw-r--r--src/pkg/net/http/response_test.go20
-rw-r--r--src/pkg/net/http/responsewrite_test.go123
-rw-r--r--src/pkg/net/http/serve_test.go586
-rw-r--r--src/pkg/net/http/server.go270
-rw-r--r--src/pkg/net/http/transfer.go155
-rw-r--r--src/pkg/net/http/transfer_test.go33
-rw-r--r--src/pkg/net/http/transport.go393
-rw-r--r--src/pkg/net/http/transport_test.go529
-rw-r--r--src/pkg/net/interface.go10
-rw-r--r--src/pkg/net/interface_linux.go58
-rw-r--r--src/pkg/net/interface_stub.go2
-rw-r--r--src/pkg/net/ip.go3
-rw-r--r--src/pkg/net/ip_test.go1
-rw-r--r--src/pkg/net/ipraw_test.go4
-rw-r--r--src/pkg/net/iprawsock_posix.go18
-rw-r--r--src/pkg/net/ipsock.go6
-rw-r--r--src/pkg/net/ipsock_plan9.go66
-rw-r--r--src/pkg/net/ipsock_posix.go9
-rw-r--r--src/pkg/net/lookup_plan9.go46
-rw-r--r--src/pkg/net/lookup_unix.go2
-rw-r--r--src/pkg/net/mail/message.go20
-rw-r--r--src/pkg/net/mail/message_test.go17
-rw-r--r--src/pkg/net/multicast_test.go8
-rw-r--r--src/pkg/net/net.go15
-rw-r--r--src/pkg/net/net_test.go25
-rw-r--r--src/pkg/net/net_windows_test.go4
-rw-r--r--src/pkg/net/netgo_unix_test.go24
-rw-r--r--src/pkg/net/packetconn_test.go32
-rw-r--r--src/pkg/net/parse.go2
-rw-r--r--src/pkg/net/port_unix.go12
-rw-r--r--src/pkg/net/protoconn_test.go6
-rw-r--r--src/pkg/net/rpc/client.go14
-rw-r--r--src/pkg/net/rpc/client_test.go36
-rw-r--r--src/pkg/net/rpc/jsonrpc/all_test.go35
-rw-r--r--src/pkg/net/rpc/jsonrpc/server.go6
-rw-r--r--src/pkg/net/rpc/server.go5
-rw-r--r--src/pkg/net/rpc/server_test.go38
-rw-r--r--src/pkg/net/sendfile_dragonfly.go2
-rw-r--r--src/pkg/net/sendfile_freebsd.go2
-rw-r--r--src/pkg/net/sendfile_stub.go2
-rw-r--r--src/pkg/net/server_test.go86
-rw-r--r--src/pkg/net/smtp/example_test.go61
-rw-r--r--src/pkg/net/smtp/smtp.go8
-rw-r--r--src/pkg/net/smtp/smtp_test.go144
-rw-r--r--src/pkg/net/sock_bsd.go2
-rw-r--r--src/pkg/net/sock_cloexec.go47
-rw-r--r--src/pkg/net/sock_posix.go2
-rw-r--r--src/pkg/net/sock_solaris.go13
-rw-r--r--src/pkg/net/sockopt_bsd.go15
-rw-r--r--src/pkg/net/sockopt_plan9.go13
-rw-r--r--src/pkg/net/sockopt_posix.go2
-rw-r--r--src/pkg/net/sockopt_solaris.go32
-rw-r--r--src/pkg/net/sockoptip_bsd.go2
-rw-r--r--src/pkg/net/sockoptip_posix.go2
-rw-r--r--src/pkg/net/sockoptip_stub.go39
-rw-r--r--src/pkg/net/sys_cloexec.go18
-rw-r--r--src/pkg/net/tcp_test.go53
-rw-r--r--src/pkg/net/tcpsock_plan9.go29
-rw-r--r--src/pkg/net/tcpsock_posix.go21
-rw-r--r--src/pkg/net/tcpsockopt_dragonfly.go29
-rw-r--r--src/pkg/net/tcpsockopt_plan9.go18
-rw-r--r--src/pkg/net/tcpsockopt_posix.go2
-rw-r--r--src/pkg/net/tcpsockopt_solaris.go27
-rw-r--r--src/pkg/net/tcpsockopt_unix.go2
-rw-r--r--src/pkg/net/tcpsockopt_windows.go17
-rw-r--r--src/pkg/net/testdata/resolv.conf5
-rw-r--r--src/pkg/net/textproto/reader.go112
-rw-r--r--src/pkg/net/textproto/reader_test.go28
-rw-r--r--src/pkg/net/timeout_test.go25
-rw-r--r--src/pkg/net/udp_test.go4
-rw-r--r--src/pkg/net/udpsock.go4
-rw-r--r--src/pkg/net/udpsock_plan9.go3
-rw-r--r--src/pkg/net/udpsock_posix.go10
-rw-r--r--src/pkg/net/unicast_posix_test.go7
-rw-r--r--src/pkg/net/unix_test.go69
-rw-r--r--src/pkg/net/unixsock_posix.go28
-rw-r--r--src/pkg/net/url/url.go2
-rw-r--r--src/pkg/net/url/url_test.go11
-rw-r--r--src/pkg/net/z_last_test.go37
-rw-r--r--src/pkg/os/dir_unix.go2
-rw-r--r--src/pkg/os/doc.go3
-rw-r--r--src/pkg/os/env_unix_test.go2
-rw-r--r--src/pkg/os/error_unix.go2
-rw-r--r--src/pkg/os/exec/exec.go88
-rw-r--r--src/pkg/os/exec/exec_test.go151
-rw-r--r--src/pkg/os/exec/lp_unix.go2
-rw-r--r--src/pkg/os/exec/lp_unix_test.go2
-rw-r--r--src/pkg/os/exec/lp_windows_test.go474
-rw-r--r--src/pkg/os/exec_plan9.go9
-rw-r--r--src/pkg/os/exec_posix.go2
-rw-r--r--src/pkg/os/exec_unix.go5
-rw-r--r--src/pkg/os/file.go8
-rw-r--r--src/pkg/os/file_plan9.go33
-rw-r--r--src/pkg/os/file_posix.go7
-rw-r--r--src/pkg/os/file_unix.go59
-rw-r--r--src/pkg/os/file_windows.go15
-rw-r--r--src/pkg/os/getwd.go28
-rw-r--r--src/pkg/os/os_test.go156
-rw-r--r--src/pkg/os/os_unix_test.go40
-rw-r--r--src/pkg/os/path_test.go5
-rw-r--r--src/pkg/os/path_unix.go2
-rw-r--r--src/pkg/os/pipe_bsd.go2
-rw-r--r--src/pkg/os/signal/example_test.go4
-rw-r--r--src/pkg/os/signal/sig.s2
-rw-r--r--src/pkg/os/signal/signal_test.go2
-rw-r--r--src/pkg/os/signal/signal_unix.go2
-rw-r--r--src/pkg/os/signal/signal_windows_test.go11
-rw-r--r--src/pkg/os/stat_nacl.go62
-rw-r--r--src/pkg/os/stat_solaris.go61
-rw-r--r--src/pkg/os/sys_bsd.go2
-rw-r--r--src/pkg/os/sys_darwin.go31
-rw-r--r--src/pkg/os/sys_freebsd.go23
-rw-r--r--src/pkg/os/sys_nacl.go9
-rw-r--r--src/pkg/os/sys_solaris.go11
-rw-r--r--src/pkg/os/sys_unix.go11
-rw-r--r--src/pkg/os/user/lookup_unix.go2
-rw-r--r--src/pkg/path/filepath/export_test.go7
-rw-r--r--src/pkg/path/filepath/match.go2
-rw-r--r--src/pkg/path/filepath/match_test.go53
-rw-r--r--src/pkg/path/filepath/path.go38
-rw-r--r--src/pkg/path/filepath/path_test.go63
-rw-r--r--src/pkg/path/filepath/path_unix.go2
-rw-r--r--src/pkg/path/filepath/path_windows_test.go4
-rw-r--r--src/pkg/reflect/all_test.go223
-rw-r--r--src/pkg/reflect/asm_amd64p32.s27
-rw-r--r--src/pkg/reflect/deepequal.go3
-rw-r--r--src/pkg/reflect/export_test.go1
-rw-r--r--src/pkg/reflect/makefunc.go8
-rw-r--r--src/pkg/reflect/type.go131
-rw-r--r--src/pkg/reflect/value.go968
-rw-r--r--src/pkg/regexp/all_test.go65
-rw-r--r--src/pkg/regexp/example_test.go4
-rw-r--r--src/pkg/regexp/exec.go121
-rw-r--r--src/pkg/regexp/onepass.go582
-rw-r--r--src/pkg/regexp/onepass_test.go208
-rw-r--r--src/pkg/regexp/regexp.go20
-rw-r--r--src/pkg/regexp/syntax/doc.go4
-rwxr-xr-xsrc/pkg/regexp/syntax/make_perl_groups.pl4
-rw-r--r--src/pkg/regexp/syntax/parse.go3
-rw-r--r--src/pkg/regexp/syntax/parse_test.go4
-rw-r--r--src/pkg/regexp/syntax/perl_groups.go4
-rw-r--r--src/pkg/regexp/syntax/prog.go54
-rw-r--r--src/pkg/regexp/syntax/prog_test.go4
-rw-r--r--src/pkg/runtime/alg.goc (renamed from src/pkg/runtime/alg.c)40
-rw-r--r--src/pkg/runtime/append_test.go19
-rw-r--r--src/pkg/runtime/arch_386.h5
-rw-r--r--src/pkg/runtime/arch_amd64.h9
-rw-r--r--src/pkg/runtime/arch_amd64p32.h16
-rw-r--r--src/pkg/runtime/arch_arm.h1
-rw-r--r--src/pkg/runtime/asm_386.s849
-rw-r--r--src/pkg/runtime/asm_amd64.s893
-rw-r--r--src/pkg/runtime/asm_amd64p32.s1073
-rw-r--r--src/pkg/runtime/asm_arm.s477
-rw-r--r--src/pkg/runtime/atomic_amd64x.c (renamed from src/pkg/runtime/atomic_amd64.c)2
-rw-r--r--src/pkg/runtime/atomic_arm.c13
-rw-r--r--src/pkg/runtime/callback_windows.c3
-rw-r--r--src/pkg/runtime/cgo/asm_nacl_amd64p32.s13
-rw-r--r--src/pkg/runtime/cgo/gcc_dragonfly_386.c4
-rw-r--r--src/pkg/runtime/cgo/gcc_dragonfly_amd64.c4
-rw-r--r--src/pkg/runtime/cgo/gcc_freebsd_386.c4
-rw-r--r--src/pkg/runtime/cgo/gcc_freebsd_amd64.c4
-rw-r--r--src/pkg/runtime/cgo/gcc_freebsd_arm.c9
-rw-r--r--src/pkg/runtime/cgo/gcc_linux_386.c4
-rw-r--r--src/pkg/runtime/cgo/gcc_linux_amd64.c4
-rw-r--r--src/pkg/runtime/cgo/gcc_linux_arm.c8
-rw-r--r--src/pkg/runtime/cgo/gcc_netbsd_386.c4
-rw-r--r--src/pkg/runtime/cgo/gcc_netbsd_amd64.c4
-rw-r--r--src/pkg/runtime/cgo/gcc_netbsd_arm.c4
-rw-r--r--src/pkg/runtime/cgo/gcc_openbsd_386.c4
-rw-r--r--src/pkg/runtime/cgo/gcc_openbsd_amd64.c4
-rw-r--r--src/pkg/runtime/cgo/gcc_windows_386.c16
-rw-r--r--src/pkg/runtime/cgo/gcc_windows_amd64.c14
-rw-r--r--src/pkg/runtime/cgo/libcgo.h1
-rw-r--r--src/pkg/runtime/cgocall.c53
-rw-r--r--src/pkg/runtime/chan.goc (renamed from src/pkg/runtime/chan.c)528
-rw-r--r--src/pkg/runtime/chan.h75
-rw-r--r--src/pkg/runtime/chan_test.go637
-rw-r--r--src/pkg/runtime/complex.goc (renamed from src/pkg/runtime/complex.c)8
-rw-r--r--src/pkg/runtime/cpuprof.goc (renamed from src/pkg/runtime/cpuprof.c)11
-rw-r--r--src/pkg/runtime/crash_test.go96
-rw-r--r--src/pkg/runtime/debug/garbage.go20
-rw-r--r--src/pkg/runtime/debug/heapdump_test.go33
-rw-r--r--src/pkg/runtime/debug/stack.go6
-rw-r--r--src/pkg/runtime/defs.c14
-rw-r--r--src/pkg/runtime/defs_freebsd.go6
-rw-r--r--src/pkg/runtime/defs_freebsd_386.h6
-rw-r--r--src/pkg/runtime/defs_freebsd_amd64.h6
-rw-r--r--src/pkg/runtime/defs_freebsd_arm.h36
-rw-r--r--src/pkg/runtime/defs_nacl_386.h63
-rw-r--r--src/pkg/runtime/defs_nacl_amd64p32.h90
-rw-r--r--src/pkg/runtime/defs_openbsd_386.h8
-rw-r--r--src/pkg/runtime/defs_openbsd_amd64.h9
-rw-r--r--src/pkg/runtime/defs_solaris.go156
-rw-r--r--src/pkg/runtime/defs_solaris_amd64.go48
-rw-r--r--src/pkg/runtime/defs_solaris_amd64.h254
-rw-r--r--src/pkg/runtime/env_plan9.c10
-rw-r--r--src/pkg/runtime/env_posix.c17
-rw-r--r--src/pkg/runtime/error.go7
-rw-r--r--src/pkg/runtime/export_test.go34
-rw-r--r--src/pkg/runtime/extern.go28
-rw-r--r--src/pkg/runtime/funcdata.h6
-rw-r--r--src/pkg/runtime/futex_test.go75
-rw-r--r--src/pkg/runtime/gc_test.go83
-rw-r--r--src/pkg/runtime/hash_test.go6
-rw-r--r--src/pkg/runtime/hashmap.goc (renamed from src/pkg/runtime/hashmap.c)707
-rw-r--r--src/pkg/runtime/hashmap.h147
-rw-r--r--src/pkg/runtime/hashmap_fast.c90
-rw-r--r--src/pkg/runtime/heapdump.c981
-rw-r--r--src/pkg/runtime/iface.goc (renamed from src/pkg/runtime/iface.c)239
-rw-r--r--src/pkg/runtime/lfstack.goc (renamed from src/pkg/runtime/lfstack.c)24
-rw-r--r--src/pkg/runtime/lfstack_test.go12
-rw-r--r--src/pkg/runtime/lock_futex.c12
-rw-r--r--src/pkg/runtime/lock_sema.c11
-rw-r--r--src/pkg/runtime/malloc.goc604
-rw-r--r--src/pkg/runtime/malloc.h215
-rw-r--r--src/pkg/runtime/map_test.go66
-rw-r--r--src/pkg/runtime/mapspeed_test.go30
-rw-r--r--src/pkg/runtime/mcache.c123
-rw-r--r--src/pkg/runtime/mcentral.c205
-rw-r--r--src/pkg/runtime/mem.go3
-rw-r--r--src/pkg/runtime/mem_darwin.c13
-rw-r--r--src/pkg/runtime/mem_dragonfly.c19
-rw-r--r--src/pkg/runtime/mem_freebsd.c19
-rw-r--r--src/pkg/runtime/mem_linux.c30
-rw-r--r--src/pkg/runtime/mem_nacl.c118
-rw-r--r--src/pkg/runtime/mem_netbsd.c17
-rw-r--r--src/pkg/runtime/mem_openbsd.c17
-rw-r--r--src/pkg/runtime/mem_plan9.c13
-rw-r--r--src/pkg/runtime/mem_solaris.c99
-rw-r--r--src/pkg/runtime/mem_windows.c43
-rw-r--r--src/pkg/runtime/memclr_386.s127
-rw-r--r--src/pkg/runtime/memclr_amd64.s116
-rw-r--r--src/pkg/runtime/memclr_arm.s6
-rw-r--r--src/pkg/runtime/memclr_plan9_386.s50
-rw-r--r--src/pkg/runtime/memclr_plan9_amd64.s48
-rw-r--r--src/pkg/runtime/memmove_386.s2
-rw-r--r--src/pkg/runtime/memmove_amd64.s2
-rw-r--r--src/pkg/runtime/memmove_nacl_amd64p32.s46
-rw-r--r--src/pkg/runtime/memmove_plan9_386.s127
-rw-r--r--src/pkg/runtime/memmove_plan9_amd64.s126
-rw-r--r--src/pkg/runtime/memmove_test.go179
-rw-r--r--src/pkg/runtime/mfinal.c219
-rw-r--r--src/pkg/runtime/mfinal_test.go175
-rw-r--r--src/pkg/runtime/mgc0.c1814
-rw-r--r--src/pkg/runtime/mgc0.go12
-rw-r--r--src/pkg/runtime/mgc0.h41
-rw-r--r--src/pkg/runtime/mheap.c506
-rw-r--r--src/pkg/runtime/mknacl.sh15
-rw-r--r--src/pkg/runtime/mprof.goc271
-rw-r--r--src/pkg/runtime/msize.c36
-rw-r--r--src/pkg/runtime/netpoll.goc169
-rw-r--r--src/pkg/runtime/netpoll_epoll.c7
-rw-r--r--src/pkg/runtime/netpoll_kqueue.c7
-rw-r--r--src/pkg/runtime/netpoll_nacl.c37
-rw-r--r--src/pkg/runtime/netpoll_solaris.c268
-rw-r--r--src/pkg/runtime/netpoll_windows.c15
-rw-r--r--src/pkg/runtime/norace_test.go36
-rw-r--r--src/pkg/runtime/os_darwin.c14
-rw-r--r--src/pkg/runtime/os_darwin.h2
-rw-r--r--src/pkg/runtime/os_dragonfly.c14
-rw-r--r--src/pkg/runtime/os_dragonfly.h1
-rw-r--r--src/pkg/runtime/os_freebsd.c20
-rw-r--r--src/pkg/runtime/os_freebsd.h1
-rw-r--r--src/pkg/runtime/os_linux.c13
-rw-r--r--src/pkg/runtime/os_linux.h1
-rw-r--r--src/pkg/runtime/os_linux_arm.c2
-rw-r--r--src/pkg/runtime/os_nacl.c278
-rw-r--r--src/pkg/runtime/os_nacl.h162
-rw-r--r--src/pkg/runtime/os_netbsd.c14
-rw-r--r--src/pkg/runtime/os_netbsd.h1
-rw-r--r--src/pkg/runtime/os_openbsd.c16
-rw-r--r--src/pkg/runtime/os_openbsd.h1
-rw-r--r--src/pkg/runtime/os_plan9.c101
-rw-r--r--src/pkg/runtime/os_plan9.h9
-rw-r--r--src/pkg/runtime/os_plan9_386.c135
-rw-r--r--src/pkg/runtime/os_plan9_amd64.c106
-rw-r--r--src/pkg/runtime/os_solaris.c583
-rw-r--r--src/pkg/runtime/os_solaris.h51
-rw-r--r--src/pkg/runtime/os_windows.c101
-rw-r--r--src/pkg/runtime/os_windows_386.c48
-rw-r--r--src/pkg/runtime/os_windows_amd64.c44
-rw-r--r--src/pkg/runtime/panic.c326
-rw-r--r--src/pkg/runtime/parfor.c28
-rw-r--r--src/pkg/runtime/pprof/pprof.go2
-rw-r--r--src/pkg/runtime/pprof/pprof_test.go29
-rw-r--r--src/pkg/runtime/print.c63
-rw-r--r--src/pkg/runtime/proc.c717
-rw-r--r--src/pkg/runtime/proc.p526
-rw-r--r--src/pkg/runtime/proc_test.go66
-rw-r--r--src/pkg/runtime/race.c394
-rw-r--r--src/pkg/runtime/race.h3
-rw-r--r--src/pkg/runtime/race/README2
-rw-r--r--src/pkg/runtime/race/race.go118
-rw-r--r--src/pkg/runtime/race/race_darwin_amd64.sysobin192988 -> 222964 bytes
-rw-r--r--src/pkg/runtime/race/race_linux_amd64.sysobin195144 -> 243208 bytes
-rw-r--r--src/pkg/runtime/race/race_test.go17
-rw-r--r--src/pkg/runtime/race/race_windows_amd64.sysobin161295 -> 210859 bytes
-rw-r--r--src/pkg/runtime/race/testdata/chan_test.go207
-rw-r--r--src/pkg/runtime/race/testdata/finalizer_test.go22
-rw-r--r--src/pkg/runtime/race/testdata/map_test.go79
-rw-r--r--src/pkg/runtime/race/testdata/mop_test.go22
-rw-r--r--src/pkg/runtime/race0.c6
-rw-r--r--src/pkg/runtime/race_amd64.s240
-rw-r--r--src/pkg/runtime/rdebug.goc27
-rw-r--r--src/pkg/runtime/rt0_freebsd_arm.s5
-rw-r--r--src/pkg/runtime/rt0_nacl_386.s22
-rw-r--r--src/pkg/runtime/rt0_nacl_amd64p32.s30
-rw-r--r--src/pkg/runtime/rt0_solaris_amd64.s18
-rw-r--r--src/pkg/runtime/runtime-gdb.py160
-rw-r--r--src/pkg/runtime/runtime.c120
-rw-r--r--src/pkg/runtime/runtime.h254
-rw-r--r--src/pkg/runtime/runtime1.goc114
-rw-r--r--src/pkg/runtime/runtime_test.go82
-rw-r--r--src/pkg/runtime/runtime_unix_test.go56
-rw-r--r--src/pkg/runtime/sema.goc6
-rw-r--r--src/pkg/runtime/signal_386.c9
-rw-r--r--src/pkg/runtime/signal_amd64x.c (renamed from src/pkg/runtime/signal_amd64.c)33
-rw-r--r--src/pkg/runtime/signal_arm.c7
-rw-r--r--src/pkg/runtime/signal_nacl_386.h23
-rw-r--r--src/pkg/runtime/signal_nacl_amd64p32.h31
-rw-r--r--src/pkg/runtime/signal_solaris_amd64.h31
-rw-r--r--src/pkg/runtime/signal_unix.c3
-rw-r--r--src/pkg/runtime/signals_freebsd.h2
-rw-r--r--src/pkg/runtime/signals_linux.h2
-rw-r--r--src/pkg/runtime/signals_nacl.h50
-rw-r--r--src/pkg/runtime/signals_plan9.h60
-rw-r--r--src/pkg/runtime/signals_solaris.h94
-rw-r--r--src/pkg/runtime/slice.goc (renamed from src/pkg/runtime/slice.c)74
-rw-r--r--src/pkg/runtime/softfloat_arm.c4
-rw-r--r--src/pkg/runtime/sqrt.go150
-rw-r--r--src/pkg/runtime/stack.c711
-rw-r--r--src/pkg/runtime/stack.h5
-rw-r--r--src/pkg/runtime/stack_gen_test.go1473
-rw-r--r--src/pkg/runtime/stack_test.go1661
-rw-r--r--src/pkg/runtime/string.goc102
-rw-r--r--src/pkg/runtime/symtab.goc (renamed from src/pkg/runtime/symtab.c)27
-rw-r--r--src/pkg/runtime/sys_darwin_386.s3
-rw-r--r--src/pkg/runtime/sys_dragonfly_386.s4
-rw-r--r--src/pkg/runtime/sys_dragonfly_amd64.s4
-rw-r--r--src/pkg/runtime/sys_freebsd_386.s11
-rw-r--r--src/pkg/runtime/sys_freebsd_amd64.s6
-rw-r--r--src/pkg/runtime/sys_freebsd_arm.s9
-rw-r--r--src/pkg/runtime/sys_linux_386.s6
-rw-r--r--src/pkg/runtime/sys_linux_amd64.s4
-rw-r--r--src/pkg/runtime/sys_linux_arm.s2
-rw-r--r--src/pkg/runtime/sys_nacl_386.s243
-rw-r--r--src/pkg/runtime/sys_nacl_amd64p32.s413
-rw-r--r--src/pkg/runtime/sys_openbsd_386.s56
-rw-r--r--src/pkg/runtime/sys_openbsd_amd64.s22
-rw-r--r--src/pkg/runtime/sys_plan9_386.s15
-rw-r--r--src/pkg/runtime/sys_plan9_amd64.s2
-rw-r--r--src/pkg/runtime/sys_solaris_amd64.s267
-rw-r--r--src/pkg/runtime/sys_windows_386.s123
-rw-r--r--src/pkg/runtime/sys_windows_amd64.s126
-rw-r--r--src/pkg/runtime/sys_x86.c30
-rw-r--r--src/pkg/runtime/syscall_nacl.h71
-rw-r--r--src/pkg/runtime/syscall_solaris.goc374
-rw-r--r--src/pkg/runtime/syscall_windows.goc19
-rw-r--r--src/pkg/runtime/syscall_windows_test.go249
-rw-r--r--src/pkg/runtime/time.goc32
-rw-r--r--src/pkg/runtime/traceback_arm.c116
-rw-r--r--src/pkg/runtime/traceback_x86.c207
-rw-r--r--src/pkg/runtime/type.go1
-rw-r--r--src/pkg/runtime/type.h8
-rw-r--r--src/pkg/runtime/typekind.h3
-rw-r--r--src/pkg/runtime/vlop_arm.s13
-rw-r--r--src/pkg/runtime/vlrt_386.c12
-rw-r--r--src/pkg/runtime/vlrt_arm.c7
-rw-r--r--src/pkg/sort/sort.go6
-rw-r--r--src/pkg/strconv/atob_test.go34
-rw-r--r--src/pkg/strconv/atof.go11
-rw-r--r--src/pkg/strconv/atoi.go8
-rw-r--r--src/pkg/strconv/isprint.go4
-rw-r--r--src/pkg/strconv/makeisprint.go3
-rw-r--r--src/pkg/strconv/quote.go3
-rw-r--r--src/pkg/strconv/quote_example_test.go35
-rw-r--r--src/pkg/strconv/quote_test.go1
-rw-r--r--src/pkg/strings/example_test.go32
-rw-r--r--src/pkg/strings/reader.go52
-rw-r--r--src/pkg/strings/reader_test.go56
-rw-r--r--src/pkg/strings/replace.go2
-rw-r--r--src/pkg/strings/strings_test.go30
-rw-r--r--src/pkg/sync/atomic/asm_386.s14
-rw-r--r--src/pkg/sync/atomic/asm_amd64.s4
-rw-r--r--src/pkg/sync/atomic/asm_amd64p32.s159
-rw-r--r--src/pkg/sync/atomic/asm_linux_arm.s12
-rw-r--r--src/pkg/sync/atomic/atomic_test.go7
-rw-r--r--src/pkg/sync/atomic/export_linux_arm_test.go2
-rw-r--r--src/pkg/sync/mutex_test.go72
-rw-r--r--src/pkg/sync/once_test.go25
-rw-r--r--src/pkg/sync/pool.go223
-rw-r--r--src/pkg/sync/pool_test.go151
-rw-r--r--src/pkg/sync/runtime_sema_test.go85
-rw-r--r--src/pkg/sync/rwmutex_test.go79
-rw-r--r--src/pkg/sync/waitgroup.go10
-rw-r--r--src/pkg/sync/waitgroup_test.go125
-rw-r--r--src/pkg/syscall/asm_darwin_386.s13
-rw-r--r--src/pkg/syscall/asm_darwin_amd64.s11
-rw-r--r--src/pkg/syscall/asm_freebsd_386.s13
-rw-r--r--src/pkg/syscall/asm_freebsd_amd64.s13
-rw-r--r--src/pkg/syscall/asm_freebsd_arm.s51
-rw-r--r--src/pkg/syscall/asm_linux_386.s17
-rw-r--r--src/pkg/syscall/asm_linux_amd64.s21
-rw-r--r--src/pkg/syscall/asm_linux_arm.s4
-rw-r--r--src/pkg/syscall/asm_nacl_386.s43
-rw-r--r--src/pkg/syscall/asm_nacl_amd64p32.s41
-rw-r--r--src/pkg/syscall/asm_netbsd_386.s13
-rw-r--r--src/pkg/syscall/asm_netbsd_amd64.s13
-rw-r--r--src/pkg/syscall/asm_openbsd_386.s13
-rw-r--r--src/pkg/syscall/asm_openbsd_amd64.s13
-rw-r--r--src/pkg/syscall/asm_plan9_386.s9
-rw-r--r--src/pkg/syscall/asm_plan9_amd64.s11
-rw-r--r--src/pkg/syscall/asm_solaris_amd64.s7
-rw-r--r--src/pkg/syscall/consistency_unix_test.go34
-rw-r--r--src/pkg/syscall/dir_plan9.go9
-rw-r--r--src/pkg/syscall/env_unix.go2
-rw-r--r--src/pkg/syscall/exec_linux.go6
-rw-r--r--src/pkg/syscall/exec_plan9.go2
-rw-r--r--src/pkg/syscall/exec_solaris.go243
-rw-r--r--src/pkg/syscall/exec_unix.go4
-rw-r--r--src/pkg/syscall/fd_nacl.go326
-rw-r--r--src/pkg/syscall/flock.go22
-rw-r--r--src/pkg/syscall/flock_linux_32bit.go13
-rw-r--r--src/pkg/syscall/fs_nacl.go815
-rw-r--r--src/pkg/syscall/lsf_linux.go4
-rwxr-xr-xsrc/pkg/syscall/mkall.sh61
-rw-r--r--src/pkg/syscall/mkall_windows.bat21
-rwxr-xr-xsrc/pkg/syscall/mkerrors.sh79
-rwxr-xr-xsrc/pkg/syscall/mkerrors_windows.sh202
-rwxr-xr-xsrc/pkg/syscall/mksyscall.pl10
-rwxr-xr-xsrc/pkg/syscall/mksyscall_solaris.pl (renamed from src/pkg/syscall/mksyscall_windows.pl)118
-rw-r--r--src/pkg/syscall/mksyscall_windows.go662
-rwxr-xr-xsrc/pkg/syscall/mksysnum_dragonfly.pl2
-rwxr-xr-xsrc/pkg/syscall/mksysnum_freebsd.pl13
-rw-r--r--src/pkg/syscall/mmap_unix_test.go22
-rw-r--r--src/pkg/syscall/net_nacl.go912
-rw-r--r--src/pkg/syscall/rlimit_linux_test.go41
-rw-r--r--src/pkg/syscall/route_bsd.go9
-rw-r--r--src/pkg/syscall/route_dragonfly.go2
-rw-r--r--src/pkg/syscall/route_freebsd.go12
-rw-r--r--src/pkg/syscall/route_freebsd_32bit.go24
-rw-r--r--src/pkg/syscall/route_freebsd_64bit.go14
-rw-r--r--src/pkg/syscall/route_netbsd.go2
-rw-r--r--src/pkg/syscall/route_openbsd.go2
-rw-r--r--src/pkg/syscall/so_solaris.go260
-rw-r--r--src/pkg/syscall/sockcmsg_unix.go8
-rw-r--r--src/pkg/syscall/srpc_nacl.go822
-rw-r--r--src/pkg/syscall/syscall_bsd.go98
-rw-r--r--src/pkg/syscall/syscall_bsd_test.go34
-rw-r--r--src/pkg/syscall/syscall_darwin.go21
-rw-r--r--src/pkg/syscall/syscall_dragonfly.go16
-rw-r--r--src/pkg/syscall/syscall_freebsd.go39
-rw-r--r--src/pkg/syscall/syscall_linux.go65
-rw-r--r--src/pkg/syscall/syscall_linux_386.go31
-rw-r--r--src/pkg/syscall/syscall_linux_amd64.go36
-rw-r--r--src/pkg/syscall/syscall_linux_arm.go26
-rw-r--r--src/pkg/syscall/syscall_nacl.go311
-rw-r--r--src/pkg/syscall/syscall_nacl_386.go32
-rw-r--r--src/pkg/syscall/syscall_nacl_amd64p32.go32
-rw-r--r--src/pkg/syscall/syscall_openbsd.go22
-rw-r--r--src/pkg/syscall/syscall_openbsd_386.go4
-rw-r--r--src/pkg/syscall/syscall_openbsd_amd64.go6
-rw-r--r--src/pkg/syscall/syscall_plan9.go2
-rw-r--r--src/pkg/syscall/syscall_solaris.go523
-rw-r--r--src/pkg/syscall/syscall_solaris_amd64.go37
-rw-r--r--src/pkg/syscall/syscall_unix.go31
-rw-r--r--src/pkg/syscall/syscall_unix_test.go (renamed from src/pkg/syscall/passfd_test.go)120
-rw-r--r--src/pkg/syscall/syscall_windows.go27
-rw-r--r--src/pkg/syscall/tables_nacl.go324
-rw-r--r--src/pkg/syscall/time_nacl_386.s11
-rw-r--r--src/pkg/syscall/time_nacl_amd64p32.s11
-rw-r--r--src/pkg/syscall/types_dragonfly.go9
-rw-r--r--src/pkg/syscall/types_freebsd.go110
-rw-r--r--src/pkg/syscall/types_linux.go2
-rw-r--r--src/pkg/syscall/types_netbsd.go5
-rw-r--r--src/pkg/syscall/types_openbsd.go5
-rw-r--r--src/pkg/syscall/types_solaris.go222
-rw-r--r--src/pkg/syscall/unzip_nacl.go685
-rw-r--r--src/pkg/syscall/zerrors_dragonfly_386.go5
-rw-r--r--src/pkg/syscall/zerrors_dragonfly_amd64.go5
-rw-r--r--src/pkg/syscall/zerrors_freebsd_386.go33
-rw-r--r--src/pkg/syscall/zerrors_freebsd_amd64.go34
-rw-r--r--src/pkg/syscall/zerrors_freebsd_arm.go35
-rw-r--r--src/pkg/syscall/zerrors_netbsd_386.go51
-rw-r--r--src/pkg/syscall/zerrors_netbsd_amd64.go51
-rw-r--r--src/pkg/syscall/zerrors_netbsd_arm.go36
-rw-r--r--src/pkg/syscall/zerrors_openbsd_386.go66
-rw-r--r--src/pkg/syscall/zerrors_openbsd_amd64.go63
-rw-r--r--src/pkg/syscall/zerrors_solaris_amd64.go1414
-rw-r--r--src/pkg/syscall/zsyscall_darwin_386.go102
-rw-r--r--src/pkg/syscall/zsyscall_darwin_amd64.go102
-rw-r--r--src/pkg/syscall/zsyscall_dragonfly_386.go34
-rw-r--r--src/pkg/syscall/zsyscall_dragonfly_amd64.go34
-rw-r--r--src/pkg/syscall/zsyscall_freebsd_386.go45
-rw-r--r--src/pkg/syscall/zsyscall_freebsd_amd64.go45
-rw-r--r--src/pkg/syscall/zsyscall_freebsd_arm.go120
-rw-r--r--src/pkg/syscall/zsyscall_linux_amd64.go15
-rw-r--r--src/pkg/syscall/zsyscall_linux_arm.go15
-rw-r--r--src/pkg/syscall/zsyscall_nacl_386.go63
-rw-r--r--src/pkg/syscall/zsyscall_nacl_amd64p32.go63
-rw-r--r--src/pkg/syscall/zsyscall_netbsd_386.go17
-rw-r--r--src/pkg/syscall/zsyscall_netbsd_amd64.go17
-rw-r--r--src/pkg/syscall/zsyscall_netbsd_arm.go28
-rw-r--r--src/pkg/syscall/zsyscall_openbsd_386.go68
-rw-r--r--src/pkg/syscall/zsyscall_openbsd_amd64.go68
-rw-r--r--src/pkg/syscall/zsyscall_solaris_amd64.go883
-rw-r--r--src/pkg/syscall/zsyscall_windows_386.go6
-rw-r--r--src/pkg/syscall/zsyscall_windows_amd64.go6
-rw-r--r--src/pkg/syscall/zsysctl_openbsd.go28
-rw-r--r--src/pkg/syscall/zsysnum_dragonfly_386.go5
-rw-r--r--src/pkg/syscall/zsysnum_dragonfly_amd64.go5
-rw-r--r--src/pkg/syscall/zsysnum_freebsd_386.go20
-rw-r--r--src/pkg/syscall/zsysnum_freebsd_amd64.go20
-rw-r--r--src/pkg/syscall/zsysnum_freebsd_arm.go27
-rw-r--r--src/pkg/syscall/zsysnum_openbsd_386.go57
-rw-r--r--src/pkg/syscall/zsysnum_openbsd_amd64.go57
-rw-r--r--src/pkg/syscall/zsysnum_solaris_amd64.go11
-rw-r--r--src/pkg/syscall/ztypes_dragonfly_386.go14
-rw-r--r--src/pkg/syscall/ztypes_dragonfly_amd64.go14
-rw-r--r--src/pkg/syscall/ztypes_freebsd_386.go55
-rw-r--r--src/pkg/syscall/ztypes_freebsd_amd64.go55
-rw-r--r--src/pkg/syscall/ztypes_freebsd_arm.go120
-rw-r--r--src/pkg/syscall/ztypes_linux_386.go8
-rw-r--r--src/pkg/syscall/ztypes_linux_amd64.go10
-rw-r--r--src/pkg/syscall/ztypes_linux_arm.go10
-rw-r--r--src/pkg/syscall/ztypes_netbsd_386.go10
-rw-r--r--src/pkg/syscall/ztypes_netbsd_amd64.go10
-rw-r--r--src/pkg/syscall/ztypes_netbsd_arm.go39
-rw-r--r--src/pkg/syscall/ztypes_openbsd_386.go55
-rw-r--r--src/pkg/syscall/ztypes_openbsd_amd64.go56
-rw-r--r--src/pkg/syscall/ztypes_solaris_amd64.go365
-rw-r--r--src/pkg/syscall/ztypes_windows.go9
-rw-r--r--src/pkg/testing/benchmark.go102
-rw-r--r--src/pkg/testing/benchmark_test.go53
-rw-r--r--src/pkg/testing/testing.go47
-rw-r--r--src/pkg/text/scanner/scanner.go6
-rw-r--r--src/pkg/text/scanner/scanner_test.go41
-rw-r--r--src/pkg/text/tabwriter/tabwriter.go12
-rw-r--r--src/pkg/text/tabwriter/tabwriter_test.go39
-rw-r--r--src/pkg/text/template/doc.go2
-rw-r--r--src/pkg/text/template/exec.go11
-rw-r--r--src/pkg/text/template/exec_test.go30
-rw-r--r--src/pkg/text/template/multi_test.go12
-rw-r--r--src/pkg/text/template/template.go2
-rw-r--r--src/pkg/time/format.go9
-rw-r--r--src/pkg/time/format_test.go511
-rw-r--r--src/pkg/time/internal_test.go20
-rw-r--r--src/pkg/time/sleep.go12
-rw-r--r--src/pkg/time/sleep_test.go31
-rw-r--r--src/pkg/time/sys_unix.go2
-rw-r--r--src/pkg/time/tick.go3
-rw-r--r--src/pkg/time/tick_test.go18
-rw-r--r--src/pkg/time/time.go2
-rw-r--r--src/pkg/time/time_test.go553
-rw-r--r--src/pkg/time/zoneinfo.go87
-rw-r--r--src/pkg/time/zoneinfo_plan9.go2
-rw-r--r--src/pkg/time/zoneinfo_read.go8
-rw-r--r--src/pkg/time/zoneinfo_test.go63
-rw-r--r--src/pkg/time/zoneinfo_unix.go2
-rw-r--r--src/pkg/time/zoneinfo_windows.go8
-rw-r--r--src/pkg/unicode/letter.go4
-rw-r--r--src/pkg/unicode/letter_test.go16
-rw-r--r--src/pkg/unicode/maketables.go8
-rw-r--r--src/pkg/unicode/script_test.go2
-rw-r--r--src/pkg/unicode/tables.go65
-rw-r--r--src/pkg/unicode/utf16/utf16.go2
-rw-r--r--src/pkg/unicode/utf16/utf16_test.go48
-rw-r--r--src/pkg/unicode/utf8/example_test.go4
-rw-r--r--src/pkg/unicode/utf8/utf8.go32
984 files changed, 57723 insertions, 19644 deletions
diff --git a/src/pkg/archive/tar/common.go b/src/pkg/archive/tar/common.go
index 1b961e3ec..e363aa793 100644
--- a/src/pkg/archive/tar/common.go
+++ b/src/pkg/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/src/pkg/archive/tar/reader.go b/src/pkg/archive/tar/reader.go
index b2d62f3c5..920a9b08f 100644
--- a/src/pkg/archive/tar/reader.go
+++ b/src/pkg/archive/tar/reader.go
@@ -29,12 +29,57 @@ 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
}
+// 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 +109,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 +144,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 +257,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 +312,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 +334,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 +344,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 +405,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
@@ -325,14 +468,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 +510,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/src/pkg/archive/tar/reader_test.go b/src/pkg/archive/tar/reader_test.go
index 128561656..9601ffe45 100644
--- a/src/pkg/archive/tar/reader_test.go
+++ b/src/pkg/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/src/pkg/archive/tar/stat_atim.go b/src/pkg/archive/tar/stat_atim.go
index 6029b0871..cf9cc79c5 100644
--- a/src/pkg/archive/tar/stat_atim.go
+++ b/src/pkg/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/src/pkg/archive/tar/stat_unix.go b/src/pkg/archive/tar/stat_unix.go
index 92bc92424..cb843db4c 100644
--- a/src/pkg/archive/tar/stat_unix.go
+++ b/src/pkg/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/src/pkg/archive/tar/tar_test.go b/src/pkg/archive/tar/tar_test.go
index 616a9cc57..ed333f3ea 100644
--- a/src/pkg/archive/tar/tar_test.go
+++ b/src/pkg/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/src/pkg/archive/tar/testdata/sparse-formats.tar b/src/pkg/archive/tar/testdata/sparse-formats.tar
new file mode 100644
index 000000000..8bd4e74d5
--- /dev/null
+++ b/src/pkg/archive/tar/testdata/sparse-formats.tar
Binary files differ
diff --git a/src/pkg/archive/tar/testdata/writer-big-long.tar b/src/pkg/archive/tar/testdata/writer-big-long.tar
new file mode 100644
index 000000000..5960ee824
--- /dev/null
+++ b/src/pkg/archive/tar/testdata/writer-big-long.tar
Binary files differ
diff --git a/src/pkg/archive/tar/testdata/xattrs.tar b/src/pkg/archive/tar/testdata/xattrs.tar
new file mode 100644
index 000000000..9701950ed
--- /dev/null
+++ b/src/pkg/archive/tar/testdata/xattrs.tar
Binary files differ
diff --git a/src/pkg/archive/tar/writer.go b/src/pkg/archive/tar/writer.go
index 549f1464c..6eff6f6f8 100644
--- a/src/pkg/archive/tar/writer.go
+++ b/src/pkg/archive/tar/writer.go
@@ -218,8 +218,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 +236,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/src/pkg/archive/tar/writer_test.go b/src/pkg/archive/tar/writer_test.go
index 30ebf977a..512fab1a6 100644
--- a/src/pkg/archive/tar/writer_test.go
+++ b/src/pkg/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)
diff --git a/src/pkg/archive/zip/reader.go b/src/pkg/archive/zip/reader.go
index 116737337..80ee03006 100644
--- a/src/pkg/archive/zip/reader.go
+++ b/src/pkg/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()
}
diff --git a/src/pkg/archive/zip/reader_test.go b/src/pkg/archive/zip/reader_test.go
index 78875ecbf..5652f3a50 100644
--- a/src/pkg/archive/zip/reader_test.go
+++ b/src/pkg/archive/zip/reader_test.go
@@ -235,6 +235,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 +355,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 +371,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
diff --git a/src/pkg/archive/zip/register.go b/src/pkg/archive/zip/register.go
index c046f081b..4211ec7af 100644
--- a/src/pkg/archive/zip/register.go
+++ b/src/pkg/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/src/pkg/archive/zip/struct.go b/src/pkg/archive/zip/struct.go
index 65e5238c3..cb28e8324 100644
--- a/src/pkg/archive/zip/struct.go
+++ b/src/pkg/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/src/pkg/archive/zip/testdata/zip64-2.zip b/src/pkg/archive/zip/testdata/zip64-2.zip
new file mode 100644
index 000000000..f844e3537
--- /dev/null
+++ b/src/pkg/archive/zip/testdata/zip64-2.zip
Binary files differ
diff --git a/src/pkg/archive/zip/writer_test.go b/src/pkg/archive/zip/writer_test.go
index 8b1c4dfd2..4bfa87080 100644
--- a/src/pkg/archive/zip/writer_test.go
+++ b/src/pkg/archive/zip/writer_test.go
@@ -125,3 +125,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/src/pkg/bufio/bufio.go b/src/pkg/bufio/bufio.go
index d1ff3c9ed..61ef26191 100644
--- a/src/pkg/bufio/bufio.go
+++ b/src/pkg/bufio/bufio.go
@@ -38,6 +38,7 @@ type Reader struct {
}
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,8 +127,9 @@ 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()
+ b.fill() // b.w-b.r < len(b.buf) => buffer is not full
}
m := b.w - b.r
if m > n {
@@ -142,7 +155,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,13 +163,16 @@ 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()
+ b.fill() // buffer is empty
if b.w == b.r {
return 0, b.readErr()
}
@@ -176,11 +192,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 +206,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 +226,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 +248,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 +271,39 @@ 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?
- if b.Buffered() >= len(b.buf) {
+ // Buffer full?
+ if n := b.Buffered(); n >= 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])
+ }
+
+ return
}
// ReadLine is a low-level line-reading primitive. Most callers should use
@@ -301,6 +319,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 +431,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 {
@@ -428,6 +461,9 @@ func (b *Reader) WriteTo(w io.Writer) (n int64, err error) {
// 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 < b.r-b.w {
+ panic(errors.New("bufio: writer did not write all data"))
+ }
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/src/pkg/bufio/bufio_test.go b/src/pkg/bufio/bufio_test.go
index 41bd3d456..76d3c8ead 100644
--- a/src/pkg/bufio/bufio_test.go
+++ b/src/pkg/bufio/bufio_test.go
@@ -14,6 +14,7 @@ import (
"strings"
"testing"
"testing/iotest"
+ "time"
"unicode/utf8"
)
@@ -65,12 +66,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 +140,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 +162,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 +175,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 +257,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 != 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)
}
- if got != data {
- t.Errorf("want=%q got=%q", data, got)
+}
+
+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)
+ }
}
}
@@ -447,7 +592,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 +661,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 +790,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 +815,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 +841,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 +931,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 +990,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 +1169,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 +1261,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/src/pkg/bufio/scan.go b/src/pkg/bufio/scan.go
index 423505fbc..715ce071e 100644
--- a/src/pkg/bufio/scan.go
+++ b/src/pkg/bufio/scan.go
@@ -135,7 +135,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
@@ -172,7 +172,7 @@ func (s *Scanner) Scan() bool {
break
}
loop++
- if loop > 100 {
+ if loop > maxConsecutiveEmptyReads {
s.setErr(io.ErrNoProgress)
break
}
@@ -306,7 +306,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
diff --git a/src/pkg/bufio/scan_test.go b/src/pkg/bufio/scan_test.go
index c1483b268..0db7cad20 100644
--- a/src/pkg/bufio/scan_test.go
+++ b/src/pkg/bufio/scan_test.go
@@ -38,7 +38,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 +60,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 +104,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 +135,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) {
@@ -248,7 +248,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 +277,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 +328,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
diff --git a/src/pkg/bytes/bytes.go b/src/pkg/bytes/bytes.go
index 01a5d9ae4..0c53e4c0b 100644
--- a/src/pkg/bytes/bytes.go
+++ b/src/pkg/bytes/bytes.go
@@ -265,8 +265,8 @@ 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.
func FieldsFunc(s []byte, f func(rune) bool) [][]byte {
n := 0
inField := false
@@ -356,7 +356,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)
diff --git a/src/pkg/bytes/bytes_test.go b/src/pkg/bytes/bytes_test.go
index ab5da4fbf..394dd7a44 100644
--- a/src/pkg/bytes/bytes_test.go
+++ b/src/pkg/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.
diff --git a/src/pkg/bytes/compare_test.go b/src/pkg/bytes/compare_test.go
index 0a36f5ad3..63522374e 100644
--- a/src/pkg/bytes/compare_test.go
+++ b/src/pkg/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/src/pkg/bytes/reader.go b/src/pkg/bytes/reader.go
index 77511b945..d2d40fa7c 100644
--- a/src/pkg/bytes/reader.go
+++ b/src/pkg/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/src/pkg/bytes/reader_test.go b/src/pkg/bytes/reader_test.go
index 19f014da0..d3dce5349 100644
--- a/src/pkg/bytes/reader_test.go
+++ b/src/pkg/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/src/pkg/compress/bzip2/bzip2_test.go b/src/pkg/compress/bzip2/bzip2_test.go
index ada1f9a00..727249dc4 100644
--- a/src/pkg/compress/bzip2/bzip2_test.go
+++ b/src/pkg/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,7 +201,7 @@ 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.
diff --git a/src/pkg/compress/bzip2/huffman.go b/src/pkg/compress/bzip2/huffman.go
index 8f6b0c9ca..75a6223d8 100644
--- a/src/pkg/compress/bzip2/huffman.go
+++ b/src/pkg/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/src/pkg/compress/flate/fixedhuff.go b/src/pkg/compress/flate/fixedhuff.go
index 41a6b25df..9be3d5349 100644
--- a/src/pkg/compress/flate/fixedhuff.go
+++ b/src/pkg/compress/flate/fixedhuff.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 flate
// autogenerated by gen.go, DO NOT EDIT
diff --git a/src/pkg/compress/flate/flate_test.go b/src/pkg/compress/flate/flate_test.go
index 57fea5ab4..068766323 100644
--- a/src/pkg/compress/flate/flate_test.go
+++ b/src/pkg/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/src/pkg/compress/flate/inflate.go b/src/pkg/compress/flate/inflate.go
index 3eb3b2b83..ce4923eca 100644
--- a/src/pkg/compress/flate/inflate.go
+++ b/src/pkg/compress/flate/inflate.go
@@ -54,7 +54,7 @@ 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
+// 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 +180,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.
diff --git a/src/pkg/compress/flate/reader_test.go b/src/pkg/compress/flate/reader_test.go
index 2a8ebbc94..a62ef741d 100644
--- a/src/pkg/compress/flate/reader_test.go
+++ b/src/pkg/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/src/pkg/compress/gzip/gunzip.go b/src/pkg/compress/gzip/gunzip.go
index 1fb9b0964..4f398b194 100644
--- a/src/pkg/compress/gzip/gunzip.go
+++ b/src/pkg/compress/gzip/gunzip.go
@@ -89,6 +89,21 @@ 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
+ return z.readHeader(true)
+}
+
// 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
diff --git a/src/pkg/compress/gzip/gunzip_test.go b/src/pkg/compress/gzip/gunzip_test.go
index 572fb5848..2471038f5 100644
--- a/src/pkg/compress/gzip/gunzip_test.go
+++ b/src/pkg/compress/gzip/gunzip_test.go
@@ -284,7 +284,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 +303,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 +353,17 @@ 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)
+ }
+}
diff --git a/src/pkg/compress/gzip/gzip.go b/src/pkg/compress/gzip/gzip.go
index fe32d6871..3a0bf54e1 100644
--- a/src/pkg/compress/gzip/gzip.go
+++ b/src/pkg/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.
diff --git a/src/pkg/compress/gzip/gzip_test.go b/src/pkg/compress/gzip/gzip_test.go
index 119be2e13..09271b24e 100644
--- a/src/pkg/compress/gzip/gzip_test.go
+++ b/src/pkg/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/src/pkg/compress/lzw/reader.go b/src/pkg/compress/lzw/reader.go
index efbc758f9..ef5969910 100644
--- a/src/pkg/compress/lzw/reader.go
+++ b/src/pkg/compress/lzw/reader.go
@@ -216,8 +216,8 @@ 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.
// 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/src/pkg/compress/lzw/reader_test.go b/src/pkg/compress/lzw/reader_test.go
index 6f155b1bd..9006c91c2 100644
--- a/src/pkg/compress/lzw/reader_test.go
+++ b/src/pkg/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/src/pkg/compress/lzw/writer.go b/src/pkg/compress/lzw/writer.go
index b20691864..961b25f94 100644
--- a/src/pkg/compress/lzw/writer.go
+++ b/src/pkg/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/src/pkg/compress/zlib/example_test.go b/src/pkg/compress/zlib/example_test.go
index b934ffa61..70408895f 100644
--- a/src/pkg/compress/zlib/example_test.go
+++ b/src/pkg/compress/zlib/example_test.go
@@ -25,7 +25,7 @@ func ExampleNewWriter() {
func ExampleNewReader() {
buff := []byte{120, 156, 202, 72, 205, 201, 201, 215, 81, 40, 207,
47, 202, 73, 225, 2, 4, 0, 0, 255, 255, 33, 231, 4, 147}
- b := bytes.NewBuffer(buff)
+ b := bytes.NewReader(buff)
r, err := zlib.NewReader(b)
if err != nil {
diff --git a/src/pkg/compress/zlib/reader.go b/src/pkg/compress/zlib/reader.go
index d54746f4c..9e1aafda9 100644
--- a/src/pkg/compress/zlib/reader.go
+++ b/src/pkg/compress/zlib/reader.go
@@ -51,7 +51,8 @@ type reader struct {
scratch [4]byte
}
-// NewReader creates a new io.ReadCloser that satisfies reads by decompressing data read from r.
+// NewReader creates a new io.ReadCloser.
+// Reads from the returned io.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.
func NewReader(r io.Reader) (io.ReadCloser, error) {
diff --git a/src/pkg/compress/zlib/reader_test.go b/src/pkg/compress/zlib/reader_test.go
index 3b02a0868..218ccba14 100644
--- a/src/pkg/compress/zlib/reader_test.go
+++ b/src/pkg/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/src/pkg/compress/zlib/writer.go b/src/pkg/compress/zlib/writer.go
index 99ff6549a..fac7e15a7 100644
--- a/src/pkg/compress/zlib/writer.go
+++ b/src/pkg/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.
diff --git a/src/pkg/compress/zlib/writer_test.go b/src/pkg/compress/zlib/writer_test.go
index cf9c83254..71ba81aaa 100644
--- a/src/pkg/compress/zlib/writer_test.go
+++ b/src/pkg/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/src/pkg/container/heap/example_pq_test.go b/src/pkg/container/heap/example_pq_test.go
index 8cbeb8d70..7017095cb 100644
--- a/src/pkg/container/heap/example_pq_test.go
+++ b/src/pkg/container/heap/example_pq_test.go
@@ -52,13 +52,12 @@ func (pq *PriorityQueue) Pop() interface{} {
// update modifies the priority and value of an Item in the queue.
func (pq *PriorityQueue) update(item *Item, value string, priority int) {
- heap.Remove(pq, item.index)
item.value = value
item.priority = priority
- heap.Push(pq, item)
+ heap.Fix(pq, item.index)
}
-// This example inserts some items into a PriorityQueue, manipulates an item,
+// This example creates a PriorityQueue with some items, adds and manipulates an item,
// and then removes the items in priority order.
func Example_priorityQueue() {
// Some items and their priorities.
@@ -66,28 +65,31 @@ func Example_priorityQueue() {
"banana": 3, "apple": 2, "pear": 4,
}
- // Create a priority queue and put the items in it.
- pq := &PriorityQueue{}
- heap.Init(pq)
+ // Create a priority queue, put the items in it, and
+ // establish the priority queue (heap) invariants.
+ pq := make(PriorityQueue, len(items))
+ i := 0
for value, priority := range items {
- item := &Item{
+ pq[i] = &Item{
value: value,
priority: priority,
+ index: i,
}
- heap.Push(pq, item)
+ i++
}
+ heap.Init(&pq)
// Insert a new item and then modify its priority.
item := &Item{
value: "orange",
priority: 1,
}
- heap.Push(pq, item)
+ heap.Push(&pq, item)
pq.update(item, item.value, 5)
// Take the items out; they arrive in decreasing priority order.
for pq.Len() > 0 {
- item := heap.Pop(pq).(*Item)
+ item := heap.Pop(&pq).(*Item)
fmt.Printf("%.2d:%s ", item.priority, item.value)
}
// Output:
diff --git a/src/pkg/container/heap/heap.go b/src/pkg/container/heap/heap.go
index 52c8507b4..c467a1191 100644
--- a/src/pkg/container/heap/heap.go
+++ b/src/pkg/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/src/pkg/container/list/example_test.go b/src/pkg/container/list/example_test.go
index 7361212d7..362178401 100644
--- a/src/pkg/container/list/example_test.go
+++ b/src/pkg/container/list/example_test.go
@@ -17,7 +17,7 @@ func Example() {
l.InsertBefore(3, e4)
l.InsertAfter(2, e1)
- // Iterate through list and and print its contents.
+ // Iterate through list and print its contents.
for e := l.Front(); e != nil; e = e.Next() {
fmt.Println(e.Value)
}
diff --git a/src/pkg/container/list/list.go b/src/pkg/container/list/list.go
index ed2d15a45..0256768ef 100644
--- a/src/pkg/container/list/list.go
+++ b/src/pkg/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/src/pkg/container/list/list_test.go b/src/pkg/container/list/list_test.go
index ee52afe82..4d8bfc2bf 100644
--- a/src/pkg/container/list/list_test.go
+++ b/src/pkg/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/src/pkg/container/ring/ring_test.go b/src/pkg/container/ring/ring_test.go
index 099d92b25..552f0e24b 100644
--- a/src/pkg/container/ring/ring_test.go
+++ b/src/pkg/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/src/pkg/crypto/aes/aes_test.go b/src/pkg/crypto/aes/aes_test.go
index 6261dd09f..363180931 100644
--- a/src/pkg/crypto/aes/aes_test.go
+++ b/src/pkg/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/src/pkg/crypto/aes/cipher.go b/src/pkg/crypto/aes/cipher.go
index d931134a7..2c6bb0a89 100644
--- a/src/pkg/crypto/aes/cipher.go
+++ b/src/pkg/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/src/pkg/crypto/aes/cipher_asm.go b/src/pkg/crypto/aes/cipher_asm.go
index 21369fc38..964eaaa6f 100644
--- a/src/pkg/crypto/aes/cipher_asm.go
+++ b/src/pkg/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/src/pkg/crypto/cipher/benchmark_test.go b/src/pkg/crypto/cipher/benchmark_test.go
new file mode 100644
index 000000000..027b24851
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/cipher/cbc.go b/src/pkg/crypto/cipher/cbc.go
index 4189677e3..241e122ee 100644
--- a/src/pkg/crypto/cipher/cbc.go
+++ b/src/pkg/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/src/pkg/crypto/cipher/cbc_aes_test.go b/src/pkg/crypto/cipher/cbc_aes_test.go
index cee3a784b..bf9e7ad70 100644
--- a/src/pkg/crypto/cipher/cbc_aes_test.go
+++ b/src/pkg/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/src/pkg/crypto/cipher/cfb.go b/src/pkg/crypto/cipher/cfb.go
index 99006b546..9b4eebf5b 100644
--- a/src/pkg/crypto/cipher/cfb.go
+++ b/src/pkg/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/src/pkg/crypto/cipher/cfb_test.go b/src/pkg/crypto/cipher/cfb_test.go
index f704b337e..ec708ab2b 100644
--- a/src/pkg/crypto/cipher/cfb_test.go
+++ b/src/pkg/crypto/cipher/cfb_test.go
@@ -19,16 +19,18 @@ func TestCFB(t *testing.T) {
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/src/pkg/crypto/cipher/cipher.go b/src/pkg/crypto/cipher/cipher.go
index 1ffaa8c2c..67afdb1e0 100644
--- a/src/pkg/crypto/cipher/cipher.go
+++ b/src/pkg/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/src/pkg/crypto/cipher/ctr.go b/src/pkg/crypto/cipher/ctr.go
index d9ee9d827..70ac40f6a 100644
--- a/src/pkg/crypto/cipher/ctr.go
+++ b/src/pkg/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/src/pkg/crypto/cipher/gcm.go b/src/pkg/crypto/cipher/gcm.go
index 2bcb46985..bdafd85fc 100644
--- a/src/pkg/crypto/cipher/gcm.go
+++ b/src/pkg/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/src/pkg/crypto/cipher/gcm_test.go b/src/pkg/crypto/cipher/gcm_test.go
index 02d421590..0c502ce40 100644
--- a/src/pkg/crypto/cipher/gcm_test.go
+++ b/src/pkg/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/src/pkg/crypto/cipher/ofb.go b/src/pkg/crypto/cipher/ofb.go
index 85e5f02b0..e86ebcb23 100644
--- a/src/pkg/crypto/cipher/ofb.go
+++ b/src/pkg/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/src/pkg/crypto/cipher/xor.go b/src/pkg/crypto/cipher/xor.go
new file mode 100644
index 000000000..f88dc8914
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/cipher/xor_test.go b/src/pkg/crypto/cipher/xor_test.go
new file mode 100644
index 000000000..cc1c9d72d
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/dsa/dsa.go b/src/pkg/crypto/dsa/dsa.go
index 5a2a65744..b7565a61b 100644
--- a/src/pkg/crypto/dsa/dsa.go
+++ b/src/pkg/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/src/pkg/crypto/ecdsa/ecdsa.go b/src/pkg/crypto/ecdsa/ecdsa.go
index d02f15c34..1bec7437a 100644
--- a/src/pkg/crypto/ecdsa/ecdsa.go
+++ b/src/pkg/crypto/ecdsa/ecdsa.go
@@ -84,6 +84,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 +112,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/src/pkg/crypto/hmac/hmac_test.go b/src/pkg/crypto/hmac/hmac_test.go
index d4860424e..e80b7e0ba 100644
--- a/src/pkg/crypto/hmac/hmac_test.go
+++ b/src/pkg/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/src/pkg/crypto/md5/example_test.go b/src/pkg/crypto/md5/example_test.go
index 28be770a7..d47bb4570 100644
--- a/src/pkg/crypto/md5/example_test.go
+++ b/src/pkg/crypto/md5/example_test.go
@@ -17,3 +17,9 @@ func ExampleNew() {
fmt.Printf("%x", h.Sum(nil))
// Output: e2c569be17396eca2a2e3c11578123ed
}
+
+func ExampleSum() {
+ data := []byte("These pretzels are making me thirsty.")
+ fmt.Printf("%x", md5.Sum(data))
+ // Output: b0804ec967f48520697662a204f5fe72
+}
diff --git a/src/pkg/crypto/md5/gen.go b/src/pkg/crypto/md5/gen.go
index ccaa7c13d..75295e4fc 100644
--- a/src/pkg/crypto/md5/gen.go
+++ b/src/pkg/crypto/md5/gen.go
@@ -160,12 +160,13 @@ var data = Data{
},
}
-var program = `
+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.
+
// DO NOT EDIT.
// Generate with: go run gen.go{{if .Full}} -full{{end}} | gofmt >md5block.go
-// +build !amd64,!386,!arm
-
package md5
import (
@@ -201,7 +202,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/src/pkg/crypto/md5/md5_test.go b/src/pkg/crypto/md5/md5_test.go
index a8b7a1a52..e7faf4961 100644
--- a/src/pkg/crypto/md5/md5_test.go
+++ b/src/pkg/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/src/pkg/crypto/md5/md5block.go b/src/pkg/crypto/md5/md5block.go
index 3e739e36f..e2a176777 100644
--- a/src/pkg/crypto/md5/md5block.go
+++ b/src/pkg/crypto/md5/md5block.go
@@ -1,8 +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.
+
// DO NOT EDIT.
// Generate with: go run gen.go -full | gofmt >md5block.go
-// +build !amd64,!386,!arm
-
package md5
import (
@@ -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/src/pkg/crypto/md5/md5block_amd64p32.s b/src/pkg/crypto/md5/md5block_amd64p32.s
new file mode 100644
index 000000000..a78a3f610
--- /dev/null
+++ b/src/pkg/crypto/md5/md5block_amd64p32.s
@@ -0,0 +1,184 @@
+// Original source:
+// http://www.zorinaq.com/papers/md5-amd64.html
+// http://www.zorinaq.com/papers/md5-amd64.tar.bz2
+//
+// Translated from Perl generating GNU assembly into
+// #defines generating 6a assembly by the Go Authors.
+//
+// Restrictions to make code safe for Native Client:
+// replace BP with R11, reloaded before use at return.
+// replace R15 with R11.
+
+#include "../../../cmd/ld/textflag.h"
+
+// MD5 optimized for AMD64.
+//
+// Author: Marc Bevand <bevand_m (at) epita.fr>
+// Licence: I hereby disclaim the copyright on this code and place it
+// in the public domain.
+
+TEXT ·block(SB),NOSPLIT,$0-32
+ MOVL dig+0(FP), R11
+ MOVL p+4(FP), SI
+ MOVL p_len+8(FP), DX
+ SHRQ $6, DX
+ SHLQ $6, DX
+
+ LEAQ (SI)(DX*1), DI
+ MOVL (0*4)(R11), AX
+ MOVL (1*4)(R11), BX
+ MOVL (2*4)(R11), CX
+ MOVL (3*4)(R11), DX
+
+ CMPQ SI, DI
+ JEQ end
+
+loop:
+ MOVL AX, R12
+ MOVL BX, R13
+ MOVL CX, R14
+ MOVL DX, R11
+
+ MOVL (0*4)(SI), R8
+ MOVL DX, R9
+
+#define ROUND1(a, b, c, d, index, const, shift) \
+ XORL c, R9; \
+ LEAL const(a)(R8*1), a; \
+ ANDL b, R9; \
+ XORL d, R9; \
+ MOVL (index*4)(SI), R8; \
+ ADDL R9, a; \
+ ROLL $shift, a; \
+ MOVL c, R9; \
+ ADDL b, a
+
+ ROUND1(AX,BX,CX,DX, 1,0xd76aa478, 7);
+ ROUND1(DX,AX,BX,CX, 2,0xe8c7b756,12);
+ ROUND1(CX,DX,AX,BX, 3,0x242070db,17);
+ ROUND1(BX,CX,DX,AX, 4,0xc1bdceee,22);
+ ROUND1(AX,BX,CX,DX, 5,0xf57c0faf, 7);
+ ROUND1(DX,AX,BX,CX, 6,0x4787c62a,12);
+ ROUND1(CX,DX,AX,BX, 7,0xa8304613,17);
+ ROUND1(BX,CX,DX,AX, 8,0xfd469501,22);
+ ROUND1(AX,BX,CX,DX, 9,0x698098d8, 7);
+ ROUND1(DX,AX,BX,CX,10,0x8b44f7af,12);
+ ROUND1(CX,DX,AX,BX,11,0xffff5bb1,17);
+ ROUND1(BX,CX,DX,AX,12,0x895cd7be,22);
+ ROUND1(AX,BX,CX,DX,13,0x6b901122, 7);
+ ROUND1(DX,AX,BX,CX,14,0xfd987193,12);
+ ROUND1(CX,DX,AX,BX,15,0xa679438e,17);
+ ROUND1(BX,CX,DX,AX, 0,0x49b40821,22);
+
+ MOVL (1*4)(SI), R8
+ MOVL DX, R9
+ MOVL DX, R10
+
+#define ROUND2(a, b, c, d, index, const, shift) \
+ NOTL R9; \
+ LEAL const(a)(R8*1),a; \
+ ANDL b, R10; \
+ ANDL c, R9; \
+ MOVL (index*4)(SI),R8; \
+ ORL R9, R10; \
+ MOVL c, R9; \
+ ADDL R10, a; \
+ MOVL c, R10; \
+ ROLL $shift, a; \
+ ADDL b, a
+
+ ROUND2(AX,BX,CX,DX, 6,0xf61e2562, 5);
+ ROUND2(DX,AX,BX,CX,11,0xc040b340, 9);
+ ROUND2(CX,DX,AX,BX, 0,0x265e5a51,14);
+ ROUND2(BX,CX,DX,AX, 5,0xe9b6c7aa,20);
+ ROUND2(AX,BX,CX,DX,10,0xd62f105d, 5);
+ ROUND2(DX,AX,BX,CX,15, 0x2441453, 9);
+ ROUND2(CX,DX,AX,BX, 4,0xd8a1e681,14);
+ ROUND2(BX,CX,DX,AX, 9,0xe7d3fbc8,20);
+ ROUND2(AX,BX,CX,DX,14,0x21e1cde6, 5);
+ ROUND2(DX,AX,BX,CX, 3,0xc33707d6, 9);
+ ROUND2(CX,DX,AX,BX, 8,0xf4d50d87,14);
+ ROUND2(BX,CX,DX,AX,13,0x455a14ed,20);
+ ROUND2(AX,BX,CX,DX, 2,0xa9e3e905, 5);
+ ROUND2(DX,AX,BX,CX, 7,0xfcefa3f8, 9);
+ ROUND2(CX,DX,AX,BX,12,0x676f02d9,14);
+ ROUND2(BX,CX,DX,AX, 0,0x8d2a4c8a,20);
+
+ MOVL (5*4)(SI), R8
+ MOVL CX, R9
+
+#define ROUND3(a, b, c, d, index, const, shift) \
+ LEAL const(a)(R8*1),a; \
+ MOVL (index*4)(SI),R8; \
+ XORL d, R9; \
+ XORL b, R9; \
+ ADDL R9, a; \
+ ROLL $shift, a; \
+ MOVL b, R9; \
+ ADDL b, a
+
+ ROUND3(AX,BX,CX,DX, 8,0xfffa3942, 4);
+ ROUND3(DX,AX,BX,CX,11,0x8771f681,11);
+ ROUND3(CX,DX,AX,BX,14,0x6d9d6122,16);
+ ROUND3(BX,CX,DX,AX, 1,0xfde5380c,23);
+ ROUND3(AX,BX,CX,DX, 4,0xa4beea44, 4);
+ ROUND3(DX,AX,BX,CX, 7,0x4bdecfa9,11);
+ ROUND3(CX,DX,AX,BX,10,0xf6bb4b60,16);
+ ROUND3(BX,CX,DX,AX,13,0xbebfbc70,23);
+ ROUND3(AX,BX,CX,DX, 0,0x289b7ec6, 4);
+ ROUND3(DX,AX,BX,CX, 3,0xeaa127fa,11);
+ ROUND3(CX,DX,AX,BX, 6,0xd4ef3085,16);
+ ROUND3(BX,CX,DX,AX, 9, 0x4881d05,23);
+ ROUND3(AX,BX,CX,DX,12,0xd9d4d039, 4);
+ ROUND3(DX,AX,BX,CX,15,0xe6db99e5,11);
+ ROUND3(CX,DX,AX,BX, 2,0x1fa27cf8,16);
+ ROUND3(BX,CX,DX,AX, 0,0xc4ac5665,23);
+
+ MOVL (0*4)(SI), R8
+ MOVL $0xffffffff, R9
+ XORL DX, R9
+
+#define ROUND4(a, b, c, d, index, const, shift) \
+ LEAL const(a)(R8*1),a; \
+ ORL b, R9; \
+ XORL c, R9; \
+ ADDL R9, a; \
+ MOVL (index*4)(SI),R8; \
+ MOVL $0xffffffff, R9; \
+ ROLL $shift, a; \
+ XORL c, R9; \
+ ADDL b, a
+
+ ROUND4(AX,BX,CX,DX, 7,0xf4292244, 6);
+ ROUND4(DX,AX,BX,CX,14,0x432aff97,10);
+ ROUND4(CX,DX,AX,BX, 5,0xab9423a7,15);
+ ROUND4(BX,CX,DX,AX,12,0xfc93a039,21);
+ ROUND4(AX,BX,CX,DX, 3,0x655b59c3, 6);
+ ROUND4(DX,AX,BX,CX,10,0x8f0ccc92,10);
+ ROUND4(CX,DX,AX,BX, 1,0xffeff47d,15);
+ ROUND4(BX,CX,DX,AX, 8,0x85845dd1,21);
+ ROUND4(AX,BX,CX,DX,15,0x6fa87e4f, 6);
+ ROUND4(DX,AX,BX,CX, 6,0xfe2ce6e0,10);
+ ROUND4(CX,DX,AX,BX,13,0xa3014314,15);
+ ROUND4(BX,CX,DX,AX, 4,0x4e0811a1,21);
+ ROUND4(AX,BX,CX,DX,11,0xf7537e82, 6);
+ ROUND4(DX,AX,BX,CX, 2,0xbd3af235,10);
+ ROUND4(CX,DX,AX,BX, 9,0x2ad7d2bb,15);
+ ROUND4(BX,CX,DX,AX, 0,0xeb86d391,21);
+
+ ADDL R12, AX
+ ADDL R13, BX
+ ADDL R14, CX
+ ADDL R11, DX
+
+ ADDQ $64, SI
+ CMPQ SI, DI
+ JB loop
+
+end:
+ MOVL dig+0(FP), R11
+ MOVL AX, (0*4)(R11)
+ MOVL BX, (1*4)(R11)
+ MOVL CX, (2*4)(R11)
+ MOVL DX, (3*4)(R11)
+ RET
diff --git a/src/pkg/crypto/md5/md5block_decl.go b/src/pkg/crypto/md5/md5block_decl.go
index c4d6aaaf0..d7956a6d2 100644
--- a/src/pkg/crypto/md5/md5block_decl.go
+++ b/src/pkg/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/src/pkg/crypto/md5/md5block_generic.go b/src/pkg/crypto/md5/md5block_generic.go
new file mode 100644
index 000000000..263463e51
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/rand/rand_unix.go b/src/pkg/crypto/rand/rand_unix.go
index 238ceee55..1e741fda1 100644
--- a/src/pkg/crypto/rand/rand_unix.go
+++ b/src/pkg/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.
diff --git a/src/pkg/crypto/rand/util.go b/src/pkg/crypto/rand/util.go
index 0cd5e0e02..5f7440785 100644
--- a/src/pkg/crypto/rand/util.go
+++ b/src/pkg/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/src/pkg/crypto/rand/util_test.go b/src/pkg/crypto/rand/util_test.go
new file mode 100644
index 000000000..1e2a4dd84
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/rc4/rc4.go b/src/pkg/crypto/rc4/rc4.go
index 3d717c63b..9acb681bf 100644
--- a/src/pkg/crypto/rc4/rc4.go
+++ b/src/pkg/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/src/pkg/crypto/rc4/rc4_amd64p32.s b/src/pkg/crypto/rc4/rc4_amd64p32.s
new file mode 100644
index 000000000..27d849507
--- /dev/null
+++ b/src/pkg/crypto/rc4/rc4_amd64p32.s
@@ -0,0 +1,192 @@
+// Original source:
+// http://www.zorinaq.com/papers/rc4-amd64.html
+// http://www.zorinaq.com/papers/rc4-amd64.tar.bz2
+
+#include "../../../cmd/ld/textflag.h"
+
+// Local modifications:
+//
+// Transliterated from GNU to 6a assembly syntax by the Go authors.
+// The comments and spacing are from the original.
+//
+// The new EXTEND macros avoid a bad stall on some systems after 8-bit math.
+//
+// The original code accumulated 64 bits of key stream in an integer
+// register and then XOR'ed the key stream into the data 8 bytes at a time.
+// Modified to accumulate 128 bits of key stream into an XMM register
+// and then XOR the key stream into the data 16 bytes at a time.
+// Approximately doubles throughput.
+//
+// Converted to amd64p32.
+//
+// To make safe for Native Client, avoid use of BP, R15,
+// and two-register addressing modes.
+
+// NOTE: Changing EXTEND to a no-op makes the code run 1.2x faster on Core i5
+// but makes the code run 2.0x slower on Xeon.
+#define EXTEND(r) MOVBLZX r, r
+
+/*
+** RC4 implementation optimized for AMD64.
+**
+** Author: Marc Bevand <bevand_m (at) epita.fr>
+** Licence: I hereby disclaim the copyright on this code and place it
+** in the public domain.
+**
+** The code has been designed to be easily integrated into openssl:
+** the exported RC4() function can replace the actual implementations
+** openssl already contains. Please note that when linking with openssl,
+** it requires that sizeof(RC4_INT) == 8. So openssl must be compiled
+** with -DRC4_INT='unsigned long'.
+**
+** The throughput achieved by this code is about 320 MBytes/sec, on
+** a 1.8 GHz AMD Opteron (rev C0) processor.
+*/
+
+TEXT ·xorKeyStream(SB),NOSPLIT,$0
+ MOVL n+8(FP), BX // rbx = ARG(len)
+ MOVL src+4(FP), SI // in = ARG(in)
+ MOVL dst+0(FP), DI // out = ARG(out)
+ MOVL state+12(FP), R10 // d = ARG(data)
+ MOVL i+16(FP), AX
+ MOVBQZX 0(AX), CX // x = *xp
+ MOVL j+20(FP), AX
+ MOVBQZX 0(AX), DX // y = *yp
+
+ LEAQ (SI)(BX*1), R9 // limit = in+len
+
+l1: CMPQ SI, R9 // cmp in with in+len
+ JGE finished // jump if (in >= in+len)
+
+ INCB CX
+ EXTEND(CX)
+ TESTL $15, CX
+ JZ wordloop
+ LEAL (R10)(CX*4), R12
+
+ MOVBLZX (R12), AX
+
+ ADDB AX, DX // y += tx
+ EXTEND(DX)
+ LEAL (R10)(DX*4), R11
+ MOVBLZX (R11), BX // ty = d[y]
+ MOVB BX, (R12) // d[x] = ty
+ ADDB AX, BX // val = ty+tx
+ EXTEND(BX)
+ LEAL (R10)(BX*4), R13
+ MOVB AX, (R11) // d[y] = tx
+ MOVBLZX (R13), R8 // val = d[val]
+ XORB (SI), R8 // xor 1 byte
+ MOVB R8, (DI)
+ INCQ SI // in++
+ INCQ DI // out++
+ JMP l1
+
+wordloop:
+ SUBQ $16, R9
+ CMPQ SI, R9
+ JGT end
+
+start:
+ ADDQ $16, SI // increment in
+ ADDQ $16, DI // increment out
+
+ // Each KEYROUND generates one byte of key and
+ // inserts it into an XMM register at the given 16-bit index.
+ // The key state array is uint32 words only using the bottom
+ // byte of each word, so the 16-bit OR only copies 8 useful bits.
+ // We accumulate alternating bytes into X0 and X1, and then at
+ // the end we OR X1<<8 into X0 to produce the actual key.
+ //
+ // At the beginning of the loop, CX%16 == 0, so the 16 loads
+ // at state[CX], state[CX+1], ..., state[CX+15] can precompute
+ // (state+CX) as R12 and then become R12[0], R12[1], ... R12[15],
+ // without fear of the byte computation CX+15 wrapping around.
+ //
+ // The first round needs R12[0], the second needs R12[1], and so on.
+ // We can avoid memory stalls by starting the load for round n+1
+ // before the end of round n, using the LOAD macro.
+ LEAQ (R10)(CX*4), R12
+
+#define KEYROUND(xmm, load, off, r1, r2, index) \
+ LEAL (R10)(DX*4), R11; \
+ MOVBLZX (R11), R8; \
+ MOVB r1, (R11); \
+ load((off+1), r2); \
+ MOVB R8, (off*4)(R12); \
+ ADDB r1, R8; \
+ EXTEND(R8); \
+ LEAL (R10)(R8*4), R14; \
+ PINSRW $index, (R14), xmm
+
+#define LOAD(off, reg) \
+ MOVBLZX (off*4)(R12), reg; \
+ ADDB reg, DX; \
+ EXTEND(DX)
+
+#define SKIP(off, reg)
+
+ LOAD(0, AX)
+ KEYROUND(X0, LOAD, 0, AX, BX, 0)
+ KEYROUND(X1, LOAD, 1, BX, AX, 0)
+ KEYROUND(X0, LOAD, 2, AX, BX, 1)
+ KEYROUND(X1, LOAD, 3, BX, AX, 1)
+ KEYROUND(X0, LOAD, 4, AX, BX, 2)
+ KEYROUND(X1, LOAD, 5, BX, AX, 2)
+ KEYROUND(X0, LOAD, 6, AX, BX, 3)
+ KEYROUND(X1, LOAD, 7, BX, AX, 3)
+ KEYROUND(X0, LOAD, 8, AX, BX, 4)
+ KEYROUND(X1, LOAD, 9, BX, AX, 4)
+ KEYROUND(X0, LOAD, 10, AX, BX, 5)
+ KEYROUND(X1, LOAD, 11, BX, AX, 5)
+ KEYROUND(X0, LOAD, 12, AX, BX, 6)
+ KEYROUND(X1, LOAD, 13, BX, AX, 6)
+ KEYROUND(X0, LOAD, 14, AX, BX, 7)
+ KEYROUND(X1, SKIP, 15, BX, AX, 7)
+
+ ADDB $16, CX
+
+ PSLLQ $8, X1
+ PXOR X1, X0
+ MOVOU -16(SI), X2
+ PXOR X0, X2
+ MOVOU X2, -16(DI)
+
+ CMPQ SI, R9 // cmp in with in+len-16
+ JLE start // jump if (in <= in+len-16)
+
+end:
+ DECB CX
+ ADDQ $16, R9 // tmp = in+len
+
+ // handle the last bytes, one by one
+l2: CMPQ SI, R9 // cmp in with in+len
+ JGE finished // jump if (in >= in+len)
+
+ INCB CX
+ EXTEND(CX)
+ LEAL (R10)(CX*4), R12
+ MOVBLZX (R12), AX
+
+ ADDB AX, DX // y += tx
+ EXTEND(DX)
+ LEAL (R10)(DX*4), R11
+ MOVBLZX (R11), BX // ty = d[y]
+ MOVB BX, (R12) // d[x] = ty
+ ADDB AX, BX // val = ty+tx
+ EXTEND(BX)
+ LEAL (R10)(BX*4), R13
+ MOVB AX, (R11) // d[y] = tx
+ MOVBLZX (R13), R8 // val = d[val]
+ XORB (SI), R8 // xor 1 byte
+ MOVB R8, (DI)
+ INCQ SI // in++
+ INCQ DI // out++
+ JMP l2
+
+finished:
+ MOVL j+20(FP), BX
+ MOVB DX, 0(BX)
+ MOVL i+16(FP), AX
+ MOVB CX, 0(AX)
+ RET
diff --git a/src/pkg/crypto/rc4/rc4_asm.go b/src/pkg/crypto/rc4/rc4_asm.go
index c582a4488..fc71b9a6f 100644
--- a/src/pkg/crypto/rc4/rc4_asm.go
+++ b/src/pkg/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 386
package rc4
diff --git a/src/pkg/crypto/rc4/rc4_ref.go b/src/pkg/crypto/rc4/rc4_ref.go
index 44d380436..1ecce1a7f 100644
--- a/src/pkg/crypto/rc4/rc4_ref.go
+++ b/src/pkg/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
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 += c.s[i]
- c.s[i], c.s[j] = c.s[j], c.s[i]
- dst[k] = v ^ c.s[c.s[i]+c.s[j]]
- }
- c.i, c.j = i, j
+ c.xorKeyStreamGeneric(dst, src)
}
diff --git a/src/pkg/crypto/rc4/rc4_test.go b/src/pkg/crypto/rc4/rc4_test.go
index 7b4df6791..af7988246 100644
--- a/src/pkg/crypto/rc4/rc4_test.go
+++ b/src/pkg/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/src/pkg/crypto/rsa/pkcs1v15.go b/src/pkg/crypto/rsa/pkcs1v15.go
index 1a055a3d6..d9957aec1 100644
--- a/src/pkg/crypto/rsa/pkcs1v15.go
+++ b/src/pkg/crypto/rsa/pkcs1v15.go
@@ -176,7 +176,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 +213,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 +251,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/src/pkg/crypto/rsa/pkcs1v15_test.go b/src/pkg/crypto/rsa/pkcs1v15_test.go
index 70bb22889..37c14d1d9 100644
--- a/src/pkg/crypto/rsa/pkcs1v15_test.go
+++ b/src/pkg/crypto/rsa/pkcs1v15_test.go
@@ -205,6 +205,28 @@ 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)
+ }
+}
+
// 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/src/pkg/crypto/rsa/pss.go b/src/pkg/crypto/rsa/pss.go
index f9abec394..18eafbc05 100644
--- a/src/pkg/crypto/rsa/pss.go
+++ b/src/pkg/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()
@@ -233,7 +233,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()
diff --git a/src/pkg/crypto/rsa/rsa.go b/src/pkg/crypto/rsa/rsa.go
index c7353ea31..bce6ba4eb 100644
--- a/src/pkg/crypto/rsa/rsa.go
+++ b/src/pkg/crypto/rsa/rsa.go
@@ -60,7 +60,7 @@ type PrivateKey struct {
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 +120,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/src/pkg/crypto/rsa/rsa_test.go b/src/pkg/crypto/rsa/rsa_test.go
index cf193c669..4ee1c3a8b 100644
--- a/src/pkg/crypto/rsa/rsa_test.go
+++ b/src/pkg/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/src/pkg/crypto/sha1/example_test.go b/src/pkg/crypto/sha1/example_test.go
index 25fe5f308..42aec8afa 100644
--- a/src/pkg/crypto/sha1/example_test.go
+++ b/src/pkg/crypto/sha1/example_test.go
@@ -12,7 +12,14 @@ import (
func ExampleNew() {
h := sha1.New()
- io.WriteString(h, "His money is twice tainted: 'taint yours and 'taint mine.")
+ io.WriteString(h, "His money is twice tainted:")
+ io.WriteString(h, " 'taint yours and 'taint mine.")
fmt.Printf("% x", h.Sum(nil))
// Output: 59 7f 6a 54 00 10 f9 4c 15 d7 18 06 a9 9a 2c 87 10 e7 47 bd
}
+
+func ExampleSum() {
+ data := []byte("This page intentionally left blank.")
+ fmt.Printf("% x", sha1.Sum(data))
+ // Output: af 06 49 23 bb f2 30 15 96 aa c4 c2 73 ba 32 17 8e bc 4a 96
+}
diff --git a/src/pkg/crypto/sha1/sha1.go b/src/pkg/crypto/sha1/sha1.go
index 8eb3f7a79..9f1a96e36 100644
--- a/src/pkg/crypto/sha1/sha1.go
+++ b/src/pkg/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/src/pkg/crypto/sha1/sha1_test.go b/src/pkg/crypto/sha1/sha1_test.go
index c3868d702..4a629518b 100644
--- a/src/pkg/crypto/sha1/sha1_test.go
+++ b/src/pkg/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/src/pkg/crypto/sha1/sha1block.go b/src/pkg/crypto/sha1/sha1block.go
index 92224fc0e..fde3c981c 100644
--- a/src/pkg/crypto/sha1/sha1block.go
+++ b/src/pkg/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/src/pkg/crypto/sha1/sha1block_386.s b/src/pkg/crypto/sha1/sha1block_386.s
index 890b3ae81..688851c31 100644
--- a/src/pkg/crypto/sha1/sha1block_386.s
+++ b/src/pkg/crypto/sha1/sha1block_386.s
@@ -46,12 +46,10 @@
ADDL DI, e
#define FUNC1(a, b, c, d, e) \
- MOVL b, SI; \
- ANDL c, SI; \
- MOVL b, DI; \
- NOTL DI; \
- ANDL d, DI; \
- ORL SI, DI
+ MOVL d, DI; \
+ XORL c, DI; \
+ ANDL b, DI; \
+ XORL d, DI
#define FUNC2(a, b, c, d, e) \
MOVL b, DI; \
diff --git a/src/pkg/crypto/sha1/sha1block_amd64.s b/src/pkg/crypto/sha1/sha1block_amd64.s
index 0bb6c204c..8ffb9d5d6 100644
--- a/src/pkg/crypto/sha1/sha1block_amd64.s
+++ b/src/pkg/crypto/sha1/sha1block_amd64.s
@@ -34,12 +34,10 @@
MOVL R10, (((index)&0xf)*4)(SP)
#define FUNC1(a, b, c, d, e) \
- MOVL b, R8; \
- ANDL c, R8; \
- MOVL b, R9; \
- NOTL R9; \
- ANDL d, R9; \
- ORL R8, R9
+ MOVL d, R9; \
+ XORL c, R9; \
+ ANDL b, R9; \
+ XORL d, R9
#define FUNC2(a, b, c, d, e) \
MOVL b, R9; \
diff --git a/src/pkg/crypto/sha1/sha1block_amd64p32.s b/src/pkg/crypto/sha1/sha1block_amd64p32.s
new file mode 100644
index 000000000..3c589d94f
--- /dev/null
+++ b/src/pkg/crypto/sha1/sha1block_amd64p32.s
@@ -0,0 +1,216 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "../../../cmd/ld/textflag.h"
+
+// SHA1 block routine. See sha1block.go for Go equivalent.
+//
+// There are 80 rounds of 4 types:
+// - rounds 0-15 are type 1 and load data (ROUND1 macro).
+// - rounds 16-19 are type 1 and do not load data (ROUND1x macro).
+// - rounds 20-39 are type 2 and do not load data (ROUND2 macro).
+// - rounds 40-59 are type 3 and do not load data (ROUND3 macro).
+// - rounds 60-79 are type 4 and do not load data (ROUND4 macro).
+//
+// Each round loads or shuffles the data, then computes a per-round
+// function of b, c, d, and then mixes the result into and rotates the
+// five registers a, b, c, d, e holding the intermediate results.
+//
+// The register rotation is implemented by rotating the arguments to
+// the round macros instead of by explicit move instructions.
+//
+// amd64p32 version.
+// To ensure safety for Native Client, avoids use of BP and R15
+// as well as two-register addressing modes.
+
+#define LOAD(index) \
+ MOVL (index*4)(SI), R10; \
+ BSWAPL R10; \
+ MOVL R10, (index*4)(SP)
+
+#define SHUFFLE(index) \
+ MOVL (((index)&0xf)*4)(SP), R10; \
+ XORL (((index-3)&0xf)*4)(SP), R10; \
+ XORL (((index-8)&0xf)*4)(SP), R10; \
+ XORL (((index-14)&0xf)*4)(SP), R10; \
+ ROLL $1, R10; \
+ MOVL R10, (((index)&0xf)*4)(SP)
+
+#define FUNC1(a, b, c, d, e) \
+ MOVL d, R9; \
+ XORL c, R9; \
+ ANDL b, R9; \
+ XORL d, R9
+
+#define FUNC2(a, b, c, d, e) \
+ MOVL b, R9; \
+ XORL c, R9; \
+ XORL d, R9
+
+#define FUNC3(a, b, c, d, e) \
+ MOVL b, R8; \
+ ORL c, R8; \
+ ANDL d, R8; \
+ MOVL b, R9; \
+ ANDL c, R9; \
+ ORL R8, R9
+
+#define FUNC4 FUNC2
+
+#define MIX(a, b, c, d, e, const) \
+ ROLL $30, b; \
+ ADDL R9, e; \
+ MOVL a, R8; \
+ ROLL $5, R8; \
+ LEAL const(e)(R10*1), e; \
+ ADDL R8, e
+
+#define ROUND1(a, b, c, d, e, index) \
+ LOAD(index); \
+ FUNC1(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0x5A827999)
+
+#define ROUND1x(a, b, c, d, e, index) \
+ SHUFFLE(index); \
+ FUNC1(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0x5A827999)
+
+#define ROUND2(a, b, c, d, e, index) \
+ SHUFFLE(index); \
+ FUNC2(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0x6ED9EBA1)
+
+#define ROUND3(a, b, c, d, e, index) \
+ SHUFFLE(index); \
+ FUNC3(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0x8F1BBCDC)
+
+#define ROUND4(a, b, c, d, e, index) \
+ SHUFFLE(index); \
+ FUNC4(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0xCA62C1D6)
+
+TEXT ·block(SB),NOSPLIT,$64-32
+ MOVL dig+0(FP), R14
+ MOVL p_base+4(FP), SI
+ MOVL p_len+8(FP), DX
+ SHRQ $6, DX
+ SHLQ $6, DX
+
+ LEAQ (SI)(DX*1), DI
+ MOVL (0*4)(R14), AX
+ MOVL (1*4)(R14), BX
+ MOVL (2*4)(R14), CX
+ MOVL (3*4)(R14), DX
+ MOVL (4*4)(R14), R13
+
+ CMPQ SI, DI
+ JEQ end
+
+loop:
+#define BP R13 /* keep diff from sha1block_amd64.s small */
+ ROUND1(AX, BX, CX, DX, BP, 0)
+ ROUND1(BP, AX, BX, CX, DX, 1)
+ ROUND1(DX, BP, AX, BX, CX, 2)
+ ROUND1(CX, DX, BP, AX, BX, 3)
+ ROUND1(BX, CX, DX, BP, AX, 4)
+ ROUND1(AX, BX, CX, DX, BP, 5)
+ ROUND1(BP, AX, BX, CX, DX, 6)
+ ROUND1(DX, BP, AX, BX, CX, 7)
+ ROUND1(CX, DX, BP, AX, BX, 8)
+ ROUND1(BX, CX, DX, BP, AX, 9)
+ ROUND1(AX, BX, CX, DX, BP, 10)
+ ROUND1(BP, AX, BX, CX, DX, 11)
+ ROUND1(DX, BP, AX, BX, CX, 12)
+ ROUND1(CX, DX, BP, AX, BX, 13)
+ ROUND1(BX, CX, DX, BP, AX, 14)
+ ROUND1(AX, BX, CX, DX, BP, 15)
+
+ ROUND1x(BP, AX, BX, CX, DX, 16)
+ ROUND1x(DX, BP, AX, BX, CX, 17)
+ ROUND1x(CX, DX, BP, AX, BX, 18)
+ ROUND1x(BX, CX, DX, BP, AX, 19)
+
+ ROUND2(AX, BX, CX, DX, BP, 20)
+ ROUND2(BP, AX, BX, CX, DX, 21)
+ ROUND2(DX, BP, AX, BX, CX, 22)
+ ROUND2(CX, DX, BP, AX, BX, 23)
+ ROUND2(BX, CX, DX, BP, AX, 24)
+ ROUND2(AX, BX, CX, DX, BP, 25)
+ ROUND2(BP, AX, BX, CX, DX, 26)
+ ROUND2(DX, BP, AX, BX, CX, 27)
+ ROUND2(CX, DX, BP, AX, BX, 28)
+ ROUND2(BX, CX, DX, BP, AX, 29)
+ ROUND2(AX, BX, CX, DX, BP, 30)
+ ROUND2(BP, AX, BX, CX, DX, 31)
+ ROUND2(DX, BP, AX, BX, CX, 32)
+ ROUND2(CX, DX, BP, AX, BX, 33)
+ ROUND2(BX, CX, DX, BP, AX, 34)
+ ROUND2(AX, BX, CX, DX, BP, 35)
+ ROUND2(BP, AX, BX, CX, DX, 36)
+ ROUND2(DX, BP, AX, BX, CX, 37)
+ ROUND2(CX, DX, BP, AX, BX, 38)
+ ROUND2(BX, CX, DX, BP, AX, 39)
+
+ ROUND3(AX, BX, CX, DX, BP, 40)
+ ROUND3(BP, AX, BX, CX, DX, 41)
+ ROUND3(DX, BP, AX, BX, CX, 42)
+ ROUND3(CX, DX, BP, AX, BX, 43)
+ ROUND3(BX, CX, DX, BP, AX, 44)
+ ROUND3(AX, BX, CX, DX, BP, 45)
+ ROUND3(BP, AX, BX, CX, DX, 46)
+ ROUND3(DX, BP, AX, BX, CX, 47)
+ ROUND3(CX, DX, BP, AX, BX, 48)
+ ROUND3(BX, CX, DX, BP, AX, 49)
+ ROUND3(AX, BX, CX, DX, BP, 50)
+ ROUND3(BP, AX, BX, CX, DX, 51)
+ ROUND3(DX, BP, AX, BX, CX, 52)
+ ROUND3(CX, DX, BP, AX, BX, 53)
+ ROUND3(BX, CX, DX, BP, AX, 54)
+ ROUND3(AX, BX, CX, DX, BP, 55)
+ ROUND3(BP, AX, BX, CX, DX, 56)
+ ROUND3(DX, BP, AX, BX, CX, 57)
+ ROUND3(CX, DX, BP, AX, BX, 58)
+ ROUND3(BX, CX, DX, BP, AX, 59)
+
+ ROUND4(AX, BX, CX, DX, BP, 60)
+ ROUND4(BP, AX, BX, CX, DX, 61)
+ ROUND4(DX, BP, AX, BX, CX, 62)
+ ROUND4(CX, DX, BP, AX, BX, 63)
+ ROUND4(BX, CX, DX, BP, AX, 64)
+ ROUND4(AX, BX, CX, DX, BP, 65)
+ ROUND4(BP, AX, BX, CX, DX, 66)
+ ROUND4(DX, BP, AX, BX, CX, 67)
+ ROUND4(CX, DX, BP, AX, BX, 68)
+ ROUND4(BX, CX, DX, BP, AX, 69)
+ ROUND4(AX, BX, CX, DX, BP, 70)
+ ROUND4(BP, AX, BX, CX, DX, 71)
+ ROUND4(DX, BP, AX, BX, CX, 72)
+ ROUND4(CX, DX, BP, AX, BX, 73)
+ ROUND4(BX, CX, DX, BP, AX, 74)
+ ROUND4(AX, BX, CX, DX, BP, 75)
+ ROUND4(BP, AX, BX, CX, DX, 76)
+ ROUND4(DX, BP, AX, BX, CX, 77)
+ ROUND4(CX, DX, BP, AX, BX, 78)
+ ROUND4(BX, CX, DX, BP, AX, 79)
+#undef BP
+
+ ADDL (0*4)(R14), AX
+ ADDL (1*4)(R14), BX
+ ADDL (2*4)(R14), CX
+ ADDL (3*4)(R14), DX
+ ADDL (4*4)(R14), R13
+
+ MOVL AX, (0*4)(R14)
+ MOVL BX, (1*4)(R14)
+ MOVL CX, (2*4)(R14)
+ MOVL DX, (3*4)(R14)
+ MOVL R13, (4*4)(R14)
+
+ ADDQ $64, SI
+ CMPQ SI, DI
+ JB loop
+
+end:
+ RET
diff --git a/src/pkg/crypto/sha1/sha1block_arm.s b/src/pkg/crypto/sha1/sha1block_arm.s
new file mode 100644
index 000000000..5917e8b24
--- /dev/null
+++ b/src/pkg/crypto/sha1/sha1block_arm.s
@@ -0,0 +1,217 @@
+// 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.
+//
+// ARM version of md5block.go
+
+#include "../../../cmd/ld/textflag.h"
+
+// SHA1 block routine. See sha1block.go for Go equivalent.
+//
+// There are 80 rounds of 4 types:
+// - rounds 0-15 are type 1 and load data (ROUND1 macro).
+// - rounds 16-19 are type 1 and do not load data (ROUND1x macro).
+// - rounds 20-39 are type 2 and do not load data (ROUND2 macro).
+// - rounds 40-59 are type 3 and do not load data (ROUND3 macro).
+// - rounds 60-79 are type 4 and do not load data (ROUND4 macro).
+//
+// Each round loads or shuffles the data, then computes a per-round
+// function of b, c, d, and then mixes the result into and rotates the
+// five registers a, b, c, d, e holding the intermediate results.
+//
+// The register rotation is implemented by rotating the arguments to
+// the round macros instead of by explicit move instructions.
+
+// Register definitions
+data = 0 // Pointer to incoming data
+const = 1 // Current constant for SHA round
+a = 2 // SHA1 accumulator
+b = 3 // SHA1 accumulator
+c = 4 // SHA1 accumulator
+d = 5 // SHA1 accumulator
+e = 6 // SHA1 accumulator
+t0 = 7 // Temporary
+t1 = 8 // Temporary
+// r9, r10 are forbidden
+// r11 is OK provided you check the assembler that no synthetic instructions use it
+t2 = 11 // Temporary
+ctr = 12 // loop counter
+w = 14 // point to w buffer
+
+// func block(dig *digest, p []byte)
+// 0(FP) is *digest
+// 4(FP) is p.array (struct Slice)
+// 8(FP) is p.len
+//12(FP) is p.cap
+//
+// Stack frame
+p_end = -4 // -4(SP) pointer to the end of data
+p_data = p_end - 4 // -8(SP) current data pointer
+w_buf = p_data - 4*80 // -328(SP) 80 words temporary buffer w uint32[80]
+saved = w_buf - 4*5 // -348(SP) saved sha1 registers a,b,c,d,e - these must be last
+// Total size +4 for saved LR is 352
+
+ // w[i] = p[j]<<24 | p[j+1]<<16 | p[j+2]<<8 | p[j+3]
+ // e += w[i]
+#define LOAD(e) \
+ MOVBU 2(R(data)), R(t0) ; \
+ MOVBU 3(R(data)), R(t1) ; \
+ MOVBU 1(R(data)), R(t2) ; \
+ ORR R(t0)<<8, R(t1), R(t0) ; \
+ MOVBU.P 4(R(data)), R(t1) ; \
+ ORR R(t2)<<16, R(t0), R(t0) ; \
+ ORR R(t1)<<24, R(t0), R(t0) ; \
+ MOVW.P R(t0), 4(R(w)) ; \
+ ADD R(t0), R(e), R(e)
+
+ // tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf]
+ // w[i&0xf] = tmp<<1 | tmp>>(32-1)
+ // e += w[i&0xf]
+#define SHUFFLE(e) \
+ MOVW (-16*4)(R(w)), R(t0) ; \
+ MOVW (-14*4)(R(w)), R(t1) ; \
+ MOVW (-8*4)(R(w)), R(t2) ; \
+ EOR R(t0), R(t1), R(t0) ; \
+ MOVW (-3*4)(R(w)), R(t1) ; \
+ EOR R(t2), R(t0), R(t0) ; \
+ EOR R(t0), R(t1), R(t0) ; \
+ MOVW R(t0)@>(32-1), R(t0) ; \
+ MOVW.P R(t0), 4(R(w)) ; \
+ ADD R(t0), R(e), R(e)
+
+ // t1 = (b & c) | ((~b) & d)
+#define FUNC1(a, b, c, d, e) \
+ MVN R(b), R(t1) ; \
+ AND R(b), R(c), R(t0) ; \
+ AND R(d), R(t1), R(t1) ; \
+ ORR R(t0), R(t1), R(t1)
+
+ // t1 = b ^ c ^ d
+#define FUNC2(a, b, c, d, e) \
+ EOR R(b), R(c), R(t1) ; \
+ EOR R(d), R(t1), R(t1)
+
+ // t1 = (b & c) | (b & d) | (c & d) =
+ // t1 = (b & c) | ((b | c) & d)
+#define FUNC3(a, b, c, d, e) \
+ ORR R(b), R(c), R(t0) ; \
+ AND R(b), R(c), R(t1) ; \
+ AND R(d), R(t0), R(t0) ; \
+ ORR R(t0), R(t1), R(t1)
+
+#define FUNC4 FUNC2
+
+ // a5 := a<<5 | a>>(32-5)
+ // b = b<<30 | b>>(32-30)
+ // e = a5 + t1 + e + const
+#define MIX(a, b, c, d, e) \
+ ADD R(t1), R(e), R(e) ; \
+ MOVW R(b)@>(32-30), R(b) ; \
+ ADD R(a)@>(32-5), R(e), R(e) ; \
+ ADD R(const), R(e), R(e)
+
+#define ROUND1(a, b, c, d, e) \
+ LOAD(e) ; \
+ FUNC1(a, b, c, d, e) ; \
+ MIX(a, b, c, d, e)
+
+#define ROUND1x(a, b, c, d, e) \
+ SHUFFLE(e) ; \
+ FUNC1(a, b, c, d, e) ; \
+ MIX(a, b, c, d, e)
+
+#define ROUND2(a, b, c, d, e) \
+ SHUFFLE(e) ; \
+ FUNC2(a, b, c, d, e) ; \
+ MIX(a, b, c, d, e)
+
+#define ROUND3(a, b, c, d, e) \
+ SHUFFLE(e) ; \
+ FUNC3(a, b, c, d, e) ; \
+ MIX(a, b, c, d, e)
+
+#define ROUND4(a, b, c, d, e) \
+ SHUFFLE(e) ; \
+ FUNC4(a, b, c, d, e) ; \
+ MIX(a, b, c, d, e)
+
+
+// func block(dig *digest, p []byte)
+TEXT ·block(SB), 0, $352-16
+ MOVW p+4(FP), R(data) // pointer to the data
+ MOVW p_len+8(FP), R(t0) // number of bytes
+ ADD R(data), R(t0)
+ MOVW R(t0), p_end(SP) // pointer to end of data
+
+ // Load up initial SHA1 accumulator
+ MOVW dig+0(FP), R(t0)
+ MOVM.IA (R(t0)), [R(a),R(b),R(c),R(d),R(e)]
+
+loop:
+ // Save registers at SP+4 onwards
+ MOVM.IB [R(a),R(b),R(c),R(d),R(e)], (R13)
+
+ MOVW $w_buf(SP), R(w)
+ MOVW $0x5A827999, R(const)
+ MOVW $3, R(ctr)
+loop1: ROUND1(a, b, c, d, e)
+ ROUND1(e, a, b, c, d)
+ ROUND1(d, e, a, b, c)
+ ROUND1(c, d, e, a, b)
+ ROUND1(b, c, d, e, a)
+ SUB.S $1, R(ctr)
+ BNE loop1
+
+ ROUND1(a, b, c, d, e)
+ ROUND1x(e, a, b, c, d)
+ ROUND1x(d, e, a, b, c)
+ ROUND1x(c, d, e, a, b)
+ ROUND1x(b, c, d, e, a)
+
+ MOVW $0x6ED9EBA1, R(const)
+ MOVW $4, R(ctr)
+loop2: ROUND2(a, b, c, d, e)
+ ROUND2(e, a, b, c, d)
+ ROUND2(d, e, a, b, c)
+ ROUND2(c, d, e, a, b)
+ ROUND2(b, c, d, e, a)
+ SUB.S $1, R(ctr)
+ BNE loop2
+
+ MOVW $0x8F1BBCDC, R(const)
+ MOVW $4, R(ctr)
+loop3: ROUND3(a, b, c, d, e)
+ ROUND3(e, a, b, c, d)
+ ROUND3(d, e, a, b, c)
+ ROUND3(c, d, e, a, b)
+ ROUND3(b, c, d, e, a)
+ SUB.S $1, R(ctr)
+ BNE loop3
+
+ MOVW $0xCA62C1D6, R(const)
+ MOVW $4, R(ctr)
+loop4: ROUND4(a, b, c, d, e)
+ ROUND4(e, a, b, c, d)
+ ROUND4(d, e, a, b, c)
+ ROUND4(c, d, e, a, b)
+ ROUND4(b, c, d, e, a)
+ SUB.S $1, R(ctr)
+ BNE loop4
+
+ // Accumulate - restoring registers from SP+4
+ MOVM.IB (R13), [R(t0),R(t1),R(t2),R(ctr),R(w)]
+ ADD R(t0), R(a)
+ ADD R(t1), R(b)
+ ADD R(t2), R(c)
+ ADD R(ctr), R(d)
+ ADD R(w), R(e)
+
+ MOVW p_end(SP), R(t0)
+ CMP R(t0), R(data)
+ BLO loop
+
+ // Save final SHA1 accumulator
+ MOVW dig+0(FP), R(t0)
+ MOVM.IA [R(a),R(b),R(c),R(d),R(e)], (R(t0))
+
+ RET
diff --git a/src/pkg/crypto/sha1/sha1block_decl.go b/src/pkg/crypto/sha1/sha1block_decl.go
index 4cb157fff..24e521af1 100644
--- a/src/pkg/crypto/sha1/sha1block_decl.go
+++ b/src/pkg/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/src/pkg/crypto/sha1/sha1block_generic.go b/src/pkg/crypto/sha1/sha1block_generic.go
new file mode 100644
index 000000000..696e26b62
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/sha256/sha256.go b/src/pkg/crypto/sha256/sha256.go
index d69ed24a3..d84cebf2f 100644
--- a/src/pkg/crypto/sha256/sha256.go
+++ b/src/pkg/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/src/pkg/crypto/sha256/sha256_test.go b/src/pkg/crypto/sha256/sha256_test.go
index bb1ec3b16..1d883d390 100644
--- a/src/pkg/crypto/sha256/sha256_test.go
+++ b/src/pkg/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/src/pkg/crypto/sha256/sha256block.go b/src/pkg/crypto/sha256/sha256block.go
index 2ac49100a..ca5efd156 100644
--- a/src/pkg/crypto/sha256/sha256block.go
+++ b/src/pkg/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/src/pkg/crypto/sha256/sha256block_386.s b/src/pkg/crypto/sha256/sha256block_386.s
new file mode 100644
index 000000000..73ae2bf30
--- /dev/null
+++ b/src/pkg/crypto/sha256/sha256block_386.s
@@ -0,0 +1,283 @@
+// 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.
+
+// SHA256 block routine. See sha256block.go for Go equivalent.
+//
+// The algorithm is detailed in FIPS 180-4:
+//
+// http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
+//
+// Wt = Mt; for 0 <= t <= 15
+// Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63
+//
+// a = H0
+// b = H1
+// c = H2
+// d = H3
+// e = H4
+// f = H5
+// g = H6
+// h = H7
+//
+// for t = 0 to 63 {
+// T1 = h + BIGSIGMA1(e) + Ch(e,f,g) + Kt + Wt
+// T2 = BIGSIGMA0(a) + Maj(a,b,c)
+// h = g
+// g = f
+// f = e
+// e = d + T1
+// d = c
+// c = b
+// b = a
+// a = T1 + T2
+// }
+//
+// H0 = a + H0
+// H1 = b + H1
+// H2 = c + H2
+// H3 = d + H3
+// H4 = e + H4
+// H5 = f + H5
+// H6 = g + H6
+// H7 = h + H7
+
+// Wt = Mt; for 0 <= t <= 15
+#define MSGSCHEDULE0(index) \
+ MOVL (index*4)(SI), AX; \
+ BSWAPL AX; \
+ MOVL AX, (index*4)(BP)
+
+// Wt = SIGMA1(Wt-2) + Wt-7 + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63
+// SIGMA0(x) = ROTR(7,x) XOR ROTR(18,x) XOR SHR(3,x)
+// SIGMA1(x) = ROTR(17,x) XOR ROTR(19,x) XOR SHR(10,x)
+#define MSGSCHEDULE1(index) \
+ MOVL ((index-2)*4)(BP), AX; \
+ MOVL AX, CX; \
+ RORL $17, AX; \
+ MOVL CX, DX; \
+ RORL $19, CX; \
+ SHRL $10, DX; \
+ MOVL ((index-15)*4)(BP), BX; \
+ XORL CX, AX; \
+ MOVL BX, CX; \
+ XORL DX, AX; \
+ RORL $7, BX; \
+ MOVL CX, DX; \
+ SHRL $3, DX; \
+ RORL $18, CX; \
+ ADDL ((index-7)*4)(BP), AX; \
+ XORL CX, BX; \
+ XORL DX, BX; \
+ ADDL ((index-16)*4)(BP), BX; \
+ ADDL BX, AX; \
+ MOVL AX, ((index)*4)(BP)
+
+// Calculate T1 in AX - uses AX, BX, CX and DX registers.
+// Wt is passed in AX.
+// T1 = h + BIGSIGMA1(e) + Ch(e, f, g) + Kt + Wt
+// BIGSIGMA1(x) = ROTR(6,x) XOR ROTR(11,x) XOR ROTR(25,x)
+// Ch(x, y, z) = (x AND y) XOR (NOT x AND z)
+#define SHA256T1(const, e, f, g, h) \
+ MOVL (h*4)(DI), BX; \
+ ADDL AX, BX; \
+ MOVL (e*4)(DI), AX; \
+ ADDL $const, BX; \
+ MOVL (e*4)(DI), CX; \
+ RORL $6, AX; \
+ MOVL (e*4)(DI), DX; \
+ RORL $11, CX; \
+ XORL CX, AX; \
+ MOVL (e*4)(DI), CX; \
+ RORL $25, DX; \
+ ANDL (f*4)(DI), CX; \
+ XORL AX, DX; \
+ MOVL (e*4)(DI), AX; \
+ NOTL AX; \
+ ADDL DX, BX; \
+ ANDL (g*4)(DI), AX; \
+ XORL CX, AX; \
+ ADDL BX, AX
+
+// Calculate T2 in BX - uses AX, BX, CX and DX registers.
+// T2 = BIGSIGMA0(a) + Maj(a, b, c)
+// BIGSIGMA0(x) = ROTR(2,x) XOR ROTR(13,x) XOR ROTR(22,x)
+// Maj(x, y, z) = (x AND y) XOR (x AND z) XOR (y AND z)
+#define SHA256T2(a, b, c) \
+ MOVL (a*4)(DI), AX; \
+ MOVL (c*4)(DI), BX; \
+ RORL $2, AX; \
+ MOVL (a*4)(DI), DX; \
+ ANDL (b*4)(DI), BX; \
+ RORL $13, DX; \
+ MOVL (a*4)(DI), CX; \
+ ANDL (c*4)(DI), CX; \
+ XORL DX, AX; \
+ XORL CX, BX; \
+ MOVL (a*4)(DI), DX; \
+ MOVL (b*4)(DI), CX; \
+ RORL $22, DX; \
+ ANDL (a*4)(DI), CX; \
+ XORL CX, BX; \
+ XORL DX, AX; \
+ ADDL AX, BX
+
+// Calculate T1 and T2, then e = d + T1 and a = T1 + T2.
+// The values for e and a are stored in d and h, ready for rotation.
+#define SHA256ROUND(index, const, a, b, c, d, e, f, g, h) \
+ SHA256T1(const, e, f, g, h); \
+ MOVL AX, 292(SP); \
+ SHA256T2(a, b, c); \
+ MOVL 292(SP), AX; \
+ ADDL AX, BX; \
+ ADDL AX, (d*4)(DI); \
+ MOVL BX, (h*4)(DI)
+
+#define SHA256ROUND0(index, const, a, b, c, d, e, f, g, h) \
+ MSGSCHEDULE0(index); \
+ SHA256ROUND(index, const, a, b, c, d, e, f, g, h)
+
+#define SHA256ROUND1(index, const, a, b, c, d, e, f, g, h) \
+ MSGSCHEDULE1(index); \
+ SHA256ROUND(index, const, a, b, c, d, e, f, g, h)
+
+TEXT ·block(SB),0,$296-12
+ MOVL p_base+4(FP), SI
+ MOVL p_len+8(FP), DX
+ SHRL $6, DX
+ SHLL $6, DX
+
+ LEAL (SI)(DX*1), DI
+ MOVL DI, 288(SP)
+ CMPL SI, DI
+ JEQ end
+
+ LEAL 256(SP), DI // variables
+
+ MOVL dig+0(FP), BP
+ MOVL (0*4)(BP), AX // a = H0
+ MOVL AX, (0*4)(DI)
+ MOVL (1*4)(BP), BX // b = H1
+ MOVL BX, (1*4)(DI)
+ MOVL (2*4)(BP), CX // c = H2
+ MOVL CX, (2*4)(DI)
+ MOVL (3*4)(BP), DX // d = H3
+ MOVL DX, (3*4)(DI)
+ MOVL (4*4)(BP), AX // e = H4
+ MOVL AX, (4*4)(DI)
+ MOVL (5*4)(BP), BX // f = H5
+ MOVL BX, (5*4)(DI)
+ MOVL (6*4)(BP), CX // g = H6
+ MOVL CX, (6*4)(DI)
+ MOVL (7*4)(BP), DX // h = H7
+ MOVL DX, (7*4)(DI)
+
+loop:
+ MOVL SP, BP // message schedule
+
+ SHA256ROUND0(0, 0x428a2f98, 0, 1, 2, 3, 4, 5, 6, 7)
+ SHA256ROUND0(1, 0x71374491, 7, 0, 1, 2, 3, 4, 5, 6)
+ SHA256ROUND0(2, 0xb5c0fbcf, 6, 7, 0, 1, 2, 3, 4, 5)
+ SHA256ROUND0(3, 0xe9b5dba5, 5, 6, 7, 0, 1, 2, 3, 4)
+ SHA256ROUND0(4, 0x3956c25b, 4, 5, 6, 7, 0, 1, 2, 3)
+ SHA256ROUND0(5, 0x59f111f1, 3, 4, 5, 6, 7, 0, 1, 2)
+ SHA256ROUND0(6, 0x923f82a4, 2, 3, 4, 5, 6, 7, 0, 1)
+ SHA256ROUND0(7, 0xab1c5ed5, 1, 2, 3, 4, 5, 6, 7, 0)
+ SHA256ROUND0(8, 0xd807aa98, 0, 1, 2, 3, 4, 5, 6, 7)
+ SHA256ROUND0(9, 0x12835b01, 7, 0, 1, 2, 3, 4, 5, 6)
+ SHA256ROUND0(10, 0x243185be, 6, 7, 0, 1, 2, 3, 4, 5)
+ SHA256ROUND0(11, 0x550c7dc3, 5, 6, 7, 0, 1, 2, 3, 4)
+ SHA256ROUND0(12, 0x72be5d74, 4, 5, 6, 7, 0, 1, 2, 3)
+ SHA256ROUND0(13, 0x80deb1fe, 3, 4, 5, 6, 7, 0, 1, 2)
+ SHA256ROUND0(14, 0x9bdc06a7, 2, 3, 4, 5, 6, 7, 0, 1)
+ SHA256ROUND0(15, 0xc19bf174, 1, 2, 3, 4, 5, 6, 7, 0)
+
+ SHA256ROUND1(16, 0xe49b69c1, 0, 1, 2, 3, 4, 5, 6, 7)
+ SHA256ROUND1(17, 0xefbe4786, 7, 0, 1, 2, 3, 4, 5, 6)
+ SHA256ROUND1(18, 0x0fc19dc6, 6, 7, 0, 1, 2, 3, 4, 5)
+ SHA256ROUND1(19, 0x240ca1cc, 5, 6, 7, 0, 1, 2, 3, 4)
+ SHA256ROUND1(20, 0x2de92c6f, 4, 5, 6, 7, 0, 1, 2, 3)
+ SHA256ROUND1(21, 0x4a7484aa, 3, 4, 5, 6, 7, 0, 1, 2)
+ SHA256ROUND1(22, 0x5cb0a9dc, 2, 3, 4, 5, 6, 7, 0, 1)
+ SHA256ROUND1(23, 0x76f988da, 1, 2, 3, 4, 5, 6, 7, 0)
+ SHA256ROUND1(24, 0x983e5152, 0, 1, 2, 3, 4, 5, 6, 7)
+ SHA256ROUND1(25, 0xa831c66d, 7, 0, 1, 2, 3, 4, 5, 6)
+ SHA256ROUND1(26, 0xb00327c8, 6, 7, 0, 1, 2, 3, 4, 5)
+ SHA256ROUND1(27, 0xbf597fc7, 5, 6, 7, 0, 1, 2, 3, 4)
+ SHA256ROUND1(28, 0xc6e00bf3, 4, 5, 6, 7, 0, 1, 2, 3)
+ SHA256ROUND1(29, 0xd5a79147, 3, 4, 5, 6, 7, 0, 1, 2)
+ SHA256ROUND1(30, 0x06ca6351, 2, 3, 4, 5, 6, 7, 0, 1)
+ SHA256ROUND1(31, 0x14292967, 1, 2, 3, 4, 5, 6, 7, 0)
+ SHA256ROUND1(32, 0x27b70a85, 0, 1, 2, 3, 4, 5, 6, 7)
+ SHA256ROUND1(33, 0x2e1b2138, 7, 0, 1, 2, 3, 4, 5, 6)
+ SHA256ROUND1(34, 0x4d2c6dfc, 6, 7, 0, 1, 2, 3, 4, 5)
+ SHA256ROUND1(35, 0x53380d13, 5, 6, 7, 0, 1, 2, 3, 4)
+ SHA256ROUND1(36, 0x650a7354, 4, 5, 6, 7, 0, 1, 2, 3)
+ SHA256ROUND1(37, 0x766a0abb, 3, 4, 5, 6, 7, 0, 1, 2)
+ SHA256ROUND1(38, 0x81c2c92e, 2, 3, 4, 5, 6, 7, 0, 1)
+ SHA256ROUND1(39, 0x92722c85, 1, 2, 3, 4, 5, 6, 7, 0)
+ SHA256ROUND1(40, 0xa2bfe8a1, 0, 1, 2, 3, 4, 5, 6, 7)
+ SHA256ROUND1(41, 0xa81a664b, 7, 0, 1, 2, 3, 4, 5, 6)
+ SHA256ROUND1(42, 0xc24b8b70, 6, 7, 0, 1, 2, 3, 4, 5)
+ SHA256ROUND1(43, 0xc76c51a3, 5, 6, 7, 0, 1, 2, 3, 4)
+ SHA256ROUND1(44, 0xd192e819, 4, 5, 6, 7, 0, 1, 2, 3)
+ SHA256ROUND1(45, 0xd6990624, 3, 4, 5, 6, 7, 0, 1, 2)
+ SHA256ROUND1(46, 0xf40e3585, 2, 3, 4, 5, 6, 7, 0, 1)
+ SHA256ROUND1(47, 0x106aa070, 1, 2, 3, 4, 5, 6, 7, 0)
+ SHA256ROUND1(48, 0x19a4c116, 0, 1, 2, 3, 4, 5, 6, 7)
+ SHA256ROUND1(49, 0x1e376c08, 7, 0, 1, 2, 3, 4, 5, 6)
+ SHA256ROUND1(50, 0x2748774c, 6, 7, 0, 1, 2, 3, 4, 5)
+ SHA256ROUND1(51, 0x34b0bcb5, 5, 6, 7, 0, 1, 2, 3, 4)
+ SHA256ROUND1(52, 0x391c0cb3, 4, 5, 6, 7, 0, 1, 2, 3)
+ SHA256ROUND1(53, 0x4ed8aa4a, 3, 4, 5, 6, 7, 0, 1, 2)
+ SHA256ROUND1(54, 0x5b9cca4f, 2, 3, 4, 5, 6, 7, 0, 1)
+ SHA256ROUND1(55, 0x682e6ff3, 1, 2, 3, 4, 5, 6, 7, 0)
+ SHA256ROUND1(56, 0x748f82ee, 0, 1, 2, 3, 4, 5, 6, 7)
+ SHA256ROUND1(57, 0x78a5636f, 7, 0, 1, 2, 3, 4, 5, 6)
+ SHA256ROUND1(58, 0x84c87814, 6, 7, 0, 1, 2, 3, 4, 5)
+ SHA256ROUND1(59, 0x8cc70208, 5, 6, 7, 0, 1, 2, 3, 4)
+ SHA256ROUND1(60, 0x90befffa, 4, 5, 6, 7, 0, 1, 2, 3)
+ SHA256ROUND1(61, 0xa4506ceb, 3, 4, 5, 6, 7, 0, 1, 2)
+ SHA256ROUND1(62, 0xbef9a3f7, 2, 3, 4, 5, 6, 7, 0, 1)
+ SHA256ROUND1(63, 0xc67178f2, 1, 2, 3, 4, 5, 6, 7, 0)
+
+ MOVL dig+0(FP), BP
+ MOVL (0*4)(BP), AX // H0 = a + H0
+ ADDL (0*4)(DI), AX
+ MOVL AX, (0*4)(DI)
+ MOVL AX, (0*4)(BP)
+ MOVL (1*4)(BP), BX // H1 = b + H1
+ ADDL (1*4)(DI), BX
+ MOVL BX, (1*4)(DI)
+ MOVL BX, (1*4)(BP)
+ MOVL (2*4)(BP), CX // H2 = c + H2
+ ADDL (2*4)(DI), CX
+ MOVL CX, (2*4)(DI)
+ MOVL CX, (2*4)(BP)
+ MOVL (3*4)(BP), DX // H3 = d + H3
+ ADDL (3*4)(DI), DX
+ MOVL DX, (3*4)(DI)
+ MOVL DX, (3*4)(BP)
+ MOVL (4*4)(BP), AX // H4 = e + H4
+ ADDL (4*4)(DI), AX
+ MOVL AX, (4*4)(DI)
+ MOVL AX, (4*4)(BP)
+ MOVL (5*4)(BP), BX // H5 = f + H5
+ ADDL (5*4)(DI), BX
+ MOVL BX, (5*4)(DI)
+ MOVL BX, (5*4)(BP)
+ MOVL (6*4)(BP), CX // H6 = g + H6
+ ADDL (6*4)(DI), CX
+ MOVL CX, (6*4)(DI)
+ MOVL CX, (6*4)(BP)
+ MOVL (7*4)(BP), DX // H7 = h + H7
+ ADDL (7*4)(DI), DX
+ MOVL DX, (7*4)(DI)
+ MOVL DX, (7*4)(BP)
+
+ ADDL $64, SI
+ CMPL SI, 288(SP)
+ JB loop
+
+end:
+ RET
diff --git a/src/pkg/crypto/sha256/sha256block_amd64.s b/src/pkg/crypto/sha256/sha256block_amd64.s
new file mode 100644
index 000000000..95aebbe76
--- /dev/null
+++ b/src/pkg/crypto/sha256/sha256block_amd64.s
@@ -0,0 +1,256 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "../../../cmd/ld/textflag.h"
+
+// SHA256 block routine. See sha256block.go for Go equivalent.
+//
+// The algorithm is detailed in FIPS 180-4:
+//
+// http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
+//
+// Wt = Mt; for 0 <= t <= 15
+// Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63
+//
+// a = H0
+// b = H1
+// c = H2
+// d = H3
+// e = H4
+// f = H5
+// g = H6
+// h = H7
+//
+// for t = 0 to 63 {
+// T1 = h + BIGSIGMA1(e) + Ch(e,f,g) + Kt + Wt
+// T2 = BIGSIGMA0(a) + Maj(a,b,c)
+// h = g
+// g = f
+// f = e
+// e = d + T1
+// d = c
+// c = b
+// b = a
+// a = T1 + T2
+// }
+//
+// H0 = a + H0
+// H1 = b + H1
+// H2 = c + H2
+// H3 = d + H3
+// H4 = e + H4
+// H5 = f + H5
+// H6 = g + H6
+// H7 = h + H7
+
+// Wt = Mt; for 0 <= t <= 15
+#define MSGSCHEDULE0(index) \
+ MOVL (index*4)(SI), AX; \
+ BSWAPL AX; \
+ MOVL AX, (index*4)(BP)
+
+// Wt = SIGMA1(Wt-2) + Wt-7 + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63
+// SIGMA0(x) = ROTR(7,x) XOR ROTR(18,x) XOR SHR(3,x)
+// SIGMA1(x) = ROTR(17,x) XOR ROTR(19,x) XOR SHR(10,x)
+#define MSGSCHEDULE1(index) \
+ MOVL ((index-2)*4)(BP), AX; \
+ MOVL AX, CX; \
+ RORL $17, AX; \
+ MOVL CX, DX; \
+ RORL $19, CX; \
+ SHRL $10, DX; \
+ MOVL ((index-15)*4)(BP), BX; \
+ XORL CX, AX; \
+ MOVL BX, CX; \
+ XORL DX, AX; \
+ RORL $7, BX; \
+ MOVL CX, DX; \
+ SHRL $3, DX; \
+ RORL $18, CX; \
+ ADDL ((index-7)*4)(BP), AX; \
+ XORL CX, BX; \
+ XORL DX, BX; \
+ ADDL ((index-16)*4)(BP), BX; \
+ ADDL BX, AX; \
+ MOVL AX, ((index)*4)(BP)
+
+// Calculate T1 in AX - uses AX, CX and DX registers.
+// h is also used as an accumulator. Wt is passed in AX.
+// T1 = h + BIGSIGMA1(e) + Ch(e, f, g) + Kt + Wt
+// BIGSIGMA1(x) = ROTR(6,x) XOR ROTR(11,x) XOR ROTR(25,x)
+// Ch(x, y, z) = (x AND y) XOR (NOT x AND z)
+#define SHA256T1(const, e, f, g, h) \
+ ADDL AX, h; \
+ MOVL e, AX; \
+ ADDL $const, h; \
+ MOVL e, CX; \
+ RORL $6, AX; \
+ MOVL e, DX; \
+ RORL $11, CX; \
+ XORL CX, AX; \
+ MOVL e, CX; \
+ RORL $25, DX; \
+ ANDL f, CX; \
+ XORL AX, DX; \
+ MOVL e, AX; \
+ NOTL AX; \
+ ADDL DX, h; \
+ ANDL g, AX; \
+ XORL CX, AX; \
+ ADDL h, AX
+
+// Calculate T2 in BX - uses BX, CX, DX and DI registers.
+// T2 = BIGSIGMA0(a) + Maj(a, b, c)
+// BIGSIGMA0(x) = ROTR(2,x) XOR ROTR(13,x) XOR ROTR(22,x)
+// Maj(x, y, z) = (x AND y) XOR (x AND z) XOR (y AND z)
+#define SHA256T2(a, b, c) \
+ MOVL a, DI; \
+ MOVL c, BX; \
+ RORL $2, DI; \
+ MOVL a, DX; \
+ ANDL b, BX; \
+ RORL $13, DX; \
+ MOVL a, CX; \
+ ANDL c, CX; \
+ XORL DX, DI; \
+ XORL CX, BX; \
+ MOVL a, DX; \
+ MOVL b, CX; \
+ RORL $22, DX; \
+ ANDL a, CX; \
+ XORL CX, BX; \
+ XORL DX, DI; \
+ ADDL DI, BX
+
+// Calculate T1 and T2, then e = d + T1 and a = T1 + T2.
+// The values for e and a are stored in d and h, ready for rotation.
+#define SHA256ROUND(index, const, a, b, c, d, e, f, g, h) \
+ SHA256T1(const, e, f, g, h); \
+ SHA256T2(a, b, c); \
+ MOVL BX, h; \
+ ADDL AX, d; \
+ ADDL AX, h
+
+#define SHA256ROUND0(index, const, a, b, c, d, e, f, g, h) \
+ MSGSCHEDULE0(index); \
+ SHA256ROUND(index, const, a, b, c, d, e, f, g, h)
+
+#define SHA256ROUND1(index, const, a, b, c, d, e, f, g, h) \
+ MSGSCHEDULE1(index); \
+ SHA256ROUND(index, const, a, b, c, d, e, f, g, h)
+
+TEXT ·block(SB),0,$264-32
+ MOVQ p_base+8(FP), SI
+ MOVQ p_len+16(FP), DX
+ SHRQ $6, DX
+ SHLQ $6, DX
+
+ LEAQ (SI)(DX*1), DI
+ MOVQ DI, 256(SP)
+ CMPQ SI, DI
+ JEQ end
+
+ MOVQ dig+0(FP), BP
+ MOVL (0*4)(BP), R8 // a = H0
+ MOVL (1*4)(BP), R9 // b = H1
+ MOVL (2*4)(BP), R10 // c = H2
+ MOVL (3*4)(BP), R11 // d = H3
+ MOVL (4*4)(BP), R12 // e = H4
+ MOVL (5*4)(BP), R13 // f = H5
+ MOVL (6*4)(BP), R14 // g = H6
+ MOVL (7*4)(BP), R15 // h = H7
+
+loop:
+ MOVQ SP, BP // message schedule
+
+ SHA256ROUND0(0, 0x428a2f98, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA256ROUND0(1, 0x71374491, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA256ROUND0(2, 0xb5c0fbcf, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA256ROUND0(3, 0xe9b5dba5, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA256ROUND0(4, 0x3956c25b, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA256ROUND0(5, 0x59f111f1, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA256ROUND0(6, 0x923f82a4, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA256ROUND0(7, 0xab1c5ed5, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA256ROUND0(8, 0xd807aa98, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA256ROUND0(9, 0x12835b01, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA256ROUND0(10, 0x243185be, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA256ROUND0(11, 0x550c7dc3, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA256ROUND0(12, 0x72be5d74, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA256ROUND0(13, 0x80deb1fe, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA256ROUND0(14, 0x9bdc06a7, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA256ROUND0(15, 0xc19bf174, R9, R10, R11, R12, R13, R14, R15, R8)
+
+ SHA256ROUND1(16, 0xe49b69c1, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA256ROUND1(17, 0xefbe4786, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA256ROUND1(18, 0x0fc19dc6, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA256ROUND1(19, 0x240ca1cc, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA256ROUND1(20, 0x2de92c6f, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA256ROUND1(21, 0x4a7484aa, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA256ROUND1(22, 0x5cb0a9dc, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA256ROUND1(23, 0x76f988da, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA256ROUND1(24, 0x983e5152, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA256ROUND1(25, 0xa831c66d, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA256ROUND1(26, 0xb00327c8, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA256ROUND1(27, 0xbf597fc7, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA256ROUND1(28, 0xc6e00bf3, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA256ROUND1(29, 0xd5a79147, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA256ROUND1(30, 0x06ca6351, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA256ROUND1(31, 0x14292967, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA256ROUND1(32, 0x27b70a85, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA256ROUND1(33, 0x2e1b2138, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA256ROUND1(34, 0x4d2c6dfc, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA256ROUND1(35, 0x53380d13, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA256ROUND1(36, 0x650a7354, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA256ROUND1(37, 0x766a0abb, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA256ROUND1(38, 0x81c2c92e, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA256ROUND1(39, 0x92722c85, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA256ROUND1(40, 0xa2bfe8a1, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA256ROUND1(41, 0xa81a664b, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA256ROUND1(42, 0xc24b8b70, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA256ROUND1(43, 0xc76c51a3, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA256ROUND1(44, 0xd192e819, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA256ROUND1(45, 0xd6990624, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA256ROUND1(46, 0xf40e3585, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA256ROUND1(47, 0x106aa070, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA256ROUND1(48, 0x19a4c116, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA256ROUND1(49, 0x1e376c08, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA256ROUND1(50, 0x2748774c, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA256ROUND1(51, 0x34b0bcb5, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA256ROUND1(52, 0x391c0cb3, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA256ROUND1(53, 0x4ed8aa4a, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA256ROUND1(54, 0x5b9cca4f, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA256ROUND1(55, 0x682e6ff3, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA256ROUND1(56, 0x748f82ee, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA256ROUND1(57, 0x78a5636f, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA256ROUND1(58, 0x84c87814, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA256ROUND1(59, 0x8cc70208, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA256ROUND1(60, 0x90befffa, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA256ROUND1(61, 0xa4506ceb, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA256ROUND1(62, 0xbef9a3f7, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA256ROUND1(63, 0xc67178f2, R9, R10, R11, R12, R13, R14, R15, R8)
+
+ MOVQ dig+0(FP), BP
+ ADDL (0*4)(BP), R8 // H0 = a + H0
+ MOVL R8, (0*4)(BP)
+ ADDL (1*4)(BP), R9 // H1 = b + H1
+ MOVL R9, (1*4)(BP)
+ ADDL (2*4)(BP), R10 // H2 = c + H2
+ MOVL R10, (2*4)(BP)
+ ADDL (3*4)(BP), R11 // H3 = d + H3
+ MOVL R11, (3*4)(BP)
+ ADDL (4*4)(BP), R12 // H4 = e + H4
+ MOVL R12, (4*4)(BP)
+ ADDL (5*4)(BP), R13 // H5 = f + H5
+ MOVL R13, (5*4)(BP)
+ ADDL (6*4)(BP), R14 // H6 = g + H6
+ MOVL R14, (6*4)(BP)
+ ADDL (7*4)(BP), R15 // H7 = h + H7
+ MOVL R15, (7*4)(BP)
+
+ ADDQ $64, SI
+ CMPQ SI, 256(SP)
+ JB loop
+
+end:
+ RET
diff --git a/src/pkg/runtime/export_test.c b/src/pkg/crypto/sha256/sha256block_decl.go
index 5ad1a7007..a50c97871 100644
--- a/src/pkg/runtime/export_test.c
+++ b/src/pkg/crypto/sha256/sha256block_decl.go
@@ -2,12 +2,10 @@
// 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_GOARCH.h"
-
-void
-·GogoBytes(int32 x)
-{
- x = RuntimeGogoBytes;
- FLUSH(&x);
-}
+// +build 386 amd64
+
+package sha256
+
+//go:noescape
+
+func block(dig *digest, p []byte)
diff --git a/src/pkg/crypto/sha512/sha512.go b/src/pkg/crypto/sha512/sha512.go
index d2ada5137..bca7a91e2 100644
--- a/src/pkg/crypto/sha512/sha512.go
+++ b/src/pkg/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/src/pkg/crypto/sha512/sha512_test.go b/src/pkg/crypto/sha512/sha512_test.go
index 167c20ad0..541860f70 100644
--- a/src/pkg/crypto/sha512/sha512_test.go
+++ b/src/pkg/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/src/pkg/crypto/sha512/sha512block.go b/src/pkg/crypto/sha512/sha512block.go
index 3577b4f3d..648ae8f7e 100644
--- a/src/pkg/crypto/sha512/sha512block.go
+++ b/src/pkg/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/src/pkg/crypto/sha512/sha512block_amd64.s b/src/pkg/crypto/sha512/sha512block_amd64.s
new file mode 100644
index 000000000..344d8d2c3
--- /dev/null
+++ b/src/pkg/crypto/sha512/sha512block_amd64.s
@@ -0,0 +1,273 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "../../../cmd/ld/textflag.h"
+
+// SHA512 block routine. See sha512block.go for Go equivalent.
+//
+// The algorithm is detailed in FIPS 180-4:
+//
+// http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
+//
+// Wt = Mt; for 0 <= t <= 15
+// Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 79
+//
+// a = H0
+// b = H1
+// c = H2
+// d = H3
+// e = H4
+// f = H5
+// g = H6
+// h = H7
+//
+// for t = 0 to 79 {
+// T1 = h + BIGSIGMA1(e) + Ch(e,f,g) + Kt + Wt
+// T2 = BIGSIGMA0(a) + Maj(a,b,c)
+// h = g
+// g = f
+// f = e
+// e = d + T1
+// d = c
+// c = b
+// b = a
+// a = T1 + T2
+// }
+//
+// H0 = a + H0
+// H1 = b + H1
+// H2 = c + H2
+// H3 = d + H3
+// H4 = e + H4
+// H5 = f + H5
+// H6 = g + H6
+// H7 = h + H7
+
+// Wt = Mt; for 0 <= t <= 15
+#define MSGSCHEDULE0(index) \
+ MOVQ (index*8)(SI), AX; \
+ BSWAPQ AX; \
+ MOVQ AX, (index*8)(BP)
+
+// Wt = SIGMA1(Wt-2) + Wt-7 + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 79
+// SIGMA0(x) = ROTR(1,x) XOR ROTR(8,x) XOR SHR(7,x)
+// SIGMA1(x) = ROTR(19,x) XOR ROTR(61,x) XOR SHR(6,x)
+#define MSGSCHEDULE1(index) \
+ MOVQ ((index-2)*8)(BP), AX; \
+ MOVQ AX, CX; \
+ RORQ $19, AX; \
+ MOVQ CX, DX; \
+ RORQ $61, CX; \
+ SHRQ $6, DX; \
+ MOVQ ((index-15)*8)(BP), BX; \
+ XORQ CX, AX; \
+ MOVQ BX, CX; \
+ XORQ DX, AX; \
+ RORQ $1, BX; \
+ MOVQ CX, DX; \
+ SHRQ $7, DX; \
+ RORQ $8, CX; \
+ ADDQ ((index-7)*8)(BP), AX; \
+ XORQ CX, BX; \
+ XORQ DX, BX; \
+ ADDQ ((index-16)*8)(BP), BX; \
+ ADDQ BX, AX; \
+ MOVQ AX, ((index)*8)(BP)
+
+// Calculate T1 in AX - uses AX, CX and DX registers.
+// h is also used as an accumulator. Wt is passed in AX.
+// T1 = h + BIGSIGMA1(e) + Ch(e, f, g) + Kt + Wt
+// BIGSIGMA1(x) = ROTR(14,x) XOR ROTR(18,x) XOR ROTR(41,x)
+// Ch(x, y, z) = (x AND y) XOR (NOT x AND z)
+#define SHA512T1(const, e, f, g, h) \
+ MOVQ $const, DX; \
+ ADDQ AX, h; \
+ MOVQ e, AX; \
+ ADDQ DX, h; \
+ MOVQ e, CX; \
+ RORQ $14, AX; \
+ MOVQ e, DX; \
+ RORQ $18, CX; \
+ XORQ CX, AX; \
+ MOVQ e, CX; \
+ RORQ $41, DX; \
+ ANDQ f, CX; \
+ XORQ AX, DX; \
+ MOVQ e, AX; \
+ NOTQ AX; \
+ ADDQ DX, h; \
+ ANDQ g, AX; \
+ XORQ CX, AX; \
+ ADDQ h, AX
+
+// Calculate T2 in BX - uses BX, CX, DX and DI registers.
+// T2 = BIGSIGMA0(a) + Maj(a, b, c)
+// BIGSIGMA0(x) = ROTR(28,x) XOR ROTR(34,x) XOR ROTR(39,x)
+// Maj(x, y, z) = (x AND y) XOR (x AND z) XOR (y AND z)
+#define SHA512T2(a, b, c) \
+ MOVQ a, DI; \
+ MOVQ c, BX; \
+ RORQ $28, DI; \
+ MOVQ a, DX; \
+ ANDQ b, BX; \
+ RORQ $34, DX; \
+ MOVQ a, CX; \
+ ANDQ c, CX; \
+ XORQ DX, DI; \
+ XORQ CX, BX; \
+ MOVQ a, DX; \
+ MOVQ b, CX; \
+ RORQ $39, DX; \
+ ANDQ a, CX; \
+ XORQ CX, BX; \
+ XORQ DX, DI; \
+ ADDQ DI, BX
+
+// Calculate T1 and T2, then e = d + T1 and a = T1 + T2.
+// The values for e and a are stored in d and h, ready for rotation.
+#define SHA512ROUND(index, const, a, b, c, d, e, f, g, h) \
+ SHA512T1(const, e, f, g, h); \
+ SHA512T2(a, b, c); \
+ MOVQ BX, h; \
+ ADDQ AX, d; \
+ ADDQ AX, h
+
+#define SHA512ROUND0(index, const, a, b, c, d, e, f, g, h) \
+ MSGSCHEDULE0(index); \
+ SHA512ROUND(index, const, a, b, c, d, e, f, g, h)
+
+#define SHA512ROUND1(index, const, a, b, c, d, e, f, g, h) \
+ MSGSCHEDULE1(index); \
+ SHA512ROUND(index, const, a, b, c, d, e, f, g, h)
+
+TEXT ·block(SB),0,$648-32
+ MOVQ p_base+8(FP), SI
+ MOVQ p_len+16(FP), DX
+ SHRQ $7, DX
+ SHLQ $7, DX
+
+ LEAQ (SI)(DX*1), DI
+ MOVQ DI, 640(SP)
+ CMPQ SI, DI
+ JEQ end
+
+ MOVQ dig+0(FP), BP
+ MOVQ (0*8)(BP), R8 // a = H0
+ MOVQ (1*8)(BP), R9 // b = H1
+ MOVQ (2*8)(BP), R10 // c = H2
+ MOVQ (3*8)(BP), R11 // d = H3
+ MOVQ (4*8)(BP), R12 // e = H4
+ MOVQ (5*8)(BP), R13 // f = H5
+ MOVQ (6*8)(BP), R14 // g = H6
+ MOVQ (7*8)(BP), R15 // h = H7
+
+loop:
+ MOVQ SP, BP // message schedule
+
+ SHA512ROUND0(0, 0x428a2f98d728ae22, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA512ROUND0(1, 0x7137449123ef65cd, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA512ROUND0(2, 0xb5c0fbcfec4d3b2f, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA512ROUND0(3, 0xe9b5dba58189dbbc, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA512ROUND0(4, 0x3956c25bf348b538, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA512ROUND0(5, 0x59f111f1b605d019, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA512ROUND0(6, 0x923f82a4af194f9b, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA512ROUND0(7, 0xab1c5ed5da6d8118, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA512ROUND0(8, 0xd807aa98a3030242, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA512ROUND0(9, 0x12835b0145706fbe, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA512ROUND0(10, 0x243185be4ee4b28c, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA512ROUND0(11, 0x550c7dc3d5ffb4e2, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA512ROUND0(12, 0x72be5d74f27b896f, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA512ROUND0(13, 0x80deb1fe3b1696b1, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA512ROUND0(14, 0x9bdc06a725c71235, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA512ROUND0(15, 0xc19bf174cf692694, R9, R10, R11, R12, R13, R14, R15, R8)
+
+ SHA512ROUND1(16, 0xe49b69c19ef14ad2, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA512ROUND1(17, 0xefbe4786384f25e3, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA512ROUND1(18, 0x0fc19dc68b8cd5b5, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA512ROUND1(19, 0x240ca1cc77ac9c65, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA512ROUND1(20, 0x2de92c6f592b0275, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA512ROUND1(21, 0x4a7484aa6ea6e483, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA512ROUND1(22, 0x5cb0a9dcbd41fbd4, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA512ROUND1(23, 0x76f988da831153b5, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA512ROUND1(24, 0x983e5152ee66dfab, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA512ROUND1(25, 0xa831c66d2db43210, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA512ROUND1(26, 0xb00327c898fb213f, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA512ROUND1(27, 0xbf597fc7beef0ee4, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA512ROUND1(28, 0xc6e00bf33da88fc2, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA512ROUND1(29, 0xd5a79147930aa725, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA512ROUND1(30, 0x06ca6351e003826f, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA512ROUND1(31, 0x142929670a0e6e70, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA512ROUND1(32, 0x27b70a8546d22ffc, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA512ROUND1(33, 0x2e1b21385c26c926, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA512ROUND1(34, 0x4d2c6dfc5ac42aed, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA512ROUND1(35, 0x53380d139d95b3df, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA512ROUND1(36, 0x650a73548baf63de, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA512ROUND1(37, 0x766a0abb3c77b2a8, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA512ROUND1(38, 0x81c2c92e47edaee6, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA512ROUND1(39, 0x92722c851482353b, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA512ROUND1(40, 0xa2bfe8a14cf10364, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA512ROUND1(41, 0xa81a664bbc423001, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA512ROUND1(42, 0xc24b8b70d0f89791, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA512ROUND1(43, 0xc76c51a30654be30, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA512ROUND1(44, 0xd192e819d6ef5218, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA512ROUND1(45, 0xd69906245565a910, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA512ROUND1(46, 0xf40e35855771202a, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA512ROUND1(47, 0x106aa07032bbd1b8, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA512ROUND1(48, 0x19a4c116b8d2d0c8, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA512ROUND1(49, 0x1e376c085141ab53, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA512ROUND1(50, 0x2748774cdf8eeb99, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA512ROUND1(51, 0x34b0bcb5e19b48a8, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA512ROUND1(52, 0x391c0cb3c5c95a63, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA512ROUND1(53, 0x4ed8aa4ae3418acb, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA512ROUND1(54, 0x5b9cca4f7763e373, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA512ROUND1(55, 0x682e6ff3d6b2b8a3, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA512ROUND1(56, 0x748f82ee5defb2fc, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA512ROUND1(57, 0x78a5636f43172f60, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA512ROUND1(58, 0x84c87814a1f0ab72, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA512ROUND1(59, 0x8cc702081a6439ec, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA512ROUND1(60, 0x90befffa23631e28, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA512ROUND1(61, 0xa4506cebde82bde9, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA512ROUND1(62, 0xbef9a3f7b2c67915, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA512ROUND1(63, 0xc67178f2e372532b, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA512ROUND1(64, 0xca273eceea26619c, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA512ROUND1(65, 0xd186b8c721c0c207, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA512ROUND1(66, 0xeada7dd6cde0eb1e, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA512ROUND1(67, 0xf57d4f7fee6ed178, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA512ROUND1(68, 0x06f067aa72176fba, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA512ROUND1(69, 0x0a637dc5a2c898a6, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA512ROUND1(70, 0x113f9804bef90dae, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA512ROUND1(71, 0x1b710b35131c471b, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA512ROUND1(72, 0x28db77f523047d84, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA512ROUND1(73, 0x32caab7b40c72493, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA512ROUND1(74, 0x3c9ebe0a15c9bebc, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA512ROUND1(75, 0x431d67c49c100d4c, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA512ROUND1(76, 0x4cc5d4becb3e42b6, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA512ROUND1(77, 0x597f299cfc657e2a, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA512ROUND1(78, 0x5fcb6fab3ad6faec, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA512ROUND1(79, 0x6c44198c4a475817, R9, R10, R11, R12, R13, R14, R15, R8)
+
+ MOVQ dig+0(FP), BP
+ ADDQ (0*8)(BP), R8 // H0 = a + H0
+ MOVQ R8, (0*8)(BP)
+ ADDQ (1*8)(BP), R9 // H1 = b + H1
+ MOVQ R9, (1*8)(BP)
+ ADDQ (2*8)(BP), R10 // H2 = c + H2
+ MOVQ R10, (2*8)(BP)
+ ADDQ (3*8)(BP), R11 // H3 = d + H3
+ MOVQ R11, (3*8)(BP)
+ ADDQ (4*8)(BP), R12 // H4 = e + H4
+ MOVQ R12, (4*8)(BP)
+ ADDQ (5*8)(BP), R13 // H5 = f + H5
+ MOVQ R13, (5*8)(BP)
+ ADDQ (6*8)(BP), R14 // H6 = g + H6
+ MOVQ R14, (6*8)(BP)
+ ADDQ (7*8)(BP), R15 // H7 = h + H7
+ MOVQ R15, (7*8)(BP)
+
+ ADDQ $128, SI
+ CMPQ SI, 640(SP)
+ JB loop
+
+end:
+ RET
diff --git a/src/pkg/crypto/sha512/sha512block_decl.go b/src/pkg/crypto/sha512/sha512block_decl.go
new file mode 100644
index 000000000..bef99de2e
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/subtle/constant_time.go b/src/pkg/crypto/subtle/constant_time.go
index dfb658465..de1a4e8c5 100644
--- a/src/pkg/crypto/subtle/constant_time.go
+++ b/src/pkg/crypto/subtle/constant_time.go
@@ -10,6 +10,10 @@ package subtle
// 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) {
+ panic("subtle: slices have different lengths")
+ }
+
var v byte
for i := 0; i < len(x); i++ {
diff --git a/src/pkg/crypto/tls/common.go b/src/pkg/crypto/tls/common.go
index b7229d29f..fca98bdd1 100644
--- a/src/pkg/crypto/tls/common.go
+++ b/src/pkg/crypto/tls/common.go
@@ -5,9 +5,11 @@
package tls
import (
+ "container/list"
"crypto"
"crypto/rand"
"crypto/x509"
+ "fmt"
"io"
"math/big"
"strings"
@@ -64,7 +66,7 @@ const (
)
// TLS extension numbers
-var (
+const (
extensionServerName uint16 = 0
extensionStatusRequest uint16 = 5
extensionSupportedCurves uint16 = 10
@@ -72,19 +74,27 @@ var (
extensionSignatureAlgorithms uint16 = 13
extensionSessionTicket uint16 = 35
extensionNextProtoNeg uint16 = 13172 // not IANA assigned
+ extensionRenegotiationInfo uint16 = 0xff01
+)
+
+// TLS signaling cipher suite values
+const (
+ scsvRenegotiation uint16 = 0x00ff
)
-// TLS Elliptic Curves
+// 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 +155,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, ...)
@@ -167,12 +178,38 @@ 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)
+}
+
+// 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.
@@ -200,8 +237,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 +283,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 +296,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 +359,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) {
@@ -406,6 +462,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 +562,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/src/pkg/crypto/tls/conn.go b/src/pkg/crypto/tls/conn.go
index 2e64b88a6..8f7d2c144 100644
--- a/src/pkg/crypto/tls/conn.go
+++ b/src/pkg/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
@@ -44,9 +46,6 @@ type Conn struct {
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 +55,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 +82,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 +93,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 +108,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 +451,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 +512,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 +541,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 +553,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 +576,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 +585,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 +594,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 +623,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 +649,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 +657,7 @@ Again:
if b != nil {
c.in.freeBlock(b)
}
- return c.error()
+ return c.in.err
}
// sendAlert sends a TLS alert message.
@@ -673,7 +673,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 +759,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 +770,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 +781,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 +798,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 +823,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 +832,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 +868,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 +884,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 +897,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 +913,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 +963,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 +986,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
@@ -988,10 +1015,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/src/pkg/crypto/tls/example_test.go b/src/pkg/crypto/tls/example_test.go
new file mode 100644
index 000000000..7628e431b
--- /dev/null
+++ b/src/pkg/crypto/tls/example_test.go
@@ -0,0 +1,57 @@
+// 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 tls_test
+
+import (
+ "crypto/tls"
+ "crypto/x509"
+)
+
+func ExampleDial() {
+ // Connecting with a custom root-certificate set.
+
+ const rootPEM = `
+-----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-----`
+
+ // First, create the set of root certificates. For this example we only
+ // have one. It's also possible to omit this in order to use the
+ // default root set of the current operating system.
+ roots := x509.NewCertPool()
+ ok := roots.AppendCertsFromPEM([]byte(rootPEM))
+ if !ok {
+ panic("failed to parse root certificate")
+ }
+
+ conn, err := tls.Dial("tcp", "mail.google.com:443", &tls.Config{
+ RootCAs: roots,
+ })
+ if err != nil {
+ panic("failed to connect: " + err.Error())
+ }
+ conn.Close()
+}
diff --git a/src/pkg/crypto/tls/generate_cert.go b/src/pkg/crypto/tls/generate_cert.go
index b417ea464..5c6d8396d 100644
--- a/src/pkg/crypto/tls/generate_cert.go
+++ b/src/pkg/crypto/tls/generate_cert.go
@@ -43,7 +43,6 @@ func main() {
priv, err := rsa.GenerateKey(rand.Reader, *rsaBits)
if err != nil {
log.Fatalf("failed to generate private key: %s", err)
- return
}
var notBefore time.Time
@@ -59,14 +58,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"},
},
@@ -95,13 +94,11 @@ func main() {
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, 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()
diff --git a/src/pkg/crypto/tls/handshake_client.go b/src/pkg/crypto/tls/handshake_client.go
index 85e4adefc..a320fde1b 100644
--- a/src/pkg/crypto/tls/handshake_client.go
+++ b/src/pkg/crypto/tls/handshake_client.go
@@ -12,24 +12,41 @@ import (
"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")
+ }
+
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,
}
possibleCipherSuites := c.config.cipherSuites()
@@ -51,21 +68,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 +131,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(); err != nil {
+ return err
+ }
+ if err := hs.sendFinished(); 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(); err != nil {
+ return err
+ }
+ if err := hs.readSessionTicket(); err != nil {
+ return err
+ }
+ if err := hs.readFinished(); 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 +257,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 +285,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 +319,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 {
@@ -271,9 +382,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 +395,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())
}
@@ -305,7 +417,7 @@ NextCipherSuite:
switch key := c.config.Certificates[0].PrivateKey.(type) {
case *ecdsa.PrivateKey:
- digest, _, hashId := finishedHash.hashForClientCertificate(signatureECDSA)
+ digest, _, hashId := hs.finishedHash.hashForClientCertificate(signatureECDSA)
r, s, err := ecdsa.Sign(c.config.rand(), key, digest)
if err == nil {
signed, err = asn1.Marshal(ecdsaSignature{r, s})
@@ -313,7 +425,7 @@ NextCipherSuite:
certVerify.signatureAndHash.signature = signatureECDSA
certVerify.signatureAndHash.hash = hashId
case *rsa.PrivateKey:
- digest, hashFunc, hashId := finishedHash.hashForClientCertificate(signatureRSA)
+ digest, hashFunc, hashId := hs.finishedHash.hashForClientCertificate(signatureRSA)
signed, err = rsa.SignPKCS1v15(c.config.rand(), key, hashFunc, digest)
certVerify.signatureAndHash.signature = signatureRSA
certVerify.signatureAndHash.hash = hashId
@@ -321,79 +433,157 @@ NextCipherSuite:
err = errors.New("unknown private key type")
}
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
+}
+
+func (hs *clientHandshakeState) establishKeys() error {
+ c := hs.c
- 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)
+ 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())
+ if !hs.hello.nextProtoNeg && hs.serverHello.nextProtoNeg {
+ c.sendAlert(alertHandshakeFailure)
+ return false, errors.New("server advertised unrequested NPN extension")
+ }
- 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 hs.serverResumedSession() {
+ // Restore masterSecret and peerCerts from previous state
+ hs.masterSecret = hs.session.masterSecret
+ c.peerCertificates = hs.session.serverCertificates
+ return true, nil
}
- c.in.prepareCipherSpec(c.vers, serverCipher, serverHash)
+ return false, nil
+}
+
+func (hs *clientHandshakeState) readFinished() 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())
+ 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
}
+func (hs *clientHandshakeState) sendFinished() 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())
+ 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 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
diff --git a/src/pkg/crypto/tls/handshake_client_test.go b/src/pkg/crypto/tls/handshake_client_test.go
index 6c564001b..0d73c8e2f 100644
--- a/src/pkg/crypto/tls/handshake_client_test.go
+++ b/src/pkg/crypto/tls/handshake_client_test.go
@@ -6,3045 +6,434 @@ 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)
- if err != nil {
- t.Fatalf("%s #%d: %s", name, i, err)
- }
- if !bytes.Equal(b, bb) {
- t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", name, i, bb, b)
- }
- }
-}
-
-func TestHandshakeClientRSARC4(t *testing.T) {
- var config = *testConfig
- config.CipherSuites = []uint16{TLS_RSA_WITH_RC4_128_SHA}
- testClientScript(t, "RSA-RC4", rsaRC4ClientScript, &config)
-}
+// blockingSource is an io.Reader that blocks a Read call until it's closed.
+type blockingSource chan bool
-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 (b blockingSource) Read([]byte) (n int, err error) {
+ <-b
+ return 0, io.EOF
}
-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)
+// 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{}
}
-func TestLongClientCerticiateChain(t *testing.T) {
- config := *testConfig
- cert, _ := X509KeyPair(testClientChainCertificate, testClientChainCertificate)
- config.Certificates = []Certificate{cert}
- testClientScript(t, "Long client certificate chains", clientChainCertificateScript, &config)
-}
+var defaultServerCommand = []string{"openssl", "s_server"}
-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)
-}
+// 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)
-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)
-}
+ 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 {
+ panic(err)
+ }
+ default:
+ panic("unknown key type")
+ }
-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)
-}
+ var pemOut bytes.Buffer
+ pem.Encode(&pemOut, &pem.Block{Type: pemType + " PRIVATE KEY", Bytes: derBytes})
-var connect = flag.Bool("connect", false, "connect to a TLS server on :10443")
+ keyPath := tempFile(string(pemOut.Bytes()))
+ defer os.Remove(keyPath)
-func TestRunClient(t *testing.T) {
- if !*connect {
- return
+ 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
}
- tcpConn, err := net.Dial("tcp", "127.0.0.1:10443")
- if err != nil {
- t.Fatal(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,
}
- config := GetTestConfig()
- conn := Client(record, config)
- if err := conn.Handshake(); err != nil {
- t.Fatalf("error from TLS handshake: %s", err)
- }
-
- conn.Write([]byte("hello\n"))
- conn.Close()
+ return record, cmd, stdin, nil
+}
- record.WriteTo(os.Stdout)
+func (test *clientTest) dataPath() string {
+ return filepath.Join("testdata", "Client-"+test.name)
}
-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.
- config := *testConfig
- config.CipherSuites = []uint16{TLS_RSA_WITH_AES_256_CBC_SHA}
+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)
+}
- 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()
+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("error reading from tls.Client: %s", err)
+ t.Fatalf("Failed to start subcommand: %s", err)
}
- const expectedLength = 197
- if n != expectedLength {
- t.Fatalf("incorrect length reading from tls.Client, got %d, want %d", n, expectedLength)
+ 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)
}
+ client.Close()
+ clientConn.Close()
+ doneChan <- true
}()
- defer c.Close()
- for i, b := range emptyRecordScript {
- if i%2 == 1 {
- s.Write(b)
- continue
+ if !write {
+ flows, err := test.loadData()
+ if err != nil {
+ t.Fatalf("%s: failed to load data from %s", test.name, test.dataPath())
+ }
+ 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)
+ }
}
- bb := make([]byte, len(b))
- _, err := io.ReadFull(s, bb)
+ 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("#%d: %s", i, err)
+ t.Fatalf("Failed to create output file: %s", err)
}
- if !bytes.Equal(b, bb) {
- t.Fatalf("#%d: mismatch on read: got:%x want:%x", i, bb, b)
+ 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)
}
}
-// 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,
- },
+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)
+}
- {
- 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,
- },
+func runClientTestTLS10(t *testing.T, template *clientTest) {
+ runClientTestForVersion(t, template, "TLSv10-", "-tls1")
+}
- {
- 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,
- },
+func runClientTestTLS11(t *testing.T, template *clientTest) {
+ runClientTestForVersion(t, template, "TLSv11-", "-tls1_1")
+}
- {
- 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,
- },
+func runClientTestTLS12(t *testing.T, template *clientTest) {
+ runClientTestForVersion(t, template, "TLSv12-", "-tls1_2")
}
-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 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)
}
-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,
- },
+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)
}
-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,
- },
+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)
}
-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,
- },
+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)
}
-// $ 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,
- },
+func TestHandshakeClientCertRSA(t *testing.T) {
+ config := *testConfig
+ cert, _ := X509KeyPair([]byte(clientCertificatePEM), []byte(clientKeyPEM))
+ config.Certificates = []Certificate{cert}
+
+ test := &clientTest{
+ name: "ClientCert-RSA-RSA",
+ command: []string{"openssl", "s_server", "-cipher", "RC4-SHA", "-verify", "1"},
+ config: &config,
+ }
+
+ 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,
+ }
+
+ runClientTestTLS10(t, test)
+ runClientTestTLS12(t, test)
}
-// $ 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,
- },
+func TestHandshakeClientCertECDSA(t *testing.T) {
+ config := *testConfig
+ cert, _ := X509KeyPair([]byte(clientECDSACertificatePEM), []byte(clientECDSAKeyPEM))
+ config.Certificates = []Certificate{cert}
+
+ test := &clientTest{
+ name: "ClientCert-ECDSA-RSA",
+ command: []string{"openssl", "s_server", "-cipher", "RC4-SHA", "-verify", "1"},
+ config: &config,
+ }
+
+ runClientTestTLS10(t, test)
+ runClientTestTLS12(t, test)
+
+ 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)
}
-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 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),
+ }
-// 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,
- },
+ testResumeState := func(test string, didResume bool) {
+ hs, err := testHandshake(clientConfig, serverConfig)
+ if err != nil {
+ t.Fatalf("%s: handshake failed: %s", test, err)
+ }
+ if hs.DidResume != didResume {
+ t.Fatalf("%s resumed: %v, expected: %v", test, hs.DidResume, didResume)
+ }
+ }
+
+ testResumeState("Handshake", false)
+ testResumeState("Resume", true)
+
+ if _, err := io.ReadFull(serverConfig.rand(), serverConfig.SessionTicketKey[:]); err != nil {
+ t.Fatalf("Failed to invalidate SessionTicketKey")
+ }
+ testResumeState("InvalidSessionTicketKey", false)
+ testResumeState("ResumeAfterInvalidSessionTicketKey", true)
+
+ clientConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA}
+ testResumeState("DifferentCipherSuite", false)
+ testResumeState("DifferentCipherSuiteRecovers", true)
+
+ clientConfig.ClientSessionCache = nil
+ testResumeState("WithoutSessionCache", false)
+}
+
+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"}
+
+ // 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])
+ }
+ }
+
+ // 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])
+ }
+ }
+
+ // 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")
+ }
+
+ // 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")
+ }
+
+ // 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")
+ }
}
diff --git a/src/pkg/crypto/tls/handshake_messages.go b/src/pkg/crypto/tls/handshake_messages.go
index 83952000f..7bcaa5eb9 100644
--- a/src/pkg/crypto/tls/handshake_messages.go
+++ b/src/pkg/crypto/tls/handshake_messages.go
@@ -7,20 +7,21 @@ 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
}
func (m *clientHelloMsg) equal(i interface{}) bool {
@@ -38,11 +39,12 @@ 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
}
func (m *clientHelloMsg) marshal() []byte {
@@ -80,6 +82,10 @@ func (m *clientHelloMsg) marshal() []byte {
extensionsLength += 2 + 2*len(m.signatureAndHashes)
numExtensions++
}
+ if m.secureRenegotiation {
+ extensionsLength += 1
+ numExtensions++
+ }
if numExtensions > 0 {
extensionsLength += 4 * numExtensions
length += 2 + extensionsLength
@@ -114,13 +120,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 +230,13 @@ 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:]
+ }
m.raw = x
@@ -256,6 +269,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 {
@@ -341,10 +357,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 +395,11 @@ 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
}
data = data[length:]
}
@@ -387,16 +408,17 @@ 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
}
func (m *serverHelloMsg) equal(i interface{}) bool {
@@ -414,7 +436,8 @@ 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
}
func (m *serverHelloMsg) marshal() []byte {
@@ -441,6 +464,10 @@ func (m *serverHelloMsg) marshal() []byte {
if m.ticketSupported {
numExtensions++
}
+ if m.secureRenegotiation {
+ extensionsLength += 1
+ numExtensions++
+ }
if numExtensions > 0 {
extensionsLength += 4 * numExtensions
length += 2 + extensionsLength
@@ -469,7 +496,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 +521,13 @@ 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:]
+ }
m.raw = x
@@ -573,6 +607,11 @@ 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
}
data = data[length:]
}
@@ -1255,6 +1294,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/src/pkg/crypto/tls/handshake_messages_test.go b/src/pkg/crypto/tls/handshake_messages_test.go
index 4f569eeb1..f46aabdfd 100644
--- a/src/pkg/crypto/tls/handshake_messages_test.go
+++ b/src/pkg/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
diff --git a/src/pkg/crypto/tls/handshake_server.go b/src/pkg/crypto/tls/handshake_server.go
index c9ccf675c..75111eba0 100644
--- a/src/pkg/crypto/tls/handshake_server.go
+++ b/src/pkg/crypto/tls/handshake_server.go
@@ -12,6 +12,7 @@ import (
"crypto/x509"
"encoding/asn1"
"errors"
+ "fmt"
"io"
)
@@ -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,20 +147,18 @@ 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
@@ -170,7 +173,8 @@ Curves:
}
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 {
@@ -199,7 +203,8 @@ 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")
}
return false, nil
@@ -349,7 +354,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 +382,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 +400,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) {
@@ -462,7 +470,7 @@ func (hs *serverHandshakeState) readFinished() error {
c := hs.c
c.readRecord(recordTypeChangeCipherSpec)
- if err := c.error(); err != nil {
+ if err := c.in.error(); err != nil {
return err
}
@@ -473,7 +481,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,13 +494,15 @@ 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())
@@ -594,7 +605,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/src/pkg/crypto/tls/handshake_server_test.go b/src/pkg/crypto/tls/handshake_server_test.go
index c08eba7f1..c3e36785b 100644
--- a/src/pkg/crypto/tls/handshake_server_test.go
+++ b/src/pkg/crypto/tls/handshake_server_test.go
@@ -12,20 +12,20 @@ import (
"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 +39,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 +69,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 +92,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 +101,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 +121,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 +178,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 +191,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 +241,327 @@ 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
- }()
-
- for i, b := range serverScript {
- if i%2 == 0 {
- c.Write(b)
- continue
- }
- bb := make([]byte, len(b))
- n, err := io.ReadFull(c, bb)
- 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)
- }
- 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))
- }
+// 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
+}
+
+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()
-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)
-}
-
-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)
-}
+ port := l.Addr().(*net.TCPAddr).Port
-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 TestHandshakeServerSSLv3(t *testing.T) {
- testServerScript(t, "SSLv3", sslv3ServerScript, testConfig, nil)
-}
-
-// 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 TestResumption(t *testing.T) {
- testServerScript(t, "IssueTicket", issueSessionTicketTest, testConfig, nil)
- testServerScript(t, "Resume", serverResumeTest, testConfig, nil)
-}
-
-func TestTLS12ClientCertServer(t *testing.T) {
- config := *testConfig
- config.MaxVersion = VersionTLS12
- config.ClientAuth = RequireAnyClientCert
- config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA}
-
- testServerScript(t, "TLS12", tls12ServerScript, &config, nil)
-}
-
-type clientauthTest struct {
- name string
- clientauth ClientAuthType
- peers []*x509.Certificate
- script [][]byte
-}
-
-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)
+ var command []string
+ command = append(command, test.command...)
+ if len(command) == 0 {
+ command = defaultClientCommand
}
-}
-
-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)
+ 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
}
-}
-// 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)
+ connChan := make(chan interface{})
+ go func() {
+ tcpConn, err := l.Accept()
+ if err != nil {
+ connChan <- err
+ }
+ connChan <- tcpConn
+ }()
- 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,
- },
+ 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")
}
- config.BuildNameToCertificate()
- config.PreferServerCipherSuites = true
- testServerScript(t, "CipherSuiteCertPreference2", ecdheECDSAAESServerScript, &config, nil)
-}
-
-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 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)
-}
-// 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 (r *recordingConn) Read(b []byte) (n int, err error) {
- if n, err = r.Conn.Read(b); n == 0 {
- return
+ record := &recordingConn{
+ Conn: tcpConn,
}
- b = b[:n]
-
- r.lock.Lock()
- defer r.lock.Unlock()
- 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]...)
- }
- r.currentlyReading = true
- return
+ return record, cmd, nil
}
-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.Lock()
- defer r.lock.Unlock()
-
- 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]...)
- }
- r.currentlyReading = false
- return
+func (test *serverTest) dataPath() string {
+ return filepath.Join("testdata", "Server-"+test.name)
}
-// 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")
- }
- fmt.Fprintf(w, "0x%02x, ", b)
- }
- fmt.Fprintf(w, "\n\t},\n")
+func (test *serverTest) loadData() (flows [][]byte, err error) {
+ in, err := os.Open(test.dataPath())
+ if err != nil {
+ return nil, err
}
- fmt.Fprintf(w, "}\n")
+ defer in.Close()
+ return parseTestData(in)
}
-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)
- }
- config.MaxVersion = uint16(maxVersion)
+func (test *serverTest) run(t *testing.T, write bool) {
+ var clientConn, serverConn net.Conn
+ var recordingConn *recordingConn
+ var childProcess *exec.Cmd
- suites := strings.Split(*testCipherSuites, ",")
- config.CipherSuites = make([]uint16, len(suites))
- for i := range suites {
- suite, err := strconv.ParseUint(suites[i], 0, 64)
+ if write {
+ var err error
+ recordingConn, childProcess, err = test.connFromCommand()
if err != nil {
- panic(err)
+ t.Fatalf("Failed to start subcommand: %s", err)
}
- config.CipherSuites[i] = uint16(suite)
+ serverConn = recordingConn
+ } else {
+ clientConn, serverConn = net.Pipe()
}
-
- 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
- }
+ config := test.config
+ if config == nil {
+ config = testConfig
}
- if ecdsa {
- config.Certificates = nil
- if !*connect {
- config.Certificates = make([]Certificate, 1)
- config.Certificates[0].Certificate = [][]byte{testECDSACertificate}
- config.Certificates[0].PrivateKey = testECDSAPrivateKey
+ server := Server(serverConn, config)
+ peerCertsChan := make(chan []*x509.Certificate, 1)
+ go func() {
+ if _, err := server.Write([]byte("hello, world\n")); err != nil {
+ t.Logf("Error from Server.Write: %s", err)
}
- config.BuildNameToCertificate()
- }
-
- config.ClientAuth = ClientAuthType(*testClientAuth)
- return &config
-}
-
-func TestRunServer(t *testing.T) {
- if !*serve {
- return
- }
-
- config := GetTestConfig()
-
- const addr = ":10443"
- l, err := net.Listen("tcp", addr)
- if err != nil {
- t.Fatal(err)
- }
- log.Printf("Now listening for connections on %s", addr)
+ server.Close()
+ serverConn.Close()
+ peerCertsChan <- server.ConnectionState().PeerCertificates
+ }()
- for {
- tcpConn, err := l.Accept()
+ if !write {
+ flows, err := test.loadData()
if err != nil {
- log.Printf("error accepting connection: %s", err)
- break
+ t.Fatalf("%s: failed to load data from %s", test.name, test.dataPath())
}
-
- record := &recordingConn{
- Conn: tcpConn,
+ 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 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()
+ }
- conn := Server(record, config)
- if err := conn.Handshake(); err != nil {
- log.Printf("error from TLS handshake: %s", err)
- break
+ peerCerts := <-peerCertsChan
+ 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))
+ }
- _, err = conn.Write([]byte("hello, world\n"))
+ if write {
+ path := test.dataPath()
+ out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
- log.Printf("error from Write: %s", err)
- continue
+ t.Fatalf("Failed to create output file: %s", err)
}
-
- conn.Close()
-
- record.WriteTo(os.Stdout)
+ defer out.Close()
+ recordingConn.Close()
+ if len(recordingConn.flows) < 3 {
+ childProcess.Stdout.(*bytes.Buffer).WriteTo(os.Stdout)
+ t.Fatalf("Handshake failed")
+ }
+ recordingConn.WriteTo(out)
+ fmt.Printf("Wrote %s\n", path)
+ childProcess.Wait()
}
}
-func bigFromString(s string) *big.Int {
- ret := new(big.Int)
- ret.SetString(s, 10)
- return ret
+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)
}
-func fromHex(s string) []byte {
- b, _ := hex.DecodeString(s)
- return b
+func runServerTestSSLv3(t *testing.T, template *serverTest) {
+ runServerTestForVersion(t, template, "SSLv3-", "-ssl3")
}
-var testRSACertificate = fromHex("308202b030820219a00302010202090085b0bba48a7fb8ca300d06092a864886f70d01010505003045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3130303432343039303933385a170d3131303432343039303933385a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819f300d06092a864886f70d010101050003818d0030818902818100bb79d6f517b5e5bf4610d0dc69bee62b07435ad0032d8a7a4385b71452e7a5654c2c78b8238cb5b482e5de1f953b7e62a52ca533d6fe125c7a56fcf506bffa587b263fb5cd04d3d0c921964ac7f4549f5abfef427100fe1899077f7e887d7df10439c4a22edb51c97ce3c04c3b326601cfafb11db8719a1ddbdb896baeda2d790203010001a381a73081a4301d0603551d0e04160414b1ade2855acfcb28db69ce2369ded3268e18883930750603551d23046e306c8014b1ade2855acfcb28db69ce2369ded3268e188839a149a4473045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746482090085b0bba48a7fb8ca300c0603551d13040530030101ff300d06092a864886f70d010105050003818100086c4524c76bb159ab0c52ccf2b014d7879d7a6475b55a9566e4c52b8eae12661feb4f38b36e60d392fdf74108b52513b1187a24fb301dbaed98b917ece7d73159db95d31d78ea50565cd5825a2d5a5f33c4b6d8c97590968c0f5298b5cd981f89205ff2a01ca31b9694dda9fd57e970e8266d71999b266e3850296c90a7bdd9")
-
-var testECDSACertificate = fromHex("3082020030820162020900b8bf2d47a0d2ebf4300906072a8648ce3d04013045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3132313132323135303633325a170d3232313132303135303633325a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819b301006072a8648ce3d020106052b81040023038186000400c4a1edbe98f90b4873367ec316561122f23d53c33b4d213dcd6b75e6f6b0dc9adf26c1bcb287f072327cb3642f1c90bcea6823107efee325c0483a69e0286dd33700ef0462dd0da09c706283d881d36431aa9e9731bd96b068c09b23de76643f1a5c7fe9120e5858b65f70dd9bd8ead5d7f5d5ccb9b69f30665b669a20e227e5bffe3b300906072a8648ce3d040103818c0030818802420188a24febe245c5487d1bacf5ed989dae4770c05e1bb62fbdf1b64db76140d311a2ceee0b7e927eff769dc33b7ea53fcefa10e259ec472d7cacda4e970e15a06fd00242014dfcbe67139c2d050ebd3fa38c25c13313830d9406bbd4377af6ec7ac9862eddd711697f857c56defb31782be4c7780daecbbe9e4e3624317b6a0f399512078f2a")
-
-var testSNICertificate = fromHex("308201f23082015da003020102020100300b06092a864886f70d01010530283110300e060355040a130741636d6520436f311430120603550403130b736e69746573742e636f6d301e170d3132303431313137343033355a170d3133303431313137343533355a30283110300e060355040a130741636d6520436f311430120603550403130b736e69746573742e636f6d30819d300b06092a864886f70d01010103818d0030818902818100bb79d6f517b5e5bf4610d0dc69bee62b07435ad0032d8a7a4385b71452e7a5654c2c78b8238cb5b482e5de1f953b7e62a52ca533d6fe125c7a56fcf506bffa587b263fb5cd04d3d0c921964ac7f4549f5abfef427100fe1899077f7e887d7df10439c4a22edb51c97ce3c04c3b326601cfafb11db8719a1ddbdb896baeda2d790203010001a3323030300e0603551d0f0101ff0404030200a0300d0603551d0e0406040401020304300f0603551d2304083006800401020304300b06092a864886f70d0101050381810089c6455f1c1f5ef8eb1ab174ee2439059f5c4259bb1a8d86cdb1d056f56a717da40e95ab90f59e8deaf627c157995094db0802266eb34fc6842dea8a4b68d9c1389103ab84fb9e1f85d9b5d23ff2312c8670fbb540148245a4ebafe264d90c8a4cf4f85b0fac12ac2fc4a3154bad52462868af96c62c6525d652b6e31845bdcc")
+func runServerTestTLS10(t *testing.T, template *serverTest) {
+ runServerTestForVersion(t, template, "TLSv10-", "-tls1")
+}
-var testRSAPrivateKey = &rsa.PrivateKey{
- PublicKey: rsa.PublicKey{
- N: bigFromString("131650079503776001033793877885499001334664249354723305978524647182322416328664556247316495448366990052837680518067798333412266673813370895702118944398081598789828837447552603077848001020611640547221687072142537202428102790818451901395596882588063427854225330436740647715202971973145151161964464812406232198521"),
- E: 65537,
- },
- D: bigFromString("29354450337804273969007277378287027274721892607543397931919078829901848876371746653677097639302788129485893852488285045793268732234230875671682624082413996177431586734171663258657462237320300610850244186316880055243099640544518318093544057213190320837094958164973959123058337475052510833916491060913053867729"),
- Primes: []*big.Int{
- bigFromString("11969277782311800166562047708379380720136961987713178380670422671426759650127150688426177829077494755200794297055316163155755835813760102405344560929062149"),
- bigFromString("10998999429884441391899182616418192492905073053684657075974935218461686523870125521822756579792315215543092255516093840728890783887287417039645833477273829"),
- },
+func runServerTestTLS11(t *testing.T, template *serverTest) {
+ runServerTestForVersion(t, template, "TLSv11-", "-tls1_1")
}
-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,
- },
- X: bigFromString("2636411247892461147287360222306590634450676461695221912739908880441342231985950069527906976759812296359387337367668045707086543273113073382714101597903639351"),
- Y: bigFromString("3204695818431246682253994090650952614555094516658732116404513121125038617915183037601737180082382202488628239201196033284060130040574800684774115478859677243"),
- },
- D: bigFromString("5477294338614160138026852784385529180817726002953041720191098180813046231640184669647735805135001309477695746518160084669446643325196003346204701381388769751"),
+func runServerTestTLS12(t *testing.T, template *serverTest) {
+ runServerTestForVersion(t, template, "TLSv12-", "-tls1_2")
}
-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")
+func TestHandshakeServerRSARC4(t *testing.T) {
+ test := &serverTest{
+ name: "RSA-RC4",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "RC4-SHA"},
}
- panic("error parsing PEM")
+ runServerTestSSLv3(t, test)
+ runServerTestTLS10(t, test)
+ runServerTestTLS11(t, test)
+ runServerTestTLS12(t, test)
}
-// 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,
- },
+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)
}
-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 TestHandshakeServerRSAAES(t *testing.T) {
+ test := &serverTest{
+ name: "RSA-AES",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA"},
+ }
+ runServerTestSSLv3(t, test)
+ runServerTestTLS10(t, test)
+ runServerTestTLS12(t, test)
}
-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,
- },
+func TestHandshakeServerAESGCM(t *testing.T) {
+ test := &serverTest{
+ name: "RSA-AES-GCM",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-RSA-AES128-GCM-SHA256"},
+ }
+ 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,
- },
-}
+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()
-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,
- },
+ test := &serverTest{
+ name: "ECDHE-ECDSA-AES",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-ECDSA-AES256-SHA"},
+ config: &config,
+ }
+ runServerTestTLS10(t, test)
+ runServerTestTLS12(t, test)
}
-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,
- },
+// 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)
}
-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,
- },
-}
+// 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 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,
- },
- }},
-
- // 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: "CipherSuiteCertPreferenceRSA",
+ config: &config,
+ }
+ runServerTestTLS12(t, test)
+
+ 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
-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,
- },
+ test = &serverTest{
+ name: "CipherSuiteCertPreferenceECDSA",
+ config: &config,
+ }
+ runServerTestTLS12(t, test)
}
-// $ 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 TestResumption(t *testing.T) {
+ sessionFilePath := tempFile("")
+ defer os.Remove(sessionFilePath)
+
+ test := &serverTest{
+ name: "IssueTicket",
+ command: []string{"openssl", "s_client", "-cipher", "RC4-SHA", "-sess_out", sessionFilePath},
+ }
+ runServerTestTLS12(t, test)
+
+ test = &serverTest{
+ name: "Resume",
+ command: []string{"openssl", "s_client", "-cipher", "RC4-SHA", "-sess_in", sessionFilePath},
+ }
+ runServerTestTLS12(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 +574,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 +591,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 +606,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 +618,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/src/pkg/crypto/tls/handshake_test.go b/src/pkg/crypto/tls/handshake_test.go
new file mode 100644
index 000000000..f95f274ab
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/key_agreement.go b/src/pkg/crypto/tls/key_agreement.go
index 7e820c1e7..f38b701f1 100644
--- a/src/pkg/crypto/tls/key_agreement.go
+++ b/src/pkg/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,11 @@ 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
}
x, _ = ka.curve.ScalarMult(x, y, ka.privateKey)
preMasterSecret := make([]byte, (ka.curve.Params().BitSize+7)>>3)
@@ -285,26 +300,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])
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA b/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA
new file mode 100644
index 000000000..00722cba9
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA b/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA
new file mode 100644
index 000000000..c0be82491
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA b/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA
new file mode 100644
index 000000000..3e6dbc271
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA b/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA
new file mode 100644
index 000000000..94e686004
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES b/src/pkg/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES
new file mode 100644
index 000000000..30c4c6b83
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES b/src/pkg/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES
new file mode 100644
index 000000000..868f0ceb0
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Client-TLSv10-RSA-RC4 b/src/pkg/crypto/tls/testdata/Client-TLSv10-RSA-RC4
new file mode 100644
index 000000000..395d53bba
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES b/src/pkg/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES
new file mode 100644
index 000000000..9f941f8ef
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES b/src/pkg/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES
new file mode 100644
index 000000000..fc723396a
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Client-TLSv11-RSA-RC4 b/src/pkg/crypto/tls/testdata/Client-TLSv11-RSA-RC4
new file mode 100644
index 000000000..f7be3f7e9
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA b/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA
new file mode 100644
index 000000000..207327036
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA b/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA
new file mode 100644
index 000000000..c3b753a7b
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA b/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA
new file mode 100644
index 000000000..0037af61a
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA b/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA
new file mode 100644
index 000000000..df3eaa440
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES b/src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES
new file mode 100644
index 000000000..76445903b
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM b/src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM
new file mode 100644
index 000000000..fb5af17f0
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES b/src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES
new file mode 100644
index 000000000..5336bbbad
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Client-TLSv12-RSA-RC4 b/src/pkg/crypto/tls/testdata/Client-TLSv12-RSA-RC4
new file mode 100644
index 000000000..0377f052a
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-3DES b/src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-3DES
new file mode 100644
index 000000000..a6c7a4196
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-AES b/src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-AES
new file mode 100644
index 000000000..4885b267d
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-RC4 b/src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-RC4
new file mode 100644
index 000000000..1314b659b
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES b/src/pkg/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES
new file mode 100644
index 000000000..9b8cb4d9b
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-3DES b/src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-3DES
new file mode 100644
index 000000000..c0e6241c0
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-AES b/src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-AES
new file mode 100644
index 000000000..1670997b0
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-RC4 b/src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-RC4
new file mode 100644
index 000000000..d653561f9
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Server-TLSv11-RSA-RC4 b/src/pkg/crypto/tls/testdata/Server-TLSv11-RSA-RC4
new file mode 100644
index 000000000..9237db078
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA b/src/pkg/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA
new file mode 100644
index 000000000..0ab8b8d74
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA b/src/pkg/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA
new file mode 100644
index 000000000..88abb15a7
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven b/src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven
new file mode 100644
index 000000000..547f79834
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven b/src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven
new file mode 100644
index 000000000..04a5b117c
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven b/src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven
new file mode 100644
index 000000000..562fe1aaa
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES b/src/pkg/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES
new file mode 100644
index 000000000..aacbb8670
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Server-TLSv12-IssueTicket b/src/pkg/crypto/tls/testdata/Server-TLSv12-IssueTicket
new file mode 100644
index 000000000..e3e62f224
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-3DES b/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-3DES
new file mode 100644
index 000000000..5995b3314
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-AES b/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-AES
new file mode 100644
index 000000000..a152a96a8
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM b/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM
new file mode 100644
index 000000000..0ddfe022f
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-RC4 b/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-RC4
new file mode 100644
index 000000000..b703a8f76
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Server-TLSv12-Resume b/src/pkg/crypto/tls/testdata/Server-TLSv12-Resume
new file mode 100644
index 000000000..c495d4adc
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/testdata/Server-TLSv12-SNI b/src/pkg/crypto/tls/testdata/Server-TLSv12-SNI
new file mode 100644
index 000000000..61b17a11d
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/tls/tls.go b/src/pkg/crypto/tls/tls.go
index 6c67506fc..d50e12029 100644
--- a/src/pkg/crypto/tls/tls.go
+++ b/src/pkg/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/src/pkg/crypto/tls/tls_test.go b/src/pkg/crypto/tls/tls_test.go
index 38229014c..f8c94ff35 100644
--- a/src/pkg/crypto/tls/tls_test.go
+++ b/src/pkg/crypto/tls/tls_test.go
@@ -5,7 +5,12 @@
package tls
import (
+ "fmt"
+ "io"
+ "net"
+ "strings"
"testing"
+ "time"
)
var rsaCertPEM = `-----BEGIN CERTIFICATE-----
@@ -105,3 +110,128 @@ 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
+}
diff --git a/src/pkg/crypto/x509/example_test.go b/src/pkg/crypto/x509/example_test.go
new file mode 100644
index 000000000..29e7c2139
--- /dev/null
+++ b/src/pkg/crypto/x509/example_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 x509_test
+
+import (
+ "crypto/x509"
+ "encoding/pem"
+)
+
+func ExampleCertificate_Verify() {
+ // Verifying with a custom list of root certificates.
+
+ const rootPEM = `
+-----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 certPEM = `
+-----BEGIN CERTIFICATE-----
+MIIDujCCAqKgAwIBAgIIE31FZVaPXTUwDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE
+BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl
+cm5ldCBBdXRob3JpdHkgRzIwHhcNMTQwMTI5MTMyNzQzWhcNMTQwNTI5MDAwMDAw
+WjBpMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN
+TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEYMBYGA1UEAwwPbWFp
+bC5nb29nbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfRrObuSW5T7q
+5CnSEqefEmtH4CCv6+5EckuriNr1CjfVvqzwfAhopXkLrq45EQm8vkmf7W96XJhC
+7ZM0dYi1/qOCAU8wggFLMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAa
+BgNVHREEEzARgg9tYWlsLmdvb2dsZS5jb20wCwYDVR0PBAQDAgeAMGgGCCsGAQUF
+BwEBBFwwWjArBggrBgEFBQcwAoYfaHR0cDovL3BraS5nb29nbGUuY29tL0dJQUcy
+LmNydDArBggrBgEFBQcwAYYfaHR0cDovL2NsaWVudHMxLmdvb2dsZS5jb20vb2Nz
+cDAdBgNVHQ4EFgQUiJxtimAuTfwb+aUtBn5UYKreKvMwDAYDVR0TAQH/BAIwADAf
+BgNVHSMEGDAWgBRK3QYWG7z2aLV29YG2u2IaulqBLzAXBgNVHSAEEDAOMAwGCisG
+AQQB1nkCBQEwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDovL3BraS5nb29nbGUuY29t
+L0dJQUcyLmNybDANBgkqhkiG9w0BAQUFAAOCAQEAH6RYHxHdcGpMpFE3oxDoFnP+
+gtuBCHan2yE2GRbJ2Cw8Lw0MmuKqHlf9RSeYfd3BXeKkj1qO6TVKwCh+0HdZk283
+TZZyzmEOyclm3UGFYe82P/iDFt+CeQ3NpmBg+GoaVCuWAARJN/KfglbLyyYygcQq
+0SgeDh8dRKUiaW3HQSoYvTvdTuqzwK4CXsr3b5/dAOY8uMuG/IAR3FgwTbZ1dtoW
+RvOTa8hYiU6A475WuZKyEHcwnGYe57u2I2KbMgcKjPniocj4QzgYsVAVKW3IwaOh
+yE+vPxsiUkvQHdO2fojCkY8jg70jxM+gu59tPDNbw3Uh/2Ij310FgTHsnGQMyA==
+-----END CERTIFICATE-----`
+
+ // First, create the set of root certificates. For this example we only
+ // have one. It's also possible to omit this in order to use the
+ // default root set of the current operating system.
+ roots := x509.NewCertPool()
+ ok := roots.AppendCertsFromPEM([]byte(rootPEM))
+ if !ok {
+ panic("failed to parse root certificate")
+ }
+
+ block, _ := pem.Decode([]byte(certPEM))
+ if block == nil {
+ panic("failed to parse certificate PEM")
+ }
+ cert, err := x509.ParseCertificate(block.Bytes)
+ if err != nil {
+ panic("failed to parse certificate: " + err.Error())
+ }
+
+ opts := x509.VerifyOptions{
+ DNSName: "mail.google.com",
+ Roots: roots,
+ }
+
+ if _, err := cert.Verify(opts); err != nil {
+ panic("failed to verify certificate: " + err.Error())
+ }
+}
diff --git a/src/pkg/crypto/x509/pkix/pkix.go b/src/pkg/crypto/x509/pkix/pkix.go
index 5034946f7..58c1e54d1 100644
--- a/src/pkg/crypto/x509/pkix/pkix.go
+++ b/src/pkg/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 {
diff --git a/src/pkg/crypto/x509/root_cgo_darwin.go b/src/pkg/crypto/x509/root_cgo_darwin.go
new file mode 100644
index 000000000..bdcc2c170
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/x509/root_darwin.go b/src/pkg/crypto/x509/root_darwin.go
index ad3bfb4b4..2a61d36ea 100644
--- a/src/pkg/crypto/x509/root_darwin.go
+++ b/src/pkg/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/src/pkg/crypto/x509/root_darwin_test.go b/src/pkg/crypto/x509/root_darwin_test.go
new file mode 100644
index 000000000..87ea4e344
--- /dev/null
+++ b/src/pkg/crypto/x509/root_darwin_test.go
@@ -0,0 +1,50 @@
+package x509
+
+import "testing"
+
+func TestSystemRoots(t *testing.T) {
+ sysRoots := systemRootsPool() // actual system roots
+ execRoots, err := execSecurityRoots() // non-cgo roots
+
+ if err != nil {
+ t.Fatalf("failed to read system roots: %v", err)
+ }
+
+ for _, tt := range []*CertPool{sysRoots, execRoots} {
+ if tt == nil {
+ t.Fatal("no system roots")
+ }
+ // On Mavericks, there are 212 bundled certs; require only
+ // 150 here, since this is just a sanity check, and the
+ // exact number will vary over time.
+ if want, have := 150, len(tt.certs); have < want {
+ t.Fatalf("want at least %d system roots, have %d", want, have)
+ }
+ }
+
+ // Check that the two cert pools are roughly the same;
+ // |A∩B| > max(|A|, |B|) / 2 should be a reasonably robust check.
+
+ isect := make(map[string]bool, len(sysRoots.certs))
+ for _, c := range sysRoots.certs {
+ isect[string(c.Raw)] = true
+ }
+
+ have := 0
+ for _, c := range execRoots.certs {
+ if isect[string(c.Raw)] {
+ have++
+ }
+ }
+
+ var want int
+ if nsys, nexec := len(sysRoots.certs), len(execRoots.certs); nsys > nexec {
+ want = nsys / 2
+ } else {
+ want = nexec / 2
+ }
+
+ if have < want {
+ t.Errorf("insufficent overlap between cgo and non-cgo roots; want at least %d, have %d", want, have)
+ }
+}
diff --git a/src/pkg/crypto/x509/root_nocgo_darwin.go b/src/pkg/crypto/x509/root_nocgo_darwin.go
new file mode 100644
index 000000000..d00e25766
--- /dev/null
+++ b/src/pkg/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/src/pkg/crypto/x509/root_stub.go b/src/pkg/crypto/x509/root_stub.go
deleted file mode 100644
index 4c742ccc3..000000000
--- a/src/pkg/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/src/pkg/crypto/x509/root_unix.go b/src/pkg/crypto/x509/root_unix.go
index 324f855b1..11ad3c440 100644
--- a/src/pkg/crypto/x509/root_unix.go
+++ b/src/pkg/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
diff --git a/src/pkg/crypto/x509/verify.go b/src/pkg/crypto/x509/verify.go
index 8327463ca..5fd8e3717 100644
--- a/src/pkg/crypto/x509/verify.go
+++ b/src/pkg/crypto/x509/verify.go
@@ -425,6 +425,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 +436,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/src/pkg/crypto/x509/verify_test.go b/src/pkg/crypto/x509/verify_test.go
index ba6c13d45..96b9d9b42 100644
--- a/src/pkg/crypto/x509/verify_test.go
+++ b/src/pkg/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/src/pkg/crypto/x509/x509.go b/src/pkg/crypto/x509/x509.go
index 57f68ba7e..c347fb384 100644
--- a/src/pkg/crypto/x509/x509.go
+++ b/src/pkg/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
}
@@ -790,6 +791,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
@@ -863,58 +916,12 @@ func parseCertificate(in *certificate) (*Certificate, error) {
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 +1158,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
@@ -1252,22 +1280,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
}
@@ -1342,11 +1355,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 +1433,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 +1591,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, Extension, 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/src/pkg/crypto/x509/x509_test.go b/src/pkg/crypto/x509/x509_test.go
index f1097e992..2fd54c78f 100644
--- a/src/pkg/crypto/x509/x509_test.go
+++ b/src/pkg/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) {
@@ -718,6 +727,226 @@ func TestParsePEMCRL(t *testing.T) {
// Can't check the signature here without a package cycle.
}
+func TestImports(t *testing.T) {
+ if runtime.GOOS == "nacl" {
+ t.Skip("skipping on nacl")
+ }
+
+ 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{
+ 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{
+ pkix.AttributeTypeAndValueSET{
+ Type: oidExtensionRequest,
+ Value: [][]pkix.AttributeTypeAndValue{
+ []pkix.AttributeTypeAndValue{
+ 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")
+ }
+}
+
+// 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/src/pkg/crypto/x509/x509_test_import.go b/src/pkg/crypto/x509/x509_test_import.go
new file mode 100644
index 000000000..3fda7da18
--- /dev/null
+++ b/src/pkg/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/src/pkg/database/sql/convert.go b/src/pkg/database/sql/convert.go
index c04adde1f..c0b38a249 100644
--- a/src/pkg/database/sql/convert.go
+++ b/src/pkg/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/src/pkg/database/sql/convert_test.go b/src/pkg/database/sql/convert_test.go
index a39c2c54f..6e2483012 100644
--- a/src/pkg/database/sql/convert_test.go
+++ b/src/pkg/database/sql/convert_test.go
@@ -8,6 +8,7 @@ import (
"database/sql/driver"
"fmt"
"reflect"
+ "runtime"
"testing"
"time"
)
@@ -279,3 +280,58 @@ func TestValueConverters(t *testing.T) {
}
}
}
+
+// Tests that assigning to RawBytes doesn't allocate (and also works).
+func TestRawBytesAllocs(t *testing.T) {
+ 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() {
+ test("uint64", uint64(12345678), "12345678")
+ test("uint32", uint32(1234), "1234")
+ test("uint16", uint16(12), "12")
+ test("uint8", uint8(1), "1")
+ test("uint", uint(123), "123")
+ test("int", int(123), "123")
+ test("int8", int8(1), "1")
+ test("int16", int16(12), "12")
+ test("int32", int32(1234), "1234")
+ test("int64", int64(12345678), "12345678")
+ test("float32", float32(1.5), "1.5")
+ test("float64", float64(64), "64")
+ test("bool", false, "false")
+ })
+
+ // 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/src/pkg/database/sql/driver/driver.go b/src/pkg/database/sql/driver/driver.go
index 0828e63c6..eca25f29a 100644
--- a/src/pkg/database/sql/driver/driver.go
+++ b/src/pkg/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/src/pkg/database/sql/example_test.go b/src/pkg/database/sql/example_test.go
index d47eed50c..dcb74e069 100644
--- a/src/pkg/database/sql/example_test.go
+++ b/src/pkg/database/sql/example_test.go
@@ -18,6 +18,7 @@ func ExampleDB_Query() {
if err != nil {
log.Fatal(err)
}
+ defer rows.Close()
for rows.Next() {
var name string
if err := rows.Scan(&name); err != nil {
diff --git a/src/pkg/database/sql/fakedb_test.go b/src/pkg/database/sql/fakedb_test.go
index a8adfdd94..c7db0dd77 100644
--- a/src/pkg/database/sql/fakedb_test.go
+++ b/src/pkg/database/sql/fakedb_test.go
@@ -23,7 +23,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
@@ -433,11 +433,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 +497,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 +581,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 +710,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/src/pkg/database/sql/sql.go b/src/pkg/database/sql/sql.go
index 84a096513..765b80c60 100644
--- a/src/pkg/database/sql/sql.go
+++ b/src/pkg/database/sql/sql.go
@@ -181,7 +181,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
@@ -256,7 +257,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 +406,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 +421,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 {
@@ -452,6 +458,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
@@ -569,7 +578,7 @@ 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 {
db.openNewConnection()
@@ -652,13 +661,16 @@ func (db *DB) conn() (*driverConn, error) {
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,
@@ -774,11 +786,11 @@ 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 {
@@ -791,20 +803,24 @@ func (db *DB) putConnDBLocked(dc *driverConn, err error) bool {
req <- dc
}
return true
- } else if err == nil && !db.closed && db.maxIdleConnsLocked() > 0 && db.maxIdleConnsLocked() > db.freeConn.Len() {
+ } else if err == nil && !db.closed && db.maxIdleConnsLocked() > db.freeConn.Len() {
dc.listElem = db.freeConn.PushFront(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 +862,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 +911,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 +999,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
@@ -1245,13 +1261,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) {
@@ -1329,26 +1356,21 @@ func (s *Stmt) connStmt() (ci *driverConn, releaseConn func(error), si driver.St
// 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)
- s.mu.Unlock()
- break
+ 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 != 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()
}
conn := cs.dc
@@ -1361,31 +1383,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 +1506,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 +1526,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 +1658,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/src/pkg/database/sql/sql_test.go b/src/pkg/database/sql/sql_test.go
index 787a5c9f7..7971f1491 100644
--- a/src/pkg/database/sql/sql_test.go
+++ b/src/pkg/database/sql/sql_test.go
@@ -348,7 +348,6 @@ func TestStatementQueryRow(t *testing.T) {
t.Errorf("%d: age=%d, want %d", n, age, tt.want)
}
}
-
}
// golang.org/issue/3734
@@ -462,7 +461,7 @@ func TestTxStmt(t *testing.T) {
}
// 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, "")
@@ -660,6 +659,35 @@ func TestQueryRowClosingStmt(t *testing.T) {
}
}
+// 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{}
@@ -1249,6 +1277,111 @@ 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
+ })
+
+ // 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
+ for _, cs := range stmt1.css {
+ cs.dc.inUse = true
+ }
+
+ 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
+ for _, cs := range stmt2.css {
+ cs.dc.inUse = true
+ }
+
+ 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)
diff --git a/src/pkg/debug/dwarf/const.go b/src/pkg/debug/dwarf/const.go
index 9d32a0af2..93c68881a 100644
--- a/src/pkg/debug/dwarf/const.go
+++ b/src/pkg/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/src/pkg/debug/dwarf/entry.go b/src/pkg/debug/dwarf/entry.go
index c0c288992..665c6840d 100644
--- a/src/pkg/debug/dwarf/entry.go
+++ b/src/pkg/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 {
@@ -387,3 +387,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/src/pkg/debug/dwarf/open.go b/src/pkg/debug/dwarf/open.go
index 37a518b6d..c1b3f37ac 100644
--- a/src/pkg/debug/dwarf/open.go
+++ b/src/pkg/debug/dwarf/open.go
@@ -24,9 +24,9 @@ type Data struct {
// parsed data
abbrevCache map[uint32]abbrevTable
- addrsize int
order binary.ByteOrder
typeCache map[Offset]Type
+ typeSigs map[uint64]*typeUnit
unit []unit
}
@@ -50,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.
@@ -76,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/src/pkg/debug/dwarf/testdata/typedef.elf4 b/src/pkg/debug/dwarf/testdata/typedef.elf4
new file mode 100644
index 000000000..3d5a5a1b1
--- /dev/null
+++ b/src/pkg/debug/dwarf/testdata/typedef.elf4
Binary files differ
diff --git a/src/pkg/debug/dwarf/type.go b/src/pkg/debug/dwarf/type.go
index 1fbae6c14..68866d0b7 100644
--- a/src/pkg/debug/dwarf/type.go
+++ b/src/pkg/debug/dwarf/type.go
@@ -251,23 +251,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 +304,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 +327,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,7 +357,7 @@ 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
}
@@ -363,7 +383,7 @@ func (d *Data) Type(off Offset) (Type, error) {
}
ndim++
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
}
}
@@ -383,12 +403,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:
@@ -408,7 +428,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 +453,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"
@@ -453,12 +473,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 +487,8 @@ func (d *Data) Type(off Offset) (Type, error) {
err = b.err
goto Error
}
+ case int64:
+ f.ByteOffset = loc
}
haveBitOffset := false
@@ -502,7 +525,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 +549,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 +575,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 +594,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,7 +621,7 @@ 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)
}
@@ -620,7 +643,7 @@ 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
}
diff --git a/src/pkg/debug/dwarf/type_test.go b/src/pkg/debug/dwarf/type_test.go
index b5b255f6f..2cb85e74b 100644
--- a/src/pkg/debug/dwarf/type_test.go
+++ b/src/pkg/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/src/pkg/debug/dwarf/typeunit.go b/src/pkg/debug/dwarf/typeunit.go
new file mode 100644
index 000000000..3fd1c9973
--- /dev/null
+++ b/src/pkg/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/src/pkg/debug/dwarf/unit.go b/src/pkg/debug/dwarf/unit.go
index 270cd2e33..0fbc8e082 100644
--- a/src/pkg/debug/dwarf/unit.go
+++ b/src/pkg/debug/dwarf/unit.go
@@ -66,7 +66,7 @@ func (d *Data) parseUnits() ([]unit, error) {
n = uint32(b.uint64())
}
vers := b.uint16()
- if vers != 2 && vers != 3 {
+ if vers != 2 && vers != 3 && vers != 4 {
b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
break
}
diff --git a/src/pkg/debug/elf/elf.go b/src/pkg/debug/elf/elf.go
index 03e42b034..d622dae2a 100644
--- a/src/pkg/debug/elf/elf.go
+++ b/src/pkg/debug/elf/elf.go
@@ -517,7 +517,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
diff --git a/src/pkg/debug/elf/elf_test.go b/src/pkg/debug/elf/elf_test.go
index 67b961b5c..e3c51bb71 100644
--- a/src/pkg/debug/elf/elf_test.go
+++ b/src/pkg/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/src/pkg/debug/elf/file.go b/src/pkg/debug/elf/file.go
index a55c37ea9..423932fe0 100644
--- a/src/pkg/debug/elf/file.go
+++ b/src/pkg/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
}
@@ -412,7 +415,7 @@ func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) {
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")
}
@@ -455,7 +458,7 @@ func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) {
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,13 +522,17 @@ 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)
+ }
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)
@@ -533,7 +540,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 {
@@ -567,6 +574,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) DWARF() (*dwarf.Data, error) {
// There are many other DWARF sections, but these
// are the required ones, and the debug/dwarf package
@@ -600,8 +644,58 @@ 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, str := dat[0], dat[1], dat[2]
- return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
+ d, err := dwarf.New(abbrev, nil, nil, info, nil, nil, nil, 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.
diff --git a/src/pkg/debug/elf/file_test.go b/src/pkg/debug/elf/file_test.go
index 38b5f9e70..7f88a54bc 100644
--- a/src/pkg/debug/elf/file_test.go
+++ b/src/pkg/debug/elf/file_test.go
@@ -261,6 +261,12 @@ var relocationTests = []relocationTest{
},
},
{
+ "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/src/pkg/debug/elf/testdata/go-relocation-test-clang-x86.obj b/src/pkg/debug/elf/testdata/go-relocation-test-clang-x86.obj
new file mode 100644
index 000000000..e909cf4e6
--- /dev/null
+++ b/src/pkg/debug/elf/testdata/go-relocation-test-clang-x86.obj
Binary files differ
diff --git a/src/pkg/debug/elf/testdata/hello.c b/src/pkg/debug/elf/testdata/hello.c
new file mode 100644
index 000000000..34d9ee792
--- /dev/null
+++ b/src/pkg/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/src/pkg/debug/gosym/pclntab.go b/src/pkg/debug/gosym/pclntab.go
index 3e6a8046b..6620aefb0 100644
--- a/src/pkg/debug/gosym/pclntab.go
+++ b/src/pkg/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/src/pkg/debug/gosym/symtab.go b/src/pkg/debug/gosym/symtab.go
index 9ab05bac2..3864e3cb4 100644
--- a/src/pkg/debug/gosym/symtab.go
+++ b/src/pkg/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 {
@@ -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/src/pkg/debug/macho/fat.go b/src/pkg/debug/macho/fat.go
new file mode 100644
index 000000000..93b831526
--- /dev/null
+++ b/src/pkg/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/src/pkg/debug/macho/file.go b/src/pkg/debug/macho/file.go
index f5f0dedb7..eefb74444 100644
--- a/src/pkg/debug/macho/file.go
+++ b/src/pkg/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/src/pkg/debug/macho/file_test.go b/src/pkg/debug/macho/file_test.go
index 640225b32..4797780ce 100644
--- a/src/pkg/debug/macho/file_test.go
+++ b/src/pkg/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/src/pkg/debug/macho/macho.go b/src/pkg/debug/macho/macho.go
index bc14226c5..d9678c8ed 100644
--- a/src/pkg/debug/macho/macho.go
+++ b/src/pkg/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/src/pkg/debug/macho/testdata/fat-gcc-386-amd64-darwin-exec b/src/pkg/debug/macho/testdata/fat-gcc-386-amd64-darwin-exec
new file mode 100644
index 000000000..7efd19300
--- /dev/null
+++ b/src/pkg/debug/macho/testdata/fat-gcc-386-amd64-darwin-exec
Binary files differ
diff --git a/src/pkg/debug/pe/file.go b/src/pkg/debug/pe/file.go
index f521566ef..ce6f1408f 100644
--- a/src/pkg/debug/pe/file.go
+++ b/src/pkg/debug/pe/file.go
@@ -13,13 +13,15 @@ import (
"io"
"os"
"strconv"
+ "unsafe"
)
// 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 +74,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
}
@@ -193,10 +198,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 uintptr(f.FileHeader.SizeOfOptionalHeader) {
+ case unsafe.Sizeof(oh32):
+ 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 unsafe.Sizeof(oh64):
+ 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 +241,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/src/pkg/debug/pe/file_test.go b/src/pkg/debug/pe/file_test.go
index c0f9fcb95..ddbb27174 100644
--- a/src/pkg/debug/pe/file_test.go
+++ b/src/pkg/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,130 @@ 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{
+ {".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, 0x9, 0x53472993, 0x0, 0x0, 0xf0, 0x22f},
+ &OptionalHeader64{
+ 0x20b, 0x2, 0x16, 0x6a00, 0x2400, 0x1600, 0x14e0, 0x1000, 0x400000, 0x1000, 0x200, 0x4, 0x0, 0x0, 0x0, 0x5, 0x2, 0x0, 0x11000, 0x400, 0x1841e, 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{
- {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", 0x6860, 0x1000, 0x6a00, 0x400, 0x0, 0x0, 0x0, 0x0, 0x60500020},
+ {".data", 0xe0, 0x8000, 0x200, 0x6e00, 0x0, 0x0, 0x0, 0x0, 0xc0500040},
+ {".rdata", 0x6b0, 0x9000, 0x800, 0x7000, 0x0, 0x0, 0x0, 0x0, 0x40600040},
+ {".pdata", 0x498, 0xa000, 0x600, 0x7800, 0x0, 0x0, 0x0, 0x0, 0x40300040},
+ {".xdata", 0x488, 0xb000, 0x600, 0x7e00, 0x0, 0x0, 0x0, 0x0, 0x40300040},
+ {".bss", 0x1410, 0xc000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0600080},
+ {".idata", 0x990, 0xe000, 0xa00, 0x8400, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
+ {".CRT", 0x68, 0xf000, 0x200, 0x8e00, 0x0, 0x0, 0x0, 0x0, 0xc0400040},
+ {".tls", 0x48, 0x10000, 0x200, 0x9000, 0x0, 0x0, 0x0, 0x0, 0xc0600040},
},
[]*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 +195,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/src/pkg/debug/pe/pe.go b/src/pkg/debug/pe/pe.go
index 0606217b3..8e90b1b51 100644
--- a/src/pkg/debug/pe/pe.go
+++ b/src/pkg/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/src/pkg/debug/pe/testdata/gcc-amd64-mingw-exec b/src/pkg/debug/pe/testdata/gcc-amd64-mingw-exec
new file mode 100644
index 000000000..78d4e5fed
--- /dev/null
+++ b/src/pkg/debug/pe/testdata/gcc-amd64-mingw-exec
Binary files differ
diff --git a/src/pkg/debug/pe/testdata/gcc-amd64-mingw-obj b/src/pkg/debug/pe/testdata/gcc-amd64-mingw-obj
new file mode 100644
index 000000000..48ae7921f
--- /dev/null
+++ b/src/pkg/debug/pe/testdata/gcc-amd64-mingw-obj
Binary files differ
diff --git a/src/pkg/debug/plan9obj/file.go b/src/pkg/debug/plan9obj/file.go
new file mode 100644
index 000000000..60a585719
--- /dev/null
+++ b/src/pkg/debug/plan9obj/file.go
@@ -0,0 +1,325 @@
+// 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
+}
+
+// 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,
+ }}
+
+ 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
+ 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(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/src/pkg/debug/plan9obj/file_test.go b/src/pkg/debug/plan9obj/file_test.go
new file mode 100644
index 000000000..96186d815
--- /dev/null
+++ b/src/pkg/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},
+ []*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},
+ []*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/src/pkg/debug/plan9obj/plan9obj.go b/src/pkg/debug/plan9obj/plan9obj.go
new file mode 100644
index 000000000..af9858562
--- /dev/null
+++ b/src/pkg/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/src/pkg/debug/plan9obj/testdata/386-plan9-exec b/src/pkg/debug/plan9obj/testdata/386-plan9-exec
new file mode 100755
index 000000000..748e83f8e
--- /dev/null
+++ b/src/pkg/debug/plan9obj/testdata/386-plan9-exec
Binary files differ
diff --git a/src/pkg/debug/plan9obj/testdata/amd64-plan9-exec b/src/pkg/debug/plan9obj/testdata/amd64-plan9-exec
new file mode 100755
index 000000000..3e257dd8f
--- /dev/null
+++ b/src/pkg/debug/plan9obj/testdata/amd64-plan9-exec
Binary files differ
diff --git a/src/pkg/debug/plan9obj/testdata/hello.c b/src/pkg/debug/plan9obj/testdata/hello.c
new file mode 100644
index 000000000..c0d633e29
--- /dev/null
+++ b/src/pkg/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/src/pkg/encoding/ascii85/ascii85.go b/src/pkg/encoding/ascii85/ascii85.go
index e2afc5871..60da304b5 100644
--- a/src/pkg/encoding/ascii85/ascii85.go
+++ b/src/pkg/encoding/ascii85/ascii85.go
@@ -281,6 +281,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/src/pkg/encoding/ascii85/ascii85_test.go b/src/pkg/encoding/ascii85/ascii85_test.go
index 42cf7e80e..aad199b4f 100644
--- a/src/pkg/encoding/ascii85/ascii85_test.go
+++ b/src/pkg/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/src/pkg/encoding/asn1/asn1.go b/src/pkg/encoding/asn1/asn1.go
index 992356c26..ec7f91c1b 100644
--- a/src/pkg/encoding/asn1/asn1.go
+++ b/src/pkg/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
@@ -632,6 +652,10 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
universalTag = tagGeneralizedTime
}
+ if params.set {
+ universalTag = tagSet
+ }
+
expectedClass := classUniversal
expectedTag := universalTag
@@ -852,13 +876,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/src/pkg/encoding/asn1/asn1_test.go b/src/pkg/encoding/asn1/asn1_test.go
index f68804ebf..b553f78e0 100644
--- a/src/pkg/encoding/asn1/asn1_test.go
+++ b/src/pkg/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{}},
@@ -389,6 +401,10 @@ type TestBigInt struct {
X *big.Int
}
+type TestSet struct {
+ Ints []int `asn1:"set"`
+}
+
var unmarshalTestData = []struct {
in []byte
out interface{}
@@ -408,6 +424,7 @@ var unmarshalTestData = []struct {
{[]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 +526,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 +786,29 @@ 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)
+ }
+ }
+}
diff --git a/src/pkg/encoding/asn1/marshal.go b/src/pkg/encoding/asn1/marshal.go
index ed17e41a5..e26fe59b3 100644
--- a/src/pkg/encoding/asn1/marshal.go
+++ b/src/pkg/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:
@@ -504,7 +542,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 +560,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 +611,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/src/pkg/encoding/asn1/marshal_test.go b/src/pkg/encoding/asn1/marshal_test.go
index 763c86da2..a15acbed0 100644
--- a/src/pkg/encoding/asn1/marshal_test.go
+++ b/src/pkg/encoding/asn1/marshal_test.go
@@ -67,6 +67,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 +91,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"},
diff --git a/src/pkg/encoding/base32/base32.go b/src/pkg/encoding/base32/base32.go
index fe17b7322..d770de391 100644
--- a/src/pkg/encoding/base32/base32.go
+++ b/src/pkg/encoding/base32/base32.go
@@ -179,13 +179,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 +266,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)
diff --git a/src/pkg/encoding/base32/base32_test.go b/src/pkg/encoding/base32/base32_test.go
index 63298d1c9..f56b996fa 100644
--- a/src/pkg/encoding/base32/base32_test.go
+++ b/src/pkg/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 {
diff --git a/src/pkg/encoding/base64/base64.go b/src/pkg/encoding/base64/base64.go
index 85e398fd0..e38c26d0e 100644
--- a/src/pkg/encoding/base64/base64.go
+++ b/src/pkg/encoding/base64/base64.go
@@ -159,13 +159,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 +224,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 +259,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 +277,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
diff --git a/src/pkg/encoding/base64/base64_test.go b/src/pkg/encoding/base64/base64_test.go
index 579591a88..a075194e0 100644
--- a/src/pkg/encoding/base64/base64_test.go
+++ b/src/pkg/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,14 @@ 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)
+ }
+}
diff --git a/src/pkg/encoding/binary/binary.go b/src/pkg/encoding/binary/binary.go
index f3466b9af..a5694876a 100644
--- a/src/pkg/encoding/binary/binary.go
+++ b/src/pkg/encoding/binary/binary.go
@@ -133,6 +133,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 {
diff --git a/src/pkg/encoding/binary/binary_test.go b/src/pkg/encoding/binary/binary_test.go
index fdfee7d87..c80c90383 100644
--- a/src/pkg/encoding/binary/binary_test.go
+++ b/src/pkg/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,30 @@ 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)
+}
+
type byteSliceReader struct {
remain []byte
}
diff --git a/src/pkg/encoding/binary/varint_test.go b/src/pkg/encoding/binary/varint_test.go
index 9476bd5fb..ca411ecbd 100644
--- a/src/pkg/encoding/binary/varint_test.go
+++ b/src/pkg/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/src/pkg/encoding/csv/reader.go b/src/pkg/encoding/csv/reader.go
index b328dcc37..d9432954a 100644
--- a/src/pkg/encoding/csv/reader.go
+++ b/src/pkg/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/src/pkg/encoding/csv/writer_test.go b/src/pkg/encoding/csv/writer_test.go
index 03ca6b093..22b740c07 100644
--- a/src/pkg/encoding/csv/writer_test.go
+++ b/src/pkg/encoding/csv/writer_test.go
@@ -26,6 +26,8 @@ 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},
}
func TestWrite(t *testing.T) {
diff --git a/src/pkg/encoding/gob/codec_test.go b/src/pkg/encoding/gob/codec_test.go
index b40f78360..fa57f3761 100644
--- a/src/pkg/encoding/gob/codec_test.go
+++ b/src/pkg/encoding/gob/codec_test.go
@@ -1364,11 +1364,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 +1375,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 +1463,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/src/pkg/encoding/gob/decode.go b/src/pkg/encoding/gob/decode.go
index 3e76f4c90..d8513148e 100644
--- a/src/pkg/encoding/gob/decode.go
+++ b/src/pkg/encoding/gob/decode.go
@@ -654,21 +654,20 @@ func (dec *Decoder) ignoreMap(state *decoderState, keyOp, elemOp decOp) {
// decodeSlice decodes a slice and stores the slice header through p.
// 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) {
+func (dec *Decoder) decodeSlice(atyp reflect.Type, state *decoderState, p unsafe.Pointer, 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 {
+ if *(*unsafe.Pointer)(p) == nil {
// Allocate the slice header.
- *(*unsafe.Pointer)(up) = unsafe.Pointer(new([]unsafe.Pointer))
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new([]unsafe.Pointer))
}
- p = *(*uintptr)(up)
+ p = *(*unsafe.Pointer)(p)
}
// 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))
+ hdrp := (*reflect.SliceHeader)(p)
if hdrp.Cap < n {
hdrp.Data = reflect.MakeSlice(atyp, n, n).Pointer()
hdrp.Cap = n
@@ -686,7 +685,7 @@ func (dec *Decoder) ignoreSlice(state *decoderState, elemOp decOp) {
// 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())
+ errorf("%s is not assignable to type %s", value.Type(), ivalue.Type())
}
ivalue.Set(value)
}
@@ -702,6 +701,9 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, p un
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)
@@ -887,7 +889,7 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg
elemOp, elemIndir := 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)
+ state.dec.decodeSlice(t, state, p, *elemOp, t.Elem().Size(), i.indir, elemIndir, ovfl)
}
case reflect.Struct:
@@ -1238,7 +1240,8 @@ func (dec *Decoder) decodeValue(wireId typeId, val reflect.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)
}
diff --git a/src/pkg/encoding/gob/decoder.go b/src/pkg/encoding/gob/decoder.go
index 04f706ca5..3a769ec12 100644
--- a/src/pkg/encoding/gob/decoder.go
+++ b/src/pkg/encoding/gob/decoder.go
@@ -183,11 +183,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 +204,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 e.
func (dec *Decoder) DecodeValue(v reflect.Value) error {
if v.IsValid() {
if v.Kind() == reflect.Ptr && !v.IsNil() {
diff --git a/src/pkg/encoding/gob/encode.go b/src/pkg/encoding/gob/encode.go
index d158b6442..7831c02d1 100644
--- a/src/pkg/encoding/gob/encode.go
+++ b/src/pkg/encoding/gob/encode.go
@@ -491,7 +491,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
diff --git a/src/pkg/encoding/gob/encoder_test.go b/src/pkg/encoding/gob/encoder_test.go
index 4ecf51d12..6445ce100 100644
--- a/src/pkg/encoding/gob/encoder_test.go
+++ b/src/pkg/encoding/gob/encoder_test.go
@@ -129,6 +129,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 +632,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)
diff --git a/src/pkg/encoding/gob/gobencdec_test.go b/src/pkg/encoding/gob/gobencdec_test.go
index 0193e2b67..157b7723a 100644
--- a/src/pkg/encoding/gob/gobencdec_test.go
+++ b/src/pkg/encoding/gob/gobencdec_test.go
@@ -705,13 +705,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 +732,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/src/pkg/encoding/hex/hex.go b/src/pkg/encoding/hex/hex.go
index 167d00e03..d1fc7024a 100644
--- a/src/pkg/encoding/hex/hex.go
+++ b/src/pkg/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/src/pkg/encoding/hex/hex_test.go b/src/pkg/encoding/hex/hex_test.go
index 356f590f0..b969636cd 100644
--- a/src/pkg/encoding/hex/hex_test.go
+++ b/src/pkg/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/src/pkg/encoding/json/decode.go b/src/pkg/encoding/json/decode.go
index 458fb39ec..af1c908ad 100644
--- a/src/pkg/encoding/json/decode.go
+++ b/src/pkg/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
@@ -500,11 +505,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 +531,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
}
}
@@ -561,6 +566,7 @@ func (d *decodeState) object(v reflect.Value) {
if destring {
d.value(reflect.ValueOf(&d.tempstr))
d.literalStore([]byte(d.tempstr), subv, true)
+ d.tempstr = "" // Zero scratch space for successive values.
} else {
d.value(subv)
}
diff --git a/src/pkg/encoding/json/decode_test.go b/src/pkg/encoding/json/decode_test.go
index 22c5f89f7..238a87fd6 100644
--- a/src/pkg/encoding/json/decode_test.go
+++ b/src/pkg/encoding/json/decode_test.go
@@ -1060,6 +1060,21 @@ func TestEmptyString(t *testing.T) {
}
}
+// Test that the returned error is non-nil when trying to unmarshal null string into int, for successive ,string option
+// Issue 7046
+func TestNullString(t *testing.T) {
+ type T struct {
+ A int `json:",string"`
+ B int `json:",string"`
+ }
+ data := []byte(`{"A": "1", "B": null}`)
+ var s T
+ err := Unmarshal(data, &s)
+ if err == nil {
+ t.Fatalf("expected error; got %v", s)
+ }
+}
+
func intp(x int) *int {
p := new(int)
*p = x
@@ -1110,8 +1125,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 +1331,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/src/pkg/encoding/json/encode.go b/src/pkg/encoding/json/encode.go
index 7d6c71d7a..741ddd89c 100644
--- a/src/pkg/encoding/json/encode.go
+++ b/src/pkg/encoding/json/encode.go
@@ -44,6 +44,7 @@ import (
// if an invalid UTF-8 sequence is encountered.
// 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
@@ -241,24 +242,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) {
@@ -813,7 +805,7 @@ func (e *encodeState) string(s string) (int, error) {
e.WriteByte('r')
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 +928,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 +938,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 +1043,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 +1064,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/src/pkg/encoding/json/encode_test.go b/src/pkg/encoding/json/encode_test.go
index 9395db7cb..2e89a78eb 100644
--- a/src/pkg/encoding/json/encode_test.go
+++ b/src/pkg/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,13 @@ 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())
+ }
+}
diff --git a/src/pkg/encoding/json/example_test.go b/src/pkg/encoding/json/example_test.go
index ea0bc149c..ca4e5ae68 100644
--- a/src/pkg/encoding/json/example_test.go
+++ b/src/pkg/encoding/json/example_test.go
@@ -5,6 +5,7 @@
package json_test
import (
+ "bytes"
"encoding/json"
"fmt"
"io"
@@ -127,3 +128,34 @@ func ExampleRawMessage() {
// YCbCr &{255 0 -10}
// RGB &{98 218 255}
}
+
+func ExampleIndent() {
+ type Road struct {
+ Name string
+ Number int
+ }
+ roads := []Road{
+ {"Diamond Fork", 29},
+ {"Sheep Creek", 51},
+ }
+
+ b, err := json.Marshal(roads)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ var out bytes.Buffer
+ json.Indent(&out, b, "=", "\t")
+ out.WriteTo(os.Stdout)
+ // Output:
+ // [
+ // = {
+ // = "Name": "Diamond Fork",
+ // = "Number": 29
+ // = },
+ // = {
+ // = "Name": "Sheep Creek",
+ // = "Number": 51
+ // = }
+ // =]
+}
diff --git a/src/pkg/encoding/json/fold.go b/src/pkg/encoding/json/fold.go
new file mode 100644
index 000000000..d6f77c93e
--- /dev/null
+++ b/src/pkg/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/src/pkg/encoding/json/fold_test.go b/src/pkg/encoding/json/fold_test.go
new file mode 100644
index 000000000..9fb94646a
--- /dev/null
+++ b/src/pkg/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/src/pkg/encoding/json/indent.go b/src/pkg/encoding/json/indent.go
index 11ef709cc..e1bacafd6 100644
--- a/src/pkg/encoding/json/indent.go
+++ b/src/pkg/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/src/pkg/encoding/json/scanner_test.go b/src/pkg/encoding/json/scanner_test.go
index 90e45ff03..788034290 100644
--- a/src/pkg/encoding/json/scanner_test.go
+++ b/src/pkg/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/src/pkg/encoding/json/stream.go b/src/pkg/encoding/json/stream.go
index 1928abadb..1cb289fd8 100644
--- a/src/pkg/encoding/json/stream.go
+++ b/src/pkg/encoding/json/stream.go
@@ -148,7 +148,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 +174,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/src/pkg/encoding/xml/marshal.go b/src/pkg/encoding/xml/marshal.go
index d9522e0b3..8c6342013 100644
--- a/src/pkg/encoding/xml/marshal.go
+++ b/src/pkg/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/src/pkg/encoding/xml/marshal_test.go b/src/pkg/encoding/xml/marshal_test.go
index d34118a3d..14f73a75d 100644
--- a/src/pkg/encoding/xml/marshal_test.go
+++ b/src/pkg/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/src/pkg/encoding/xml/read.go b/src/pkg/encoding/xml/read.go
index 8890508f8..75b9f2ba1 100644
--- a/src/pkg/encoding/xml/read.go
+++ b/src/pkg/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/src/pkg/encoding/xml/read_test.go b/src/pkg/encoding/xml/read_test.go
index 1404c900f..01f55d0dd 100644
--- a/src/pkg/encoding/xml/read_test.go
+++ b/src/pkg/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/src/pkg/encoding/xml/typeinfo.go b/src/pkg/encoding/xml/typeinfo.go
index 83e65402c..22248d20a 100644
--- a/src/pkg/encoding/xml/typeinfo.go
+++ b/src/pkg/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/src/pkg/encoding/xml/xml.go b/src/pkg/encoding/xml/xml.go
index 5b9d67002..b473cb845 100644
--- a/src/pkg/encoding/xml/xml.go
+++ b/src/pkg/encoding/xml/xml.go
@@ -200,6 +200,8 @@ type Decoder struct {
}
// 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),
diff --git a/src/pkg/expvar/expvar.go b/src/pkg/expvar/expvar.go
index b06599505..9b6dab487 100644
--- a/src/pkg/expvar/expvar.go
+++ b/src/pkg/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/src/pkg/expvar/expvar_test.go b/src/pkg/expvar/expvar_test.go
index 572c62bee..765e3b757 100644
--- a/src/pkg/expvar/expvar_test.go
+++ b/src/pkg/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/src/pkg/flag/flag.go b/src/pkg/flag/flag.go
index e7c863ee9..cd2a165be 100644
--- a/src/pkg/flag/flag.go
+++ b/src/pkg/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
@@ -269,7 +270,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
}
@@ -755,7 +755,7 @@ func (f *FlagSet) parseOne() (bool, error) {
if fv, ok := flag.Value.(boolFlag); ok && fv.IsBoolFlag() { // special case: doesn't need an arg
if has_value {
if 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")
diff --git a/src/pkg/fmt/doc.go b/src/pkg/fmt/doc.go
index 095fd03b2..02642d6ae 100644
--- a/src/pkg/fmt/doc.go
+++ b/src/pkg/fmt/doc.go
@@ -37,6 +37,7 @@
%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
+ %F synonym for %f
%g whichever of %e or %f produces more compact output
%G whichever of %E or %f produces more compact output
String and slice of bytes:
@@ -50,23 +51,39 @@
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
+ 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.
+ (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.
- For numeric values, width sets the minimum width of the field and
+ 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 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,20 +115,33 @@
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) }
diff --git a/src/pkg/fmt/fmt_test.go b/src/pkg/fmt/fmt_test.go
index bf50675f5..7e3d06b9f 100644
--- a/src/pkg/fmt/fmt_test.go
+++ b/src/pkg/fmt/fmt_test.go
@@ -220,6 +220,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 +245,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)"},
@@ -397,6 +405,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 +505,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 +592,43 @@ 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)"},
+}
+
+// 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 +668,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 signs = []float64{1, 0, -1}
+ 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 _, realSign := range signs {
+ for _, imagSign := range signs {
+ one := Sprintf(realFmt, complex(realSign, imagSign))
+ two := Sprintf("("+realFmt+imagFmt+"i)", realSign, imagSign)
+ if one != two {
+ t.Error(f, one, two)
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
type SE []interface{} // slice of empty; notational compactness.
var reorderTests = []struct {
@@ -604,47 +762,61 @@ 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) {
- for i := 0; i < b.N; i++ {
- Sprintf("%g", 5.23184)
- }
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("%g", 5.23184)
+ }
+ })
}
func BenchmarkManyArgs(b *testing.B) {
- 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")
- }
+ 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")
+ }
+ })
}
var mallocBuf bytes.Buffer
diff --git a/src/pkg/fmt/format.go b/src/pkg/fmt/format.go
index 2e2b0716e..a89c542cf 100644
--- a/src/pkg/fmt/format.go
+++ b/src/pkg/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"
@@ -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
@@ -351,35 +361,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
}
- f.pad(slice)
+ // 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
+ }
+ // 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 +447,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/src/pkg/fmt/print.go b/src/pkg/fmt/print.go
index 1ea816d6d..302661f4c 100644
--- a/src/pkg/fmt/print.go
+++ b/src/pkg/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.
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 }
@@ -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)
@@ -555,6 +523,15 @@ 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) {
if verb == 'v' || verb == 'd' {
if goSyntax {
+ 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 {
diff --git a/src/pkg/fmt/scan.go b/src/pkg/fmt/scan.go
index 5b1be5891..8a337e479 100644
--- a/src/pkg/fmt/scan.go
+++ b/src/pkg/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},
@@ -380,7 +380,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 +397,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 +429,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/src/pkg/go/ast/commentmap.go b/src/pkg/go/ast/commentmap.go
index 1fb4867dd..ac999d627 100644
--- a/src/pkg/go/ast/commentmap.go
+++ b/src/pkg/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/src/pkg/go/ast/example_test.go b/src/pkg/go/ast/example_test.go
index 632bfcfd0..d2e734f2c 100644
--- a/src/pkg/go/ast/example_test.go
+++ b/src/pkg/go/ast/example_test.go
@@ -5,8 +5,10 @@
package ast_test
import (
+ "bytes"
"fmt"
"go/ast"
+ "go/format"
"go/parser"
"go/token"
)
@@ -134,3 +136,75 @@ func main() {
// 57 . }
// 58 }
}
+
+// This example illustrates how to remove a variable declaration
+// in a Go program while maintaining correct comment association
+// using an ast.CommentMap.
+func ExampleCommentMap() {
+ // src is the input for which we create the AST that we
+ // are going to manipulate.
+ src := `
+// This is the package comment.
+package main
+
+// This comment is associated with the hello constant.
+const hello = "Hello, World!" // line comment 1
+
+// This comment is associated with the foo variable.
+var foo = hello // line comment 2
+
+// This comment is associated with the main function.
+func main() {
+ fmt.Println(hello) // line comment 3
+}
+`
+
+ // Create the AST by parsing src.
+ fset := token.NewFileSet() // positions are relative to fset
+ f, err := parser.ParseFile(fset, "src.go", src, parser.ParseComments)
+ if err != nil {
+ panic(err)
+ }
+
+ // Create an ast.CommentMap from the ast.File's comments.
+ // This helps keeping the association between comments
+ // and AST nodes.
+ cmap := ast.NewCommentMap(fset, f, f.Comments)
+
+ // Remove the first variable declaration from the list of declarations.
+ f.Decls = removeFirstVarDecl(f.Decls)
+
+ // Use the comment map to filter comments that don't belong anymore
+ // (the comments associated with the variable declaration), and create
+ // the new comments list.
+ f.Comments = cmap.Filter(f).Comments()
+
+ // Print the modified AST.
+ var buf bytes.Buffer
+ if err := format.Node(&buf, fset, f); err != nil {
+ panic(err)
+ }
+ fmt.Printf("%s", buf.Bytes())
+
+ // output:
+ // // This is the package comment.
+ // package main
+ //
+ // // This comment is associated with the hello constant.
+ // const hello = "Hello, World!" // line comment 1
+ //
+ // // This comment is associated with the main function.
+ // func main() {
+ // fmt.Println(hello) // line comment 3
+ // }
+}
+
+func removeFirstVarDecl(list []ast.Decl) []ast.Decl {
+ for i, decl := range list {
+ if gen, ok := decl.(*ast.GenDecl); ok && gen.Tok == token.VAR {
+ copy(list[i:], list[i+1:])
+ return list[:len(list)-1]
+ }
+ }
+ panic("variable declaration not found")
+}
diff --git a/src/pkg/go/build/build.go b/src/pkg/go/build/build.go
index 50d2fb4ae..412abea3a 100644
--- a/src/pkg/go/build/build.go
+++ b/src/pkg/go/build/build.go
@@ -292,10 +292,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.4 the line will read
+ // c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4"}
// and so on.
- c.ReleaseTags = []string{"go1.1", "go1.2"}
+ c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3"}
switch os.Getenv("CGO_ENABLED") {
case "1":
@@ -303,8 +303,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
@@ -358,6 +357,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
@@ -622,6 +622,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
@@ -789,7 +792,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
@@ -1207,7 +1210,7 @@ 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
diff --git a/src/pkg/go/build/deps_test.go b/src/pkg/go/build/deps_test.go
index dd162c7db..7421e144f 100644
--- a/src/pkg/go/build/deps_test.go
+++ b/src/pkg/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,
@@ -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",
@@ -359,7 +360,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{"darwin", "dragonfly", "freebsd", "linux", "nacl", "netbsd", "openbsd", "plan9", "solaris", "windows"}
var goarches = []string{"386", "amd64", "arm"}
type osPkg struct {
@@ -374,6 +375,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 +393,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/src/pkg/go/build/doc.go b/src/pkg/go/build/doc.go
index b2f04ea45..f17f76ccc 100644
--- a/src/pkg/go/build/doc.go
+++ b/src/pkg/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,7 @@
// - "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
// - any additional words listed in ctxt.BuildTags
//
// If a file's name, after stripping the extension and a possible _test suffix,
diff --git a/src/pkg/go/build/syslist.go b/src/pkg/go/build/syslist.go
index e1fbf6330..5c42b946b 100644
--- a/src/pkg/go/build/syslist.go
+++ b/src/pkg/go/build/syslist.go
@@ -4,5 +4,5 @@
package build
-const goosList = "darwin dragonfly freebsd linux netbsd openbsd plan9 windows "
-const goarchList = "386 amd64 arm "
+const goosList = "darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris windows "
+const goarchList = "386 amd64 amd64p32 arm "
diff --git a/src/pkg/go/doc/comment.go b/src/pkg/go/doc/comment.go
index 5c8c43e0c..f414ca409 100644
--- a/src/pkg/go/doc/comment.go
+++ b/src/pkg/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/src/pkg/go/doc/comment_test.go b/src/pkg/go/doc/comment_test.go
index aa21b8d1b..ad65c2a27 100644
--- a/src/pkg/go/doc/comment_test.go
+++ b/src/pkg/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/src/pkg/go/doc/example.go b/src/pkg/go/doc/example.go
index 2358ed389..c414e548c 100644
--- a/src/pkg/go/doc/example.go
+++ b/src/pkg/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/src/pkg/go/parser/error_test.go b/src/pkg/go/parser/error_test.go
index d4d4f909d..8506077ce 100644
--- a/src/pkg/go/parser/error_test.go
+++ b/src/pkg/go/parser/error_test.go
@@ -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)
}
}
}
diff --git a/src/pkg/go/parser/interface.go b/src/pkg/go/parser/interface.go
index 0f83ca931..57da4ddcd 100644
--- a/src/pkg/go/parser/interface.go
+++ b/src/pkg/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.next()
+ }
+ p.expect(token.EOF)
+
if p.errors.Len() > 0 {
p.errors.Sort()
return nil, p.errors.Err()
diff --git a/src/pkg/go/parser/parser.go b/src/pkg/go/parser/parser.go
index c4523318f..00dd532b2 100644
--- a/src/pkg/go/parser/parser.go
+++ b/src/pkg/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
@@ -679,7 +699,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())}
}
}
@@ -1168,16 +1188,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 +1210,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 +1357,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 +1420,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 +1706,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 +1724,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 +1739,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 +1782,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 +1816,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 +1947,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 {
@@ -2035,7 +2072,7 @@ func (p *parser) parseForStmt() ast.Stmt {
key = as.Lhs[0]
default:
p.errorExpected(as.Lhs[0].Pos(), "1 or 2 expressions")
- return &ast.BadStmt{From: pos, To: body.End()}
+ 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 +2092,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,
}
@@ -2282,7 +2319,7 @@ func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
p.errorExpected(base.Pos(), "(unqualified) identifier")
}
par.List = []*ast.Field{
- {Type: &ast.BadExpr{From: recv.Pos(), To: recv.End()}},
+ {Type: &ast.BadExpr{From: recv.Pos(), To: p.safePos(recv.End())}},
}
}
diff --git a/src/pkg/go/parser/parser_test.go b/src/pkg/go/parser/parser_test.go
index 0a34b7e50..2797ea518 100644
--- a/src/pkg/go/parser/parser_test.go
+++ b/src/pkg/go/parser/parser_test.go
@@ -78,7 +78,7 @@ func TestParseExpr(t *testing.T) {
}
// sanity check
if _, ok := x.(*ast.BinaryExpr); !ok {
- t.Errorf("ParseExpr(%s): got %T, expected *ast.BinaryExpr", src, x)
+ t.Errorf("ParseExpr(%s): got %T, want *ast.BinaryExpr", src, x)
}
// a valid type expression
@@ -89,17 +89,24 @@ func TestParseExpr(t *testing.T) {
}
// sanity check
if _, ok := x.(*ast.StructType); !ok {
- t.Errorf("ParseExpr(%s): got %T, expected *ast.StructType", src, x)
+ t.Errorf("ParseExpr(%s): 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)
+ t.Fatalf("ParseExpr(%s): got no error", src)
+ }
+
+ // a valid expression followed by extra tokens is invalid
+ src = "a[i] := x"
+ _, err = ParseExpr(src)
+ if err == nil {
+ t.Fatalf("ParseExpr(%s): got no error", src)
}
- // it must not crash
+ // ParseExpr must not crash
for _, src := range valids {
ParseExpr(src)
}
diff --git a/src/pkg/go/parser/short_test.go b/src/pkg/go/parser/short_test.go
index 0ef0c560c..b79406099 100644
--- a/src/pkg/go/parser/short_test.go
+++ b/src/pkg/go/parser/short_test.go
@@ -48,14 +48,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 +76,19 @@ 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 '\)'" */ (){}) } } }`,
}
func TestInvalid(t *testing.T) {
diff --git a/src/pkg/go/printer/nodes.go b/src/pkg/go/printer/nodes.go
index 583c6c370..04b5f1a76 100644
--- a/src/pkg/go/printer/nodes.go
+++ b/src/pkg/go/printer/nodes.go
@@ -378,10 +378,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 +424,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 +457,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 +468,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 +484,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 {
@@ -826,10 +822,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 +903,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++
}
}
@@ -1375,22 +1388,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 +1461,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 +1504,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/src/pkg/go/printer/printer.go b/src/pkg/go/printer/printer.go
index e06d2edfb..280c697a0 100644
--- a/src/pkg/go/printer/printer.go
+++ b/src/pkg/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/src/pkg/go/printer/printer_test.go b/src/pkg/go/printer/printer_test.go
index 8454ac12b..306928a69 100644
--- a/src/pkg/go/printer/printer_test.go
+++ b/src/pkg/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())
@@ -179,7 +179,7 @@ func check(t *testing.T, source, golden string, mode checkMode) {
// 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 +212,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.
//
diff --git a/src/pkg/go/printer/testdata/comments.golden b/src/pkg/go/printer/testdata/comments.golden
index 610a42a68..b1af7958a 100644
--- a/src/pkg/go/printer/testdata/comments.golden
+++ b/src/pkg/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/src/pkg/go/printer/testdata/comments.input b/src/pkg/go/printer/testdata/comments.input
index d121dd4be..983e2b2c9 100644
--- a/src/pkg/go/printer/testdata/comments.input
+++ b/src/pkg/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/src/pkg/go/printer/testdata/comments2.golden b/src/pkg/go/printer/testdata/comments2.golden
index d3b50bf3e..7676a26c1 100644
--- a/src/pkg/go/printer/testdata/comments2.golden
+++ b/src/pkg/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/src/pkg/go/printer/testdata/comments2.input b/src/pkg/go/printer/testdata/comments2.input
index 6f8c85c94..4a055c827 100644
--- a/src/pkg/go/printer/testdata/comments2.input
+++ b/src/pkg/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/src/pkg/go/printer/testdata/declarations.golden b/src/pkg/go/printer/testdata/declarations.golden
index 0331615e5..a27f21fc8 100644
--- a/src/pkg/go/printer/testdata/declarations.golden
+++ b/src/pkg/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
@@ -723,7 +738,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/src/pkg/go/printer/testdata/declarations.input b/src/pkg/go/printer/testdata/declarations.input
index dbdbdfe74..d9951d386 100644
--- a/src/pkg/go/printer/testdata/declarations.input
+++ b/src/pkg/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
@@ -737,7 +755,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/src/pkg/go/scanner/scanner.go b/src/pkg/go/scanner/scanner.go
index 1e259d5ed..cec82ea10 100644
--- a/src/pkg/go/scanner/scanner.go
+++ b/src/pkg/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/src/pkg/go/scanner/scanner_test.go b/src/pkg/go/scanner/scanner_test.go
index 8c64c2b95..fc450d8a6 100644
--- a/src/pkg/go/scanner/scanner_test.go
+++ b/src/pkg/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/src/pkg/hash/crc32/crc32_amd64p32.s b/src/pkg/hash/crc32/crc32_amd64p32.s
new file mode 100644
index 000000000..e34f20867
--- /dev/null
+++ b/src/pkg/hash/crc32/crc32_amd64p32.s
@@ -0,0 +1,64 @@
+// 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.
+
+#include "../../../cmd/ld/textflag.h"
+
+// func castagnoliSSE42(crc uint32, p []byte) uint32
+TEXT ·castagnoliSSE42(SB),NOSPLIT,$0
+ MOVL crc+0(FP), AX // CRC value
+ MOVL p+4(FP), SI // data pointer
+ MOVL p_len+8(FP), CX // len(p)
+
+ NOTL AX
+
+ /* If there's less than 8 bytes to process, we do it byte-by-byte. */
+ CMPQ CX, $8
+ JL cleanup
+
+ /* Process individual bytes until the input is 8-byte aligned. */
+startup:
+ MOVQ SI, BX
+ ANDQ $7, BX
+ JZ aligned
+
+ CRC32B (SI), AX
+ DECQ CX
+ INCQ SI
+ JMP startup
+
+aligned:
+ /* The input is now 8-byte aligned and we can process 8-byte chunks. */
+ CMPQ CX, $8
+ JL cleanup
+
+ CRC32Q (SI), AX
+ ADDQ $8, SI
+ SUBQ $8, CX
+ JMP aligned
+
+cleanup:
+ /* We may have some bytes left over that we process one at a time. */
+ CMPQ CX, $0
+ JE done
+
+ CRC32B (SI), AX
+ INCQ SI
+ DECQ CX
+ JMP cleanup
+
+done:
+ NOTL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func haveSSE42() bool
+TEXT ·haveSSE42(SB),NOSPLIT,$0
+ XORQ AX, AX
+ INCL AX
+ CPUID
+ SHRQ $20, CX
+ ANDQ $1, CX
+ MOVB CX, ret+0(FP)
+ RET
+
diff --git a/src/pkg/hash/crc32/crc32_amd64.go b/src/pkg/hash/crc32/crc32_amd64x.go
index b5bc6d3cf..b7e359930 100644
--- a/src/pkg/hash/crc32/crc32_amd64.go
+++ b/src/pkg/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/src/pkg/hash/fnv/fnv.go b/src/pkg/hash/fnv/fnv.go
index b5ecd4a7c..c0206613a 100644
--- a/src/pkg/hash/fnv/fnv.go
+++ b/src/pkg/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/src/pkg/html/escape_test.go b/src/pkg/html/escape_test.go
index b405d4b4a..2d7ad8ac2 100644
--- a/src/pkg/html/escape_test.go
+++ b/src/pkg/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/src/pkg/html/template/attr.go b/src/pkg/html/template/attr.go
index 3ea02880d..d65d34007 100644
--- a/src/pkg/html/template/attr.go
+++ b/src/pkg/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/src/pkg/html/template/content.go b/src/pkg/html/template/content.go
index 41b1116a6..3715ed5c9 100644
--- a/src/pkg/html/template/content.go
+++ b/src/pkg/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/src/pkg/html/template/context.go b/src/pkg/html/template/context.go
index eb47e2be3..59e794d68 100644
--- a/src/pkg/html/template/context.go
+++ b/src/pkg/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/src/pkg/html/template/escape.go b/src/pkg/html/template/escape.go
index 9ae9749db..4e379828d 100644
--- a/src/pkg/html/template/escape.go
+++ b/src/pkg/html/template/escape.go
@@ -40,10 +40,14 @@ func escapeTemplates(tmpl *Template, names ...string) error {
}
return err
}
- tmpl.escaped = true
- tmpl.Tree = tmpl.text.Tree
}
e.commit()
+ for _, name := range names {
+ if t := tmpl.set[name]; t != nil {
+ t.escaped = true
+ t.Tree = t.text.Tree
+ }
+ }
return nil
}
@@ -207,6 +211,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 +245,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 {
@@ -664,7 +684,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,
diff --git a/src/pkg/html/template/escape_test.go b/src/pkg/html/template/escape_test.go
index 58383a6cd..3ccf93ece 100644
--- a/src/pkg/html/template/escape_test.go
+++ b/src/pkg/html/template/escape_test.go
@@ -1649,6 +1649,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/src/pkg/html/template/html.go b/src/pkg/html/template/html.go
index f25f1074c..9c069efd1 100644
--- a/src/pkg/html/template/html.go
+++ b/src/pkg/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/src/pkg/html/template/js.go b/src/pkg/html/template/js.go
index d594e0ad7..999a61ed0 100644
--- a/src/pkg/html/template/js.go
+++ b/src/pkg/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/src/pkg/html/template/template.go b/src/pkg/html/template/template.go
index 11cc34a50..d38965897 100644
--- a/src/pkg/html/template/template.go
+++ b/src/pkg/html/template/template.go
@@ -62,6 +62,10 @@ func (t *Template) escape() error {
// 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 +75,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 {
diff --git a/src/pkg/image/color/palette/gen.go b/src/pkg/image/color/palette/gen.go
index f20c021de..4f4d88345 100644
--- a/src/pkg/image/color/palette/gen.go
+++ b/src/pkg/image/color/palette/gen.go
@@ -14,6 +14,10 @@ import (
)
func main() {
+ fmt.Println(`// 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.Println()
fmt.Println("// generated by go run gen.go; DO NOT EDIT")
fmt.Println()
fmt.Println("// Package palette provides standard color palettes.")
diff --git a/src/pkg/image/color/palette/palette.go b/src/pkg/image/color/palette/palette.go
index 3aba7401d..f761e5368 100644
--- a/src/pkg/image/color/palette/palette.go
+++ b/src/pkg/image/color/palette/palette.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 go run gen.go; DO NOT EDIT
// Package palette provides standard color palettes.
diff --git a/src/pkg/image/gif/reader.go b/src/pkg/image/gif/reader.go
index 8b0298a29..926710a45 100644
--- a/src/pkg/image/gif/reader.go
+++ b/src/pkg/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
@@ -175,11 +176,12 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
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) {
+ m.Palette[d.transparentIndex] = color.RGBA{}
+ }
litWidth, err := d.r.ReadByte()
if err != nil {
return err
@@ -228,7 +230,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 +345,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/src/pkg/image/gif/reader_test.go b/src/pkg/image/gif/reader_test.go
index 09867132d..fc2041e99 100644
--- a/src/pkg/image/gif/reader_test.go
+++ b/src/pkg/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 (
diff --git a/src/pkg/image/jpeg/huffman.go b/src/pkg/image/jpeg/huffman.go
index 9b731fdc4..f53d873a5 100644
--- a/src/pkg/image/jpeg/huffman.go
+++ b/src/pkg/image/jpeg/huffman.go
@@ -37,6 +37,9 @@ func (d *decoder) ensureNBits(n int) error {
for d.b.n < n {
c, err := d.r.ReadByte()
if err != nil {
+ if err == io.EOF {
+ return FormatError("short Huffman data")
+ }
return err
}
d.b.a = d.b.a<<8 | uint32(c)
@@ -50,6 +53,9 @@ func (d *decoder) ensureNBits(n int) error {
if c == 0xff {
c, err = d.r.ReadByte()
if err != nil {
+ if err == io.EOF {
+ return FormatError("short Huffman data")
+ }
return err
}
if c != 0x00 {
diff --git a/src/pkg/image/jpeg/reader_test.go b/src/pkg/image/jpeg/reader_test.go
index e951e038c..926bb0434 100644
--- a/src/pkg/image/jpeg/reader_test.go
+++ b/src/pkg/image/jpeg/reader_test.go
@@ -28,6 +28,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 +45,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)
@@ -84,18 +91,15 @@ func decodeFile(filename string) (image.Image, error) {
// 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 +112,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/src/pkg/image/jpeg/scan.go b/src/pkg/image/jpeg/scan.go
index a69ed1748..559235d51 100644
--- a/src/pkg/image/jpeg/scan.go
+++ b/src/pkg/image/jpeg/scan.go
@@ -141,25 +141,30 @@ 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 {
+ if nComp != 1 {
mx0, my0 = d.comp[compIndex].h*mx, d.comp[compIndex].v*my
if h0 == 1 {
my0 += j
diff --git a/src/pkg/image/png/reader.go b/src/pkg/image/png/reader.go
index a6bf86ede..dfe299102 100644
--- a/src/pkg/image/png/reader.go
+++ b/src/pkg/image/png/reader.go
@@ -505,8 +505,14 @@ func (d *decoder) decode() (image.Image, error) {
}
// Check for EOF, to verify the zlib checksum.
- n, err := r.Read(pr[:1])
- if err != io.EOF {
+ n := 0
+ for i := 0; n == 0 && err == nil; i++ {
+ if i == 100 {
+ return nil, io.ErrNoProgress
+ }
+ n, err = r.Read(pr[:1])
+ }
+ if err != nil && err != io.EOF {
return nil, FormatError(err.Error())
}
if n != 0 || d.idatLength != 0 {
diff --git a/src/pkg/image/testdata/video-001.separate.dc.progression.jpeg b/src/pkg/image/testdata/video-001.separate.dc.progression.jpeg
new file mode 100644
index 000000000..107f0fa0c
--- /dev/null
+++ b/src/pkg/image/testdata/video-001.separate.dc.progression.jpeg
Binary files differ
diff --git a/src/pkg/image/testdata/video-001.separate.dc.progression.progressive.jpeg b/src/pkg/image/testdata/video-001.separate.dc.progression.progressive.jpeg
new file mode 100644
index 000000000..a1d493ef8
--- /dev/null
+++ b/src/pkg/image/testdata/video-001.separate.dc.progression.progressive.jpeg
Binary files differ
diff --git a/src/pkg/io/io.go b/src/pkg/io/io.go
index f7073ffc0..022fdb676 100644
--- a/src/pkg/io/io.go
+++ b/src/pkg/io/io.go
@@ -74,6 +74,7 @@ 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.
type Writer interface {
Write(p []byte) (n int, err error)
}
diff --git a/src/pkg/io/io_test.go b/src/pkg/io/io_test.go
index bd7a82f17..57db1fbf0 100644
--- a/src/pkg/io/io_test.go
+++ b/src/pkg/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/src/pkg/io/ioutil/blackhole.go b/src/pkg/io/ioutil/blackhole.go
deleted file mode 100644
index 101d2c121..000000000
--- a/src/pkg/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/src/pkg/io/ioutil/ioutil.go b/src/pkg/io/ioutil/ioutil.go
index b2508b789..909a81563 100644
--- a/src/pkg/io/ioutil/ioutil.go
+++ b/src/pkg/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/src/pkg/io/multi.go b/src/pkg/io/multi.go
index 2c7e816cf..e26cc53e9 100644
--- a/src/pkg/io/multi.go
+++ b/src/pkg/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/src/pkg/io/multi_test.go b/src/pkg/io/multi_test.go
index eb717f7bc..56c6769a9 100644
--- a/src/pkg/io/multi_test.go
+++ b/src/pkg/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/src/pkg/log/example_test.go b/src/pkg/log/example_test.go
new file mode 100644
index 000000000..74385a3a0
--- /dev/null
+++ b/src/pkg/log/example_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.
+
+package log_test
+
+import (
+ "bytes"
+ "fmt"
+ "log"
+)
+
+func ExampleLogger() {
+ var buf bytes.Buffer
+ logger := log.New(&buf, "logger: ", log.Lshortfile)
+ logger.Print("Hello, log file!")
+
+ fmt.Print(&buf)
+ // Output:
+ // logger: example_test.go:16: Hello, log file!
+}
diff --git a/src/pkg/log/syslog/syslog.go b/src/pkg/log/syslog/syslog.go
index 0cbfa9011..5e0959916 100644
--- a/src/pkg/log/syslog/syslog.go
+++ b/src/pkg/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/src/pkg/log/syslog/syslog_test.go b/src/pkg/log/syslog/syslog_test.go
index 760a5c7d1..24a460f6d 100644
--- a/src/pkg/log/syslog/syslog_test.go
+++ b/src/pkg/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
diff --git a/src/pkg/log/syslog/syslog_unix.go b/src/pkg/log/syslog/syslog_unix.go
index 28a294af9..f6d2f1b7a 100644
--- a/src/pkg/log/syslog/syslog_unix.go
+++ b/src/pkg/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
diff --git a/src/pkg/math/abs_amd64p32.s b/src/pkg/math/abs_amd64p32.s
new file mode 100644
index 000000000..08c8c6b33
--- /dev/null
+++ b/src/pkg/math/abs_amd64p32.s
@@ -0,0 +1,5 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "abs_amd64.s"
diff --git a/src/pkg/math/asin_amd64p32.s b/src/pkg/math/asin_amd64p32.s
new file mode 100644
index 000000000..2751c475f
--- /dev/null
+++ b/src/pkg/math/asin_amd64p32.s
@@ -0,0 +1,5 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "asin_amd64.s"
diff --git a/src/pkg/math/atan2_amd64p32.s b/src/pkg/math/atan2_amd64p32.s
new file mode 100644
index 000000000..3fdc03ca8
--- /dev/null
+++ b/src/pkg/math/atan2_amd64p32.s
@@ -0,0 +1,5 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "atan2_amd64.s"
diff --git a/src/pkg/math/atan_amd64p32.s b/src/pkg/math/atan_amd64p32.s
new file mode 100644
index 000000000..1c1f6ceda
--- /dev/null
+++ b/src/pkg/math/atan_amd64p32.s
@@ -0,0 +1,5 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "atan_amd64.s"
diff --git a/src/pkg/math/big/arith.go b/src/pkg/math/big/arith.go
index f316806d7..3d5a8682d 100644
--- a/src/pkg/math/big/arith.go
+++ b/src/pkg/math/big/arith.go
@@ -131,12 +131,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
}
}
@@ -144,12 +143,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/src/pkg/math/big/arith_amd64p32.s b/src/pkg/math/big/arith_amd64p32.s
new file mode 100644
index 000000000..227870a00
--- /dev/null
+++ b/src/pkg/math/big/arith_amd64p32.s
@@ -0,0 +1,41 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "../../../cmd/ld/textflag.h"
+
+TEXT ·mulWW(SB),NOSPLIT,$0
+ JMP ·mulWW_g(SB)
+
+TEXT ·divWW(SB),NOSPLIT,$0
+ JMP ·divWW_g(SB)
+
+TEXT ·addVV(SB),NOSPLIT,$0
+ JMP ·addVV_g(SB)
+
+TEXT ·subVV(SB),NOSPLIT,$0
+ JMP ·subVV_g(SB)
+
+TEXT ·addVW(SB),NOSPLIT,$0
+ JMP ·addVW_g(SB)
+
+TEXT ·subVW(SB),NOSPLIT,$0
+ JMP ·subVW_g(SB)
+
+TEXT ·shlVU(SB),NOSPLIT,$0
+ JMP ·shlVU_g(SB)
+
+TEXT ·shrVU(SB),NOSPLIT,$0
+ JMP ·shrVU_g(SB)
+
+TEXT ·mulAddVWW(SB),NOSPLIT,$0
+ JMP ·mulAddVWW_g(SB)
+
+TEXT ·addMulVVW(SB),NOSPLIT,$0
+ JMP ·addMulVVW_g(SB)
+
+TEXT ·divWVW(SB),NOSPLIT,$0
+ JMP ·divWVW_g(SB)
+
+TEXT ·bitLen(SB),NOSPLIT,$0
+ JMP ·bitLen_g(SB)
diff --git a/src/pkg/math/big/arith_arm.s b/src/pkg/math/big/arith_arm.s
index ecf55b344..8d36761c4 100644
--- a/src/pkg/math/big/arith_arm.s
+++ b/src/pkg/math/big/arith_arm.s
@@ -7,31 +7,26 @@
// This file provides fast assembly versions for the elementary
// arithmetic operations on vectors implemented in arith.go.
-#define CFLAG 29 // bit position of carry flag
-
// func addVV(z, x, y []Word) (c Word)
TEXT ·addVV(SB),NOSPLIT,$0
- MOVW $0, R0
+ ADD.S $0, R0 // clear carry flag
MOVW z+0(FP), R1
+ MOVW z_len+4(FP), R4
MOVW x+12(FP), R2
MOVW y+24(FP), R3
- MOVW z_len+4(FP), R4
- MOVW R4<<2, R4
- ADD R1, R4
+ ADD R4<<2, R1, R4
B E1
L1:
MOVW.P 4(R2), R5
MOVW.P 4(R3), R6
- MOVW R0, CPSR
ADC.S R6, R5
MOVW.P R5, 4(R1)
- MOVW CPSR, R0
E1:
- CMP R1, R4
+ TEQ R1, R4
BNE L1
- MOVW R0>>CFLAG, R0
- AND $1, R0
+ MOVW $0, R0
+ MOVW.CS $1, R0
MOVW R0, c+36(FP)
RET
@@ -39,28 +34,24 @@ E1:
// func subVV(z, x, y []Word) (c Word)
// (same as addVV except for SBC instead of ADC and label names)
TEXT ·subVV(SB),NOSPLIT,$0
- MOVW $(1<<CFLAG), R0
+ SUB.S $0, R0 // clear borrow flag
MOVW z+0(FP), R1
+ MOVW z_len+4(FP), R4
MOVW x+12(FP), R2
MOVW y+24(FP), R3
- MOVW z_len+4(FP), R4
- MOVW R4<<2, R4
- ADD R1, R4
+ ADD R4<<2, R1, R4
B E2
L2:
MOVW.P 4(R2), R5
MOVW.P 4(R3), R6
- MOVW R0, CPSR
SBC.S R6, R5
MOVW.P R5, 4(R1)
- MOVW CPSR, R0
E2:
- CMP R1, R4
+ TEQ R1, R4
BNE L2
- MOVW R0>>CFLAG, R0
- AND $1, R0
- EOR $1, R0
+ MOVW $0, R0
+ MOVW.CC $1, R0
MOVW R0, c+36(FP)
RET
@@ -68,12 +59,11 @@ E2:
// func addVW(z, x []Word, y Word) (c Word)
TEXT ·addVW(SB),NOSPLIT,$0
MOVW z+0(FP), R1
+ MOVW z_len+4(FP), R4
MOVW x+12(FP), R2
MOVW y+24(FP), R3
- MOVW z_len+4(FP), R4
- MOVW R4<<2, R4
- ADD R1, R4
- CMP R1, R4
+ ADD R4<<2, R1, R4
+ TEQ R1, R4
BNE L3a
MOVW R3, c+28(FP)
RET
@@ -81,20 +71,17 @@ L3a:
MOVW.P 4(R2), R5
ADD.S R3, R5
MOVW.P R5, 4(R1)
- MOVW CPSR, R0
B E3
L3:
MOVW.P 4(R2), R5
- MOVW R0, CPSR
ADC.S $0, R5
MOVW.P R5, 4(R1)
- MOVW CPSR, R0
E3:
- CMP R1, R4
+ TEQ R1, R4
BNE L3
- MOVW R0>>CFLAG, R0
- AND $1, R0
+ MOVW $0, R0
+ MOVW.CS $1, R0
MOVW R0, c+28(FP)
RET
@@ -102,12 +89,11 @@ E3:
// func subVW(z, x []Word, y Word) (c Word)
TEXT ·subVW(SB),NOSPLIT,$0
MOVW z+0(FP), R1
+ MOVW z_len+4(FP), R4
MOVW x+12(FP), R2
MOVW y+24(FP), R3
- MOVW z_len+4(FP), R4
- MOVW R4<<2, R4
- ADD R1, R4
- CMP R1, R4
+ ADD R4<<2, R1, R4
+ TEQ R1, R4
BNE L4a
MOVW R3, c+28(FP)
RET
@@ -115,21 +101,17 @@ L4a:
MOVW.P 4(R2), R5
SUB.S R3, R5
MOVW.P R5, 4(R1)
- MOVW CPSR, R0
B E4
L4:
MOVW.P 4(R2), R5
- MOVW R0, CPSR
SBC.S $0, R5
MOVW.P R5, 4(R1)
- MOVW CPSR, R0
E4:
- CMP R1, R4
+ TEQ R1, R4
BNE L4
- MOVW R0>>CFLAG, R0
- AND $1, R0
- EOR $1, R0
+ MOVW $0, R0
+ MOVW.CC $1, R0
MOVW R0, c+28(FP)
RET
@@ -137,16 +119,15 @@ E4:
// func shlVU(z, x []Word, s uint) (c Word)
TEXT ·shlVU(SB),NOSPLIT,$0
MOVW z_len+4(FP), R5
- CMP $0, R5
+ TEQ $0, R5
BEQ X7
MOVW z+0(FP), R1
MOVW x+12(FP), R2
- MOVW R5<<2, R5
- ADD R5, R2
- ADD R1, R5
+ ADD R5<<2, R2, R2
+ ADD R5<<2, R1, R5
MOVW s+24(FP), R3
- CMP $0, R3 // shift 0 is special
+ TEQ $0, R3 // shift 0 is special
BEQ Y7
ADD $4, R1 // stop one word early
MOVW $32, R4
@@ -165,7 +146,7 @@ L7:
MOVW.W R7, -4(R5)
MOVW R6<<R3, R7
E7:
- CMP R1, R5
+ TEQ R1, R5
BNE L7
MOVW R7, -4(R5)
@@ -174,7 +155,7 @@ E7:
Y7: // copy loop, because shift 0 == shift 32
MOVW.W -4(R2), R6
MOVW.W R6, -4(R5)
- CMP R1, R5
+ TEQ R1, R5
BNE Y7
X7:
@@ -186,15 +167,14 @@ X7:
// func shrVU(z, x []Word, s uint) (c Word)
TEXT ·shrVU(SB),NOSPLIT,$0
MOVW z_len+4(FP), R5
- CMP $0, R5
+ TEQ $0, R5
BEQ X6
MOVW z+0(FP), R1
MOVW x+12(FP), R2
- MOVW R5<<2, R5
- ADD R1, R5
+ ADD R5<<2, R1, R5
MOVW s+24(FP), R3
- CMP $0, R3 // shift 0 is special
+ TEQ $0, R3 // shift 0 is special
BEQ Y6
SUB $4, R5 // stop one word early
MOVW $32, R4
@@ -215,7 +195,7 @@ L6:
MOVW.P R7, 4(R1)
MOVW R6>>R3, R7
E6:
- CMP R1, R5
+ TEQ R1, R5
BNE L6
MOVW R7, 0(R1)
@@ -224,7 +204,7 @@ E6:
Y6: // copy loop, because shift 0 == shift 32
MOVW.P 4(R2), R6
MOVW.P R6, 4(R1)
- CMP R1, R5
+ TEQ R1, R5
BNE Y6
X6:
@@ -237,12 +217,11 @@ X6:
TEXT ·mulAddVWW(SB),NOSPLIT,$0
MOVW $0, R0
MOVW z+0(FP), R1
+ MOVW z_len+4(FP), R5
MOVW x+12(FP), R2
MOVW y+24(FP), R3
MOVW r+28(FP), R4
- MOVW z_len+4(FP), R5
- MOVW R5<<2, R5
- ADD R1, R5
+ ADD R5<<2, R1, R5
B E8
// word loop
@@ -254,7 +233,7 @@ L8:
MOVW.P R6, 4(R1)
MOVW R7, R4
E8:
- CMP R1, R5
+ TEQ R1, R5
BNE L8
MOVW R4, c+32(FP)
@@ -265,11 +244,10 @@ E8:
TEXT ·addMulVVW(SB),NOSPLIT,$0
MOVW $0, R0
MOVW z+0(FP), R1
+ MOVW z_len+4(FP), R5
MOVW x+12(FP), R2
MOVW y+24(FP), R3
- MOVW z_len+4(FP), R5
- MOVW R5<<2, R5
- ADD R1, R5
+ ADD R5<<2, R1, R5
MOVW $0, R4
B E9
@@ -285,7 +263,7 @@ L9:
MOVW.P R6, 4(R1)
MOVW R7, R4
E9:
- CMP R1, R5
+ TEQ R1, R5
BNE L9
MOVW R4, c+28(FP)
@@ -317,7 +295,6 @@ TEXT ·mulWW(SB),NOSPLIT,$0
TEXT ·bitLen(SB),NOSPLIT,$0
MOVW x+0(FP), R0
CLZ R0, R0
- MOVW $32, R1
- SUB.S R0, R1
- MOVW R1, n+4(FP)
+ RSB $32, R0
+ MOVW R0, n+4(FP)
RET
diff --git a/src/pkg/math/big/int.go b/src/pkg/math/big/int.go
index 7bbb152d7..269949d61 100644
--- a/src/pkg/math/big/int.go
+++ b/src/pkg/math/big/int.go
@@ -576,21 +576,22 @@ 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
return z
}
@@ -982,17 +983,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/src/pkg/math/big/int_test.go b/src/pkg/math/big/int_test.go
index 87b975d5c..299dc72fb 100644
--- a/src/pkg/math/big/int_test.go
+++ b/src/pkg/math/big/int_test.go
@@ -9,6 +9,7 @@ import (
"encoding/gob"
"encoding/hex"
"encoding/json"
+ "encoding/xml"
"fmt"
"math/rand"
"testing"
@@ -767,6 +768,19 @@ 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"},
@@ -1528,6 +1542,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/src/pkg/math/big/nat.go b/src/pkg/math/big/nat.go
index 6874900d0..16a87f5c5 100644
--- a/src/pkg/math/big/nat.go
+++ b/src/pkg/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/src/pkg/math/big/nat_test.go b/src/pkg/math/big/nat_test.go
index 1d4dfe80d..a2ae53385 100644
--- a/src/pkg/math/big/nat_test.go
+++ b/src/pkg/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/src/pkg/math/big/rat.go b/src/pkg/math/big/rat.go
index 7faee61a4..f0973b390 100644
--- a/src/pkg/math/big/rat.go
+++ b/src/pkg/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--
@@ -477,7 +477,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 +486,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 +495,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 +585,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/src/pkg/math/big/rat_test.go b/src/pkg/math/big/rat_test.go
index 0d432637b..414a67d41 100644
--- a/src/pkg/math/big/rat_test.go
+++ b/src/pkg/math/big/rat_test.go
@@ -7,6 +7,8 @@ package big
import (
"bytes"
"encoding/gob"
+ "encoding/json"
+ "encoding/xml"
"fmt"
"math"
"strconv"
@@ -433,6 +435,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)
diff --git a/src/pkg/math/cmplx/cmath_test.go b/src/pkg/math/cmplx/cmath_test.go
index 610ca8ceb..f285646af 100644
--- a/src/pkg/math/cmplx/cmath_test.go
+++ b/src/pkg/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/src/pkg/math/cmplx/pow.go b/src/pkg/math/cmplx/pow.go
index 4dbc58398..1630b879b 100644
--- a/src/pkg/math/cmplx/pow.go
+++ b/src/pkg/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/src/pkg/math/cmplx/sqrt.go b/src/pkg/math/cmplx/sqrt.go
index 179b5396a..4ef6807ad 100644
--- a/src/pkg/math/cmplx/sqrt.go
+++ b/src/pkg/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/src/pkg/math/dim_amd64p32.s b/src/pkg/math/dim_amd64p32.s
new file mode 100644
index 000000000..e5e34479d
--- /dev/null
+++ b/src/pkg/math/dim_amd64p32.s
@@ -0,0 +1,5 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "dim_amd64.s"
diff --git a/src/pkg/math/exp2_amd64p32.s b/src/pkg/math/exp2_amd64p32.s
new file mode 100644
index 000000000..4d3830914
--- /dev/null
+++ b/src/pkg/math/exp2_amd64p32.s
@@ -0,0 +1,5 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "exp2_amd64.s"
diff --git a/src/pkg/math/exp_amd64p32.s b/src/pkg/math/exp_amd64p32.s
new file mode 100644
index 000000000..98ac2e91e
--- /dev/null
+++ b/src/pkg/math/exp_amd64p32.s
@@ -0,0 +1,5 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "exp_amd64.s"
diff --git a/src/pkg/math/expm1_amd64p32.s b/src/pkg/math/expm1_amd64p32.s
new file mode 100644
index 000000000..709ebefcb
--- /dev/null
+++ b/src/pkg/math/expm1_amd64p32.s
@@ -0,0 +1,5 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "expm1_amd64.s"
diff --git a/src/pkg/math/floor_amd64p32.s b/src/pkg/math/floor_amd64p32.s
new file mode 100644
index 000000000..5b87d7a40
--- /dev/null
+++ b/src/pkg/math/floor_amd64p32.s
@@ -0,0 +1,5 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "floor_amd64.s"
diff --git a/src/pkg/math/frexp_amd64p32.s b/src/pkg/math/frexp_amd64p32.s
new file mode 100644
index 000000000..fbb564539
--- /dev/null
+++ b/src/pkg/math/frexp_amd64p32.s
@@ -0,0 +1,5 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "frexp_amd64.s"
diff --git a/src/pkg/math/hypot_amd64p32.s b/src/pkg/math/hypot_amd64p32.s
new file mode 100644
index 000000000..b84542ae3
--- /dev/null
+++ b/src/pkg/math/hypot_amd64p32.s
@@ -0,0 +1,5 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "hypot_amd64.s"
diff --git a/src/pkg/math/ldexp_amd64p32.s b/src/pkg/math/ldexp_amd64p32.s
new file mode 100644
index 000000000..9aa9d9da3
--- /dev/null
+++ b/src/pkg/math/ldexp_amd64p32.s
@@ -0,0 +1,5 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "ldexp_amd64.s"
diff --git a/src/pkg/math/log10_amd64p32.s b/src/pkg/math/log10_amd64p32.s
new file mode 100644
index 000000000..bf43841e2
--- /dev/null
+++ b/src/pkg/math/log10_amd64p32.s
@@ -0,0 +1,5 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "log10_amd64.s"
diff --git a/src/pkg/math/log1p_amd64p32.s b/src/pkg/math/log1p_amd64p32.s
new file mode 100644
index 000000000..a14b5e38a
--- /dev/null
+++ b/src/pkg/math/log1p_amd64p32.s
@@ -0,0 +1,5 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "log1p_amd64.s"
diff --git a/src/pkg/math/log_amd64p32.s b/src/pkg/math/log_amd64p32.s
new file mode 100644
index 000000000..5058d607e
--- /dev/null
+++ b/src/pkg/math/log_amd64p32.s
@@ -0,0 +1,5 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "log_amd64.s"
diff --git a/src/pkg/math/mod_amd64p32.s b/src/pkg/math/mod_amd64p32.s
new file mode 100644
index 000000000..c1b231124
--- /dev/null
+++ b/src/pkg/math/mod_amd64p32.s
@@ -0,0 +1,5 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "mod_amd64.s"
diff --git a/src/pkg/math/modf_amd64p32.s b/src/pkg/math/modf_amd64p32.s
new file mode 100644
index 000000000..5508c2547
--- /dev/null
+++ b/src/pkg/math/modf_amd64p32.s
@@ -0,0 +1,5 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "modf_amd64.s"
diff --git a/src/pkg/math/rand/rand.go b/src/pkg/math/rand/rand.go
index 2157cdb46..3ffb5c4e5 100644
--- a/src/pkg/math/rand/rand.go
+++ b/src/pkg/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/src/pkg/math/rand/rand_test.go b/src/pkg/math/rand/rand_test.go
index 4d3abdb60..ab0dc49b4 100644
--- a/src/pkg/math/rand/rand_test.go
+++ b/src/pkg/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/src/pkg/math/rand/regress_test.go b/src/pkg/math/rand/regress_test.go
new file mode 100644
index 000000000..2b012af89
--- /dev/null
+++ b/src/pkg/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/src/pkg/math/remainder_amd64p32.s b/src/pkg/math/remainder_amd64p32.s
new file mode 100644
index 000000000..cd5cf55ff
--- /dev/null
+++ b/src/pkg/math/remainder_amd64p32.s
@@ -0,0 +1,5 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "remainder_amd64.s"
diff --git a/src/pkg/math/sin_amd64p32.s b/src/pkg/math/sin_amd64p32.s
new file mode 100644
index 000000000..9f93eba20
--- /dev/null
+++ b/src/pkg/math/sin_amd64p32.s
@@ -0,0 +1,5 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "sin_amd64.s"
diff --git a/src/pkg/math/sincos_amd64p32.s b/src/pkg/math/sincos_amd64p32.s
new file mode 100644
index 000000000..360e94d09
--- /dev/null
+++ b/src/pkg/math/sincos_amd64p32.s
@@ -0,0 +1,5 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "sincos_amd64.s"
diff --git a/src/pkg/math/sqrt_amd64p32.s b/src/pkg/math/sqrt_amd64p32.s
new file mode 100644
index 000000000..d83a286c2
--- /dev/null
+++ b/src/pkg/math/sqrt_amd64p32.s
@@ -0,0 +1,5 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "sqrt_amd64.s"
diff --git a/src/pkg/math/tan_amd64p32.s b/src/pkg/math/tan_amd64p32.s
new file mode 100644
index 000000000..9b3f70de7
--- /dev/null
+++ b/src/pkg/math/tan_amd64p32.s
@@ -0,0 +1,5 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "tan_amd64.s"
diff --git a/src/pkg/mime/mediatype.go b/src/pkg/mime/mediatype.go
index 608f759da..ad63f9bb9 100644
--- a/src/pkg/mime/mediatype.go
+++ b/src/pkg/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/src/pkg/mime/mediatype_test.go b/src/pkg/mime/mediatype_test.go
index 29511445b..026bfa4d7 100644
--- a/src/pkg/mime/mediatype_test.go
+++ b/src/pkg/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/src/pkg/mime/multipart/example_test.go b/src/pkg/mime/multipart/example_test.go
new file mode 100644
index 000000000..26135b785
--- /dev/null
+++ b/src/pkg/mime/multipart/example_test.go
@@ -0,0 +1,53 @@
+// 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 multipart_test
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "mime"
+ "mime/multipart"
+ "net/mail"
+ "strings"
+)
+
+func ExampleNewReader() {
+ msg := &mail.Message{
+ Header: map[string][]string{
+ "Content-Type": []string{"multipart/mixed; boundary=foo"},
+ },
+ Body: strings.NewReader(
+ "--foo\r\nFoo: one\r\n\r\nA section\r\n" +
+ "--foo\r\nFoo: two\r\n\r\nAnd another\r\n" +
+ "--foo--\r\n"),
+ }
+ mediaType, params, err := mime.ParseMediaType(msg.Header.Get("Content-Type"))
+ if err != nil {
+ log.Fatal(err)
+ }
+ if strings.HasPrefix(mediaType, "multipart/") {
+ mr := multipart.NewReader(msg.Body, params["boundary"])
+ for {
+ p, err := mr.NextPart()
+ if err == io.EOF {
+ return
+ }
+ if err != nil {
+ log.Fatal(err)
+ }
+ slurp, err := ioutil.ReadAll(p)
+ if err != nil {
+ log.Fatal(err)
+ }
+ fmt.Printf("Part %q: %q\n", p.Header.Get("Foo"), slurp)
+ }
+ }
+
+ // Output:
+ // Part "one": "A section"
+ // Part "two": "And another"
+}
diff --git a/src/pkg/mime/multipart/formdata_test.go b/src/pkg/mime/multipart/formdata_test.go
index 4bc464931..6e2388baf 100644
--- a/src/pkg/mime/multipart/formdata_test.go
+++ b/src/pkg/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/src/pkg/mime/multipart/multipart.go b/src/pkg/mime/multipart/multipart.go
index 2b4f5b433..7382efab9 100644
--- a/src/pkg/mime/multipart/multipart.go
+++ b/src/pkg/mime/multipart/multipart.go
@@ -81,12 +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],
diff --git a/src/pkg/mime/multipart/quotedprintable_test.go b/src/pkg/mime/multipart/quotedprintable_test.go
index 8a95f7f03..c4de3eb75 100644
--- a/src/pkg/mime/multipart/quotedprintable_test.go
+++ b/src/pkg/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/src/pkg/mime/type_unix.go b/src/pkg/mime/type_unix.go
index 713e301cd..1d394315a 100644
--- a/src/pkg/mime/type_unix.go
+++ b/src/pkg/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
diff --git a/src/pkg/net/cgo_bsd.go b/src/pkg/net/cgo_bsd.go
index 388eab4fe..3090d3019 100644
--- a/src/pkg/net/cgo_bsd.go
+++ b/src/pkg/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/src/pkg/net/cgo_unix_test.go b/src/pkg/net/cgo_unix_test.go
new file mode 100644
index 000000000..33566ce9c
--- /dev/null
+++ b/src/pkg/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/src/pkg/net/conn_test.go b/src/pkg/net/conn_test.go
index 98bd69549..37bb4e2c0 100644
--- a/src/pkg/net/conn_test.go
+++ b/src/pkg/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 "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/src/pkg/net/dial.go b/src/pkg/net/dial.go
index 6304818bf..93569c253 100644
--- a/src/pkg/net/dial.go
+++ b/src/pkg/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.
@@ -162,9 +168,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 +188,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 +199,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,7 +210,6 @@ 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 {
@@ -205,12 +219,11 @@ func dialMulti(net, addr string, la Addr, ras addrList, deadline time.Time) (Con
if racer.error == nil {
return racer.Conn, nil
}
- failAddr = racer.Addr
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/src/pkg/net/dial_test.go b/src/pkg/net/dial_test.go
index f1d813f41..f9260fd28 100644
--- a/src/pkg/net/dial_test.go
+++ b/src/pkg/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.
@@ -141,13 +141,13 @@ func TestSelfConnect(t *testing.T) {
n = 1000
}
switch runtime.GOOS {
- case "darwin", "dragonfly", "freebsd", "netbsd", "openbsd", "plan9", "windows":
+ case "darwin", "dragonfly", "freebsd", "netbsd", "openbsd", "plan9", "solaris", "windows":
// Non-Linux systems take a long time to figure
// out that there is nothing listening on localhost.
n = 100
}
for i := 0; i < n; i++ {
- c, err := Dial("tcp", addr)
+ c, err := DialTimeout("tcp", addr, time.Millisecond)
if err == nil {
c.Close()
t.Errorf("#%d: Dial %q succeeded", i, addr)
@@ -425,60 +425,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 {
@@ -555,3 +501,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/src/pkg/net/dialgoogle_test.go b/src/pkg/net/dialgoogle_test.go
index b4ebad0e0..df5895afa 100644
--- a/src/pkg/net/dialgoogle_test.go
+++ b/src/pkg/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/src/pkg/net/dnsclient.go b/src/pkg/net/dnsclient.go
index 01db43729..9bffa11f9 100644
--- a/src/pkg/net/dnsclient.go
+++ b/src/pkg/net/dnsclient.go
@@ -191,10 +191,10 @@ 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])
diff --git a/src/pkg/net/dnsclient_test.go b/src/pkg/net/dnsclient_test.go
new file mode 100644
index 000000000..435eb3550
--- /dev/null
+++ b/src/pkg/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/src/pkg/net/dnsclient_unix.go b/src/pkg/net/dnsclient_unix.go
index 16cf420dc..3713efd0e 100644
--- a/src/pkg/net/dnsclient_unix.go
+++ b/src/pkg/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 nacl 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).
@@ -19,6 +18,7 @@ package net
import (
"io"
"math/rand"
+ "os"
"sync"
"time"
)
@@ -156,32 +156,90 @@ 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)
+ cname, addrs, err = tryOneName(cfg.dnsConfig, rname, qtype)
if err == nil {
return
}
@@ -191,12 +249,12 @@ func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err error)
}
// 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
}
@@ -207,7 +265,7 @@ func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err error)
if !rooted {
rname += "."
}
- cname, addrs, err = tryOneName(cfg, rname, qtype)
+ cname, addrs, err = tryOneName(cfg.dnsConfig, rname, qtype)
if err == nil {
return
}
@@ -232,11 +290,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,11 +320,6 @@ 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
@@ -307,11 +355,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/src/pkg/net/dnsclient_unix_test.go b/src/pkg/net/dnsclient_unix_test.go
index 47dcb563b..2350142d6 100644
--- a/src/pkg/net/dnsclient_unix_test.go
+++ b/src/pkg/net/dnsclient_unix_test.go
@@ -2,12 +2,18 @@
// 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) {
@@ -25,3 +31,129 @@ func TestTCPLookup(t *testing.T) {
t.Fatalf("exchange failed: %v", err)
}
}
+
+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("could not create temp dir: %v", err)
+ }
+
+ // Disable the default loadConfig
+ onceLoadConfig.Do(func() {})
+
+ r := &resolvConfTest{
+ T: t,
+ dir: dir,
+ path: path.Join(dir, "resolv.conf"),
+ quitc: make(chan chan struct{}),
+ }
+
+ 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 {
+ 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]"})
+}
diff --git a/src/pkg/net/dnsconfig_unix.go b/src/pkg/net/dnsconfig_unix.go
index 2f0f6c031..af288253e 100644
--- a/src/pkg/net/dnsconfig_unix.go
+++ b/src/pkg/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 nacl netbsd openbsd solaris
// Read system DNS config from /etc/resolv.conf
@@ -20,14 +20,13 @@ 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.servers = make([]string, 0, 3) // small, but the standard limit
conf.search = make([]string, 0)
conf.ndots = 1
conf.timeout = 5
diff --git a/src/pkg/net/dnsconfig_unix_test.go b/src/pkg/net/dnsconfig_unix_test.go
new file mode 100644
index 000000000..37ed4931d
--- /dev/null
+++ b/src/pkg/net/dnsconfig_unix_test.go
@@ -0,0 +1,46 @@
+// 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 "testing"
+
+func TestDNSReadConfig(t *testing.T) {
+ dnsConfig, err := dnsReadConfig("testdata/resolv.conf")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if len(dnsConfig.servers) != 1 {
+ t.Errorf("len(dnsConfig.servers) = %d; want %d", len(dnsConfig.servers), 1)
+ }
+ if dnsConfig.servers[0] != "[192.168.1.1]" {
+ t.Errorf("dnsConfig.servers[0] = %s; want %s", dnsConfig.servers[0], "[192.168.1.1]")
+ }
+
+ if len(dnsConfig.search) != 1 {
+ t.Errorf("len(dnsConfig.search) = %d; want %d", len(dnsConfig.search), 1)
+ }
+ if dnsConfig.search[0] != "Home" {
+ t.Errorf("dnsConfig.search[0] = %s; want %s", dnsConfig.search[0], "Home")
+ }
+
+ if dnsConfig.ndots != 5 {
+ t.Errorf("dnsConfig.ndots = %d; want %d", dnsConfig.ndots, 5)
+ }
+
+ if dnsConfig.timeout != 10 {
+ t.Errorf("dnsConfig.timeout = %d; want %d", dnsConfig.timeout, 10)
+ }
+
+ if dnsConfig.attempts != 3 {
+ t.Errorf("dnsConfig.attempts = %d; want %d", dnsConfig.attempts, 3)
+ }
+
+ if dnsConfig.rotate != true {
+ t.Errorf("dnsConfig.rotate = %t; want %t", dnsConfig.rotate, true)
+ }
+}
diff --git a/src/pkg/net/fd_mutex_test.go b/src/pkg/net/fd_mutex_test.go
index 8383084b7..c34ec59b9 100644
--- a/src/pkg/net/fd_mutex_test.go
+++ b/src/pkg/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/src/pkg/net/fd_plan9.go b/src/pkg/net/fd_plan9.go
index acc829402..5fe8effc2 100644
--- a/src/pkg/net/fd_plan9.go
+++ b/src/pkg/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/src/pkg/net/fd_poll_nacl.go b/src/pkg/net/fd_poll_nacl.go
new file mode 100644
index 000000000..a3701f876
--- /dev/null
+++ b/src/pkg/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/src/pkg/net/fd_poll_runtime.go b/src/pkg/net/fd_poll_runtime.go
index e2b276886..2bddc836c 100644
--- a/src/pkg/net/fd_poll_runtime.go
+++ b/src/pkg/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/src/pkg/net/fd_unix.go b/src/pkg/net/fd_unix.go
index 9ed4f7536..b82ecd11c 100644
--- a/src/pkg/net/fd_unix.go
+++ b/src/pkg/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
@@ -75,19 +75,47 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr) error {
if err := fd.pd.PrepareWrite(); err != nil {
return err
}
+ switch err := syscall.Connect(fd.sysfd, ra); err {
+ case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
+ case nil, syscall.EISCONN:
+ 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" {
+ return nil
+ }
+ fallthrough
+ default:
+ return err
+ }
for {
- err := syscall.Connect(fd.sysfd, ra)
- if err == nil || err == syscall.EISCONN {
- break
+ // 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 != syscall.EINPROGRESS && err != syscall.EALREADY && err != syscall.EINTR {
+ nerr, err := syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
+ if err != nil {
return err
}
- if err = fd.pd.WaitWrite(); err != nil {
+ 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() {
@@ -180,11 +208,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)
}
@@ -215,7 +243,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
}
@@ -242,7 +270,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
}
@@ -313,7 +341,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
}
@@ -338,7 +366,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
}
@@ -347,7 +375,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
@@ -356,7 +384,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}
@@ -455,7 +482,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/src/pkg/net/fd_unix_test.go b/src/pkg/net/fd_unix_test.go
index 65d3e69a7..fe8e8ff6a 100644
--- a/src/pkg/net/fd_unix_test.go
+++ b/src/pkg/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/src/pkg/net/fd_windows.go b/src/pkg/net/fd_windows.go
index 630fc5e6f..a1f6bc5f8 100644
--- a/src/pkg/net/fd_windows.go
+++ b/src/pkg/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]
}
}
@@ -431,11 +431,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 +458,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 +497,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
}
@@ -628,10 +628,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/src/pkg/net/file_plan9.go b/src/pkg/net/file_plan9.go
index f6ee1c29e..068f0881d 100644
--- a/src/pkg/net/file_plan9.go
+++ b/src/pkg/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/src/pkg/net/file_test.go b/src/pkg/net/file_test.go
index acaf18851..d81bca782 100644
--- a/src/pkg/net/file_test.go
+++ b/src/pkg/net/file_test.go
@@ -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/src/pkg/net/file_unix.go b/src/pkg/net/file_unix.go
index 8fe1b0eb0..07b3ecf62 100644
--- a/src/pkg/net/file_unix.go
+++ b/src/pkg/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 nacl 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/src/pkg/net/hosts_test.go b/src/pkg/net/hosts_test.go
index b07ed0baa..2fe358e07 100644
--- a/src/pkg/net/hosts_test.go
+++ b/src/pkg/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/src/pkg/net/http/cgi/host.go b/src/pkg/net/http/cgi/host.go
index d27cc4dc9..ec95a972c 100644
--- a/src/pkg/net/http/cgi/host.go
+++ b/src/pkg/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/src/pkg/net/http/cgi/matryoshka_test.go b/src/pkg/net/http/cgi/matryoshka_test.go
index e1a78c8f6..18c4803e7 100644
--- a/src/pkg/net/http/cgi/matryoshka_test.go
+++ b/src/pkg/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/src/pkg/net/http/chunked.go b/src/pkg/net/http/chunked.go
index 91db01724..749f29d32 100644
--- a/src/pkg/net/http/chunked.go
+++ b/src/pkg/net/http/chunked.go
@@ -4,13 +4,14 @@
// The wire protocol for HTTP's "chunked" Transfer-Encoding.
-// This code is duplicated in httputil/chunked.go.
+// This code is duplicated in net/http and net/http/httputil.
// Please make any changes in both files.
package http
import (
"bufio"
+ "bytes"
"errors"
"fmt"
"io"
@@ -57,26 +58,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")
+ }
}
}
}
diff --git a/src/pkg/net/http/chunked_test.go b/src/pkg/net/http/chunked_test.go
index 0b18c7b55..34544790a 100644
--- a/src/pkg/net/http/chunked_test.go
+++ b/src/pkg/net/http/chunked_test.go
@@ -2,17 +2,18 @@
// 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.
+// This code is duplicated in net/http and net/http/httputil.
// Please make any changes in both files.
package http
import (
+ "bufio"
"bytes"
"fmt"
"io"
"io/ioutil"
- "runtime"
+ "strings"
"testing"
)
@@ -41,9 +42,77 @@ func TestChunk(t *testing.T) {
}
}
+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) {
- // temporarily set GOMAXPROCS to 1 as we are testing memory allocations
- defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
+ 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")
@@ -52,26 +121,23 @@ func TestChunkReaderAllocs(t *testing.T) {
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)
+ 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)
}
}
diff --git a/src/pkg/net/http/client.go b/src/pkg/net/http/client.go
index 22f2e865c..a5a3abe61 100644
--- a/src/pkg/net/http/client.go
+++ b/src/pkg/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)
}
@@ -97,7 +115,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 +141,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 +155,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,21 +284,40 @@ 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
}
@@ -279,15 +325,18 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo
// Add the Referer header.
lastReq := via[len(via)-1]
if lastReq.URL.Scheme != "https" {
- req.Header.Set("Referer", lastReq.URL.String())
+ nreq.Header.Set("Referer", lastReq.URL.String())
}
- 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 +345,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 +360,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 +407,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 +466,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/src/pkg/net/http/client_test.go b/src/pkg/net/http/client_test.go
index 997d04151..6392c1baf 100644
--- a/src/pkg/net/http/client_test.go
+++ b/src/pkg/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,198 @@ 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)
+ }
+}
diff --git a/src/pkg/net/http/cookie.go b/src/pkg/net/http/cookie.go
index 8b01c508e..dc60ba87f 100644
--- a/src/pkg/net/http/cookie.go
+++ b/src/pkg/net/http/cookie.go
@@ -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)
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])
@@ -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
- }
- 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)
+ // Strip the quotes, if present.
+ if len(raw) > 1 && raw[0] == '"' && raw[len(raw)-1] == '"' {
+ raw = raw[1 : len(raw)-1]
+ }
for i := 0; i < len(raw); i++ {
- if !validByte(raw[i]) {
+ if !validCookieValueByte(raw[i]) {
return "", false
}
}
diff --git a/src/pkg/net/http/cookie_test.go b/src/pkg/net/http/cookie_test.go
index 11b01cc57..f78f37299 100644
--- a/src/pkg/net/http/cookie_test.go
+++ b/src/pkg/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
@@ -244,22 +328,39 @@ func TestReadCookies(t *testing.T) {
}
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 +373,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/src/pkg/net/http/export_test.go b/src/pkg/net/http/export_test.go
index 22b7f2796..960563b24 100644
--- a/src/pkg/net/http/export_test.go
+++ b/src/pkg/net/http/export_test.go
@@ -21,7 +21,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 +32,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 +43,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 {
@@ -63,4 +64,9 @@ func NewTestTimeoutHandler(handler Handler, ch <-chan time.Time) Handler {
return &timeoutHandler{handler, f, ""}
}
+func ResetCachedEnvironment() {
+ httpProxyEnv.reset()
+ noProxyEnv.reset()
+}
+
var DefaultUserAgent = defaultUserAgent
diff --git a/src/pkg/net/http/fcgi/child.go b/src/pkg/net/http/fcgi/child.go
index 60b794e07..a3beaa33a 100644
--- a/src/pkg/net/http/fcgi/child.go
+++ b/src/pkg/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/src/pkg/net/http/fs.go b/src/pkg/net/http/fs.go
index 8b32ca1d0..8576cf844 100644
--- a/src/pkg/net/http/fs.go
+++ b/src/pkg/net/http/fs.go
@@ -13,6 +13,7 @@ import (
"mime"
"mime/multipart"
"net/textproto"
+ "net/url"
"os"
"path"
"path/filepath"
@@ -52,12 +53,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 +76,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")
@@ -521,7 +527,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/src/pkg/net/http/fs_test.go b/src/pkg/net/http/fs_test.go
index ae54edf0c..f968565f9 100644
--- a/src/pkg/net/http/fs_test.go
+++ b/src/pkg/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
diff --git a/src/pkg/net/http/header.go b/src/pkg/net/http/header.go
index ca1ae07c2..153b94370 100644
--- a/src/pkg/net/http/header.go
+++ b/src/pkg/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/src/pkg/net/http/header_test.go b/src/pkg/net/http/header_test.go
index 9fd9837a5..9dcd591fa 100644
--- a/src/pkg/net/http/header_test.go
+++ b/src/pkg/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")
}
if runtime.GOMAXPROCS(0) > 1 {
t.Skip("skipping; GOMAXPROCS>1")
@@ -204,6 +207,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/src/pkg/net/http/httptest/server_test.go b/src/pkg/net/http/httptest/server_test.go
index 500a9f0b8..501cc8a99 100644
--- a/src/pkg/net/http/httptest/server_test.go
+++ b/src/pkg/net/http/httptest/server_test.go
@@ -8,6 +8,7 @@ import (
"io/ioutil"
"net/http"
"testing"
+ "time"
)
func TestServer(t *testing.T) {
@@ -27,3 +28,25 @@ func TestServer(t *testing.T) {
t.Errorf("got %q, want hello", string(got))
}
}
+
+func TestIssue7264(t *testing.T) {
+ for i := 0; i < 1000; i++ {
+ func() {
+ inHandler := make(chan bool, 1)
+ ts := NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ inHandler <- true
+ }))
+ defer ts.Close()
+ tr := &http.Transport{
+ ResponseHeaderTimeout: time.Nanosecond,
+ }
+ defer tr.CloseIdleConnections()
+ c := &http.Client{Transport: tr}
+ res, err := c.Get(ts.URL)
+ <-inHandler
+ if err == nil {
+ res.Body.Close()
+ }
+ }()
+ }
+}
diff --git a/src/pkg/net/http/httputil/chunked.go b/src/pkg/net/http/httputil/chunked.go
index b66d40951..9632bfd19 100644
--- a/src/pkg/net/http/httputil/chunked.go
+++ b/src/pkg/net/http/httputil/chunked.go
@@ -4,15 +4,14 @@
// 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/
+// This code is duplicated in net/http and net/http/httputil.
// Please make any changes in both files.
package httputil
import (
"bufio"
+ "bytes"
"errors"
"fmt"
"io"
@@ -22,13 +21,13 @@ 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
+// 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
+// newChunkedReader is not needed by normal applications. The http package
// automatically decodes chunking when reading response bodies.
-func NewChunkedReader(r io.Reader) io.Reader {
+func newChunkedReader(r io.Reader) io.Reader {
br, ok := r.(*bufio.Reader)
if !ok {
br = bufio.NewReader(r)
@@ -59,26 +58,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")
+ }
}
}
}
@@ -117,16 +135,16 @@ func isASCIISpace(b byte) bool {
return b == ' ' || b == '\t' || b == '\n' || b == '\r'
}
-// NewChunkedWriter returns a new chunkedWriter that translates writes into HTTP
+// 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
+// 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 {
+func newChunkedWriter(w io.Writer) io.WriteCloser {
return &chunkedWriter{w}
}
diff --git a/src/pkg/net/http/httputil/chunked_test.go b/src/pkg/net/http/httputil/chunked_test.go
index a06bffad5..a7a577468 100644
--- a/src/pkg/net/http/httputil/chunked_test.go
+++ b/src/pkg/net/http/httputil/chunked_test.go
@@ -2,26 +2,25 @@
// 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/
+// This code is duplicated in net/http and net/http/httputil.
// Please make any changes in both files.
package httputil
import (
+ "bufio"
"bytes"
"fmt"
"io"
"io/ioutil"
- "runtime"
+ "strings"
"testing"
)
func TestChunk(t *testing.T) {
var b bytes.Buffer
- w := NewChunkedWriter(&b)
+ w := newChunkedWriter(&b)
const chunk1 = "hello, "
const chunk2 = "world! 0123456789abcdef"
w.Write([]byte(chunk1))
@@ -32,7 +31,7 @@ func TestChunk(t *testing.T) {
t.Fatalf("chunk writer wrote %q; want %q", g, e)
}
- r := NewChunkedReader(&b)
+ r := newChunkedReader(&b)
data, err := ioutil.ReadAll(r)
if err != nil {
t.Logf(`data: "%s"`, data)
@@ -43,37 +42,102 @@ func TestChunk(t *testing.T) {
}
}
+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) {
- // temporarily set GOMAXPROCS to 1 as we are testing memory allocations
- defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
+ if testing.Short() {
+ t.Skip("skipping in short mode")
+ }
var buf bytes.Buffer
- w := NewChunkedWriter(&buf)
+ 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)
+ 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)
}
}
diff --git a/src/pkg/net/http/httputil/dump.go b/src/pkg/net/http/httputil/dump.go
index 265499fb0..2a7a413d0 100644
--- a/src/pkg/net/http/httputil/dump.go
+++ b/src/pkg/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
@@ -106,6 +107,7 @@ func DumpRequestOut(req *http.Request, body bool) ([]byte, error) {
return &dumpConn{io.MultiWriter(&buf, pw), dr}, nil
},
}
+ defer t.CloseIdleConnections()
_, err := t.RoundTrip(reqSend)
@@ -230,14 +232,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 +264,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/src/pkg/net/http/httputil/dump_test.go b/src/pkg/net/http/httputil/dump_test.go
index 987a82048..e1ffb3935 100644
--- a/src/pkg/net/http/httputil/dump_test.go
+++ b/src/pkg/net/http/httputil/dump_test.go
@@ -11,6 +11,8 @@ import (
"io/ioutil"
"net/http"
"net/url"
+ "runtime"
+ "strings"
"testing"
)
@@ -112,6 +114,7 @@ var dumpTests = []dumpTest{
}
func TestDumpRequest(t *testing.T) {
+ numg0 := runtime.NumGoroutine()
for i, tt := range dumpTests {
setBody := func() {
if tt.Body == nil {
@@ -119,7 +122,7 @@ 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()
}
@@ -155,6 +158,9 @@ func TestDumpRequest(t *testing.T) {
}
}
}
+ if dg := runtime.NumGoroutine() - numg0; dg > 4 {
+ t.Errorf("Unexpectedly large number of new goroutines: %d new", dg)
+ }
}
func chunk(s string) string {
@@ -176,3 +182,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/src/pkg/net/http/httputil/httputil.go b/src/pkg/net/http/httputil/httputil.go
new file mode 100644
index 000000000..74fb6c655
--- /dev/null
+++ b/src/pkg/net/http/httputil/httputil.go
@@ -0,0 +1,32 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package httputil provides HTTP utility functions, complementing the
+// more common ones in the net/http package.
+package httputil
+
+import "io"
+
+// 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 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 newChunkedWriter(w)
+}
diff --git a/src/pkg/net/http/httputil/persist.go b/src/pkg/net/http/httputil/persist.go
index 507938aca..987bcc96b 100644
--- a/src/pkg/net/http/httputil/persist.go
+++ b/src/pkg/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/src/pkg/net/http/httputil/reverseproxy.go b/src/pkg/net/http/httputil/reverseproxy.go
index 1990f64db..48ada5f5f 100644
--- a/src/pkg/net/http/httputil/reverseproxy.go
+++ b/src/pkg/net/http/httputil/reverseproxy.go
@@ -144,6 +144,10 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
}
defer res.Body.Close()
+ for _, h := range hopHeaders {
+ res.Header.Del(h)
+ }
+
copyHeader(rw.Header(), res.Header)
rw.WriteHeader(res.StatusCode)
diff --git a/src/pkg/net/http/httputil/reverseproxy_test.go b/src/pkg/net/http/httputil/reverseproxy_test.go
index 1c0444ec4..e9539b44b 100644
--- a/src/pkg/net/http/httputil/reverseproxy_test.go
+++ b/src/pkg/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/src/pkg/net/http/proxy_test.go b/src/pkg/net/http/proxy_test.go
index 449ccaeea..b6aed3792 100644
--- a/src/pkg/net/http/proxy_test.go
+++ b/src/pkg/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/src/pkg/net/http/race.go b/src/pkg/net/http/race.go
new file mode 100644
index 000000000..766503967
--- /dev/null
+++ b/src/pkg/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/src/pkg/net/http/request.go b/src/pkg/net/http/request.go
index 57b5d0948..a67092066 100644
--- a/src/pkg/net/http/request.go
+++ b/src/pkg/net/http/request.go
@@ -20,6 +20,7 @@ import (
"net/url"
"strconv"
"strings"
+ "sync"
)
const (
@@ -68,18 +69,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 +117,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 +140,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 +151,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 +182,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
@@ -381,7 +417,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
@@ -494,25 +529,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,32 +618,6 @@ 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
@@ -677,6 +681,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 +716,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 +736,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 +789,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
}
@@ -860,3 +867,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/src/pkg/net/http/request_test.go b/src/pkg/net/http/request_test.go
index 89303c336..b9fa3c2bf 100644
--- a/src/pkg/net/http/request_test.go
+++ b/src/pkg/net/http/request_test.go
@@ -60,6 +60,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 +99,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 +111,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 +154,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 +238,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")
}
}
@@ -343,7 +440,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/src/pkg/net/http/requestwrite_test.go b/src/pkg/net/http/requestwrite_test.go
index b27b1f7ce..dc0e204ca 100644
--- a/src/pkg/net/http/requestwrite_test.go
+++ b/src/pkg/net/http/requestwrite_test.go
@@ -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()
}
diff --git a/src/pkg/net/http/response.go b/src/pkg/net/http/response.go
index 35d0ba3bb..5d2c39080 100644
--- a/src/pkg/net/http/response.go
+++ b/src/pkg/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/src/pkg/net/http/response_test.go b/src/pkg/net/http/response_test.go
index 5044306a8..4b8946f7a 100644
--- a/src/pkg/net/http/response_test.go
+++ b/src/pkg/net/http/response_test.go
@@ -14,6 +14,7 @@ import (
"io/ioutil"
"net/url"
"reflect"
+ "regexp"
"strings"
"testing"
)
@@ -28,6 +29,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.
{
@@ -406,8 +411,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
@@ -506,6 +510,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 +622,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/src/pkg/net/http/responsewrite_test.go b/src/pkg/net/http/responsewrite_test.go
index 5c10e2161..585b13b85 100644
--- a/src/pkg/net/http/responsewrite_test.go
+++ b/src/pkg/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/src/pkg/net/http/serve_test.go b/src/pkg/net/http/serve_test.go
index 955112bc2..9e4d226bf 100644
--- a/src/pkg/net/http/serve_test.go
+++ b/src/pkg/net/http/serve_test.go
@@ -419,7 +419,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 +441,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 +520,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)
@@ -840,9 +846,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 +868,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 +888,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 +933,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 +1005,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.
@@ -1414,6 +1470,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 +1993,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 +2121,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"))
+ }))
+ 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)
}))
- 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 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")
}
}
@@ -2073,8 +2286,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)
}
@@ -2093,6 +2306,230 @@ 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: []ConnState{StateNew, StateActive, StateIdle, StateActive, StateClosed},
+ 2: []ConnState{StateNew, StateActive, StateIdle, StateActive, StateClosed},
+ 3: []ConnState{StateNew, StateActive, StateHijacked},
+ 4: []ConnState{StateNew, StateActive, StateHijacked},
+ 5: []ConnState{StateNew, StateClosed},
+ 6: []ConnState{StateNew, StateActive, StateClosed},
+ 7: []ConnState{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")
+ }
+}
+
func BenchmarkClientServer(b *testing.B) {
b.ReportAllocs()
b.StopTimer()
@@ -2108,6 +2545,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)
}
@@ -2128,41 +2566,33 @@ func BenchmarkClientServerParallel64(b *testing.B) {
benchmarkClientServerParallel(b, 64)
}
-func benchmarkClientServerParallel(b *testing.B, conc int) {
+func benchmarkClientServerParallel(b *testing.B, parallelism int) {
b.ReportAllocs()
- b.StopTimer()
ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, r *Request) {
fmt.Fprintf(rw, "Hello world.\n")
}))
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) {
+ for pb.Next() {
+ res, err := 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.
@@ -2187,6 +2617,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)
}
@@ -2390,3 +2821,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/src/pkg/net/http/server.go b/src/pkg/net/http/server.go
index 0e46863d5..eae097eb8 100644
--- a/src/pkg/net/http/server.go
+++ b/src/pkg/net/http/server.go
@@ -22,6 +22,7 @@ import (
"strconv"
"strings"
"sync"
+ "sync/atomic"
"time"
)
@@ -138,6 +139,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
}
@@ -435,56 +437,52 @@ func (srv *Server) newConn(rwc net.Conn) (c *conn, err error) {
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 +498,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 +572,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 +620,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 +639,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 +709,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 +742,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 +750,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 +776,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 +799,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,13 +820,13 @@ 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")
@@ -855,7 +856,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 +920,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:
@@ -965,7 +966,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 +1002,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()
}
@@ -1084,17 +1084,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 +1114,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 +1130,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 +1156,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 +1182,7 @@ func (c *conn) serve() {
}
break
}
+ c.setState(c.rwc, StateIdle)
}
}
@@ -1202,7 +1210,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 +1577,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 +1594,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 +1681,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 +1706,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 +1717,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 +1840,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)
}
@@ -1834,6 +1935,24 @@ func (tw *timeoutWriter) WriteHeader(code int) {
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 +1969,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.
diff --git a/src/pkg/net/http/transfer.go b/src/pkg/net/http/transfer.go
index bacd83732..7f6368652 100644
--- a/src/pkg/net/http/transfer.go
+++ b/src/pkg/net/http/transfer.go
@@ -12,10 +12,20 @@ import (
"io"
"io/ioutil"
"net/textproto"
+ "sort"
"strconv"
"strings"
+ "sync"
)
+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 +62,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 +144,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,43 +155,44 @@ 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
@@ -216,11 +229,16 @@ func (t *transferWriter) WriteBody(w io.Writer) (err error) {
// 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 +270,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"}
@@ -331,17 +365,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: 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
@@ -498,7 +532,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 +548,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 +564,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 +586,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 +664,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 +695,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/src/pkg/net/http/transfer_test.go b/src/pkg/net/http/transfer_test.go
index 8627a374c..48cd540b9 100644
--- a/src/pkg/net/http/transfer_test.go
+++ b/src/pkg/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/src/pkg/net/http/transport.go b/src/pkg/net/http/transport.go
index f6871afac..b1cc632a7 100644
--- a/src/pkg/net/http/transport.go
+++ b/src/pkg/net/http/transport.go
@@ -30,7 +30,14 @@ 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.
@@ -40,13 +47,13 @@ const DefaultMaxIdleConnsPerHost = 2
// https, and http proxies (for either http or https with CONNECT).
// Transport can also cache connections for future re-use.
type Transport struct {
- idleMu sync.Mutex
- idleConn map[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
+ idleMu sync.Mutex
+ 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
@@ -63,6 +70,10 @@ type Transport struct {
// 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
@@ -98,8 +109,11 @@ type Transport struct {
// An error is returned if the proxy environment is invalid.
// 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.
+//
+// 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")
+ proxy := httpProxyEnv.Get()
if proxy == "" {
return nil, nil
}
@@ -149,9 +163,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 +178,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 +198,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
}
@@ -218,9 +239,6 @@ func (t *Transport) CloseIdleConnections() {
t.idleConn = nil
t.idleConnCh = nil
t.idleMu.Unlock()
- if m == nil {
- return
- }
for _, conns := range m {
for _, pconn := range conns {
pconn.close()
@@ -232,10 +250,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,24 +261,49 @@ 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"},
}
- 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
}
@@ -316,7 +359,7 @@ func (t *Transport) putIdleConn(pconn *persistConn) bool {
}
}
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,7 +379,7 @@ 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
}
@@ -344,7 +387,7 @@ func (t *Transport) getIdleConnCh(cm *connectMethod) chan *persistConn {
t.idleMu.Lock()
defer t.idleMu.Unlock()
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 +397,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 +416,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 +424,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)
}
}
@@ -405,7 +448,7 @@ func (t *Transport) dial(network, addr string) (c net.Conn, err error) {
// 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 +458,16 @@ func (t *Transport) getConn(cm *connectMethod) (*persistConn, error) {
err error
}
dialc := make(chan dialRes)
+
+ handlePendingDial := func() {
+ if v := <-dialc; v.err == nil {
+ t.putIdleConn(v.pc)
+ }
+ }
+
+ cancelc := make(chan struct{})
+ t.setReqCanceler(req, func() { close(cancelc) })
+
go func() {
pc, err := t.dialConn(cm)
dialc <- dialRes{pc, err}
@@ -431,16 +484,15 @@ 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)
- }
- }()
+ go handlePendingDial()
return pc, nil
+ case <-cancelc:
+ go handlePendingDial()
+ return nil, errors.New("net/http: request canceled while waiting for connection")
}
}
-func (t *Transport) dialConn(cm *connectMethod) (*persistConn, error) {
+func (t *Transport) dialConn(cm connectMethod) (*persistConn, error) {
conn, err := t.dial("tcp", cm.addr())
if err != nil {
if cm.proxyURL != nil {
@@ -452,12 +504,13 @@ func (t *Transport) dialConn(cm *connectMethod) (*persistConn, error) {
pa := cm.proxyAuth()
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(),
+ conn: conn,
+ reqch: make(chan requestAndChan, 1),
+ writech: make(chan writeRequest, 1),
+ closech: make(chan struct{}),
+ writeErrCh: make(chan error, 1),
}
switch {
@@ -511,19 +564,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 := 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 +622,7 @@ func useProxy(addr string) bool {
}
}
- no_proxy := getenvEitherCase("NO_PROXY")
+ no_proxy := noProxyEnv.Get()
if no_proxy == "*" {
return false
}
@@ -590,8 +662,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 +675,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 +709,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 +751,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 +759,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 +776,6 @@ func remoteSideClosed(err error) bool {
}
func (pc *persistConn) readLoop() {
- defer close(pc.closech)
alive := true
for alive {
@@ -688,12 +783,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 +809,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 +823,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 +846,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 +865,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 +894,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 +956,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
@@ -902,11 +1038,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 +1054,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 +1079,7 @@ func (pc *persistConn) closeLocked() {
if !pc.closed {
pc.conn.Close()
pc.closed = true
+ close(pc.closech)
}
pc.mutateHeaderFunc = nil
}
@@ -1025,7 +1162,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/src/pkg/net/http/transport_test.go b/src/pkg/net/http/transport_test.go
index e4df30a98..964ca0fca 100644
--- a/src/pkg/net/http/transport_test.go
+++ b/src/pkg/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) {
}))
@@ -1014,6 +1111,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 +1175,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 +1250,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 +1279,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 +1370,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 +1464,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 +1553,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 +1591,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
@@ -1559,13 +1742,11 @@ 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("NO_PROXY", tt.noenv)
+ ResetCachedEnvironment()
reqURL := tt.req
if reqURL == "" {
reqURL = "http://example.com"
@@ -1643,6 +1824,308 @@ 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 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/src/pkg/net/interface.go b/src/pkg/net/interface.go
index 0713e9cd6..2e9f1ebc6 100644
--- a/src/pkg/net/interface.go
+++ b/src/pkg/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/src/pkg/net/interface_linux.go b/src/pkg/net/interface_linux.go
index 1207c0f26..1115d0fc4 100644
--- a/src/pkg/net/interface_linux.go
+++ b/src/pkg/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/src/pkg/net/interface_stub.go b/src/pkg/net/interface_stub.go
index a4eb731da..c38fb7f76 100644
--- a/src/pkg/net/interface_stub.go
+++ b/src/pkg/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/src/pkg/net/ip.go b/src/pkg/net/ip.go
index fd6a7d4ee..0582009b8 100644
--- a/src/pkg/net/ip.go
+++ b/src/pkg/net/ip.go
@@ -623,6 +623,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
}
diff --git a/src/pkg/net/ip_test.go b/src/pkg/net/ip_test.go
index 26b53729b..ffeb9d315 100644
--- a/src/pkg/net/ip_test.go
+++ b/src/pkg/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) {
diff --git a/src/pkg/net/ipraw_test.go b/src/pkg/net/ipraw_test.go
index ea183f1d3..0632dafc6 100644
--- a/src/pkg/net/ipraw_test.go
+++ b/src/pkg/net/ipraw_test.go
@@ -247,7 +247,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 +277,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/src/pkg/net/iprawsock_posix.go b/src/pkg/net/iprawsock_posix.go
index 722853257..bbb3f3ed6 100644
--- a/src/pkg/net/iprawsock_posix.go
+++ b/src/pkg/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
diff --git a/src/pkg/net/ipsock.go b/src/pkg/net/ipsock.go
index 8b586ef7c..dda857803 100644
--- a/src/pkg/net/ipsock.go
+++ b/src/pkg/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/src/pkg/net/ipsock_plan9.go b/src/pkg/net/ipsock_plan9.go
index fcec4164f..94ceea31b 100644
--- a/src/pkg/net/ipsock_plan9.go
+++ b/src/pkg/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/src/pkg/net/ipsock_posix.go b/src/pkg/net/ipsock_posix.go
index a83e52561..2ba4c8efd 100644
--- a/src/pkg/net/ipsock_posix.go
+++ b/src/pkg/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
diff --git a/src/pkg/net/lookup_plan9.go b/src/pkg/net/lookup_plan9.go
index f1204a99f..b80ac10e0 100644
--- a/src/pkg/net/lookup_plan9.go
+++ b/src/pkg/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/src/pkg/net/lookup_unix.go b/src/pkg/net/lookup_unix.go
index 59e9f6321..b1d2f8f31 100644
--- a/src/pkg/net/lookup_unix.go
+++ b/src/pkg/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 nacl netbsd openbsd solaris
package net
diff --git a/src/pkg/net/mail/message.go b/src/pkg/net/mail/message.go
index dc2ab44da..ba0778caa 100644
--- a/src/pkg/net/mail/message.go
+++ b/src/pkg/net/mail/message.go
@@ -159,7 +159,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 +169,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 +363,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 +442,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)
+ return "", fmt.Errorf("charset not supported: %q", charset)
}
in := bytes.NewBufferString(fields[3])
@@ -455,7 +457,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)
@@ -535,3 +537,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/src/pkg/net/mail/message_test.go b/src/pkg/net/mail/message_test.go
index 3c037f383..eb9c8cbdc 100644
--- a/src/pkg/net/mail/message_test.go
+++ b/src/pkg/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
@@ -277,6 +286,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/src/pkg/net/multicast_test.go b/src/pkg/net/multicast_test.go
index 5660fd42f..63dbce88e 100644
--- a/src/pkg/net/multicast_test.go
+++ b/src/pkg/net/multicast_test.go
@@ -25,8 +25,10 @@ var ipv4MulticastListenerTests = []struct {
// port.
func TestIPv4MulticastListener(t *testing.T) {
switch runtime.GOOS {
- case "plan9":
+ case "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/src/pkg/net/net.go b/src/pkg/net/net.go
index 2e6db5551..ca56af54f 100644
--- a/src/pkg/net/net.go
+++ b/src/pkg/net/net.go
@@ -275,7 +275,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 +346,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/src/pkg/net/net_test.go b/src/pkg/net/net_test.go
index 1320096df..bfed4d657 100644
--- a/src/pkg/net/net_test.go
+++ b/src/pkg/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/src/pkg/net/net_windows_test.go b/src/pkg/net/net_windows_test.go
index 8b1c9cdc5..2f57745e3 100644
--- a/src/pkg/net/net_windows_test.go
+++ b/src/pkg/net/net_windows_test.go
@@ -84,7 +84,7 @@ func TestAcceptIgnoreSomeErrors(t *testing.T) {
}
err = cmd.Start()
if err != nil {
- t.Fatalf("cmd.Start failed: %v\n%s\n", err)
+ t.Fatalf("cmd.Start failed: %v\n", err)
}
outReader := bufio.NewReader(stdout)
for {
@@ -107,7 +107,7 @@ func TestAcceptIgnoreSomeErrors(t *testing.T) {
result := make(chan error)
go func() {
time.Sleep(alittle)
- err = send(ln.Addr().String(), "abc")
+ err := send(ln.Addr().String(), "abc")
if err != nil {
result <- err
}
diff --git a/src/pkg/net/netgo_unix_test.go b/src/pkg/net/netgo_unix_test.go
new file mode 100644
index 000000000..9fb2a567d
--- /dev/null
+++ b/src/pkg/net/netgo_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 solaris
+
+package net
+
+import "testing"
+
+func TestGoLookupIP(t *testing.T) {
+ host := "localhost"
+ _, err, ok := cgoLookupIP(host)
+ if ok {
+ t.Errorf("cgoLookupIP must 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/src/pkg/net/packetconn_test.go b/src/pkg/net/packetconn_test.go
index 945003f67..b6e4e76f9 100644
--- a/src/pkg/net/packetconn_test.go
+++ b/src/pkg/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/src/pkg/net/parse.go b/src/pkg/net/parse.go
index 6056de248..ee6e7e995 100644
--- a/src/pkg/net/parse.go
+++ b/src/pkg/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 {
diff --git a/src/pkg/net/port_unix.go b/src/pkg/net/port_unix.go
index 3cd9ca2aa..89558c1f0 100644
--- a/src/pkg/net/port_unix.go
+++ b/src/pkg/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 nacl 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/src/pkg/net/protoconn_test.go b/src/pkg/net/protoconn_test.go
index 5a8958b08..12856b6c3 100644
--- a/src/pkg/net/protoconn_test.go
+++ b/src/pkg/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/src/pkg/net/rpc/client.go b/src/pkg/net/rpc/client.go
index c524d0a0a..21f79b068 100644
--- a/src/pkg/net/rpc/client.go
+++ b/src/pkg/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
+
+ sending sync.Mutex
+
+ mutex sync.Mutex // protects following
request Request
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
@@ -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/src/pkg/net/rpc/client_test.go b/src/pkg/net/rpc/client_test.go
new file mode 100644
index 000000000..bbfc1ec3a
--- /dev/null
+++ b/src/pkg/net/rpc/client_test.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 rpc
+
+import (
+ "errors"
+ "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")
+ }
+}
diff --git a/src/pkg/net/rpc/jsonrpc/all_test.go b/src/pkg/net/rpc/jsonrpc/all_test.go
index 40d4b82d7..a433a365e 100644
--- a/src/pkg/net/rpc/jsonrpc/all_test.go
+++ b/src/pkg/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/src/pkg/net/rpc/jsonrpc/server.go b/src/pkg/net/rpc/jsonrpc/server.go
index 16ec0fe9a..e6d37cfa6 100644
--- a/src/pkg/net/rpc/jsonrpc/server.go
+++ b/src/pkg/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/src/pkg/net/rpc/server.go b/src/pkg/net/rpc/server.go
index 7eb2dcf5a..6b264b46b 100644
--- a/src/pkg/net/rpc/server.go
+++ b/src/pkg/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 {
diff --git a/src/pkg/net/rpc/server_test.go b/src/pkg/net/rpc/server_test.go
index 3b9a88380..0dc4ddc2d 100644
--- a/src/pkg/net/rpc/server_test.go
+++ b/src/pkg/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/src/pkg/net/sendfile_dragonfly.go b/src/pkg/net/sendfile_dragonfly.go
index a2219c163..bc88fd3b9 100644
--- a/src/pkg/net/sendfile_dragonfly.go
+++ b/src/pkg/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/src/pkg/net/sendfile_freebsd.go b/src/pkg/net/sendfile_freebsd.go
index 42fe799ef..ffc147262 100644
--- a/src/pkg/net/sendfile_freebsd.go
+++ b/src/pkg/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/src/pkg/net/sendfile_stub.go b/src/pkg/net/sendfile_stub.go
index 3660849c1..03426ef0d 100644
--- a/src/pkg/net/sendfile_stub.go
+++ b/src/pkg/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/src/pkg/net/server_test.go b/src/pkg/net/server_test.go
index 9194a8ec2..6a2bb9243 100644
--- a/src/pkg/net/server_test.go
+++ b/src/pkg/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/src/pkg/net/smtp/example_test.go b/src/pkg/net/smtp/example_test.go
new file mode 100644
index 000000000..d551e365a
--- /dev/null
+++ b/src/pkg/net/smtp/example_test.go
@@ -0,0 +1,61 @@
+// 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 smtp_test
+
+import (
+ "fmt"
+ "log"
+ "net/smtp"
+)
+
+func Example() {
+ // Connect to the remote SMTP server.
+ c, err := smtp.Dial("mail.example.com:25")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // Set the sender and recipient first
+ if err := c.Mail("sender@example.org"); err != nil {
+ log.Fatal(err)
+ }
+ if err := c.Rcpt("recipient@example.net"); err != nil {
+ log.Fatal(err)
+ }
+
+ // Send the email body.
+ wc, err := c.Data()
+ if err != nil {
+ log.Fatal(err)
+ }
+ _, err = fmt.Fprintf(wc, "This is the email body")
+ if err != nil {
+ log.Fatal(err)
+ }
+ err = wc.Close()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // Send the QUIT command and close the connection.
+ err = c.Quit()
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+func ExamplePlainAuth() {
+ // Set up authentication information.
+ auth := smtp.PlainAuth("", "user@example.com", "password", "mail.example.com")
+
+ // Connect to the server, authenticate, set the sender and recipient,
+ // and send the email all in one step.
+ to := []string{"recipient@example.net"}
+ msg := []byte("This is the email body.")
+ err := smtp.SendMail("mail.example.com:25", auth, "sender@example.org", to, msg)
+ if err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/src/pkg/net/smtp/smtp.go b/src/pkg/net/smtp/smtp.go
index a0a478a85..87dea442c 100644
--- a/src/pkg/net/smtp/smtp.go
+++ b/src/pkg/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/src/pkg/net/smtp/smtp_test.go b/src/pkg/net/smtp/smtp_test.go
index 2133dc7c7..3fba1ea5a 100644
--- a/src/pkg/net/smtp/smtp_test.go
+++ b/src/pkg/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/pkg/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/src/pkg/net/sock_bsd.go b/src/pkg/net/sock_bsd.go
index 6c37109f5..48fb78527 100644
--- a/src/pkg/net/sock_bsd.go
+++ b/src/pkg/net/sock_bsd.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd netbsd openbsd
+// +build darwin dragonfly freebsd nacl netbsd openbsd
package net
diff --git a/src/pkg/net/sock_cloexec.go b/src/pkg/net/sock_cloexec.go
index 3f22cd8f5..dec81855b 100644
--- a/src/pkg/net/sock_cloexec.go
+++ b/src/pkg/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/src/pkg/net/sock_posix.go b/src/pkg/net/sock_posix.go
index c2d343c58..a6ef874c9 100644
--- a/src/pkg/net/sock_posix.go
+++ b/src/pkg/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
diff --git a/src/pkg/net/sock_solaris.go b/src/pkg/net/sock_solaris.go
new file mode 100644
index 000000000..90fe9de89
--- /dev/null
+++ b/src/pkg/net/sock_solaris.go
@@ -0,0 +1,13 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import "syscall"
+
+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/src/pkg/net/sockopt_bsd.go b/src/pkg/net/sockopt_bsd.go
index ef6eb8505..77d51d737 100644
--- a/src/pkg/net/sockopt_bsd.go
+++ b/src/pkg/net/sockopt_bsd.go
@@ -2,16 +2,29 @@
// 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
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 6355 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/src/pkg/net/sockopt_plan9.go b/src/pkg/net/sockopt_plan9.go
new file mode 100644
index 000000000..8bc689b6c
--- /dev/null
+++ b/src/pkg/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/src/pkg/net/sockopt_posix.go b/src/pkg/net/sockopt_posix.go
index ff3bc6899..921918c37 100644
--- a/src/pkg/net/sockopt_posix.go
+++ b/src/pkg/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 nacl netbsd openbsd solaris windows
package net
diff --git a/src/pkg/net/sockopt_solaris.go b/src/pkg/net/sockopt_solaris.go
new file mode 100644
index 000000000..54c20b140
--- /dev/null
+++ b/src/pkg/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/src/pkg/net/sockoptip_bsd.go b/src/pkg/net/sockoptip_bsd.go
index 2199e480d..87132f0f4 100644
--- a/src/pkg/net/sockoptip_bsd.go
+++ b/src/pkg/net/sockoptip_bsd.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd netbsd openbsd
+// +build darwin dragonfly freebsd nacl netbsd openbsd
package net
diff --git a/src/pkg/net/sockoptip_posix.go b/src/pkg/net/sockoptip_posix.go
index c2579be91..b5c80e449 100644
--- a/src/pkg/net/sockoptip_posix.go
+++ b/src/pkg/net/sockoptip_posix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd windows
package net
diff --git a/src/pkg/net/sockoptip_stub.go b/src/pkg/net/sockoptip_stub.go
new file mode 100644
index 000000000..dcd3a22b5
--- /dev/null
+++ b/src/pkg/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 solaris
+
+package net
+
+import "syscall"
+
+func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
+ // See golang.org/issue/7399.
+ return syscall.EINVAL
+}
+
+func setIPv4MulticastLoopback(fd *netFD, v bool) error {
+ // See golang.org/issue/7399.
+ return syscall.EINVAL
+}
+
+func joinIPv4Group(fd *netFD, ifi *Interface, ip IP) error {
+ // See golang.org/issue/7399.
+ return syscall.EINVAL
+}
+
+func setIPv6MulticastInterface(fd *netFD, ifi *Interface) error {
+ // See golang.org/issue/7399.
+ return syscall.EINVAL
+}
+
+func setIPv6MulticastLoopback(fd *netFD, v bool) error {
+ // See golang.org/issue/7399.
+ return syscall.EINVAL
+}
+
+func joinIPv6Group(fd *netFD, ifi *Interface, ip IP) error {
+ // See golang.org/issue/7399.
+ return syscall.EINVAL
+}
diff --git a/src/pkg/net/sys_cloexec.go b/src/pkg/net/sys_cloexec.go
index bbfcc1a4f..898fb7c0c 100644
--- a/src/pkg/net/sys_cloexec.go
+++ b/src/pkg/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/src/pkg/net/tcp_test.go b/src/pkg/net/tcp_test.go
index 62fd99f5c..c04198ea0 100644
--- a/src/pkg/net/tcp_test.go
+++ b/src/pkg/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/src/pkg/net/tcpsock_plan9.go b/src/pkg/net/tcpsock_plan9.go
index cf9c0f890..52019d7b4 100644
--- a/src/pkg/net/tcpsock_plan9.go
+++ b/src/pkg/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/src/pkg/net/tcpsock_posix.go b/src/pkg/net/tcpsock_posix.go
index 00c692e42..b79b115ca 100644
--- a/src/pkg/net/tcpsock_posix.go
+++ b/src/pkg/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
diff --git a/src/pkg/net/tcpsockopt_dragonfly.go b/src/pkg/net/tcpsockopt_dragonfly.go
new file mode 100644
index 000000000..d10a77773
--- /dev/null
+++ b/src/pkg/net/tcpsockopt_dragonfly.go
@@ -0,0 +1,29 @@
+// 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"
+)
+
+// Set keep alive period.
+func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
+ if err := fd.incref(); err != nil {
+ return err
+ }
+ defer fd.decref()
+
+ // The kernel expects milliseconds so round to next highest millisecond.
+ d += (time.Millisecond - time.Nanosecond)
+ msecs := int(time.Duration(d.Nanoseconds()) / time.Millisecond)
+
+ err := os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, msecs))
+ if err != nil {
+ return err
+ }
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, msecs))
+}
diff --git a/src/pkg/net/tcpsockopt_plan9.go b/src/pkg/net/tcpsockopt_plan9.go
new file mode 100644
index 000000000..0e7a6647c
--- /dev/null
+++ b/src/pkg/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/src/pkg/net/tcpsockopt_posix.go b/src/pkg/net/tcpsockopt_posix.go
index e03476ac6..6484bad4b 100644
--- a/src/pkg/net/tcpsockopt_posix.go
+++ b/src/pkg/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 nacl netbsd openbsd solaris windows
package net
diff --git a/src/pkg/net/tcpsockopt_solaris.go b/src/pkg/net/tcpsockopt_solaris.go
new file mode 100644
index 000000000..eaab6b678
--- /dev/null
+++ b/src/pkg/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/src/pkg/net/tcpsockopt_unix.go b/src/pkg/net/tcpsockopt_unix.go
index 89d9143b5..2693a541d 100644
--- a/src/pkg/net/tcpsockopt_unix.go
+++ b/src/pkg/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 nacl netbsd
package net
diff --git a/src/pkg/net/tcpsockopt_windows.go b/src/pkg/net/tcpsockopt_windows.go
index 0bf4312f2..8ef140797 100644
--- a/src/pkg/net/tcpsockopt_windows.go
+++ b/src/pkg/net/tcpsockopt_windows.go
@@ -7,7 +7,10 @@
package net
import (
+ "os"
+ "syscall"
"time"
+ "unsafe"
)
func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
@@ -16,6 +19,16 @@ func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
}
defer fd.decref()
- // We can't actually set this per connection. Act as a noop rather than an error.
- return nil
+ // Windows expects milliseconds so round to next highest millisecond.
+ d += (time.Millisecond - time.Nanosecond)
+ millis := uint32(d / time.Millisecond)
+ ka := syscall.TCPKeepalive{
+ OnOff: 1,
+ Time: millis,
+ Interval: millis,
+ }
+ 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/src/pkg/net/testdata/resolv.conf b/src/pkg/net/testdata/resolv.conf
new file mode 100644
index 000000000..b5972e09c
--- /dev/null
+++ b/src/pkg/net/testdata/resolv.conf
@@ -0,0 +1,5 @@
+# /etc/resolv.conf
+
+domain Home
+nameserver 192.168.1.1
+options ndots:5 timeout:10 attempts:3 rotate
diff --git a/src/pkg/net/textproto/reader.go b/src/pkg/net/textproto/reader.go
index b0c07413c..eea9207f2 100644
--- a/src/pkg/net/textproto/reader.go
+++ b/src/pkg/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/src/pkg/net/textproto/reader_test.go b/src/pkg/net/textproto/reader_test.go
index cc12912b6..cbc0ed183 100644
--- a/src/pkg/net/textproto/reader_test.go
+++ b/src/pkg/net/textproto/reader_test.go
@@ -247,24 +247,20 @@ 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)
+ }
+ 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/src/pkg/net/timeout_test.go b/src/pkg/net/timeout_test.go
index 35d427a69..9ef0c4d15 100644
--- a/src/pkg/net/timeout_test.go
+++ b/src/pkg/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/src/pkg/net/udp_test.go b/src/pkg/net/udp_test.go
index 6f4d2152c..e1778779c 100644
--- a/src/pkg/net/udp_test.go
+++ b/src/pkg/net/udp_test.go
@@ -201,6 +201,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/src/pkg/net/udpsock.go b/src/pkg/net/udpsock.go
index 0dd0dbd71..4c99ae4af 100644
--- a/src/pkg/net/udpsock.go
+++ b/src/pkg/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/src/pkg/net/udpsock_plan9.go b/src/pkg/net/udpsock_plan9.go
index 73621706d..510ac5e4a 100644
--- a/src/pkg/net/udpsock_plan9.go
+++ b/src/pkg/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/src/pkg/net/udpsock_posix.go b/src/pkg/net/udpsock_posix.go
index 142da8186..5dfba94e9 100644
--- a/src/pkg/net/udpsock_posix.go
+++ b/src/pkg/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,
diff --git a/src/pkg/net/unicast_posix_test.go b/src/pkg/net/unicast_posix_test.go
index 5deb8f47c..452ac9254 100644
--- a/src/pkg/net/unicast_posix_test.go
+++ b/src/pkg/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 {
diff --git a/src/pkg/net/unix_test.go b/src/pkg/net/unix_test.go
index 91df3ff88..05643ddf9 100644
--- a/src/pkg/net/unix_test.go
+++ b/src/pkg/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
diff --git a/src/pkg/net/unixsock_posix.go b/src/pkg/net/unixsock_posix.go
index b82f3cee0..2610779bf 100644
--- a/src/pkg/net/unixsock_posix.go
+++ b/src/pkg/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
@@ -124,7 +124,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 +151,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 +171,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 +181,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 +203,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 +222,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 +231,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 +286,11 @@ func (l *UnixListener) AcceptUnix() (*UnixConn, error) {
if l == nil || l.fd == nil {
return nil, syscall.EINVAL
}
- fd, err := l.fd.accept(sockaddrToUnix)
+ toAddr := sockaddrToUnix
+ if l.fd.sotype == syscall.SOCK_SEQPACKET {
+ toAddr = sockaddrToUnixpacket
+ }
+ fd, err := l.fd.accept(toAddr)
if err != nil {
return nil, err
}
diff --git a/src/pkg/net/url/url.go b/src/pkg/net/url/url.go
index 3b3787202..75f650a27 100644
--- a/src/pkg/net/url/url.go
+++ b/src/pkg/net/url/url.go
@@ -502,7 +502,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/src/pkg/net/url/url_test.go b/src/pkg/net/url/url_test.go
index 7578eb15b..cad758f23 100644
--- a/src/pkg/net/url/url_test.go
+++ b/src/pkg/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",
diff --git a/src/pkg/net/z_last_test.go b/src/pkg/net/z_last_test.go
new file mode 100644
index 000000000..4f6a54a56
--- /dev/null
+++ b/src/pkg/net/z_last_test.go
@@ -0,0 +1,37 @@
+// 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"
+)
+
+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.
+}
diff --git a/src/pkg/os/dir_unix.go b/src/pkg/os/dir_unix.go
index 9fa7ad664..d353e405e 100644
--- a/src/pkg/os/dir_unix.go
+++ b/src/pkg/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
diff --git a/src/pkg/os/doc.go b/src/pkg/os/doc.go
index a954e313d..389a8eb14 100644
--- a/src/pkg/os/doc.go
+++ b/src/pkg/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/src/pkg/os/env_unix_test.go b/src/pkg/os/env_unix_test.go
index e16d71a64..5ec07ee1b 100644
--- a/src/pkg/os/env_unix_test.go
+++ b/src/pkg/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/src/pkg/os/error_unix.go b/src/pkg/os/error_unix.go
index 6250349e5..f2aabbb45 100644
--- a/src/pkg/os/error_unix.go
+++ b/src/pkg/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/src/pkg/os/exec/exec.go b/src/pkg/os/exec/exec.go
index 491cc242b..a70ed0d20 100644
--- a/src/pkg/os/exec/exec.go
+++ b/src/pkg/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].
@@ -84,7 +88,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 +100,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 +110,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 +239,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 +344,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")
@@ -383,15 +429,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/src/pkg/os/exec/exec_test.go b/src/pkg/os/exec/exec_test.go
index c380d6506..6f77ac38a 100644
--- a/src/pkg/os/exec/exec_test.go
+++ b/src/pkg/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,16 +27,19 @@ 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"}
return 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)
}
@@ -40,10 +48,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 {
@@ -57,9 +92,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)
@@ -77,7 +112,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")
}
@@ -85,19 +120,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)
}
}
@@ -108,7 +143,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()
@@ -161,7 +196,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.`
@@ -182,9 +217,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()
@@ -192,19 +227,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", "-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
@@ -270,7 +316,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 {
@@ -370,11 +416,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 {
@@ -393,7 +443,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
@@ -425,7 +475,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()
@@ -436,10 +486,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)
@@ -476,6 +526,8 @@ func TestHelperProcess(*testing.T) {
switch runtime.GOOS {
case "dragonfly", "freebsd", "netbsd", "openbsd":
ofcmd = "fstat"
+ case "plan9":
+ ofcmd = "/bin/cat"
}
args := os.Args
@@ -566,6 +618,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
@@ -577,7 +637,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)
}
@@ -634,6 +701,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/src/pkg/os/exec/lp_unix.go b/src/pkg/os/exec/lp_unix.go
index 7ff2d201b..3f895d5b3 100644
--- a/src/pkg/os/exec/lp_unix.go
+++ b/src/pkg/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/src/pkg/os/exec/lp_unix_test.go b/src/pkg/os/exec/lp_unix_test.go
index f1ab6deff..051db664a 100644
--- a/src/pkg/os/exec/lp_unix_test.go
+++ b/src/pkg/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/src/pkg/os/exec/lp_windows_test.go b/src/pkg/os/exec/lp_windows_test.go
index 385dd331b..72df03ed2 100644
--- a/src/pkg/os/exec/lp_windows_test.go
+++ b/src/pkg/os/exec/lp_windows_test.go
@@ -13,10 +13,48 @@ import (
"strconv"
"strings"
"testing"
- "text/template"
)
+func installExe(t *testing.T, dest, src string) {
+ fsrc, err := os.Open(src)
+ if err != nil {
+ t.Fatal("os.Open failed: ", err)
+ }
+ defer fsrc.Close()
+ fdest, err := os.Create(dest)
+ if err != nil {
+ t.Fatal("os.Create failed: ", err)
+ }
+ defer fdest.Close()
+ _, err = io.Copy(fdest, fsrc)
+ if err != nil {
+ t.Fatal("io.Copy failed: ", err)
+ }
+}
+
+func installBat(t *testing.T, dest string) {
+ f, err := os.Create(dest)
+ if err != nil {
+ t.Fatalf("failed to create batch file: %v", err)
+ }
+ defer f.Close()
+ fmt.Fprintf(f, "@echo %s\n", dest)
+}
+
+func installProg(t *testing.T, dest, srcExe string) {
+ err := os.MkdirAll(filepath.Dir(dest), 0700)
+ if err != nil {
+ t.Fatal("os.MkdirAll failed: ", err)
+ }
+ if strings.ToLower(filepath.Ext(dest)) == ".bat" {
+ installBat(t, dest)
+ return
+ }
+ installExe(t, dest, srcExe)
+}
+
type lookPathTest struct {
+ rootDir string
PATH string
PATHEXT string
files []string
@@ -24,13 +62,97 @@ type lookPathTest struct {
fails bool // test is expected to fail
}
-// PrefixPATH returns p.PATH with every element prefixed by prefix.
-func (t lookPathTest) PrefixPATH(prefix string) string {
- a := strings.SplitN(t.PATH, ";", -1)
- for i := range a {
- a[i] = filepath.Join(prefix, a[i])
+func (test lookPathTest) runProg(t *testing.T, env []string, args ...string) (string, error) {
+ cmd := Command(args[0], args[1:]...)
+ cmd.Env = env
+ cmd.Dir = test.rootDir
+ args[0] = filepath.Base(args[0])
+ cmdText := fmt.Sprintf("%q command", strings.Join(args, " "))
+ out, err := cmd.CombinedOutput()
+ if (err != nil) != test.fails {
+ if test.fails {
+ t.Fatalf("test=%+v: %s succeeded, but expected to fail", test, cmdText)
+ }
+ t.Fatalf("test=%+v: %s failed, but expected to succeed: %v - %v", test, cmdText, err, string(out))
+ }
+ if err != nil {
+ return "", fmt.Errorf("test=%+v: %s failed: %v - %v", test, cmdText, err, string(out))
+ }
+ // normalise program output
+ p := string(out)
+ // trim terminating \r and \n that batch file outputs
+ for len(p) > 0 && (p[len(p)-1] == '\n' || p[len(p)-1] == '\r') {
+ p = p[:len(p)-1]
+ }
+ if !filepath.IsAbs(p) {
+ return p, nil
+ }
+ if p[:len(test.rootDir)] != test.rootDir {
+ t.Fatalf("test=%+v: %s output is wrong: %q must have %q prefix", test, cmdText, p, test.rootDir)
+ }
+ return p[len(test.rootDir)+1:], nil
+}
+
+func updateEnv(env []string, name, value string) []string {
+ for i, e := range env {
+ if strings.HasPrefix(strings.ToUpper(e), name+"=") {
+ env[i] = name + "=" + value
+ return env
+ }
+ }
+ return append(env, name+"="+value)
+}
+
+func createEnv(dir, PATH, PATHEXT string) []string {
+ env := os.Environ()
+ env = updateEnv(env, "PATHEXT", PATHEXT)
+ // Add dir in front of every directory in the PATH.
+ dirs := splitList(PATH)
+ for i := range dirs {
+ dirs[i] = filepath.Join(dir, dirs[i])
+ }
+ path := strings.Join(dirs, ";")
+ env = updateEnv(env, "PATH", path)
+ return env
+}
+
+// createFiles copies srcPath file into multiply files.
+// It uses dir as preifx for all destination files.
+func createFiles(t *testing.T, dir string, files []string, srcPath string) {
+ for _, f := range files {
+ installProg(t, filepath.Join(dir, f), srcPath)
+ }
+}
+
+func (test lookPathTest) run(t *testing.T, tmpdir, printpathExe string) {
+ test.rootDir = tmpdir
+ createFiles(t, test.rootDir, test.files, printpathExe)
+ env := createEnv(test.rootDir, test.PATH, test.PATHEXT)
+ // Run "cmd.exe /c test.searchFor" with new environment and
+ // work directory set. All candidates are copies of printpath.exe.
+ // These will output their program paths when run.
+ should, errCmd := test.runProg(t, env, "cmd", "/c", test.searchFor)
+ // Run the lookpath program with new environment and work directory set.
+ env = append(env, "GO_WANT_HELPER_PROCESS=1")
+ have, errLP := test.runProg(t, env, os.Args[0], "-test.run=TestHelperProcess", "--", "lookpath", test.searchFor)
+ // Compare results.
+ if errCmd == nil && errLP == nil {
+ // both succeeded
+ if should != have {
+ t.Fatalf("test=%+v failed: expected to find %q, but found %q", test, should, have)
+ }
+ return
+ }
+ if errCmd != nil && errLP != nil {
+ // both failed -> continue
+ return
+ }
+ if errCmd != nil {
+ t.Fatal(errCmd)
+ }
+ if errLP != nil {
+ t.Fatal(errLP)
}
- return strings.Join(a, ";")
}
var lookPathTests = []lookPathTest{
@@ -179,190 +301,250 @@ var lookPathTests = []lookPathTest{
},
}
-func updateEnv(env []string, name, value string) []string {
- for i, e := range env {
- if strings.HasPrefix(strings.ToUpper(e), name+"=") {
- env[i] = name + "=" + value
- return env
- }
- }
- return append(env, name+"="+value)
-}
-
-func installExe(t *testing.T, dest, src string) {
- fsrc, err := os.Open(src)
- if err != nil {
- t.Fatal("os.Open failed: ", err)
- }
- defer fsrc.Close()
- fdest, err := os.Create(dest)
+func TestLookPath(t *testing.T) {
+ tmp, err := ioutil.TempDir("", "TestLookPath")
if err != nil {
- t.Fatal("os.Create failed: ", err)
+ t.Fatal("TempDir failed: ", err)
}
- defer fdest.Close()
- _, err = io.Copy(fdest, fsrc)
- if err != nil {
- t.Fatal("io.Copy failed: ", err)
+ defer os.RemoveAll(tmp)
+
+ printpathExe := buildPrintPathExe(t, tmp)
+
+ // Run all tests.
+ for i, test := range lookPathTests {
+ dir := filepath.Join(tmp, "d"+strconv.Itoa(i))
+ err := os.Mkdir(dir, 0700)
+ if err != nil {
+ t.Fatal("Mkdir failed: ", err)
+ }
+ test.run(t, dir, printpathExe)
}
}
-func installBat(t *testing.T, dest string) {
- f, err := os.Create(dest)
- if err != nil {
- t.Fatalf("failed to create batch file: %v", err)
- }
- defer f.Close()
- fmt.Fprintf(f, "@echo %s\n", dest)
+type commandTest struct {
+ PATH string
+ files []string
+ dir string
+ arg0 string
+ want string
+ fails bool // test is expected to fail
}
-func installProg(t *testing.T, dest, srcExe string) {
- err := os.MkdirAll(filepath.Dir(dest), 0700)
+func (test commandTest) isSuccess(rootDir, output string, err error) error {
if err != nil {
- t.Fatal("os.MkdirAll failed: ", err)
+ return fmt.Errorf("test=%+v: exec: %v %v", test, err, output)
}
- if strings.ToLower(filepath.Ext(dest)) == ".bat" {
- installBat(t, dest)
- return
+ path := output
+ if path[:len(rootDir)] != rootDir {
+ return fmt.Errorf("test=%+v: %q must have %q prefix", test, path, rootDir)
}
- installExe(t, dest, srcExe)
+ path = path[len(rootDir)+1:]
+ if path != test.want {
+ return fmt.Errorf("test=%+v: want %q, got %q", test, test.want, path)
+ }
+ return nil
}
-func runProg(t *testing.T, test lookPathTest, env []string, dir string, args ...string) (string, error) {
- cmd := Command(args[0], args[1:]...)
+func (test commandTest) runOne(rootDir string, env []string, dir, arg0 string) error {
+ cmd := Command(os.Args[0], "-test.run=TestHelperProcess", "--", "exec", dir, arg0)
+ cmd.Dir = rootDir
cmd.Env = env
- cmd.Dir = dir
- args[0] = filepath.Base(args[0])
- cmdText := fmt.Sprintf("%q command", strings.Join(args, " "))
- out, err := cmd.CombinedOutput()
+ output, err := cmd.CombinedOutput()
+ err = test.isSuccess(rootDir, string(output), err)
if (err != nil) != test.fails {
if test.fails {
- t.Fatalf("test=%+v: %s succeeded, but expected to fail", test, cmdText)
+ return fmt.Errorf("test=%+v: succeeded, but expected to fail", test)
}
- t.Fatalf("test=%+v: %s failed, but expected to succeed: %v - %v", test, cmdText, err, string(out))
- }
- if err != nil {
- return "", fmt.Errorf("test=%+v: %s failed: %v - %v", test, cmdText, err, string(out))
- }
- // normalise program output
- p := string(out)
- // trim terminating \r and \n that batch file outputs
- for len(p) > 0 && (p[len(p)-1] == '\n' || p[len(p)-1] == '\r') {
- p = p[:len(p)-1]
- }
- if !filepath.IsAbs(p) {
- return p, nil
- }
- if p[:len(dir)] != dir {
- t.Fatalf("test=%+v: %s output is wrong: %q must have %q prefix", test, cmdText, p, dir)
+ return err
}
- return p[len(dir)+1:], nil
+ return nil
}
-func testLookPath(t *testing.T, test lookPathTest, tmpdir, lookpathExe, printpathExe string) {
- // Create files listed in test.files in tmp directory.
- for i := range test.files {
- installProg(t, filepath.Join(tmpdir, test.files[i]), printpathExe)
- }
- // Create environment with test.PATH and test.PATHEXT set.
- env := os.Environ()
- env = updateEnv(env, "PATH", test.PrefixPATH(tmpdir))
- env = updateEnv(env, "PATHEXT", test.PATHEXT)
- // Run "cmd.exe /c test.searchFor" with new environment and
- // work directory set. All candidates are copies of printpath.exe.
- // These will output their program paths when run.
- should, errCmd := runProg(t, test, env, tmpdir, "cmd", "/c", test.searchFor)
- // Run the lookpath program with new environment and work directory set.
- have, errLP := runProg(t, test, env, tmpdir, lookpathExe, test.searchFor)
- // Compare results.
- if errCmd == nil && errLP == nil {
- // both succeeded
- if should != have {
- // t.Fatalf("test=%+v failed: expected to find %v, but found %v", test, should, have)
- t.Fatalf("test=%+v failed: expected to find %q, but found %q", test, should, have)
- }
- return
- }
- if errCmd != nil && errLP != nil {
- // both failed -> continue
- return
- }
- if errCmd != nil {
- t.Fatal(errCmd)
- }
- if errLP != nil {
- t.Fatal(errLP)
+func (test commandTest) run(t *testing.T, rootDir, printpathExe string) {
+ createFiles(t, rootDir, test.files, printpathExe)
+ PATHEXT := `.COM;.EXE;.BAT`
+ env := createEnv(rootDir, test.PATH, PATHEXT)
+ env = append(env, "GO_WANT_HELPER_PROCESS=1")
+ err := test.runOne(rootDir, env, test.dir, test.arg0)
+ if err != nil {
+ t.Error(err)
}
}
-func buildExe(t *testing.T, templ, dir, name string) string {
- srcname := name + ".go"
- f, err := os.Create(filepath.Join(dir, srcname))
- if err != nil {
- t.Fatalf("failed to create source: %v", err)
- }
- err = template.Must(template.New("template").Parse(templ)).Execute(f, nil)
- f.Close()
- if err != nil {
- t.Fatalf("failed to execute template: %v", err)
- }
- outname := name + ".exe"
- cmd := Command("go", "build", "-o", outname, srcname)
- cmd.Dir = dir
- out, err := cmd.CombinedOutput()
- if err != nil {
- t.Fatalf("failed to build executable: %v - %v", err, string(out))
- }
- return filepath.Join(dir, outname)
+var commandTests = []commandTest{
+ // testing commands with no slash, like `a.exe`
+ {
+ // should find a.exe in current directory
+ files: []string{`a.exe`},
+ arg0: `a.exe`,
+ want: `a.exe`,
+ },
+ {
+ // like above, but add PATH in attempt to break the test
+ PATH: `p2;p`,
+ files: []string{`a.exe`, `p\a.exe`, `p2\a.exe`},
+ arg0: `a.exe`,
+ want: `a.exe`,
+ },
+ {
+ // like above, but use "a" instead of "a.exe" for command
+ PATH: `p2;p`,
+ files: []string{`a.exe`, `p\a.exe`, `p2\a.exe`},
+ arg0: `a`,
+ want: `a.exe`,
+ },
+ // testing commands with slash, like `.\a.exe`
+ {
+ // should find p\a.exe
+ files: []string{`p\a.exe`},
+ arg0: `p\a.exe`,
+ want: `p\a.exe`,
+ },
+ {
+ // like above, but adding `.` in front of executable should still be OK
+ files: []string{`p\a.exe`},
+ arg0: `.\p\a.exe`,
+ want: `p\a.exe`,
+ },
+ {
+ // like above, but with PATH added in attempt to break it
+ PATH: `p2`,
+ files: []string{`p\a.exe`, `p2\a.exe`},
+ arg0: `p\a.exe`,
+ want: `p\a.exe`,
+ },
+ {
+ // like above, but make sure .exe is tried even for commands with slash
+ PATH: `p2`,
+ files: []string{`p\a.exe`, `p2\a.exe`},
+ arg0: `p\a`,
+ want: `p\a.exe`,
+ },
+ // tests commands, like `a.exe`, with c.Dir set
+ {
+ // should not find a.exe in p, becasue LookPath(`a.exe`) will fail
+ files: []string{`p\a.exe`},
+ dir: `p`,
+ arg0: `a.exe`,
+ want: `p\a.exe`,
+ fails: true,
+ },
+ {
+ // LookPath(`a.exe`) will find `.\a.exe`, but prefixing that with
+ // dir `p\a.exe` will refer to not existant file
+ files: []string{`a.exe`, `p\not_important_file`},
+ dir: `p`,
+ arg0: `a.exe`,
+ want: `a.exe`,
+ fails: true,
+ },
+ {
+ // like above, but making test succeed by installing file
+ // in refered destination (so LookPath(`a.exe`) will still
+ // find `.\a.exe`, but we successfully execute `p\a.exe`)
+ files: []string{`a.exe`, `p\a.exe`},
+ dir: `p`,
+ arg0: `a.exe`,
+ want: `p\a.exe`,
+ },
+ {
+ // like above, but add PATH in attempt to break the test
+ PATH: `p2;p`,
+ files: []string{`a.exe`, `p\a.exe`, `p2\a.exe`},
+ dir: `p`,
+ arg0: `a.exe`,
+ want: `p\a.exe`,
+ },
+ {
+ // like above, but use "a" instead of "a.exe" for command
+ PATH: `p2;p`,
+ files: []string{`a.exe`, `p\a.exe`, `p2\a.exe`},
+ dir: `p`,
+ arg0: `a`,
+ want: `p\a.exe`,
+ },
+ {
+ // finds `a.exe` in the PATH regardless of dir set
+ // because LookPath returns full path in that case
+ PATH: `p2;p`,
+ files: []string{`p\a.exe`, `p2\a.exe`},
+ dir: `p`,
+ arg0: `a.exe`,
+ want: `p2\a.exe`,
+ },
+ // tests commands, like `.\a.exe`, with c.Dir set
+ {
+ // should use dir when command is path, like ".\a.exe"
+ files: []string{`p\a.exe`},
+ dir: `p`,
+ arg0: `.\a.exe`,
+ want: `p\a.exe`,
+ },
+ {
+ // like above, but with PATH added in attempt to break it
+ PATH: `p2`,
+ files: []string{`p\a.exe`, `p2\a.exe`},
+ dir: `p`,
+ arg0: `.\a.exe`,
+ want: `p\a.exe`,
+ },
+ {
+ // like above, but make sure .exe is tried even for commands with slash
+ PATH: `p2`,
+ files: []string{`p\a.exe`, `p2\a.exe`},
+ dir: `p`,
+ arg0: `.\a`,
+ want: `p\a.exe`,
+ },
}
-func TestLookPath(t *testing.T) {
- tmp, err := ioutil.TempDir("", "TestLookPath")
+func TestCommand(t *testing.T) {
+ tmp, err := ioutil.TempDir("", "TestCommand")
if err != nil {
t.Fatal("TempDir failed: ", err)
}
defer os.RemoveAll(tmp)
- // Create a Go program that uses LookPath to find executable passed as command line parameter.
- lookpathExe := buildExe(t, lookpathSrc, tmp, "lookpath")
-
- // Create a Go program that prints its own path.
- printpathExe := buildExe(t, printpathSrc, tmp, "printpath")
+ printpathExe := buildPrintPathExe(t, tmp)
// Run all tests.
- for i, test := range lookPathTests {
+ for i, test := range commandTests {
dir := filepath.Join(tmp, "d"+strconv.Itoa(i))
err := os.Mkdir(dir, 0700)
if err != nil {
t.Fatal("Mkdir failed: ", err)
}
- testLookPath(t, test, dir, lookpathExe, printpathExe)
+ test.run(t, dir, printpathExe)
}
}
-const lookpathSrc = `
-package main
-
-import (
- "fmt"
- "os"
- "os/exec"
-)
-
-func main() {
- p, err := exec.LookPath(os.Args[1])
+// buildPrintPathExe creates a Go program that prints its own path.
+// dir is a temp directory where executable will be created.
+// The function returns full path to the created program.
+func buildPrintPathExe(t *testing.T, dir string) string {
+ const name = "printpath"
+ srcname := name + ".go"
+ err := ioutil.WriteFile(filepath.Join(dir, srcname), []byte(printpathSrc), 0644)
if err != nil {
- fmt.Printf("LookPath failed: %v\n", err)
- os.Exit(1)
+ t.Fatalf("failed to create source: %v", err)
+ }
+ if err != nil {
+ t.Fatalf("failed to execute template: %v", err)
+ }
+ outname := name + ".exe"
+ cmd := Command("go", "build", "-o", outname, srcname)
+ cmd.Dir = dir
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("failed to build executable: %v - %v", err, string(out))
}
- fmt.Print(p)
+ return filepath.Join(dir, outname)
}
-`
const printpathSrc = `
package main
import (
- "fmt"
"os"
"syscall"
"unicode/utf16"
@@ -383,9 +565,9 @@ func getMyName() (string, error) {
func main() {
path, err := getMyName()
if err != nil {
- fmt.Printf("getMyName failed: %v\n", err)
+ os.Stderr.Write([]byte("getMyName failed: " + err.Error() + "\n"))
os.Exit(1)
}
- fmt.Print(path)
+ os.Stdout.Write([]byte(path))
}
`
diff --git a/src/pkg/os/exec_plan9.go b/src/pkg/os/exec_plan9.go
index 2bd5b6888..676be36ac 100644
--- a/src/pkg/os/exec_plan9.go
+++ b/src/pkg/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/src/pkg/os/exec_posix.go b/src/pkg/os/exec_posix.go
index fb123aefb..fb9d291e6 100644
--- a/src/pkg/os/exec_posix.go
+++ b/src/pkg/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/src/pkg/os/exec_unix.go b/src/pkg/os/exec_unix.go
index 5572e628e..1b1e3350b 100644
--- a/src/pkg/os/exec_unix.go
+++ b/src/pkg/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
@@ -38,6 +38,9 @@ func (p *Process) signal(sig Signal) error {
if p.done() {
return errors.New("os: process already finished")
}
+ if p.Pid == -1 {
+ return errors.New("os: process already released")
+ }
s, ok := sig.(syscall.Signal)
if !ok {
return errors.New("os: unsupported signal type")
diff --git a/src/pkg/os/file.go b/src/pkg/os/file.go
index 2dd1fcf28..b4a745801 100644
--- a/src/pkg/os/file.go
+++ b/src/pkg/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,8 @@ 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)
+}
diff --git a/src/pkg/os/file_plan9.go b/src/pkg/os/file_plan9.go
index 708163ee1..a804b8197 100644
--- a/src/pkg/os/file_plan9.go
+++ b/src/pkg/os/file_plan9.go
@@ -313,8 +313,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 +348,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/src/pkg/os/file_posix.go b/src/pkg/os/file_posix.go
index a8bef359b..b3466b15c 100644
--- a/src/pkg/os/file_posix.go
+++ b/src/pkg/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
@@ -48,8 +48,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 +144,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/src/pkg/os/file_unix.go b/src/pkg/os/file_unix.go
index ff1a597e7..76168339d 100644
--- a/src/pkg/os/file_unix.go
+++ b/src/pkg/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
@@ -81,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)
}
@@ -160,30 +155,48 @@ 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) {
+ if needsMaxRW && len(b) > maxRW {
+ b = b[:maxRW]
+ }
return 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) {
+ if needsMaxRW && len(b) > maxRW {
+ b = b[:maxRW]
+ }
return syscall.Pread(f.fd, b, off)
}
@@ -191,13 +204,22 @@ func (f *File) pread(b []byte, off int64) (n int, err error) {
// 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 := 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
}
@@ -209,6 +231,9 @@ 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) {
+ if needsMaxRW && len(b) > maxRW {
+ b = b[:maxRW]
+ }
return syscall.Pwrite(f.fd, b, off)
}
diff --git a/src/pkg/os/file_windows.go b/src/pkg/os/file_windows.go
index fab7de342..efe8bc03f 100644
--- a/src/pkg/os/file_windows.go
+++ b/src/pkg/os/file_windows.go
@@ -134,20 +134,19 @@ func OpenFile(name string, flag int, perm FileMode) (file *File, err error) {
if name == "" {
return nil, &PathError{"open", name, syscall.ENOENT}
}
- // TODO(brainman): not sure about my logic of assuming it is dir first, then fall back to file
- r, e := openDir(name)
- if e == nil {
+ r, errf := openFile(name, flag, perm)
+ if errf == nil {
+ return r, nil
+ }
+ r, errd := openDir(name)
+ if errd == nil {
if flag&O_WRONLY != 0 || flag&O_RDWR != 0 {
r.Close()
return nil, &PathError{"open", name, syscall.EISDIR}
}
return r, nil
}
- r, e = openFile(name, flag, perm)
- if e == nil {
- return r, nil
- }
- return nil, &PathError{"open", name, e}
+ return nil, &PathError{"open", name, errf}
}
// Close closes the File, rendering it unusable for I/O.
diff --git a/src/pkg/os/getwd.go b/src/pkg/os/getwd.go
index 8c5ff7fca..a72edeaee 100644
--- a/src/pkg/os/getwd.go
+++ b/src/pkg/os/getwd.go
@@ -22,7 +22,7 @@ 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) {
+func Getwd() (dir string, err error) {
// If the operating system provides a Getwd call, use it.
if syscall.ImplementsGetwd {
s, e := syscall.Getwd()
@@ -39,22 +39,22 @@ func Getwd() (pwd string, err error) {
// 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
}
}
// 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 +71,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 +91,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 +112,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/src/pkg/os/os_test.go b/src/pkg/os/os_test.go
index 9462ebd42..16d5984e9 100644
--- a/src/pkg/os/os_test.go
+++ b/src/pkg/os/os_test.go
@@ -6,6 +6,7 @@ package os_test
import (
"bytes"
+ "errors"
"flag"
"fmt"
"io"
@@ -13,7 +14,9 @@ import (
. "os"
osexec "os/exec"
"path/filepath"
+ "reflect"
"runtime"
+ "sort"
"strings"
"syscall"
"testing"
@@ -382,6 +385,84 @@ 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" {
@@ -415,10 +496,10 @@ 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 "windows", "plan9", "nacl":
+ t.Skipf("skipping on %s", runtime.GOOS)
}
from, to := "symlinktestfrom", "symlinktestto"
Remove(from) // Just in case.
@@ -478,9 +559,9 @@ 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 "windows", "plan9", "nacl":
+ t.Skipf("skipping on %s", runtime.GOOS)
}
s := "0123456789abcdef"
// Long, but not too long: a common limit is 255.
@@ -549,6 +630,10 @@ func exec(t *testing.T, dir, cmd string, args []string, expect string) {
}
func TestStartProcess(t *testing.T) {
+ if runtime.GOOS == "nacl" {
+ t.Skip("skipping on nacl")
+ }
+
var dir, cmd string
var args []string
if runtime.GOOS == "windows" {
@@ -622,8 +707,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) {
@@ -640,8 +727,10 @@ 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,
@@ -676,13 +765,13 @@ func TestChtimes(t *testing.T) {
}
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)
}
@@ -884,8 +973,9 @@ 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
+ switch runtime.GOOS {
+ case "windows", "plan9", "nacl":
+ t.Skipf("skipping on %s", runtime.GOOS)
}
// Check internal Hostname() against the output of /bin/hostname.
@@ -1144,6 +1234,10 @@ func TestReadAtEOF(t *testing.T) {
}
func testKillProcess(t *testing.T, processKiller func(p *Process)) {
+ if runtime.GOOS == "nacl" {
+ t.Skip("skipping on nacl")
+ }
+
dir, err := ioutil.TempDir("", "go-build")
if err != nil {
t.Fatalf("Failed to create temp directory: %v", err)
@@ -1211,3 +1305,35 @@ 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)
+ }
+ }
+}
diff --git a/src/pkg/os/os_unix_test.go b/src/pkg/os/os_unix_test.go
index b0fc0256d..21d40ccaf 100644
--- a/src/pkg/os/os_unix_test.go
+++ b/src/pkg/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/src/pkg/os/path_test.go b/src/pkg/os/path_test.go
index 27abf5982..3af21cde9 100644
--- a/src/pkg/os/path_test.go
+++ b/src/pkg/os/path_test.go
@@ -167,8 +167,9 @@ 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", "windows":
+ t.Skipf("skipping on %s", runtime.GOOS)
}
tmpDir, err := ioutil.TempDir("", "TestMkdirAllWithSymlink-")
diff --git a/src/pkg/os/path_unix.go b/src/pkg/os/path_unix.go
index 3bf63bf80..0211107dd 100644
--- a/src/pkg/os/path_unix.go
+++ b/src/pkg/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/src/pkg/os/pipe_bsd.go b/src/pkg/os/pipe_bsd.go
index 73d35b4d5..3b81ed20f 100644
--- a/src/pkg/os/pipe_bsd.go
+++ b/src/pkg/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/src/pkg/os/signal/example_test.go b/src/pkg/os/signal/example_test.go
index 600ed315d..079ee5070 100644
--- a/src/pkg/os/signal/example_test.go
+++ b/src/pkg/os/signal/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 signal_test
import (
diff --git a/src/pkg/os/signal/sig.s b/src/pkg/os/signal/sig.s
index 888823cf4..f860924aa 100644
--- a/src/pkg/os/signal/sig.s
+++ b/src/pkg/os/signal/sig.s
@@ -4,7 +4,7 @@
// Assembly to get into package runtime without using exported symbols.
-// +build amd64 arm 386
+// +build amd64 amd64p32 arm 386
#include "../../../cmd/ld/textflag.h"
diff --git a/src/pkg/os/signal/signal_test.go b/src/pkg/os/signal/signal_test.go
index 741f2a0ed..076fe3f93 100644
--- a/src/pkg/os/signal/signal_test.go
+++ b/src/pkg/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
diff --git a/src/pkg/os/signal/signal_unix.go b/src/pkg/os/signal/signal_unix.go
index 318488dc0..94b8ab3dd 100644
--- a/src/pkg/os/signal/signal_unix.go
+++ b/src/pkg/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/src/pkg/os/signal/signal_windows_test.go b/src/pkg/os/signal/signal_windows_test.go
index 26712f35b..f3e6706b7 100644
--- a/src/pkg/os/signal/signal_windows_test.go
+++ b/src/pkg/os/signal/signal_windows_test.go
@@ -6,6 +6,7 @@ package signal
import (
"bytes"
+ "io/ioutil"
"os"
"os/exec"
"path/filepath"
@@ -55,9 +56,15 @@ func main() {
}
}
`
- name := filepath.Join(os.TempDir(), "ctlbreak")
+ tmp, err := ioutil.TempDir("", "TestCtrlBreak")
+ if err != nil {
+ t.Fatal("TempDir failed: ", err)
+ }
+ defer os.RemoveAll(tmp)
+
+ // write ctrlbreak.go
+ name := filepath.Join(tmp, "ctlbreak")
src := name + ".go"
- defer os.Remove(src)
f, err := os.Create(src)
if err != nil {
t.Fatalf("Failed to create %v: %v", src, err)
diff --git a/src/pkg/os/stat_nacl.go b/src/pkg/os/stat_nacl.go
new file mode 100644
index 000000000..a503b59fa
--- /dev/null
+++ b/src/pkg/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/src/pkg/os/stat_solaris.go b/src/pkg/os/stat_solaris.go
new file mode 100644
index 000000000..605c1d9b6
--- /dev/null
+++ b/src/pkg/os/stat_solaris.go
@@ -0,0 +1,61 @@
+// 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.Mtim),
+ 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(ts syscall.Timespec) time.Time {
+ return time.Unix(int64(ts.Sec), int64(ts.Nsec))
+}
+
+// For testing.
+func atime(fi FileInfo) time.Time {
+ return timespecToTime(fi.Sys().(*syscall.Stat_t).Atim)
+}
diff --git a/src/pkg/os/sys_bsd.go b/src/pkg/os/sys_bsd.go
index 9ad2f8546..8ad5e2183 100644
--- a/src/pkg/os/sys_bsd.go
+++ b/src/pkg/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/src/pkg/os/sys_darwin.go b/src/pkg/os/sys_darwin.go
new file mode 100644
index 000000000..7a8330abb
--- /dev/null
+++ b/src/pkg/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/src/pkg/os/sys_freebsd.go b/src/pkg/os/sys_freebsd.go
new file mode 100644
index 000000000..273c2df1c
--- /dev/null
+++ b/src/pkg/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/src/pkg/os/sys_nacl.go b/src/pkg/os/sys_nacl.go
new file mode 100644
index 000000000..07907c847
--- /dev/null
+++ b/src/pkg/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/src/pkg/os/sys_solaris.go b/src/pkg/os/sys_solaris.go
new file mode 100644
index 000000000..917e8f2b0
--- /dev/null
+++ b/src/pkg/os/sys_solaris.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.
+
+package os
+
+import "syscall"
+
+func hostname() (name string, err error) {
+ return syscall.Gethostname()
+}
diff --git a/src/pkg/os/sys_unix.go b/src/pkg/os/sys_unix.go
new file mode 100644
index 000000000..39c20dc73
--- /dev/null
+++ b/src/pkg/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/src/pkg/os/user/lookup_unix.go b/src/pkg/os/user/lookup_unix.go
index 5459268fa..f2baf05bb 100644
--- a/src/pkg/os/user/lookup_unix.go
+++ b/src/pkg/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 linux netbsd openbsd solaris
// +build cgo
package user
diff --git a/src/pkg/path/filepath/export_test.go b/src/pkg/path/filepath/export_test.go
new file mode 100644
index 000000000..0cf9e3bca
--- /dev/null
+++ b/src/pkg/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/src/pkg/path/filepath/match.go b/src/pkg/path/filepath/match.go
index 3d84145d7..a9bcc103c 100644
--- a/src/pkg/path/filepath/match.go
+++ b/src/pkg/path/filepath/match.go
@@ -230,7 +230,7 @@ func getEsc(chunk string) (r rune, nchunk string, err error) {
//
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
diff --git a/src/pkg/path/filepath/match_test.go b/src/pkg/path/filepath/match_test.go
index 13108ce1e..382692eaa 100644
--- a/src/pkg/path/filepath/match_test.go
+++ b/src/pkg/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"
@@ -153,3 +156,51 @@ 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", "windows":
+ 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/src/pkg/path/filepath/path.go b/src/pkg/path/filepath/path.go
index f8c7e4b2f..71603cc59 100644
--- a/src/pkg/path/filepath/path.go
+++ b/src/pkg/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.
@@ -336,6 +336,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 +352,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 +390,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 ".".
diff --git a/src/pkg/path/filepath/path_test.go b/src/pkg/path/filepath/path_test.go
index d32b70d6e..819bd217c 100644
--- a/src/pkg/path/filepath/path_test.go
+++ b/src/pkg/path/filepath/path_test.go
@@ -5,6 +5,7 @@
package filepath_test
import (
+ "errors"
"io/ioutil"
"os"
"path/filepath"
@@ -458,6 +459,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{
{"", "."},
{".", "."},
@@ -633,8 +691,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")
diff --git a/src/pkg/path/filepath/path_unix.go b/src/pkg/path/filepath/path_unix.go
index d927b342b..7aba0ab5b 100644
--- a/src/pkg/path/filepath/path_unix.go
+++ b/src/pkg/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
diff --git a/src/pkg/path/filepath/path_windows_test.go b/src/pkg/path/filepath/path_windows_test.go
index d8926adde..8a9be8e89 100644
--- a/src/pkg/path/filepath/path_windows_test.go
+++ b/src/pkg/path/filepath/path_windows_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 filepath_test
import (
diff --git a/src/pkg/reflect/all_test.go b/src/pkg/reflect/all_test.go
index e9a20963f..e9949012c 100644
--- a/src/pkg/reflect/all_test.go
+++ b/src/pkg/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{[]int{1}}, [][]int{[]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
@@ -1434,6 +1461,46 @@ func TestFunc(t *testing.T) {
}
}
+type emptyStruct struct{}
+
+type nonEmptyStruct struct {
+ member int
+}
+
+func returnEmpty() emptyStruct {
+ return emptyStruct{}
+}
+
+func takesEmpty(e emptyStruct) {
+}
+
+func returnNonEmpty(i int) nonEmptyStruct {
+ return nonEmptyStruct{member: i}
+}
+
+func takesNonEmpty(n nonEmptyStruct) int {
+ return n.member
+}
+
+func TestCallWithStruct(t *testing.T) {
+ r := ValueOf(returnEmpty).Call(nil)
+ if len(r) != 1 || r[0].Type() != TypeOf(emptyStruct{}) {
+ 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: %#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 %#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 %#v", r)
+ }
+}
+
func TestMakeFunc(t *testing.T) {
f := dummy
fv := MakeFunc(TypeOf(f), func(in []Value) []Value { return in })
@@ -1470,6 +1537,23 @@ 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 := 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])
+ }
+}
+
type Point struct {
x, y int
}
@@ -3616,3 +3700,142 @@ 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 (p Point) GCMethod(k int) int {
+ runtime.GC()
+ return k + p.x
+}
+
+func TestReflectMethodTraceback(t *testing.T) {
+ p := Point{3, 4}
+ m := ValueOf(p).MethodByName("GCMethod")
+ 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
+}
diff --git a/src/pkg/reflect/asm_amd64p32.s b/src/pkg/reflect/asm_amd64p32.s
new file mode 100644
index 000000000..75413c752
--- /dev/null
+++ b/src/pkg/reflect/asm_amd64p32.s
@@ -0,0 +1,27 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "../../cmd/ld/textflag.h"
+
+// makeFuncStub is the code half of the function returned by MakeFunc.
+// See the comment on the declaration of makeFuncStub in makefunc.go
+// for more details.
+// No argsize here, gc generates argsize info at call site.
+TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8
+ MOVL DX, 0(SP)
+ LEAL argframe+0(FP), CX
+ MOVL CX, 4(SP)
+ CALL ·callReflect(SB)
+ RET
+
+// methodValueCall is the code half of the function returned by makeMethodValue.
+// See the comment on the declaration of methodValueCall in makefunc.go
+// for more details.
+// No argsize here, gc generates argsize info at call site.
+TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$8
+ MOVL DX, 0(SP)
+ LEAL argframe+0(FP), CX
+ MOVL CX, 4(SP)
+ CALL ·callMethod(SB)
+ RET
diff --git a/src/pkg/reflect/deepequal.go b/src/pkg/reflect/deepequal.go
index e3bf3dcac..f63715c9a 100644
--- a/src/pkg/reflect/deepequal.go
+++ b/src/pkg/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/src/pkg/reflect/export_test.go b/src/pkg/reflect/export_test.go
index cd8cf2cf2..0778ad37f 100644
--- a/src/pkg/reflect/export_test.go
+++ b/src/pkg/reflect/export_test.go
@@ -16,3 +16,4 @@ func IsRO(v Value) bool {
}
var ArrayOf = arrayOf
+var CallGC = &callGC
diff --git a/src/pkg/reflect/makefunc.go b/src/pkg/reflect/makefunc.go
index e1608ea6c..0e61fdea7 100644
--- a/src/pkg/reflect/makefunc.go
+++ b/src/pkg/reflect/makefunc.go
@@ -56,7 +56,7 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
impl := &makeFuncImpl{code: code, typ: ftyp, fn: fn}
- return Value{t, unsafe.Pointer(impl), flag(Func) << flagKindShift}
+ return Value{t, unsafe.Pointer(impl), 0, flag(Func) << flagKindShift}
}
// makeFuncStub is an assembly function that is the code half of
@@ -81,13 +81,13 @@ type methodValue struct {
// 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")
+ 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}
+ rcvr := Value{v.typ, v.ptr, v.scalar, fl}
// v.Type returns the actual type of the method value.
funcType := v.Type().(*rtype)
@@ -109,7 +109,7 @@ func makeMethodValue(op string, v Value) Value {
// but we want Interface() and other operations to fail early.
methodReceiver(op, fv.rcvr, fv.method)
- return Value{funcType, unsafe.Pointer(fv), v.flag&flagRO | flag(Func)<<flagKindShift}
+ return Value{funcType, unsafe.Pointer(fv), 0, v.flag&flagRO | flag(Func)<<flagKindShift}
}
// methodValueCall is an assembly function that is the code half of
diff --git a/src/pkg/reflect/type.go b/src/pkg/reflect/type.go
index 7afb7defe..40d76f99d 100644
--- a/src/pkg/reflect/type.go
+++ b/src/pkg/reflect/type.go
@@ -16,6 +16,7 @@
package reflect
import (
+ "runtime"
"strconv"
"sync"
"unsafe"
@@ -252,6 +253,7 @@ type rtype struct {
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
@@ -477,6 +479,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) {
@@ -495,7 +499,7 @@ func (t *uncommonType) Method(i int) (m Method) {
mt := p.typ
m.Type = mt
fn := unsafe.Pointer(&p.tfn)
- m.Func = Value{mt, fn, fl}
+ m.Func = Value{mt, fn, 0, fl}
m.Index = i
return
}
@@ -1089,6 +1093,7 @@ 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 {
@@ -1475,6 +1480,7 @@ 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,
@@ -1534,6 +1540,14 @@ func MapOf(key, elem Type) Type {
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: mt.hmap.gc,
+ end: _GC_END,
+ })
// INCORRECT. Uncomment to check that TestMapOfGC and TestMapOfGCValues
// fail when mt.gc is wrong.
@@ -1566,6 +1580,10 @@ func bucketOf(ktyp, etyp *rtype) *rtype {
gc = append(gc, _GC_PTR, offset, 0 /*self pointer set below*/) // overflow
offset += ptrsize
+ if runtime.GOARCH == "amd64p32" {
+ offset += 4
+ }
+
// keys
if ktyp.kind&kindNoPointers == 0 {
gc = append(gc, _GC_ARRAY_START, offset, _BUCKETSIZE, ktyp.size)
@@ -1709,6 +1727,7 @@ 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)
@@ -1778,6 +1797,7 @@ func arrayOf(count int, elem Type) Type {
// TODO: array.gc
array.uncommonType = nil
array.ptrToThis = nil
+ array.zero = unsafe.Pointer(&make([]byte, array.size)[0])
array.len = uintptr(count)
array.slice = slice.(*rtype)
@@ -1795,3 +1815,112 @@ func toType(t *rtype) Type {
}
return t
}
+
+type layoutKey struct {
+ t *rtype // function signature
+ rcvr *rtype // receiver type, or nil if none
+}
+
+type layoutType struct {
+ t *rtype
+ argSize uintptr // size of arguments
+ retOffset uintptr // offset of return values.
+}
+
+var layoutCache struct {
+ sync.RWMutex
+ m map[layoutKey]layoutType
+}
+
+// funcLayout computes a struct type representing the layout of the
+// function arguments and return values for the function type t.
+// If rcvr != nil, rcvr specifies the type of the receiver.
+// The returned type exists only for GC, so we only fill out GC relevant info.
+// Currently, that's just size and the GC program. We also fill in
+// the name for possible debugging use.
+func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uintptr) {
+ if t.Kind() != Func {
+ panic("reflect: funcLayout of non-func type")
+ }
+ if rcvr != nil && rcvr.Kind() == Interface {
+ panic("reflect: funcLayout with interface receiver " + rcvr.String())
+ }
+ k := layoutKey{t, rcvr}
+ layoutCache.RLock()
+ if x := layoutCache.m[k]; x.t != nil {
+ layoutCache.RUnlock()
+ return x.t, x.argSize, x.retOffset
+ }
+ layoutCache.RUnlock()
+ layoutCache.Lock()
+ if x := layoutCache.m[k]; x.t != nil {
+ layoutCache.Unlock()
+ return x.t, x.argSize, x.retOffset
+ }
+
+ tt := (*funcType)(unsafe.Pointer(t))
+
+ // compute gc program for arguments
+ gc := make([]uintptr, 1) // first entry is size, filled in at the end
+ offset := uintptr(0)
+ if rcvr != nil {
+ // Reflect uses the "interface" calling convention for
+ // methods, where receivers take one word of argument
+ // space no matter how big they actually are.
+ if rcvr.size > ptrSize {
+ // we pass a pointer to the receiver.
+ gc = append(gc, _GC_PTR, offset, uintptr(rcvr.gc))
+ } else if rcvr.pointers() {
+ // rcvr is a one-word pointer object. Its gc program
+ // is just what we need here.
+ gc = appendGCProgram(gc, rcvr)
+ }
+ offset += ptrSize
+ }
+ for _, arg := range tt.in {
+ offset = align(offset, uintptr(arg.align))
+ if arg.pointers() {
+ gc = append(gc, _GC_REGION, offset, arg.size, uintptr(arg.gc))
+ }
+ offset += arg.size
+ }
+ argSize = offset
+ if runtime.GOARCH == "amd64p32" {
+ offset = align(offset, 8)
+ }
+ offset = align(offset, ptrSize)
+ retOffset = offset
+ for _, res := range tt.out {
+ offset = align(offset, uintptr(res.align))
+ if res.pointers() {
+ gc = append(gc, _GC_REGION, offset, res.size, uintptr(res.gc))
+ }
+ offset += res.size
+ }
+ gc = append(gc, _GC_END)
+ gc[0] = offset
+
+ // build dummy rtype holding gc program
+ x := new(rtype)
+ x.size = offset
+ x.gc = unsafe.Pointer(&gc[0])
+ var s string
+ if rcvr != nil {
+ s = "methodargs(" + *rcvr.string + ")(" + *t.string + ")"
+ } else {
+ s = "funcargs(" + *t.string + ")"
+ }
+ x.string = &s
+
+ // cache result for future callers
+ if layoutCache.m == nil {
+ layoutCache.m = make(map[layoutKey]layoutType)
+ }
+ layoutCache.m[k] = layoutType{
+ t: x,
+ argSize: argSize,
+ retOffset: retOffset,
+ }
+ layoutCache.Unlock()
+ return x, argSize, retOffset
+}
diff --git a/src/pkg/reflect/value.go b/src/pkg/reflect/value.go
index df549f5e1..576cbc398 100644
--- a/src/pkg/reflect/value.go
+++ b/src/pkg/reflect/value.go
@@ -62,14 +62,15 @@ 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
+
+ // Non-pointer-valued data. When the data is smaller
+ // than a word, it begins at the first byte (in the memory
+ // address sense) of this field.
+ // Valid when flagIndir is not set and typ.pointers() is false.
+ scalar uintptr
// flag holds metadata about the value.
// The lowest bits are flag bits:
@@ -108,6 +109,78 @@ func (f flag) kind() Kind {
return Kind((f >> flagKindShift) & 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 t.size > ptrSize:
+ // 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 = iword(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.
+ if t.pointers() {
+ e.word = iword(*(*unsafe.Pointer)(v.ptr))
+ } else {
+ e.word = iword(loadScalar(v.ptr, t.size))
+ }
+ default:
+ // Value is direct, and so is the interface.
+ if t.pointers() {
+ e.word = iword(v.ptr)
+ } else {
+ e.word = iword(v.scalar)
+ }
+ }
+ // 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()) << flagKindShift
+ if t.size > ptrSize {
+ return Value{t, unsafe.Pointer(e.word), 0, f | flagIndir}
+ }
+ if t.pointers() {
+ return Value{t, unsafe.Pointer(e.word), 0, f}
+ }
+ return Value{t, nil, uintptr(e.word), f}
+}
+
// A ValueError occurs when a Value method is invoked on
// a Value that does not support it. Such cases are documented
// in the description of each method.
@@ -139,28 +212,21 @@ func methodName() string {
// 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.
+// This type is very dangerous for the garbage collector because
+// it must be treated conservatively. We try to never expose it
+// to the GC here so that GC remains precise.
type iword unsafe.Pointer
-func (v Value) iword() iword {
- if v.flag&flagIndir != 0 && v.typ.size <= ptrSize {
- // 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 {
+// loadScalar loads n bytes at p from memory into a uintptr
+// that forms the second word of an interface. The data
+// must be non-pointer in nature.
+func loadScalar(p unsafe.Pointer, n uintptr) uintptr {
// Run the copy ourselves instead of calling memmove
// to avoid moving w to the heap.
- var w iword
+ var w uintptr
switch n {
default:
- panic("reflect: internal error: loadIword of " + strconv.Itoa(int(n)) + "-byte value")
+ panic("reflect: internal error: loadScalar of " + strconv.Itoa(int(n)) + "-byte value")
case 0:
case 1:
*(*uint8)(unsafe.Pointer(&w)) = *(*uint8)(p)
@@ -182,13 +248,13 @@ func loadIword(p unsafe.Pointer, n uintptr) iword {
return w
}
-// storeIword stores n bytes from w into p.
-func storeIword(p unsafe.Pointer, w iword, n uintptr) {
+// storeScalar stores n bytes from w into p.
+func storeScalar(p unsafe.Pointer, w uintptr, 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")
+ panic("reflect: internal error: storeScalar of " + strconv.Itoa(int(n)) + "-byte value")
case 0:
case 1:
*(*uint8)(p) = *(*uint8)(unsafe.Pointer(&w))
@@ -278,7 +344,7 @@ 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, 0, (v.flag & flagRO) | flag(Ptr)<<flagKindShift}
}
// Bool returns v's underlying value.
@@ -286,9 +352,9 @@ func (v Value) Addr() Value {
func (v Value) Bool() bool {
v.mustBe(Bool)
if v.flag&flagIndir != 0 {
- return *(*bool)(v.val)
+ return *(*bool)(v.ptr)
}
- return *(*bool)(unsafe.Pointer(&v.val))
+ return *(*bool)(unsafe.Pointer(&v.scalar))
}
// Bytes returns v's underlying value.
@@ -299,7 +365,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.
@@ -310,7 +376,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.
@@ -358,19 +424,28 @@ func (v Value) CallSlice(in []Value) []Value {
return v.call("CallSlice", in)
}
+var callGC bool // for testing; see TestCallMethodJump
+
+var makeFuncStubFn = makeFuncStub
+var makeFuncStubCode = **(**uintptr)(unsafe.Pointer(&makeFuncStubFn))
+var methodValueCallFn = methodValueCall
+var methodValueCallCode = **(**uintptr)(unsafe.Pointer(&methodValueCallFn))
+
func (v Value) call(op string, in []Value) []Value {
// Get function pointer, type.
t := v.typ
var (
- fn unsafe.Pointer
- rcvr iword
+ fn unsafe.Pointer
+ rcvr Value
+ rcvrtype *rtype
)
if v.flag&flagMethod != 0 {
- t, fn, rcvr = methodReceiver(op, v, int(v.flag)>>flagMethodShift)
+ rcvr = v
+ rcvrtype, 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 {
@@ -434,23 +509,36 @@ func (v Value) call(op string, in []Value) []Value {
}
nout := t.NumOut()
- // Compute arg size & allocate.
- // This computation is 5g/6g/8g-dependent
- // and probably wrong for gccgo, but so
- // is most of this function.
- size, _, _, _ := frameSize(t, v.flag&flagMethod != 0)
-
- // Copy into args.
- //
- // TODO(rsc): This will need to be updated for any new garbage collector.
- // For now make everything look like a pointer by allocating
- // a []unsafe.Pointer.
- args := make([]unsafe.Pointer, size/ptrSize)
- ptr := unsafe.Pointer(&args[0])
+ // If target is makeFuncStub, short circuit the unpack onto stack /
+ // pack back into []Value for the args and return values. Just do the
+ // call directly.
+ // We need to do this here because otherwise we have a situation where
+ // reflect.callXX calls makeFuncStub, neither of which knows the
+ // layout of the args. That's bad for precise gc & stack copying.
+ x := (*makeFuncImpl)(fn)
+ if x.code == makeFuncStubCode {
+ return x.fn(in)
+ }
+
+ // If the target is methodValueCall, do its work here: add the receiver
+ // argument and call the real target directly.
+ // We need to do this here because otherwise we have a situation where
+ // reflect.callXX calls methodValueCall, neither of which knows the
+ // layout of the args. That's bad for precise gc & stack copying.
+ y := (*methodValue)(fn)
+ if y.fn == methodValueCallCode {
+ rcvr = y.rcvr
+ rcvrtype, t, fn = methodReceiver("call", rcvr, y.method)
+ }
+
+ // Compute frame type, allocate a chunk of memory for frame
+ frametype, _, retOffset := funcLayout(t, rcvrtype)
+ args := unsafe_New(frametype)
off := uintptr(0)
- if v.flag&flagMethod != 0 {
- // Hard-wired first argument.
- *(*iword)(ptr) = rcvr
+
+ // Copy inputs into args.
+ if rcvrtype != nil {
+ storeRcvr(rcvr, args)
off = ptrSize
}
for i, v := range in {
@@ -459,30 +547,35 @@ func (v Value) call(op string, in []Value) []Value {
a := uintptr(targ.align)
off = (off + a - 1) &^ (a - 1)
n := targ.size
- addr := unsafe.Pointer(uintptr(ptr) + off)
+ addr := unsafe.Pointer(uintptr(args) + off)
v = v.assignTo("reflect.Value.Call", targ, (*interface{})(addr))
- if v.flag&flagIndir == 0 {
- storeIword(addr, iword(v.val), n)
+ if v.flag&flagIndir != 0 {
+ memmove(addr, v.ptr, n)
+ } else if targ.pointers() {
+ *(*unsafe.Pointer)(addr) = v.ptr
} else {
- memmove(addr, v.val, n)
+ storeScalar(addr, v.scalar, n)
}
off += n
}
- off = (off + ptrSize - 1) &^ (ptrSize - 1)
// Call.
- call(fn, ptr, uint32(size))
+ call(fn, args, uint32(frametype.size), uint32(retOffset))
+
+ // For testing; see TestCallMethodJump.
+ if callGC {
+ runtime.GC()
+ }
// Copy return values out of args.
- //
- // TODO(rsc): revisit like above.
ret := make([]Value, nout)
+ off = retOffset
for i := 0; i < nout; i++ {
tv := t.Out(i)
a := uintptr(tv.Align())
off = (off + a - 1) &^ (a - 1)
fl := flagIndir | flag(tv.Kind())<<flagKindShift
- ret[i] = Value{tv.common(), unsafe.Pointer(uintptr(ptr) + off), fl}
+ ret[i] = Value{tv.common(), unsafe.Pointer(uintptr(args) + off), 0, fl}
off += tv.Size()
}
@@ -512,18 +605,20 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
for _, arg := range ftyp.in {
typ := arg
off += -off & uintptr(typ.align-1)
- v := Value{typ, nil, flag(typ.Kind()) << flagKindShift}
- if typ.size <= ptrSize {
- // value fits in word.
- v.val = unsafe.Pointer(loadIword(unsafe.Pointer(uintptr(ptr)+off), typ.size))
- } else {
+ addr := unsafe.Pointer(uintptr(ptr) + off)
+ v := Value{typ, nil, 0, flag(typ.Kind()) << flagKindShift}
+ if typ.size > ptrSize {
// value does not fit in word.
// Must make a copy, because f might keep a reference to it,
// and we cannot let f keep a reference to the stack frame
// after this function returns, not even a read-only reference.
- v.val = unsafe_New(typ)
- memmove(v.val, unsafe.Pointer(uintptr(ptr)+off), typ.size)
+ v.ptr = unsafe_New(typ)
+ memmove(v.ptr, addr, typ.size)
v.flag |= flagIndir
+ } else if typ.pointers() {
+ v.ptr = *(*unsafe.Pointer)(addr)
+ } else {
+ v.scalar = loadScalar(addr, typ.size)
}
in = append(in, v)
off += typ.size
@@ -538,6 +633,9 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
// Copy results back into argument frame.
if len(ftyp.out) > 0 {
off += -off & (ptrSize - 1)
+ if runtime.GOARCH == "amd64p32" {
+ off = align(off, 8)
+ }
for i, arg := range ftyp.out {
typ := arg
v := out[i]
@@ -552,10 +650,12 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
}
off += -off & uintptr(typ.align-1)
addr := unsafe.Pointer(uintptr(ptr) + off)
- if v.flag&flagIndir == 0 {
- storeIword(addr, iword(v.val), typ.size)
+ if v.flag&flagIndir != 0 {
+ memmove(addr, v.ptr, typ.size)
+ } else if typ.pointers() {
+ *(*unsafe.Pointer)(addr) = v.ptr
} else {
- memmove(addr, v.val, typ.size)
+ storeScalar(addr, v.scalar, typ.size)
}
off += typ.size
}
@@ -566,7 +666,10 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
// 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))
@@ -577,14 +680,15 @@ func methodReceiver(op string, v Value, methodIndex int) (t *rtype, fn unsafe.Po
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) {
panic("reflect: internal error: invalid method index")
@@ -595,58 +699,41 @@ func methodReceiver(op string, v Value, methodIndex int) (t *rtype, fn unsafe.Po
}
fn = unsafe.Pointer(&m.ifn)
t = m.mtyp
- rcvr = v.iword()
}
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 {
+ if t.size > ptrSize {
+ *(*unsafe.Pointer)(p) = v.ptr
+ } else if t.pointers() {
+ *(*unsafe.Pointer)(p) = *(*unsafe.Pointer)(v.ptr)
+ } else {
+ *(*uintptr)(p) = loadScalar(v.ptr, t.size)
+ }
+ } else if t.pointers() {
+ *(*unsafe.Pointer)(p) = v.ptr
+ } else {
+ *(*uintptr)(p) = v.scalar
+ }
+}
+
// 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 {
return (x + n - 1) &^ (n - 1)
}
-// frameSize returns the sizes of the argument and result frame
-// for a function of the given type. The rcvr bool specifies whether
-// a one-word receiver should be included in the total.
-func frameSize(t *rtype, rcvr bool) (total, in, outOffset, out uintptr) {
- if rcvr {
- // extra word for receiver interface word
- total += ptrSize
- }
-
- nin := t.NumIn()
- in = -total
- for i := 0; i < nin; i++ {
- tv := t.In(i)
- total = align(total, uintptr(tv.Align()))
- total += tv.Size()
- }
- in += total
- total = align(total, ptrSize)
- nout := t.NumOut()
- outOffset = total
- out = -total
- for i := 0; i < nout; i++ {
- tv := t.Out(i)
- total = align(total, uintptr(tv.Align()))
- total += tv.Size()
- }
- out += total
-
- // total must be > 0 in order for &args[0] to be valid.
- // the argument copying is going to round it up to
- // a multiple of ptrSize anyway, so make it ptrSize to begin with.
- if total < ptrSize {
- total = ptrSize
- }
-
- // round to pointer
- total = align(total, ptrSize)
-
- return
-}
-
// callMethod is the call implementation used by a function returned
// by makeMethodValue (used by v.Method(i).Interface()).
// It is a streamlined version of the usual reflect call: the caller has
@@ -659,24 +746,31 @@ func frameSize(t *rtype, rcvr bool) (total, in, outOffset, out uintptr) {
// so that the linker can make it work correctly for panic and recover.
// The gc compilers know to do that for the name "reflect.callMethod".
func callMethod(ctxt *methodValue, frame unsafe.Pointer) {
- t, fn, rcvr := methodReceiver("call", ctxt.rcvr, ctxt.method)
- total, in, outOffset, out := frameSize(t, true)
-
- // Copy into args.
- //
- // TODO(rsc): This will need to be updated for any new garbage collector.
- // For now make everything look like a pointer by allocating
- // a []unsafe.Pointer.
- args := make([]unsafe.Pointer, total/ptrSize)
- args[0] = unsafe.Pointer(rcvr)
- base := unsafe.Pointer(&args[0])
- memmove(unsafe.Pointer(uintptr(base)+ptrSize), frame, in)
+ rcvr := ctxt.rcvr
+ rcvrtype, t, fn := methodReceiver("call", rcvr, ctxt.method)
+ frametype, argSize, retOffset := funcLayout(t, rcvrtype)
+
+ // Make a new frame that is one word bigger so we can store the receiver.
+ args := unsafe_New(frametype)
+
+ // Copy in receiver and rest of args.
+ storeRcvr(rcvr, args)
+ memmove(unsafe.Pointer(uintptr(args)+ptrSize), frame, argSize-ptrSize)
// Call.
- call(fn, unsafe.Pointer(&args[0]), uint32(total))
+ call(fn, args, uint32(frametype.size), uint32(retOffset))
- // Copy return values.
- memmove(unsafe.Pointer(uintptr(frame)+outOffset-ptrSize), unsafe.Pointer(uintptr(base)+outOffset), out)
+ // Copy return values. On amd64p32, the beginning of return values
+ // is 64-bit aligned, so the caller's frame layout (which doesn't have
+ // a receiver) is different from the layout of the fn call, which has
+ // a receiver.
+ // Ignore any changes to args and just copy return values.
+ callerRetOffset := retOffset - ptrSize
+ if runtime.GOARCH == "amd64p32" {
+ callerRetOffset = align(argSize-ptrSize, 8)
+ }
+ memmove(unsafe.Pointer(uintptr(frame)+callerRetOffset),
+ unsafe.Pointer(uintptr(args)+retOffset), frametype.size-retOffset)
}
// funcName returns the name of f, for use in error messages.
@@ -697,10 +791,10 @@ func (v Value) Cap() int {
case Array:
return v.typ.Len()
case Chan:
- return int(chancap(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})
}
@@ -710,7 +804,7 @@ func (v Value) Cap() int {
func (v Value) Close() {
v.mustBe(Chan)
v.mustBeExported()
- chanclose(v.iword())
+ chanclose(v.pointer())
}
// Complex returns v's underlying value, as a complex128.
@@ -720,12 +814,12 @@ func (v Value) Complex() complex128 {
switch k {
case Complex64:
if v.flag&flagIndir != 0 {
- return complex128(*(*complex64)(v.val))
+ return complex128(*(*complex64)(v.ptr))
}
- return complex128(*(*complex64)(unsafe.Pointer(&v.val)))
+ return complex128(*(*complex64)(unsafe.Pointer(&v.scalar)))
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})
}
@@ -738,48 +832,31 @@ 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)
- }
- fl := v.flag & flagRO
- fl |= flag(typ.Kind()) << flagKindShift
- if typ.size > ptrSize {
- fl |= flagIndir
+ eface = (interface{})(*(*interface {
+ M()
+ })(v.ptr))
}
- return Value{typ, val, fl}
-
+ x := unpackEface(eface)
+ x.flag |= v.flag & flagRO
+ 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}
+ return Value{typ, ptr, 0, fl}
}
panic(&ValueError{"reflect.Value.Elem", k})
}
@@ -803,20 +880,26 @@ func (v Value) Field(i int) Value {
}
fl |= flag(typ.Kind()) << flagKindShift
- var val unsafe.Pointer
+ var ptr unsafe.Pointer
+ var scalar uintptr
switch {
case fl&flagIndir != 0:
// Indirect. Just bump pointer.
- val = unsafe.Pointer(uintptr(v.val) + field.offset)
+ ptr = unsafe.Pointer(uintptr(v.ptr) + field.offset)
+ case typ.pointers():
+ if field.offset != 0 {
+ panic("field access of ptr value isn't at offset 0")
+ }
+ ptr = v.ptr
case bigEndian:
- // Direct. Discard leading bytes.
- val = unsafe.Pointer(uintptr(v.val) << (field.offset * 8))
+ // Must be scalar. Discard leading bytes.
+ scalar = v.scalar << (field.offset * 8)
default:
- // Direct. Discard leading bytes.
- val = unsafe.Pointer(uintptr(v.val) >> (field.offset * 8))
+ // Must be scalar. Discard leading bytes.
+ scalar = v.scalar >> (field.offset * 8)
}
- return Value{typ, val, fl}
+ return Value{typ, ptr, scalar, fl}
}
// FieldByIndex returns the nested field corresponding to index.
@@ -825,7 +908,10 @@ func (v Value) FieldByIndex(index []int) Value {
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()
}
}
@@ -864,14 +950,14 @@ func (v Value) Float() float64 {
switch k {
case Float32:
if v.flag&flagIndir != 0 {
- return float64(*(*float32)(v.val))
+ return float64(*(*float32)(v.ptr))
}
- return float64(*(*float32)(unsafe.Pointer(&v.val)))
+ return float64(*(*float32)(unsafe.Pointer(&v.scalar)))
case Float64:
if v.flag&flagIndir != 0 {
- return *(*float64)(v.val)
+ return *(*float64)(v.ptr)
}
- return *(*float64)(unsafe.Pointer(&v.val))
+ return *(*float64)(unsafe.Pointer(&v.scalar))
}
panic(&ValueError{"reflect.Value.Float", k})
}
@@ -894,41 +980,48 @@ func (v Value) Index(i int) Value {
offset := uintptr(i) * typ.size
var val unsafe.Pointer
+ var scalar uintptr
switch {
case fl&flagIndir != 0:
// Indirect. Just bump pointer.
- val = unsafe.Pointer(uintptr(v.val) + offset)
+ val = unsafe.Pointer(uintptr(v.ptr) + offset)
+ case typ.pointers():
+ if offset != 0 {
+ panic("can't Index(i) with i!=0 on ptrLike value")
+ }
+ val = v.ptr
case bigEndian:
// Direct. Discard leading bytes.
- val = unsafe.Pointer(uintptr(v.val) << (offset * 8))
+ scalar = v.scalar << (offset * 8)
default:
// Direct. Discard leading bytes.
- val = unsafe.Pointer(uintptr(v.val) >> (offset * 8))
+ scalar = v.scalar >> (offset * 8)
}
- return Value{typ, val, fl}
+ return Value{typ, val, scalar, 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)
+ s := (*sliceHeader)(v.ptr)
if i < 0 || i >= 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)
- return Value{typ, val, fl}
+ val := unsafe.Pointer(uintptr(s.Data) + uintptr(i)*typ.size)
+ return Value{typ, val, 0, fl}
case String:
fl := v.flag&flagRO | flag(Uint8<<flagKindShift)
- s := (*StringHeader)(v.val)
+ s := (*stringHeader)(v.ptr)
if i < 0 || i >= s.Len {
panic("reflect: string index out of range")
}
- val := *(*byte)(unsafe.Pointer(s.Data + uintptr(i)))
- return Value{uint8Type, unsafe.Pointer(uintptr(val)), fl}
+ b := uintptr(0)
+ *(*byte)(unsafe.Pointer(&b)) = *(*byte)(unsafe.Pointer(uintptr(s.Data) + uintptr(i)))
+ return Value{uint8Type, nil, b, fl}
}
panic(&ValueError{"reflect.Value.Index", k})
}
@@ -939,11 +1032,11 @@ func (v Value) Int() int64 {
k := v.kind()
var p unsafe.Pointer
if v.flag&flagIndir != 0 {
- p = v.val
+ p = v.ptr
} else {
- // The escape analysis is good enough that &v.val
+ // The escape analysis is good enough that &v.scalar
// does not trigger a heap allocation.
- p = unsafe.Pointer(&v.val)
+ p = unsafe.Pointer(&v.scalar)
}
switch k {
case Int:
@@ -991,51 +1084,42 @@ func valueInterface(v Value, safe bool) interface{} {
v = makeMethodValue("Interface", v)
}
- 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 = v.typ
- 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.typ.size > ptrSize {
- // 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)
}
- 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 {
@@ -1043,7 +1127,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)
}
@@ -1051,7 +1135,7 @@ 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})
}
@@ -1080,15 +1164,15 @@ func (v Value) Len() int {
tt := (*arrayType)(unsafe.Pointer(v.typ))
return int(tt.len)
case Chan:
- return chanlen(v.iword())
+ return chanlen(v.pointer())
case Map:
- return maplen(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})
}
@@ -1110,17 +1194,32 @@ func (v Value) MapIndex(key Value) Value {
// of unexported fields.
key = key.assignTo("reflect.Value.MapIndex", tt.key, nil)
- word, ok := mapaccess(v.typ, v.iword(), key.iword())
- if !ok {
+ var k unsafe.Pointer
+ if key.flag&flagIndir != 0 {
+ k = key.ptr
+ } else if key.typ.pointers() {
+ k = unsafe.Pointer(&key.ptr)
+ } else {
+ k = unsafe.Pointer(&key.scalar)
+ }
+ e := mapaccess(v.typ, v.pointer(), k)
+ if e == nil {
return Value{}
}
typ := tt.elem
fl := (v.flag | key.flag) & flagRO
+ fl |= flag(typ.Kind()) << flagKindShift
if typ.size > ptrSize {
- fl |= flagIndir
+ // 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, 0, fl | flagIndir}
+ } else if typ.pointers() {
+ return Value{typ, *(*unsafe.Pointer)(e), 0, fl}
+ } else {
+ return Value{typ, nil, loadScalar(e, typ.size), 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,
@@ -1132,13 +1231,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.size > ptrSize {
- fl |= flagIndir
- }
+ fl := v.flag&flagRO | flag(keyType.Kind())<<flagKindShift
- m := v.iword()
+ m := v.pointer()
mlen := int(0)
if m != nil {
mlen = maplen(m)
@@ -1147,11 +1242,24 @@ 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 keyType.size > ptrSize {
+ // 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, 0, fl | flagIndir}
+ } else if keyType.pointers() {
+ a[i] = Value{keyType, *(*unsafe.Pointer)(key), 0, fl}
+ } else {
+ a[i] = Value{keyType, nil, loadScalar(key, keyType.size), fl}
+ }
mapiternext(it)
}
return a[:i]
@@ -1174,7 +1282,7 @@ func (v Value) Method(i int) Value {
fl := v.flag & (flagRO | flagIndir)
fl |= flag(Func) << flagKindShift
fl |= flag(i)<<flagMethodShift | flagMethod
- return Value{v.typ, v.val, fl}
+ return Value{v.typ, v.ptr, v.scalar, fl}
}
// NumMethod returns the number of methods in the value's method set.
@@ -1284,15 +1392,16 @@ 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
@@ -1304,10 +1413,7 @@ func (v Value) Pointer() uintptr {
f := methodValueCall
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 {
@@ -1316,7 +1422,7 @@ 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})
}
@@ -1339,14 +1445,21 @@ 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, v.iword(), nb)
- if selected {
- typ := tt.elem
- fl := flag(typ.Kind()) << flagKindShift
- if typ.size > ptrSize {
- fl |= flagIndir
- }
- val = Value{typ, unsafe.Pointer(word), fl}
+ t := tt.elem
+ val = Value{t, nil, 0, flag(t.Kind()) << flagKindShift}
+ var p unsafe.Pointer
+ if t.size > ptrSize {
+ p = unsafe_New(t)
+ val.ptr = p
+ val.flag |= flagIndir
+ } else if t.pointers() {
+ p = unsafe.Pointer(&val.ptr)
+ } else {
+ p = unsafe.Pointer(&val.scalar)
+ }
+ selected, ok := chanrecv(v.typ, v.pointer(), nb, p)
+ if !selected {
+ val = Value{}
}
return
}
@@ -1369,7 +1482,15 @@ 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, v.iword(), x.iword(), nb)
+ var p unsafe.Pointer
+ if x.flag&flagIndir != 0 {
+ p = x.ptr
+ } else if x.typ.pointers() {
+ p = unsafe.Pointer(&x.ptr)
+ } else {
+ p = unsafe.Pointer(&x.scalar)
+ }
+ return chansend(v.typ, v.pointer(), p, nb)
}
// Set assigns x to the value v.
@@ -1380,13 +1501,15 @@ func (v Value) Set(x Value) {
x.mustBeExported() // do not let unexported x leak
var target *interface{}
if v.kind() == Interface {
- target = (*interface{})(v.val)
+ target = (*interface{})(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 if x.typ.pointers() {
+ *(*unsafe.Pointer)(v.ptr) = x.ptr
} else {
- storeIword(v.val, iword(x.val), v.typ.size)
+ memmove(v.ptr, unsafe.Pointer(&x.scalar), v.typ.size)
}
}
@@ -1395,7 +1518,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.
@@ -1406,7 +1529,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.
@@ -1417,7 +1540,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.
@@ -1428,9 +1551,9 @@ func (v Value) SetComplex(x complex128) {
default:
panic(&ValueError{"reflect.Value.SetComplex", k})
case Complex64:
- *(*complex64)(v.val) = complex64(x)
+ *(*complex64)(v.ptr) = complex64(x)
case Complex128:
- *(*complex128)(v.val) = x
+ *(*complex128)(v.ptr) = x
}
}
@@ -1442,9 +1565,9 @@ func (v Value) SetFloat(x float64) {
default:
panic(&ValueError{"reflect.Value.SetFloat", k})
case Float32:
- *(*float32)(v.val) = float32(x)
+ *(*float32)(v.ptr) = float32(x)
case Float64:
- *(*float64)(v.val) = x
+ *(*float64)(v.ptr) = x
}
}
@@ -1456,15 +1579,15 @@ func (v Value) SetInt(x int64) {
default:
panic(&ValueError{"reflect.Value.SetInt", k})
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
}
}
@@ -1474,7 +1597,7 @@ func (v Value) SetInt(x int64) {
func (v Value) SetLen(n int) {
v.mustBeAssignable()
v.mustBe(Slice)
- s := (*SliceHeader)(v.val)
+ s := (*sliceHeader)(v.ptr)
if n < 0 || n > int(s.Cap) {
panic("reflect: slice length out of range in SetLen")
}
@@ -1487,7 +1610,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")
}
@@ -1497,6 +1620,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) {
@@ -1505,11 +1629,29 @@ 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 if key.typ.pointers() {
+ k = unsafe.Pointer(&key.ptr)
+ } else {
+ k = unsafe.Pointer(&key.scalar)
+ }
+ 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 if val.typ.pointers() {
+ e = unsafe.Pointer(&val.ptr)
+ } else {
+ e = unsafe.Pointer(&val.scalar)
}
- mapassign(v.typ, v.iword(), key.iword(), val.iword(), val.typ != nil)
+ mapassign(v.typ, v.pointer(), k, e)
}
// SetUint sets v's underlying value to x.
@@ -1520,17 +1662,17 @@ func (v Value) SetUint(x uint64) {
default:
panic(&ValueError{"reflect.Value.SetUint", k})
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)
}
}
@@ -1539,7 +1681,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.
@@ -1547,7 +1689,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].
@@ -1570,24 +1712,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), 0, v.flag}
}
if i < 0 || j < i || j > cap {
@@ -1597,14 +1736,14 @@ 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.Data = unsafe.Pointer(uintptr(base) + uintptr(i)*typ.elem.Size())
s.Len = j - i
s.Cap = cap - i
fl := v.flag&flagRO | flagIndir | flag(Slice)<<flagKindShift
- return Value{typ.common(), unsafe.Pointer(&x), fl}
+ return Value{typ.common(), unsafe.Pointer(&x), 0, fl}
}
// Slice3 is the 3-index form of the slice operation: it returns v[i:j:k].
@@ -1622,17 +1761,17 @@ func (v Value) Slice3(i, j, k int) Value {
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
}
@@ -1644,14 +1783,14 @@ 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.Data = unsafe.Pointer(uintptr(base) + uintptr(i)*typ.elem.Size())
s.Len = j - i
s.Cap = k - i
fl := v.flag&flagRO | flagIndir | flag(Slice)<<flagKindShift
- return Value{typ.common(), unsafe.Pointer(&x), fl}
+ return Value{typ.common(), unsafe.Pointer(&x), 0, fl}
}
// String returns the string v's underlying value, as a string.
@@ -1663,7 +1802,7 @@ 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.
@@ -1672,9 +1811,9 @@ func (v Value) String() string {
// 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()
@@ -1729,11 +1868,11 @@ func (v Value) Uint() uint64 {
k := v.kind()
var p unsafe.Pointer
if v.flag&flagIndir != 0 {
- p = v.val
+ p = v.ptr
} else {
- // The escape analysis is good enough that &v.val
+ // The escape analysis is good enough that &v.scalar
// does not trigger a heap allocation.
- p = unsafe.Pointer(&v.val)
+ p = unsafe.Pointer(&v.scalar)
}
switch k {
case Uint:
@@ -1756,13 +1895,14 @@ func (v Value) Uint() uint64 {
// 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.
@@ -1776,6 +1916,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.
@@ -1788,6 +1934,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())
@@ -1876,6 +2029,8 @@ func Copy(dst, src Value) int {
// If sk is an in-line array, cannot take its address.
// Instead, copy element by element.
+ // TODO: memmove would be ok for this (sa = unsafe.Pointer(&v.scalar))
+ // if we teach the compiler that ptrs don't escape from memmove.
if src.flag&flagIndir == 0 {
for i := 0; i < n; i++ {
dst.Index(i).Set(src.Index(i))
@@ -1886,14 +2041,14 @@ func Copy(dst, src Value) int {
// 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
+ 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
@@ -1902,17 +2057,18 @@ func Copy(dst, src Value) int {
// A runtimeSelect is a single case passed to rselect.
// This must match ../runtime/chan.c:/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
@@ -1992,7 +2148,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 = ch.iword()
+ rc.ch = ch.pointer()
rc.typ = &tt.rtype
v := c.Send
if !v.IsValid() {
@@ -2000,7 +2156,13 @@ 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 if v.typ.pointers() {
+ rc.val = unsafe.Pointer(&v.ptr)
+ } else {
+ rc.val = unsafe.Pointer(&v.scalar)
+ }
case SelectRecv:
if c.Send.IsValid() {
@@ -2013,23 +2175,28 @@ 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 = 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.size > ptrSize {
- fl |= flagIndir
+ t := tt.elem
+ p := runcases[chosen].val
+ fl := flag(t.Kind()) << flagKindShift
+ if t.size > ptrSize {
+ recv = Value{t, p, 0, fl | flagIndir}
+ } else if t.pointers() {
+ recv = Value{t, *(*unsafe.Pointer)(p), 0, fl}
+ } else {
+ recv = Value{t, nil, loadScalar(p, t.size), fl}
}
- recv = Value{typ, unsafe.Pointer(word), fl}
}
return chosen, recv, recvOK
}
@@ -2058,16 +2225,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), 0, flagIndir | flag(Slice)<<flagKindShift}
}
// MakeChan creates a new channel with the specified type and buffer size.
@@ -2082,7 +2241,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), flag(Chan) << flagKindShift}
+ return Value{typ.common(), ch, 0, flag(Chan) << flagKindShift}
}
// MakeMap creates a new map of the specified type.
@@ -2091,7 +2250,7 @@ func MakeMap(typ Type) Value {
panic("reflect.MakeMap of non-map type")
}
m := makemap(typ.(*rtype))
- return Value{typ.common(), unsafe.Pointer(m), flag(Map) << flagKindShift}
+ return Value{typ.common(), m, 0, flag(Map) << flagKindShift}
}
// Indirect returns the value that v points to.
@@ -2112,21 +2271,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.size > ptrSize {
- 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.
@@ -2141,27 +2292,27 @@ func Zero(typ Type) Value {
t := typ.common()
fl := flag(t.Kind()) << flagKindShift
if t.size <= ptrSize {
- return Value{t, nil, fl}
+ return Value{t, nil, 0, fl}
}
- return Value{t, unsafe_New(typ.(*rtype)), fl | flagIndir}
+ return Value{t, unsafe_New(typ.(*rtype)), 0, fl | flagIndir}
}
// 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
- return Value{typ.common().ptrTo(), ptr, fl}
+ return Value{typ.common().ptrTo(), ptr, 0, 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
- return Value{typ.common().ptrTo(), p, fl}
+ return Value{typ.common().ptrTo(), p, 0, fl}
}
// assignTo returns a value v that can be assigned directly to typ.
@@ -2179,7 +2330,7 @@ func (v Value) assignTo(context string, dst *rtype, target *interface{}) Value {
v.typ = dst
fl := v.flag & (flagRO | flagAddr | flagIndir)
fl |= flag(dst.Kind()) << flagKindShift
- return Value{dst, v.val, fl}
+ return Value{dst, v.ptr, v.scalar, fl}
case implements(dst, v.typ):
if target == nil {
@@ -2191,7 +2342,7 @@ func (v Value) assignTo(context string, dst *rtype, target *interface{}) Value {
} else {
ifaceE2I(dst, x, unsafe.Pointer(target))
}
- return Value{dst, unsafe.Pointer(target), flagIndir | flag(Interface)<<flagKindShift}
+ return Value{dst, unsafe.Pointer(target), 0, flagIndir | flag(Interface)<<flagKindShift}
}
// Failed.
@@ -2303,20 +2454,20 @@ func makeInt(f flag, bits uint64, t Type) Value {
// 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}
+ return Value{typ, ptr, 0, f | flagIndir | flag(typ.Kind())<<flagKindShift}
}
- var w iword
+ var s uintptr
switch typ.size {
case 1:
- *(*uint8)(unsafe.Pointer(&w)) = uint8(bits)
+ *(*uint8)(unsafe.Pointer(&s)) = uint8(bits)
case 2:
- *(*uint16)(unsafe.Pointer(&w)) = uint16(bits)
+ *(*uint16)(unsafe.Pointer(&s)) = uint16(bits)
case 4:
- *(*uint32)(unsafe.Pointer(&w)) = uint32(bits)
+ *(*uint32)(unsafe.Pointer(&s)) = uint32(bits)
case 8:
- *(*uint64)(unsafe.Pointer(&w)) = uint64(bits)
+ *(*uint64)(unsafe.Pointer(&s)) = uint64(bits)
}
- return Value{typ, unsafe.Pointer(w), f | flag(typ.Kind())<<flagKindShift}
+ return Value{typ, nil, s, f | flag(typ.Kind())<<flagKindShift}
}
// makeFloat returns a Value of type t equal to v (possibly truncated to float32),
@@ -2327,17 +2478,17 @@ func makeFloat(f flag, v float64, t Type) Value {
// 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}
+ return Value{typ, ptr, 0, f | flagIndir | flag(typ.Kind())<<flagKindShift}
}
- var w iword
+ var s uintptr
switch typ.size {
case 4:
- *(*float32)(unsafe.Pointer(&w)) = float32(v)
+ *(*float32)(unsafe.Pointer(&s)) = float32(v)
case 8:
- *(*float64)(unsafe.Pointer(&w)) = v
+ *(*float64)(unsafe.Pointer(&s)) = v
}
- return Value{typ, unsafe.Pointer(w), f | flag(typ.Kind())<<flagKindShift}
+ return Value{typ, nil, s, f | flag(typ.Kind())<<flagKindShift}
}
// makeComplex returns a Value of type t equal to v (possibly truncated to complex64),
@@ -2352,13 +2503,13 @@ func makeComplex(f flag, v complex128, t Type) Value {
case 16:
*(*complex128)(unsafe.Pointer(ptr)) = v
}
- return Value{typ, ptr, f | flagIndir | flag(typ.Kind())<<flagKindShift}
+ return Value{typ, ptr, 0, f | flagIndir | flag(typ.Kind())<<flagKindShift}
}
// 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}
+ var s uintptr
+ *(*complex64)(unsafe.Pointer(&s)) = complex64(v)
+ return Value{typ, nil, s, f | flag(typ.Kind())<<flagKindShift}
}
func makeString(f flag, v string, t Type) Value {
@@ -2461,15 +2612,15 @@ 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.scalar, v.flag&flagRO | f} // v.flag&flagRO|f == f?
}
// convertOp: concrete -> interface
@@ -2481,7 +2632,7 @@ func cvtT2I(v Value, typ Type) Value {
} else {
ifaceE2I(typ.(*rtype), x, unsafe.Pointer(target))
}
- return Value{typ.common(), unsafe.Pointer(target), v.flag&flagRO | flagIndir | flag(Interface)<<flagKindShift}
+ return Value{typ.common(), unsafe.Pointer(target), 0, v.flag&flagRO | flagIndir | flag(Interface)<<flagKindShift}
}
// convertOp: interface -> interface
@@ -2495,22 +2646,27 @@ func cvtI2I(v Value, typ Type) Value {
}
// 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
-
-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
-
-func call(fn, arg unsafe.Pointer, n uint32)
+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)
+
+//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(fn, arg unsafe.Pointer, n uint32, retoffset uint32)
func ifaceE2I(t *rtype, src interface{}, dst unsafe.Pointer)
// Dummy annotation marking that the value x escapes,
diff --git a/src/pkg/regexp/all_test.go b/src/pkg/regexp/all_test.go
index e914a7ccb..301a1dfcd 100644
--- a/src/pkg/regexp/all_test.go
+++ b/src/pkg/regexp/all_test.go
@@ -473,6 +473,11 @@ func TestSplit(t *testing.T) {
}
}
+// This ran out of stack before issue 7608 was fixed.
+func TestOnePassCutoff(t *testing.T) {
+ MustCompile(`^(?:x{1,1000}){1,1000}$`)
+}
+
func BenchmarkLiteral(b *testing.B) {
x := strings.Repeat("x", 50) + "y"
b.StopTimer()
@@ -578,3 +583,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/src/pkg/regexp/example_test.go b/src/pkg/regexp/example_test.go
index b0ad9d340..a4e0da8ea 100644
--- a/src/pkg/regexp/example_test.go
+++ b/src/pkg/regexp/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 regexp_test
import (
diff --git a/src/pkg/regexp/exec.go b/src/pkg/regexp/exec.go
index 333ca2554..c4cb201f6 100644
--- a/src/pkg/regexp/exec.go
+++ b/src/pkg/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/src/pkg/regexp/onepass.go b/src/pkg/regexp/onepass.go
new file mode 100644
index 000000000..501fb28af
--- /dev/null
+++ b/src/pkg/regexp/onepass.go
@@ -0,0 +1,582 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+
+package regexp
+
+import (
+ "bytes"
+ "regexp/syntax"
+ "sort"
+ "unicode"
+)
+
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// "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/src/pkg/regexp/onepass_test.go b/src/pkg/regexp/onepass_test.go
new file mode 100644
index 000000000..7b2beea67
--- /dev/null
+++ b/src/pkg/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/src/pkg/regexp/regexp.go b/src/pkg/regexp/regexp.go
index 0046026ea..0b8336a04 100644
--- a/src/pkg/regexp/regexp.go
+++ b/src/pkg/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
}
diff --git a/src/pkg/regexp/syntax/doc.go b/src/pkg/regexp/syntax/doc.go
index e52632ef7..8e72c90d3 100644
--- a/src/pkg/regexp/syntax/doc.go
+++ b/src/pkg/regexp/syntax/doc.go
@@ -46,6 +46,10 @@ Repetitions:
x{n,}? n or more x, prefer fewer
x{n}? exactly n x
+Implementation restriction: The counting forms x{n} etc. (but not the other
+forms x* etc.) have an upper limit of n=1000. Negative or higher explicit
+counts yield the parse error ErrInvalidRepeatSize.
+
Grouping:
(re) numbered capturing group (submatch)
(?P<name>re) named & numbered capturing group (submatch)
diff --git a/src/pkg/regexp/syntax/make_perl_groups.pl b/src/pkg/regexp/syntax/make_perl_groups.pl
index d024f5090..90040fcb4 100755
--- a/src/pkg/regexp/syntax/make_perl_groups.pl
+++ b/src/pkg/regexp/syntax/make_perl_groups.pl
@@ -92,6 +92,10 @@ sub PrintClasses($@) {
}
print <<EOF;
+// 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/src/pkg/regexp/syntax/parse.go b/src/pkg/regexp/syntax/parse.go
index 42d0bf4a1..cb25dca39 100644
--- a/src/pkg/regexp/syntax/parse.go
+++ b/src/pkg/regexp/syntax/parse.go
@@ -668,7 +668,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 +739,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
diff --git a/src/pkg/regexp/syntax/parse_test.go b/src/pkg/regexp/syntax/parse_test.go
index 269d6c3b8..f3089294c 100644
--- a/src/pkg/regexp/syntax/parse_test.go
+++ b/src/pkg/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)},
diff --git a/src/pkg/regexp/syntax/perl_groups.go b/src/pkg/regexp/syntax/perl_groups.go
index 1a11ca62f..effe4e686 100644
--- a/src/pkg/regexp/syntax/perl_groups.go
+++ b/src/pkg/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/src/pkg/regexp/syntax/prog.go b/src/pkg/regexp/syntax/prog.go
index a482a82f2..29bd282d0 100644
--- a/src/pkg/regexp/syntax/prog.go
+++ b/src/pkg/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/src/pkg/regexp/syntax/prog_test.go b/src/pkg/regexp/syntax/prog_test.go
index cd71abc2a..50bfa3d4b 100644
--- a/src/pkg/regexp/syntax/prog_test.go
+++ b/src/pkg/regexp/syntax/prog_test.go
@@ -4,9 +4,7 @@
package syntax
-import (
- "testing"
-)
+import "testing"
var compileTests = []struct {
Regexp string
diff --git a/src/pkg/runtime/alg.c b/src/pkg/runtime/alg.goc
index c3a839695..f1b8d5982 100644
--- a/src/pkg/runtime/alg.c
+++ b/src/pkg/runtime/alg.goc
@@ -2,6 +2,7 @@
// 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 "type.h"
#include "../../cmd/ld/textflag.h"
@@ -20,7 +21,7 @@ runtime·memhash(uintptr *h, uintptr s, void *a)
{
byte *b;
uintptr hash;
- if(use_aeshash) {
+ if(!NaCl && use_aeshash) {
runtime·aeshash(h, s, a);
return;
}
@@ -464,11 +465,15 @@ runtime·algarray[] =
// Runtime helpers.
// used in asm_{386,amd64}.s
+#pragma dataflag NOPTR
byte runtime·aeskeysched[HashRandomBytes];
void
runtime·hashinit(void)
{
+ if(NaCl)
+ return;
+
// Install aes hash algorithm if we have the instructions we need
if((runtime·cpuid_ecx & (1 << 25)) != 0 && // aes (aesenc)
(runtime·cpuid_ecx & (1 << 9)) != 0 && // sse3 (pshufb)
@@ -505,37 +510,40 @@ void
runtime·equal(Type *t, ...)
{
byte *x, *y;
- uintptr ret;
+ bool *ret;
- x = (byte*)(&t+1);
+ x = (byte*)ROUND((uintptr)(&t+1), t->align);
y = x + t->size;
- ret = (uintptr)(y + t->size);
- ret = ROUND(ret, Structrnd);
- t->alg->equal((bool*)ret, t->size, x, y);
+ ret = (bool*)ROUND((uintptr)(y+t->size), Structrnd);
+ t->alg->equal(ret, t->size, x, y);
+}
+
+// Testing adapter for memclr
+func memclrBytes(s Slice) {
+ runtime·memclr(s.array, s.len);
}
// Testing adapters for hash quality tests (see hash_test.go)
-void runtime·haveGoodHash(bool res) {
+func haveGoodHash() (res bool) {
res = use_aeshash;
- FLUSH(&res);
}
-void runtime·stringHash(String s, uintptr seed, uintptr res) {
+
+func stringHash(s String, seed uintptr) (res uintptr) {
runtime·algarray[ASTRING].hash(&seed, sizeof(String), &s);
res = seed;
- FLUSH(&res);
}
-void runtime·bytesHash(Slice s, uintptr seed, uintptr res) {
+
+func bytesHash(s Slice, seed uintptr) (res uintptr) {
runtime·algarray[AMEM].hash(&seed, s.len, s.array);
res = seed;
- FLUSH(&res);
}
-void runtime·int32Hash(uint32 i, uintptr seed, uintptr res) {
+
+func int32Hash(i uint32, seed uintptr) (res uintptr) {
runtime·algarray[AMEM32].hash(&seed, sizeof(uint32), &i);
res = seed;
- FLUSH(&res);
}
-void runtime·int64Hash(uint64 i, uintptr seed, uintptr res) {
+
+func int64Hash(i uint64, seed uintptr) (res uintptr) {
runtime·algarray[AMEM64].hash(&seed, sizeof(uint64), &i);
res = seed;
- FLUSH(&res);
}
diff --git a/src/pkg/runtime/append_test.go b/src/pkg/runtime/append_test.go
index 937c8259f..a67dc9b49 100644
--- a/src/pkg/runtime/append_test.go
+++ b/src/pkg/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/src/pkg/runtime/arch_386.h b/src/pkg/runtime/arch_386.h
index ebdb3ff4e..5c0a54f8c 100644
--- a/src/pkg/runtime/arch_386.h
+++ b/src/pkg/runtime/arch_386.h
@@ -7,5 +7,10 @@ enum {
BigEndian = 0,
CacheLineSize = 64,
RuntimeGogoBytes = 64,
+#ifdef GOOS_nacl
+ PhysPageSize = 65536,
+#else
+ PhysPageSize = 4096,
+#endif
PCQuantum = 1
};
diff --git a/src/pkg/runtime/arch_amd64.h b/src/pkg/runtime/arch_amd64.h
index 2bddf0796..c8a21847c 100644
--- a/src/pkg/runtime/arch_amd64.h
+++ b/src/pkg/runtime/arch_amd64.h
@@ -6,6 +6,15 @@ enum {
thechar = '6',
BigEndian = 0,
CacheLineSize = 64,
+#ifdef GOOS_solaris
+ RuntimeGogoBytes = 80,
+#else
+#ifdef GOOS_windows
+ RuntimeGogoBytes = 80,
+#else
RuntimeGogoBytes = 64,
+#endif // Windows
+#endif // Solaris
+ PhysPageSize = 4096,
PCQuantum = 1
};
diff --git a/src/pkg/runtime/arch_amd64p32.h b/src/pkg/runtime/arch_amd64p32.h
new file mode 100644
index 000000000..073a9e30e
--- /dev/null
+++ b/src/pkg/runtime/arch_amd64p32.h
@@ -0,0 +1,16 @@
+// 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.
+
+enum {
+ thechar = '6',
+ BigEndian = 0,
+ CacheLineSize = 64,
+ RuntimeGogoBytes = 64,
+#ifdef GOOS_nacl
+ PhysPageSize = 65536,
+#else
+ PhysPageSize = 4096,
+#endif
+ PCQuantum = 1
+};
diff --git a/src/pkg/runtime/arch_arm.h b/src/pkg/runtime/arch_arm.h
index e5da01c60..b9711289f 100644
--- a/src/pkg/runtime/arch_arm.h
+++ b/src/pkg/runtime/arch_arm.h
@@ -7,5 +7,6 @@ enum {
BigEndian = 0,
CacheLineSize = 32,
RuntimeGogoBytes = 80,
+ PhysPageSize = 4096,
PCQuantum = 4
};
diff --git a/src/pkg/runtime/asm_386.s b/src/pkg/runtime/asm_386.s
index 5c642c0ed..95312089d 100644
--- a/src/pkg/runtime/asm_386.s
+++ b/src/pkg/runtime/asm_386.s
@@ -247,6 +247,10 @@ TEXT runtime·morestack(SB),NOSPLIT,$0-0
MOVL $0, 0x1003 // crash if newstack returns
RET
+TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0-0
+ MOVL $0, DX
+ JMP runtime·morestack(SB)
+
// Called from panic. Mimics morestack,
// reuses stack growth code to create a frame
// with the desired args running the desired function.
@@ -307,7 +311,7 @@ TEXT runtime·newstackcall(SB), NOSPLIT, $0-12
JMP AX
// Note: can't just "JMP runtime·NAME(SB)" - bad inlining results.
-TEXT reflect·call(SB), NOSPLIT, $0-12
+TEXT reflect·call(SB), NOSPLIT, $0-16
MOVL argsize+8(FP), CX
DISPATCH(call16, 16)
DISPATCH(call32, 32)
@@ -339,8 +343,22 @@ TEXT reflect·call(SB), NOSPLIT, $0-12
MOVL $runtime·badreflectcall(SB), AX
JMP AX
+// Argument map for the callXX frames. Each has one
+// stack map (for the single call) with 3 arguments.
+DATA gcargs_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap
+DATA gcargs_reflectcall<>+0x04(SB)/4, $6 // 3 args
+DATA gcargs_reflectcall<>+0x08(SB)/4, $(const_BitsPointer+(const_BitsPointer<<2)+(const_BitsScalar<<4))
+GLOBL gcargs_reflectcall<>(SB),RODATA,$12
+
+// callXX frames have no locals
+DATA gclocals_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap
+DATA gclocals_reflectcall<>+0x04(SB)/4, $0 // 0 locals
+GLOBL gclocals_reflectcall<>(SB),RODATA,$8
+
#define CALLFN(NAME,MAXSIZE) \
-TEXT runtime·NAME(SB), WRAPPER, $MAXSIZE-12; \
+TEXT runtime·NAME(SB), WRAPPER, $MAXSIZE-16; \
+ FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_reflectcall<>(SB); \
+ FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_reflectcall<>(SB);\
/* copy arguments to stack */ \
MOVL argptr+4(FP), SI; \
MOVL argsize+8(FP), CX; \
@@ -348,11 +366,17 @@ TEXT runtime·NAME(SB), WRAPPER, $MAXSIZE-12; \
REP;MOVSB; \
/* call function */ \
MOVL f+0(FP), DX; \
- CALL (DX); \
+ MOVL (DX), AX; \
+ PCDATA $PCDATA_StackMapIndex, $0; \
+ CALL AX; \
/* copy return values back */ \
MOVL argptr+4(FP), DI; \
MOVL argsize+8(FP), CX; \
+ MOVL retoffset+12(FP), BX; \
MOVL SP, SI; \
+ ADDL BX, DI; \
+ ADDL BX, SI; \
+ SUBL BX, CX; \
REP;MOVSB; \
RET
@@ -483,6 +507,12 @@ TEXT runtime·xchg(SB), NOSPLIT, $0-8
XCHGL AX, 0(BX)
RET
+TEXT runtime·xchgp(SB), NOSPLIT, $0-8
+ MOVL 4(SP), BX
+ MOVL 8(SP), AX
+ XCHGL AX, 0(BX)
+ RET
+
TEXT runtime·procyield(SB),NOSPLIT,$0-0
MOVL 4(SP), AX
again:
@@ -646,7 +676,6 @@ havem:
// Save current sp in m->g0->sched.sp in preparation for
// switch back to m->curg stack.
// NOTE: unwindm knows that the saved g->sched.sp is at 0(SP).
- // On Windows, the SEH is at 4(SP) and 8(SP).
MOVL m_g0(BP), SI
MOVL (g_sched+gobuf_sp)(SI), AX
MOVL AX, 0(SP)
@@ -747,21 +776,6 @@ TEXT runtime·stackcheck(SB), NOSPLIT, $0-0
INT $3
RET
-TEXT runtime·memclr(SB),NOSPLIT,$0-8
- MOVL 4(SP), DI // arg 1 addr
- MOVL 8(SP), CX // arg 2 count
- MOVL CX, BX
- ANDL $3, BX
- SHRL $2, CX
- MOVL $0, AX
- CLD
- REP
- STOSL
- MOVL BX, CX
- REP
- STOSB
- RET
-
TEXT runtime·getcallerpc(SB),NOSPLIT,$0-4
MOVL x+0(FP),AX // addr of first arg
MOVL -4(AX),AX // get calling pc
@@ -1353,3 +1367,800 @@ cmp_allsame:
SETEQ CX // 1 if alen == blen
LEAL -1(CX)(AX*2), AX // 1,0,-1 result
RET
+
+// A Duff's device for zeroing memory.
+// The compiler jumps to computed addresses within
+// this routine to zero chunks of memory. Do not
+// change this code without also changing the code
+// in ../../cmd/8g/ggen.c:clearfat.
+// AX: zero
+// DI: ptr to memory to be zeroed
+// DI is updated as a side effect.
+TEXT runtime·duffzero(SB), NOSPLIT, $0-0
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ RET
+
+// A Duff's device for copying memory.
+// The compiler jumps to computed addresses within
+// this routine to copy chunks of memory. Source
+// and destination must not overlap. Do not
+// change this code without also changing the code
+// in ../../cmd/6g/cgen.c:sgen.
+// SI: ptr to source memory
+// DI: ptr to destination memory
+// SI and DI are updated as a side effect.
+
+// NOTE: this is equivalent to a sequence of MOVSL but
+// for some reason MOVSL is really slow.
+TEXT runtime·duffcopy(SB), NOSPLIT, $0-0
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ RET
+
+TEXT runtime·timenow(SB), NOSPLIT, $0-0
+ JMP time·now(SB)
diff --git a/src/pkg/runtime/asm_amd64.s b/src/pkg/runtime/asm_amd64.s
index 2c2ffedd1..3c7eaf343 100644
--- a/src/pkg/runtime/asm_amd64.s
+++ b/src/pkg/runtime/asm_amd64.s
@@ -53,6 +53,9 @@ needtls:
// skip TLS setup on Plan 9
CMPL runtime·isplan9(SB), $1
JEQ ok
+ // skip TLS setup on Solaris
+ CMPL runtime·issolaris(SB), $1
+ JEQ ok
LEAQ runtime·tls0(SB), DI
CALL runtime·settls(SB)
@@ -286,7 +289,7 @@ TEXT runtime·newstackcall(SB), NOSPLIT, $0-20
JMP AX
// Note: can't just "JMP runtime·NAME(SB)" - bad inlining results.
-TEXT reflect·call(SB), NOSPLIT, $0-20
+TEXT reflect·call(SB), NOSPLIT, $0-24
MOVLQZX argsize+16(FP), CX
DISPATCH(call16, 16)
DISPATCH(call32, 32)
@@ -318,8 +321,22 @@ TEXT reflect·call(SB), NOSPLIT, $0-20
MOVQ $runtime·badreflectcall(SB), AX
JMP AX
+// Argument map for the callXX frames. Each has one
+// stack map (for the single call) with 3 arguments.
+DATA gcargs_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap
+DATA gcargs_reflectcall<>+0x04(SB)/4, $6 // 3 args
+DATA gcargs_reflectcall<>+0x08(SB)/4, $(const_BitsPointer+(const_BitsPointer<<2)+(const_BitsScalar<<4))
+GLOBL gcargs_reflectcall<>(SB),RODATA,$12
+
+// callXX frames have no locals
+DATA gclocals_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap
+DATA gclocals_reflectcall<>+0x04(SB)/4, $0 // 0 locals
+GLOBL gclocals_reflectcall<>(SB),RODATA,$8
+
#define CALLFN(NAME,MAXSIZE) \
-TEXT runtime·NAME(SB), WRAPPER, $MAXSIZE-20; \
+TEXT runtime·NAME(SB), WRAPPER, $MAXSIZE-24; \
+ FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_reflectcall<>(SB); \
+ FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_reflectcall<>(SB);\
/* copy arguments to stack */ \
MOVQ argptr+8(FP), SI; \
MOVLQZX argsize+16(FP), CX; \
@@ -327,11 +344,16 @@ TEXT runtime·NAME(SB), WRAPPER, $MAXSIZE-20; \
REP;MOVSB; \
/* call function */ \
MOVQ f+0(FP), DX; \
+ PCDATA $PCDATA_StackMapIndex, $0; \
CALL (DX); \
/* copy return values back */ \
MOVQ argptr+8(FP), DI; \
MOVLQZX argsize+16(FP), CX; \
+ MOVLQZX retoffset+20(FP), BX; \
MOVQ SP, SI; \
+ ADDQ BX, DI; \
+ ADDQ BX, SI; \
+ SUBQ BX, CX; \
REP;MOVSB; \
RET
@@ -453,6 +475,46 @@ TEXT morestack<>(SB),NOSPLIT,$0
MOVQ $runtime·morestack(SB), AX
JMP AX
+TEXT runtime·morestack00_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack00(SB)
+
+TEXT runtime·morestack01_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack01(SB)
+
+TEXT runtime·morestack10_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack10(SB)
+
+TEXT runtime·morestack11_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack11(SB)
+
+TEXT runtime·morestack8_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack8(SB)
+
+TEXT runtime·morestack16_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack16(SB)
+
+TEXT runtime·morestack24_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack24(SB)
+
+TEXT runtime·morestack32_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack32(SB)
+
+TEXT runtime·morestack40_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack40(SB)
+
+TEXT runtime·morestack48_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack48(SB)
+
// bool cas(int32 *val, int32 old, int32 new)
// Atomically:
// if(*val == old){
@@ -546,6 +608,12 @@ TEXT runtime·xchg64(SB), NOSPLIT, $0-16
XCHGQ AX, 0(BX)
RET
+TEXT runtime·xchgp(SB), NOSPLIT, $0-16
+ MOVQ 8(SP), BX
+ MOVQ 16(SP), AX
+ XCHGQ AX, 0(BX)
+ RET
+
TEXT runtime·procyield(SB),NOSPLIT,$0-0
MOVL 8(SP), AX
again:
@@ -614,10 +682,16 @@ TEXT runtime·asmcgocall(SB),NOSPLIT,$0-16
MOVQ m_g0(BP), SI
MOVQ g(CX), DI
CMPQ SI, DI
- JEQ 4(PC)
+ JEQ nosave
+ MOVQ m_gsignal(BP), SI
+ CMPQ SI, DI
+ JEQ nosave
+
+ MOVQ m_g0(BP), SI
CALL gosave<>(SB)
MOVQ SI, g(CX)
MOVQ (g_sched+gobuf_sp)(SI), SP
+nosave:
// Now on a scheduling stack (a pthread-created stack).
// Make sure we have enough room for 4 stack-backed fast-call
@@ -779,21 +853,6 @@ TEXT runtime·stackcheck(SB), NOSPLIT, $0-0
INT $3
RET
-TEXT runtime·memclr(SB),NOSPLIT,$0-16
- MOVQ 8(SP), DI // arg 1 addr
- MOVQ 16(SP), CX // arg 2 count
- MOVQ CX, BX
- ANDQ $7, BX
- SHRQ $3, CX
- MOVQ $0, AX
- CLD
- REP
- STOSQ
- MOVQ BX, CX
- REP
- STOSB
- RET
-
TEXT runtime·getcallerpc(SB),NOSPLIT,$0-8
MOVQ x+0(FP),AX // addr of first arg
MOVQ -8(AX),AX // get calling pc
@@ -1340,3 +1399,801 @@ TEXT bytes·Equal(SB),NOSPLIT,$0-49
eqret:
MOVB AX, ret+48(FP)
RET
+
+// A Duff's device for zeroing memory.
+// The compiler jumps to computed addresses within
+// this routine to zero chunks of memory. Do not
+// change this code without also changing the code
+// in ../../cmd/6g/ggen.c:clearfat.
+// AX: zero
+// DI: ptr to memory to be zeroed
+// DI is updated as a side effect.
+TEXT runtime·duffzero(SB), NOSPLIT, $0-0
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ RET
+
+// A Duff's device for copying memory.
+// The compiler jumps to computed addresses within
+// this routine to copy chunks of memory. Source
+// and destination must not overlap. Do not
+// change this code without also changing the code
+// in ../../cmd/6g/cgen.c:sgen.
+// SI: ptr to source memory
+// DI: ptr to destination memory
+// SI and DI are updated as a side effect.
+
+// NOTE: this is equivalent to a sequence of MOVSQ but
+// for some reason that is 3.5x slower than this code.
+// The STOSQ above seem fine, though.
+TEXT runtime·duffcopy(SB), NOSPLIT, $0-0
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ RET
+
+TEXT runtime·timenow(SB), NOSPLIT, $0-0
+ JMP time·now(SB)
diff --git a/src/pkg/runtime/asm_amd64p32.s b/src/pkg/runtime/asm_amd64p32.s
new file mode 100644
index 000000000..d47f12283
--- /dev/null
+++ b/src/pkg/runtime/asm_amd64p32.s
@@ -0,0 +1,1073 @@
+// 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 "zasm_GOOS_GOARCH.h"
+#include "funcdata.h"
+#include "../../cmd/ld/textflag.h"
+
+TEXT _rt0_go(SB),NOSPLIT,$0
+ // copy arguments forward on an even stack
+ MOVL argc+0(FP), AX
+ MOVL argv+4(FP), BX
+ MOVL SP, CX
+ SUBL $128, SP // plenty of scratch
+ ANDL $~15, CX
+ MOVL CX, SP
+
+ MOVL AX, 16(SP)
+ MOVL BX, 24(SP)
+
+ // create istack out of the given (operating system) stack.
+ MOVL $runtime·g0(SB), DI
+ LEAL (-64*1024+104)(SP), DI
+ MOVL BX, g_stackguard(DI)
+ MOVL BX, g_stackguard0(DI)
+ MOVL SP, g_stackbase(DI)
+
+ // find out information about the processor we're on
+ MOVQ $0, AX
+ CPUID
+ CMPQ AX, $0
+ JE nocpuinfo
+ MOVQ $1, AX
+ CPUID
+ MOVL CX, runtime·cpuid_ecx(SB)
+ MOVL DX, runtime·cpuid_edx(SB)
+nocpuinfo:
+
+needtls:
+ LEAL runtime·tls0(SB), DI
+ CALL runtime·settls(SB)
+
+ // store through it, to make sure it works
+ get_tls(BX)
+ MOVQ $0x123, g(BX)
+ MOVQ runtime·tls0(SB), AX
+ CMPQ AX, $0x123
+ JEQ 2(PC)
+ MOVL AX, 0 // abort
+ok:
+ // set the per-goroutine and per-mach "registers"
+ get_tls(BX)
+ LEAL runtime·g0(SB), CX
+ MOVL CX, g(BX)
+ LEAL runtime·m0(SB), AX
+ MOVL AX, m(BX)
+
+ // save m->g0 = g0
+ MOVL CX, m_g0(AX)
+
+ CLD // convention is D is always left cleared
+ CALL runtime·check(SB)
+
+ MOVL 16(SP), AX // copy argc
+ MOVL AX, 0(SP)
+ MOVL 24(SP), AX // copy argv
+ MOVL AX, 4(SP)
+ CALL runtime·args(SB)
+ CALL runtime·osinit(SB)
+ CALL runtime·hashinit(SB)
+ CALL runtime·schedinit(SB)
+
+ // create a new goroutine to start program
+ MOVL $runtime·main·f(SB), AX // entry
+ MOVL $0, 0(SP)
+ MOVL AX, 4(SP)
+ ARGSIZE(8)
+ CALL runtime·newproc(SB)
+ ARGSIZE(-1)
+
+ // start this M
+ CALL runtime·mstart(SB)
+
+ MOVL $0xf1, 0xf1 // crash
+ RET
+
+DATA runtime·main·f+0(SB)/4,$runtime·main(SB)
+GLOBL runtime·main·f(SB),RODATA,$4
+
+TEXT runtime·breakpoint(SB),NOSPLIT,$0-0
+ INT $3
+ RET
+
+TEXT runtime·asminit(SB),NOSPLIT,$0-0
+ // No per-thread init.
+ RET
+
+/*
+ * go-routine
+ */
+
+// void gosave(Gobuf*)
+// save state in Gobuf; setjmp
+TEXT runtime·gosave(SB), NOSPLIT, $0-4
+ MOVL b+0(FP), AX // gobuf
+ LEAL b+0(FP), BX // caller's SP
+ MOVL BX, gobuf_sp(AX)
+ MOVL 0(SP), BX // caller's PC
+ MOVL BX, gobuf_pc(AX)
+ MOVL $0, gobuf_ctxt(AX)
+ MOVQ $0, gobuf_ret(AX)
+ get_tls(CX)
+ MOVL g(CX), BX
+ MOVL BX, gobuf_g(AX)
+ RET
+
+// void gogo(Gobuf*)
+// restore state from Gobuf; longjmp
+TEXT runtime·gogo(SB), NOSPLIT, $0-4
+ MOVL b+0(FP), BX // gobuf
+ MOVL gobuf_g(BX), DX
+ MOVL 0(DX), CX // make sure g != nil
+ get_tls(CX)
+ MOVL DX, g(CX)
+ MOVL gobuf_sp(BX), SP // restore SP
+ MOVL gobuf_ctxt(BX), DX
+ MOVQ gobuf_ret(BX), AX
+ MOVL $0, gobuf_sp(BX) // clear to help garbage collector
+ MOVQ $0, gobuf_ret(BX)
+ MOVL $0, gobuf_ctxt(BX)
+ MOVL gobuf_pc(BX), BX
+ JMP BX
+
+// void mcall(void (*fn)(G*))
+// Switch to m->g0's stack, call fn(g).
+// Fn must never return. It should gogo(&g->sched)
+// to keep running g.
+TEXT runtime·mcall(SB), NOSPLIT, $0-4
+ MOVL fn+0(FP), DI
+
+ get_tls(CX)
+ MOVL g(CX), AX // save state in g->sched
+ MOVL 0(SP), BX // caller's PC
+ MOVL BX, (g_sched+gobuf_pc)(AX)
+ LEAL fn+0(FP), BX // caller's SP
+ MOVL BX, (g_sched+gobuf_sp)(AX)
+ MOVL AX, (g_sched+gobuf_g)(AX)
+
+ // switch to m->g0 & its stack, call fn
+ MOVL m(CX), BX
+ MOVL m_g0(BX), SI
+ CMPL SI, AX // if g == m->g0 call badmcall
+ JNE 3(PC)
+ MOVL $runtime·badmcall(SB), AX
+ JMP AX
+ MOVL SI, g(CX) // g = m->g0
+ MOVL (g_sched+gobuf_sp)(SI), SP // sp = m->g0->sched.sp
+ PUSHQ AX
+ ARGSIZE(8)
+ CALL DI
+ POPQ AX
+ MOVL $runtime·badmcall2(SB), AX
+ JMP AX
+ RET
+
+/*
+ * support for morestack
+ */
+
+// Called during function prolog when more stack is needed.
+// Caller has already done get_tls(CX); MOVQ m(CX), BX.
+//
+// The traceback routines see morestack on a g0 as being
+// the top of a stack (for example, morestack calling newstack
+// calling the scheduler calling newm calling gc), so we must
+// record an argument size. For that purpose, it has no arguments.
+TEXT runtime·morestack(SB),NOSPLIT,$0-0
+ // Cannot grow scheduler stack (m->g0).
+ MOVL m_g0(BX), SI
+ CMPL g(CX), SI
+ JNE 2(PC)
+ MOVL 0, AX
+
+ // Called from f.
+ // Set m->morebuf to f's caller.
+ MOVL 8(SP), AX // f's caller's PC
+ MOVL AX, (m_morebuf+gobuf_pc)(BX)
+ LEAL 16(SP), AX // f's caller's SP
+ MOVL AX, (m_morebuf+gobuf_sp)(BX)
+ MOVL AX, m_moreargp(BX)
+ get_tls(CX)
+ MOVL g(CX), SI
+ MOVL SI, (m_morebuf+gobuf_g)(BX)
+
+ // Set g->sched to context in f.
+ MOVL 0(SP), AX // f's PC
+ MOVL AX, (g_sched+gobuf_pc)(SI)
+ MOVL SI, (g_sched+gobuf_g)(SI)
+ LEAL 8(SP), AX // f's SP
+ MOVL AX, (g_sched+gobuf_sp)(SI)
+ MOVL DX, (g_sched+gobuf_ctxt)(SI)
+
+ // Call newstack on m->g0's stack.
+ MOVL m_g0(BX), BX
+ MOVL BX, g(CX)
+ MOVL (g_sched+gobuf_sp)(BX), SP
+ CALL runtime·newstack(SB)
+ MOVL $0, 0x1003 // crash if newstack returns
+ RET
+
+// Called from panic. Mimics morestack,
+// reuses stack growth code to create a frame
+// with the desired args running the desired function.
+//
+// func call(fn *byte, arg *byte, argsize uint32).
+TEXT runtime·newstackcall(SB), NOSPLIT, $0-20
+ get_tls(CX)
+ MOVL m(CX), BX
+
+ // Save our caller's state as the PC and SP to
+ // restore when returning from f.
+ MOVL 0(SP), AX // our caller's PC
+ MOVL AX, (m_morebuf+gobuf_pc)(BX)
+ LEAL 8(SP), AX // our caller's SP
+ MOVL AX, (m_morebuf+gobuf_sp)(BX)
+ MOVL g(CX), AX
+ MOVL AX, (m_morebuf+gobuf_g)(BX)
+
+ // Save our own state as the PC and SP to restore
+ // if this goroutine needs to be restarted.
+ MOVL $runtime·newstackcall(SB), DI
+ MOVL DI, (g_sched+gobuf_pc)(AX)
+ MOVL SP, (g_sched+gobuf_sp)(AX)
+
+ // Set up morestack arguments to call f on a new stack.
+ // We set f's frame size to 1, as a hint to newstack
+ // that this is a call from runtime·newstackcall.
+ // If it turns out that f needs a larger frame than
+ // the default stack, f's usual stack growth prolog will
+ // allocate a new segment (and recopy the arguments).
+ MOVL 8(SP), AX // fn
+ MOVL 12(SP), DX // arg frame
+ MOVL 16(SP), CX // arg size
+
+ MOVQ AX, m_cret(BX) // f's PC
+ MOVL DX, m_moreargp(BX) // argument frame pointer
+ MOVL CX, m_moreargsize(BX) // f's argument size
+ MOVL $1, m_moreframesize(BX) // f's frame size
+
+ // Call newstack on m->g0's stack.
+ MOVL m_g0(BX), BX
+ get_tls(CX)
+ MOVL BX, g(CX)
+ MOVL (g_sched+gobuf_sp)(BX), SP
+ CALL runtime·newstack(SB)
+ MOVL $0, 0x1103 // crash if newstack returns
+ RET
+
+// reflect·call: call a function with the given argument list
+// func call(f *FuncVal, arg *byte, argsize uint32).
+// we don't have variable-sized frames, so we use a small number
+// of constant-sized-frame functions to encode a few bits of size in the pc.
+// Caution: ugly multiline assembly macros in your future!
+
+#define DISPATCH(NAME,MAXSIZE) \
+ CMPL CX, $MAXSIZE; \
+ JA 3(PC); \
+ MOVL $runtime·NAME(SB), AX; \
+ JMP AX
+// Note: can't just "JMP runtime·NAME(SB)" - bad inlining results.
+
+TEXT reflect·call(SB), NOSPLIT, $0-20
+ MOVLQZX argsize+8(FP), CX
+ DISPATCH(call16, 16)
+ DISPATCH(call32, 32)
+ DISPATCH(call64, 64)
+ DISPATCH(call128, 128)
+ DISPATCH(call256, 256)
+ DISPATCH(call512, 512)
+ DISPATCH(call1024, 1024)
+ DISPATCH(call2048, 2048)
+ DISPATCH(call4096, 4096)
+ DISPATCH(call8192, 8192)
+ DISPATCH(call16384, 16384)
+ DISPATCH(call32768, 32768)
+ DISPATCH(call65536, 65536)
+ DISPATCH(call131072, 131072)
+ DISPATCH(call262144, 262144)
+ DISPATCH(call524288, 524288)
+ DISPATCH(call1048576, 1048576)
+ DISPATCH(call2097152, 2097152)
+ DISPATCH(call4194304, 4194304)
+ DISPATCH(call8388608, 8388608)
+ DISPATCH(call16777216, 16777216)
+ DISPATCH(call33554432, 33554432)
+ DISPATCH(call67108864, 67108864)
+ DISPATCH(call134217728, 134217728)
+ DISPATCH(call268435456, 268435456)
+ DISPATCH(call536870912, 536870912)
+ DISPATCH(call1073741824, 1073741824)
+ MOVL $runtime·badreflectcall(SB), AX
+ JMP AX
+
+#define CALLFN(NAME,MAXSIZE) \
+TEXT runtime·NAME(SB), WRAPPER, $MAXSIZE-16; \
+ /* copy arguments to stack */ \
+ MOVL argptr+4(FP), SI; \
+ MOVL argsize+8(FP), CX; \
+ MOVL SP, DI; \
+ REP;MOVSB; \
+ /* call function */ \
+ MOVL f+0(FP), DX; \
+ MOVL (DX), AX; \
+ CALL AX; \
+ /* copy return values back */ \
+ MOVL argptr+4(FP), DI; \
+ MOVL argsize+8(FP), CX; \
+ MOVL retoffset+12(FP), BX; \
+ MOVL SP, SI; \
+ ADDL BX, DI; \
+ ADDL BX, SI; \
+ SUBL BX, CX; \
+ REP;MOVSB; \
+ RET
+
+CALLFN(call16, 16)
+CALLFN(call32, 32)
+CALLFN(call64, 64)
+CALLFN(call128, 128)
+CALLFN(call256, 256)
+CALLFN(call512, 512)
+CALLFN(call1024, 1024)
+CALLFN(call2048, 2048)
+CALLFN(call4096, 4096)
+CALLFN(call8192, 8192)
+CALLFN(call16384, 16384)
+CALLFN(call32768, 32768)
+CALLFN(call65536, 65536)
+CALLFN(call131072, 131072)
+CALLFN(call262144, 262144)
+CALLFN(call524288, 524288)
+CALLFN(call1048576, 1048576)
+CALLFN(call2097152, 2097152)
+CALLFN(call4194304, 4194304)
+CALLFN(call8388608, 8388608)
+CALLFN(call16777216, 16777216)
+CALLFN(call33554432, 33554432)
+CALLFN(call67108864, 67108864)
+CALLFN(call134217728, 134217728)
+CALLFN(call268435456, 268435456)
+CALLFN(call536870912, 536870912)
+CALLFN(call1073741824, 1073741824)
+
+// Return point when leaving stack.
+//
+// Lessstack can appear in stack traces for the same reason
+// as morestack; in that context, it has 0 arguments.
+TEXT runtime·lessstack(SB), NOSPLIT, $0-0
+ // Save return value in m->cret
+ get_tls(CX)
+ MOVL m(CX), BX
+ MOVQ AX, m_cret(BX) // MOVQ, to save all 64 bits
+
+ // Call oldstack on m->g0's stack.
+ MOVL m_g0(BX), BX
+ MOVL BX, g(CX)
+ MOVL (g_sched+gobuf_sp)(BX), SP
+ CALL runtime·oldstack(SB)
+ MOVL $0, 0x1004 // crash if oldstack returns
+ RET
+
+// morestack trampolines
+TEXT runtime·morestack00(SB),NOSPLIT,$0
+ get_tls(CX)
+ MOVL m(CX), BX
+ MOVQ $0, AX
+ MOVQ AX, m_moreframesize(BX)
+ MOVL $runtime·morestack(SB), AX
+ JMP AX
+
+TEXT runtime·morestack01(SB),NOSPLIT,$0
+ get_tls(CX)
+ MOVL m(CX), BX
+ SHLQ $32, AX
+ MOVQ AX, m_moreframesize(BX)
+ MOVL $runtime·morestack(SB), AX
+ JMP AX
+
+TEXT runtime·morestack10(SB),NOSPLIT,$0
+ get_tls(CX)
+ MOVL m(CX), BX
+ MOVLQZX AX, AX
+ MOVQ AX, m_moreframesize(BX)
+ MOVL $runtime·morestack(SB), AX
+ JMP AX
+
+TEXT runtime·morestack11(SB),NOSPLIT,$0
+ get_tls(CX)
+ MOVL m(CX), BX
+ MOVQ AX, m_moreframesize(BX)
+ MOVL $runtime·morestack(SB), AX
+ JMP AX
+
+// subcases of morestack01
+// with const of 8,16,...48
+TEXT runtime·morestack8(SB),NOSPLIT,$0
+ MOVQ $1, R8
+ MOVL $morestack<>(SB), AX
+ JMP AX
+
+TEXT runtime·morestack16(SB),NOSPLIT,$0
+ MOVQ $2, R8
+ MOVL $morestack<>(SB), AX
+ JMP AX
+
+TEXT runtime·morestack24(SB),NOSPLIT,$0
+ MOVQ $3, R8
+ MOVL $morestack<>(SB), AX
+ JMP AX
+
+TEXT runtime·morestack32(SB),NOSPLIT,$0
+ MOVQ $4, R8
+ MOVL $morestack<>(SB), AX
+ JMP AX
+
+TEXT runtime·morestack40(SB),NOSPLIT,$0
+ MOVQ $5, R8
+ MOVL $morestack<>(SB), AX
+ JMP AX
+
+TEXT runtime·morestack48(SB),NOSPLIT,$0
+ MOVQ $6, R8
+ MOVL $morestack<>(SB), AX
+ JMP AX
+
+TEXT morestack<>(SB),NOSPLIT,$0
+ get_tls(CX)
+ MOVL m(CX), BX
+ SHLQ $35, R8
+ MOVQ R8, m_moreframesize(BX)
+ MOVL $runtime·morestack(SB), AX
+ JMP AX
+
+TEXT runtime·morestack00_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack00(SB)
+
+TEXT runtime·morestack01_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack01(SB)
+
+TEXT runtime·morestack10_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack10(SB)
+
+TEXT runtime·morestack11_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack11(SB)
+
+TEXT runtime·morestack8_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack8(SB)
+
+TEXT runtime·morestack16_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack16(SB)
+
+TEXT runtime·morestack24_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack24(SB)
+
+TEXT runtime·morestack32_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack32(SB)
+
+TEXT runtime·morestack40_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack40(SB)
+
+TEXT runtime·morestack48_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack48(SB)
+
+// bool cas(int32 *val, int32 old, int32 new)
+// Atomically:
+// if(*val == old){
+// *val = new;
+// return 1;
+// } else
+// return 0;
+TEXT runtime·cas(SB), NOSPLIT, $0-12
+ MOVL val+0(FP), BX
+ MOVL old+4(FP), AX
+ MOVL new+8(FP), CX
+ LOCK
+ CMPXCHGL CX, 0(BX)
+ JZ 3(PC)
+ MOVL $0, AX
+ RET
+ MOVL $1, AX
+ RET
+
+// bool runtime·cas64(uint64 *val, uint64 old, uint64 new)
+// Atomically:
+// if(*val == *old){
+// *val = new;
+// return 1;
+// } else {
+// return 0;
+// }
+TEXT runtime·cas64(SB), NOSPLIT, $0-24
+ MOVL val+0(FP), BX
+ MOVQ old+8(FP), AX
+ MOVQ new+16(FP), CX
+ LOCK
+ CMPXCHGQ CX, 0(BX)
+ JNZ cas64_fail
+ MOVL $1, AX
+ RET
+cas64_fail:
+ MOVL $0, AX
+ RET
+
+// bool casp(void **val, void *old, void *new)
+// Atomically:
+// if(*val == old){
+// *val = new;
+// return 1;
+// } else
+// return 0;
+TEXT runtime·casp(SB), NOSPLIT, $0-12
+ MOVL val+0(FP), BX
+ MOVL old+4(FP), AX
+ MOVL new+8(FP), CX
+ LOCK
+ CMPXCHGL CX, 0(BX)
+ JZ 3(PC)
+ MOVL $0, AX
+ RET
+ MOVL $1, AX
+ RET
+
+// uint32 xadd(uint32 volatile *val, int32 delta)
+// Atomically:
+// *val += delta;
+// return *val;
+TEXT runtime·xadd(SB), NOSPLIT, $0-8
+ MOVL val+0(FP), BX
+ MOVL delta+4(FP), AX
+ MOVL AX, CX
+ LOCK
+ XADDL AX, 0(BX)
+ ADDL CX, AX
+ RET
+
+TEXT runtime·xadd64(SB), NOSPLIT, $0-16
+ MOVL val+0(FP), BX
+ MOVQ delta+8(FP), AX
+ MOVQ AX, CX
+ LOCK
+ XADDQ AX, 0(BX)
+ ADDQ CX, AX
+ RET
+
+TEXT runtime·xchg(SB), NOSPLIT, $0-8
+ MOVL val+0(FP), BX
+ MOVL new+4(FP), AX
+ XCHGL AX, 0(BX)
+ RET
+
+TEXT runtime·xchg64(SB), NOSPLIT, $0-16
+ MOVL val+0(FP), BX
+ MOVQ new+8(FP), AX
+ XCHGQ AX, 0(BX)
+ RET
+
+TEXT runtime·procyield(SB),NOSPLIT,$0-0
+ MOVL val+0(FP), AX
+again:
+ PAUSE
+ SUBL $1, AX
+ JNZ again
+ RET
+
+TEXT runtime·atomicstorep(SB), NOSPLIT, $0-8
+ MOVL ptr+0(FP), BX
+ MOVL val+4(FP), AX
+ XCHGL AX, 0(BX)
+ RET
+
+TEXT runtime·atomicstore(SB), NOSPLIT, $0-8
+ MOVL ptr+0(FP), BX
+ MOVL val+4(FP), AX
+ XCHGL AX, 0(BX)
+ RET
+
+TEXT runtime·atomicstore64(SB), NOSPLIT, $0-16
+ MOVL ptr+0(FP), BX
+ MOVQ val+8(FP), AX
+ XCHGQ AX, 0(BX)
+ RET
+
+// void jmpdefer(fn, sp);
+// called from deferreturn.
+// 1. pop the caller
+// 2. sub 5 bytes from the callers return
+// 3. jmp to the argument
+TEXT runtime·jmpdefer(SB), NOSPLIT, $0-16
+ MOVL fn+0(FP), DX
+ MOVL callersp+4(FP), BX
+ LEAL -8(BX), SP // caller sp after CALL
+ SUBL $5, (SP) // return to CALL again
+ MOVL 0(DX), BX
+ JMP BX // but first run the deferred function
+
+// asmcgocall(void(*fn)(void*), void *arg)
+// Not implemented.
+TEXT runtime·asmcgocall(SB),NOSPLIT,$0-8
+ MOVL 0, AX
+ RET
+
+// cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
+// Not implemented.
+TEXT runtime·cgocallback(SB),NOSPLIT,$0-12
+ MOVL 0, AX
+ RET
+
+// void setmg(M*, G*); set m and g. for use by needm.
+// Not implemented.
+TEXT runtime·setmg(SB), NOSPLIT, $0-8
+ MOVL 0, AX
+ RET
+
+// check that SP is in range [g->stackbase, g->stackguard)
+TEXT runtime·stackcheck(SB), NOSPLIT, $0-0
+ get_tls(CX)
+ MOVL g(CX), AX
+ CMPL g_stackbase(AX), SP
+ JHI 2(PC)
+ MOVL 0, AX
+ CMPL SP, g_stackguard(AX)
+ JHI 2(PC)
+ MOVL 0, AX
+ RET
+
+TEXT runtime·memclr(SB),NOSPLIT,$0-8
+ MOVL addr+0(FP), DI
+ MOVL count+4(FP), CX
+ MOVQ CX, BX
+ ANDQ $7, BX
+ SHRQ $3, CX
+ MOVQ $0, AX
+ CLD
+ REP
+ STOSQ
+ MOVQ BX, CX
+ REP
+ STOSB
+ RET
+
+TEXT runtime·getcallerpc(SB),NOSPLIT,$0-8
+ MOVL x+0(FP),AX // addr of first arg
+ MOVL -8(AX),AX // get calling pc
+ RET
+
+TEXT runtime·setcallerpc(SB),NOSPLIT,$0-16
+ MOVL x+0(FP),AX // addr of first arg
+ MOVL pc+4(FP), BX // pc to set
+ MOVQ BX, -8(AX) // set calling pc
+ RET
+
+TEXT runtime·getcallersp(SB),NOSPLIT,$0-8
+ MOVL sp+0(FP), AX
+ RET
+
+// int64 runtime·cputicks(void)
+TEXT runtime·cputicks(SB),NOSPLIT,$0-0
+ RDTSC
+ SHLQ $32, DX
+ ADDQ DX, AX
+ RET
+
+TEXT runtime·stackguard(SB),NOSPLIT,$0-16
+ MOVL SP, DX
+ MOVL DX, sp+0(FP)
+ get_tls(CX)
+ MOVL g(CX), BX
+ MOVL g_stackguard(BX), DX
+ MOVL DX, limit+4(FP)
+ RET
+
+GLOBL runtime·tls0(SB), $64
+
+// hash function using AES hardware instructions
+// For now, our one amd64p32 system (NaCl) does not
+// support using AES instructions, so have not bothered to
+// write the implementations. Can copy and adjust the ones
+// in asm_amd64.s when the time comes.
+
+TEXT runtime·aeshash(SB),NOSPLIT,$0-24
+ RET
+
+TEXT runtime·aeshashstr(SB),NOSPLIT,$0-24
+ RET
+
+TEXT runtime·aeshash32(SB),NOSPLIT,$0-24
+ RET
+
+TEXT runtime·aeshash64(SB),NOSPLIT,$0-24
+ RET
+
+TEXT runtime·memeq(SB),NOSPLIT,$0-12
+ MOVL a+0(FP), SI
+ MOVL b+4(FP), DI
+ MOVL count+8(FP), BX
+ JMP runtime·memeqbody(SB)
+
+// a in SI
+// b in DI
+// count in BX
+TEXT runtime·memeqbody(SB),NOSPLIT,$0-0
+ XORQ AX, AX
+
+ CMPQ BX, $8
+ JB small
+
+ // 64 bytes at a time using xmm registers
+hugeloop:
+ CMPQ BX, $64
+ JB bigloop
+ MOVOU (SI), X0
+ MOVOU (DI), X1
+ MOVOU 16(SI), X2
+ MOVOU 16(DI), X3
+ MOVOU 32(SI), X4
+ MOVOU 32(DI), X5
+ MOVOU 48(SI), X6
+ MOVOU 48(DI), X7
+ PCMPEQB X1, X0
+ PCMPEQB X3, X2
+ PCMPEQB X5, X4
+ PCMPEQB X7, X6
+ PAND X2, X0
+ PAND X6, X4
+ PAND X4, X0
+ PMOVMSKB X0, DX
+ ADDQ $64, SI
+ ADDQ $64, DI
+ SUBQ $64, BX
+ CMPL DX, $0xffff
+ JEQ hugeloop
+ RET
+
+ // 8 bytes at a time using 64-bit register
+bigloop:
+ CMPQ BX, $8
+ JBE leftover
+ MOVQ (SI), CX
+ MOVQ (DI), DX
+ ADDQ $8, SI
+ ADDQ $8, DI
+ SUBQ $8, BX
+ CMPQ CX, DX
+ JEQ bigloop
+ RET
+
+ // remaining 0-8 bytes
+leftover:
+ ADDQ BX, SI
+ ADDQ BX, DI
+ MOVQ -8(SI), CX
+ MOVQ -8(DI), DX
+ CMPQ CX, DX
+ SETEQ AX
+ RET
+
+small:
+ CMPQ BX, $0
+ JEQ equal
+
+ LEAQ 0(BX*8), CX
+ NEGQ CX
+
+ CMPB SI, $0xf8
+ JA si_high
+
+ // load at SI won't cross a page boundary.
+ MOVQ (SI), SI
+ JMP si_finish
+si_high:
+ // address ends in 11111xxx. Load up to bytes we want, move to correct position.
+ MOVQ BX, DX
+ ADDQ SI, DX
+ MOVQ -8(DX), SI
+ SHRQ CX, SI
+si_finish:
+
+ // same for DI.
+ CMPB DI, $0xf8
+ JA di_high
+ MOVQ (DI), DI
+ JMP di_finish
+di_high:
+ MOVQ BX, DX
+ ADDQ DI, DX
+ MOVQ -8(DX), DI
+ SHRQ CX, DI
+di_finish:
+
+ SUBQ SI, DI
+ SHLQ CX, DI
+equal:
+ SETEQ AX
+ RET
+
+TEXT runtime·cmpstring(SB),NOSPLIT,$0-20
+ MOVL s1+0(FP), SI
+ MOVL s1+4(FP), BX
+ MOVL s2+8(FP), DI
+ MOVL s2+12(FP), DX
+ CALL runtime·cmpbody(SB)
+ MOVL AX, res+16(FP)
+ RET
+
+TEXT bytes·Compare(SB),NOSPLIT,$0-28
+ MOVL s1+0(FP), SI
+ MOVL s1+4(FP), BX
+ MOVL s2+12(FP), DI
+ MOVL s2+16(FP), DX
+ CALL runtime·cmpbody(SB)
+ MOVQ AX, res+24(FP)
+ RET
+
+// input:
+// SI = a
+// DI = b
+// BX = alen
+// DX = blen
+// output:
+// AX = 1/0/-1
+TEXT runtime·cmpbody(SB),NOSPLIT,$0-0
+ CMPQ SI, DI
+ JEQ cmp_allsame
+ CMPQ BX, DX
+ MOVQ DX, R8
+ CMOVQLT BX, R8 // R8 = min(alen, blen) = # of bytes to compare
+ CMPQ R8, $8
+ JB cmp_small
+
+cmp_loop:
+ CMPQ R8, $16
+ JBE cmp_0through16
+ MOVOU (SI), X0
+ MOVOU (DI), X1
+ PCMPEQB X0, X1
+ PMOVMSKB X1, AX
+ XORQ $0xffff, AX // convert EQ to NE
+ JNE cmp_diff16 // branch if at least one byte is not equal
+ ADDQ $16, SI
+ ADDQ $16, DI
+ SUBQ $16, R8
+ JMP cmp_loop
+
+ // AX = bit mask of differences
+cmp_diff16:
+ BSFQ AX, BX // index of first byte that differs
+ XORQ AX, AX
+ ADDQ BX, SI
+ MOVB (SI), CX
+ ADDQ BX, DI
+ CMPB CX, (DI)
+ SETHI AX
+ LEAQ -1(AX*2), AX // convert 1/0 to +1/-1
+ RET
+
+ // 0 through 16 bytes left, alen>=8, blen>=8
+cmp_0through16:
+ CMPQ R8, $8
+ JBE cmp_0through8
+ MOVQ (SI), AX
+ MOVQ (DI), CX
+ CMPQ AX, CX
+ JNE cmp_diff8
+cmp_0through8:
+ ADDQ R8, SI
+ ADDQ R8, DI
+ MOVQ -8(SI), AX
+ MOVQ -8(DI), CX
+ CMPQ AX, CX
+ JEQ cmp_allsame
+
+ // AX and CX contain parts of a and b that differ.
+cmp_diff8:
+ BSWAPQ AX // reverse order of bytes
+ BSWAPQ CX
+ XORQ AX, CX
+ BSRQ CX, CX // index of highest bit difference
+ SHRQ CX, AX // move a's bit to bottom
+ ANDQ $1, AX // mask bit
+ LEAQ -1(AX*2), AX // 1/0 => +1/-1
+ RET
+
+ // 0-7 bytes in common
+cmp_small:
+ LEAQ (R8*8), CX // bytes left -> bits left
+ NEGQ CX // - bits lift (== 64 - bits left mod 64)
+ JEQ cmp_allsame
+
+ // load bytes of a into high bytes of AX
+ CMPB SI, $0xf8
+ JA cmp_si_high
+ MOVQ (SI), SI
+ JMP cmp_si_finish
+cmp_si_high:
+ ADDQ R8, SI
+ MOVQ -8(SI), SI
+ SHRQ CX, SI
+cmp_si_finish:
+ SHLQ CX, SI
+
+ // load bytes of b in to high bytes of BX
+ CMPB DI, $0xf8
+ JA cmp_di_high
+ MOVQ (DI), DI
+ JMP cmp_di_finish
+cmp_di_high:
+ ADDQ R8, DI
+ MOVQ -8(DI), DI
+ SHRQ CX, DI
+cmp_di_finish:
+ SHLQ CX, DI
+
+ BSWAPQ SI // reverse order of bytes
+ BSWAPQ DI
+ XORQ SI, DI // find bit differences
+ JEQ cmp_allsame
+ BSRQ DI, CX // index of highest bit difference
+ SHRQ CX, SI // move a's bit to bottom
+ ANDQ $1, SI // mask bit
+ LEAQ -1(SI*2), AX // 1/0 => +1/-1
+ RET
+
+cmp_allsame:
+ XORQ AX, AX
+ XORQ CX, CX
+ CMPQ BX, DX
+ SETGT AX // 1 if alen > blen
+ SETEQ CX // 1 if alen == blen
+ LEAQ -1(CX)(AX*2), AX // 1,0,-1 result
+ RET
+
+TEXT bytes·IndexByte(SB),NOSPLIT,$0
+ MOVL s+0(FP), SI
+ MOVL s_len+4(FP), BX
+ MOVB c+12(FP), AL
+ CALL runtime·indexbytebody(SB)
+ MOVL AX, ret+16(FP)
+ RET
+
+TEXT strings·IndexByte(SB),NOSPLIT,$0
+ MOVL s+0(FP), SI
+ MOVL s_len+4(FP), BX
+ MOVB c+8(FP), AL
+ CALL runtime·indexbytebody(SB)
+ MOVL AX, ret+16(FP)
+ RET
+
+// input:
+// SI: data
+// BX: data len
+// AL: byte sought
+// output:
+// AX
+TEXT runtime·indexbytebody(SB),NOSPLIT,$0
+ MOVL SI, DI
+
+ CMPL BX, $16
+ JLT indexbyte_small
+
+ // round up to first 16-byte boundary
+ TESTL $15, SI
+ JZ aligned
+ MOVL SI, CX
+ ANDL $~15, CX
+ ADDL $16, CX
+
+ // search the beginning
+ SUBL SI, CX
+ REPN; SCASB
+ JZ success
+
+// DI is 16-byte aligned; get ready to search using SSE instructions
+aligned:
+ // round down to last 16-byte boundary
+ MOVL BX, R11
+ ADDL SI, R11
+ ANDL $~15, R11
+
+ // shuffle X0 around so that each byte contains c
+ MOVD AX, X0
+ PUNPCKLBW X0, X0
+ PUNPCKLBW X0, X0
+ PSHUFL $0, X0, X0
+ JMP condition
+
+sse:
+ // move the next 16-byte chunk of the buffer into X1
+ MOVO (DI), X1
+ // compare bytes in X0 to X1
+ PCMPEQB X0, X1
+ // take the top bit of each byte in X1 and put the result in DX
+ PMOVMSKB X1, DX
+ TESTL DX, DX
+ JNZ ssesuccess
+ ADDL $16, DI
+
+condition:
+ CMPL DI, R11
+ JLT sse
+
+ // search the end
+ MOVL SI, CX
+ ADDL BX, CX
+ SUBL R11, CX
+ // if CX == 0, the zero flag will be set and we'll end up
+ // returning a false success
+ JZ failure
+ REPN; SCASB
+ JZ success
+
+failure:
+ MOVL $-1, AX
+ RET
+
+// handle for lengths < 16
+indexbyte_small:
+ MOVL BX, CX
+ REPN; SCASB
+ JZ success
+ MOVL $-1, AX
+ RET
+
+// we've found the chunk containing the byte
+// now just figure out which specific byte it is
+ssesuccess:
+ // get the index of the least significant set bit
+ BSFW DX, DX
+ SUBL SI, DI
+ ADDL DI, DX
+ MOVL DX, AX
+ RET
+
+success:
+ SUBL SI, DI
+ SUBL $1, DI
+ MOVL DI, AX
+ RET
+
+TEXT bytes·Equal(SB),NOSPLIT,$0-25
+ MOVL a_len+4(FP), BX
+ MOVL b_len+16(FP), CX
+ XORL AX, AX
+ CMPL BX, CX
+ JNE eqret
+ MOVL a+0(FP), SI
+ MOVL b+12(FP), DI
+ CALL runtime·memeqbody(SB)
+eqret:
+ MOVB AX, ret+24(FP)
+ RET
+
+TEXT runtime·timenow(SB), NOSPLIT, $0-0
+ JMP time·now(SB)
diff --git a/src/pkg/runtime/asm_arm.s b/src/pkg/runtime/asm_arm.s
index f483e6fc8..1aea9036a 100644
--- a/src/pkg/runtime/asm_arm.s
+++ b/src/pkg/runtime/asm_arm.s
@@ -89,11 +89,9 @@ TEXT runtime·breakpoint(SB),NOSPLIT,$0-0
WORD $0xe1200071 // BKPT 0x0001
RET
-GLOBL runtime·goarm(SB), $4
-
TEXT runtime·asminit(SB),NOSPLIT,$0-0
// disable runfast (flush-to-zero) mode of vfp if runtime.goarm > 5
- MOVW runtime·goarm(SB), R11
+ MOVB runtime·goarm(SB), R11
CMP $5, R11
BLE 4(PC)
WORD $0xeef1ba10 // vmrs r11, fpscr
@@ -215,6 +213,10 @@ TEXT runtime·morestack(SB),NOSPLIT,$-4-0
// is still in this function, and not the beginning of the next.
RET
+TEXT runtime·morestack_noctxt(SB),NOSPLIT,$-4-0
+ MOVW $0, R7
+ B runtime·morestack(SB)
+
// Called from panic. Mimics morestack,
// reuses stack growth code to create a frame
// with the desired args running the desired function.
@@ -267,7 +269,7 @@ TEXT runtime·newstackcall(SB), NOSPLIT, $-4-12
MOVW $runtime·NAME(SB), R1; \
B (R1)
-TEXT reflect·call(SB), NOSPLIT, $-4-12
+TEXT reflect·call(SB), NOSPLIT, $-4-16
MOVW argsize+8(FP), R0
DISPATCH(call16, 16)
DISPATCH(call32, 32)
@@ -299,8 +301,22 @@ TEXT reflect·call(SB), NOSPLIT, $-4-12
MOVW $runtime·badreflectcall(SB), R1
B (R1)
+// Argument map for the callXX frames. Each has one
+// stack map (for the single call) with 3 arguments.
+DATA gcargs_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap
+DATA gcargs_reflectcall<>+0x04(SB)/4, $6 // 3 args
+DATA gcargs_reflectcall<>+0x08(SB)/4, $(const_BitsPointer+(const_BitsPointer<<2)+(const_BitsScalar<<4))
+GLOBL gcargs_reflectcall<>(SB),RODATA,$12
+
+// callXX frames have no locals
+DATA gclocals_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap
+DATA gclocals_reflectcall<>+0x04(SB)/4, $0 // 0 locals
+GLOBL gclocals_reflectcall<>(SB),RODATA,$8
+
#define CALLFN(NAME,MAXSIZE) \
-TEXT runtime·NAME(SB), WRAPPER, $MAXSIZE-12; \
+TEXT runtime·NAME(SB), WRAPPER, $MAXSIZE-16; \
+ FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_reflectcall<>(SB); \
+ FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_reflectcall<>(SB);\
/* copy arguments to stack */ \
MOVW argptr+4(FP), R0; \
MOVW argsize+8(FP), R2; \
@@ -314,11 +330,16 @@ TEXT runtime·NAME(SB), WRAPPER, $MAXSIZE-12; \
/* call function */ \
MOVW f+0(FP), R7; \
MOVW (R7), R0; \
+ PCDATA $PCDATA_StackMapIndex, $0; \
BL (R0); \
/* copy return values back */ \
MOVW argptr+4(FP), R0; \
MOVW argsize+8(FP), R2; \
+ MOVW retoffset+12(FP), R3; \
ADD $4, SP, R1; \
+ ADD R3, R1; \
+ ADD R3, R0; \
+ SUB R3, R2; \
CMP $0, R2; \
RET.EQ ; \
MOVBU.P 1(R1), R5; \
@@ -373,6 +394,10 @@ TEXT runtime·lessstack(SB), NOSPLIT, $-4-0
// 1. grab stored LR for caller
// 2. sub 4 bytes to get back to BL deferreturn
// 3. B to fn
+// TODO(rsc): Push things on stack and then use pop
+// to load all registers simultaneously, so that a profiling
+// interrupt can never see mismatched SP/LR/PC.
+// (And double-check that pop is atomic in that way.)
TEXT runtime·jmpdefer(SB), NOSPLIT, $0-8
MOVW 0(SP), LR
MOVW $-4(LR), LR // BL deferreturn
@@ -629,17 +654,33 @@ _next:
// Note: all three functions will clobber R0, and the last
// two can be called from 5c ABI code.
-// g (R10) at 8(TP), m (R9) at 12(TP)
+// save_gm saves the g and m registers into pthread-provided
+// thread-local memory, so that we can call externally compiled
+// ARM code that will overwrite those registers.
+// NOTE: runtime.gogo assumes that R1 is preserved by this function.
TEXT runtime·save_gm(SB),NOSPLIT,$0
- MRC 15, 0, R0, C13, C0, 3 // Fetch TLS register
- MOVW g, 8(R0)
- MOVW m, 12(R0)
+ MRC 15, 0, R0, C13, C0, 3 // fetch TLS base pointer
+ // $runtime.tlsgm(SB) is a special linker symbol.
+ // It is the offset from the TLS base pointer to our
+ // thread-local storage for g and m.
+ MOVW $runtime·tlsgm(SB), R11
+ ADD R11, R0
+ MOVW g, 0(R0)
+ MOVW m, 4(R0)
RET
+// load_gm loads the g and m registers from pthread-provided
+// thread-local memory, for use after calling externally compiled
+// ARM code that overwrote those registers.
TEXT runtime·load_gm(SB),NOSPLIT,$0
- MRC 15, 0, R0, C13, C0, 3 // Fetch TLS register
- MOVW 8(R0), g
- MOVW 12(R0), m
+ MRC 15, 0, R0, C13, C0, 3 // fetch TLS base pointer
+ // $runtime.tlsgm(SB) is a special linker symbol.
+ // It is the offset from the TLS base pointer to our
+ // thread-local storage for g and m.
+ MOVW $runtime·tlsgm(SB), R11
+ ADD R11, R0
+ MOVW 0(R0), g
+ MOVW 4(R0), m
RET
// void setmg_gcc(M*, G*); set m and g called from gcc.
@@ -648,7 +689,6 @@ TEXT setmg_gcc<>(SB),NOSPLIT,$0
MOVW R1, g
B runtime·save_gm(SB)
-
// TODO: share code with memeq?
TEXT bytes·Equal(SB),NOSPLIT,$0
MOVW a_len+4(FP), R1
@@ -726,3 +766,414 @@ _sib_notfound:
MOVW $-1, R0
MOVW R0, ret+12(FP)
RET
+
+TEXT runtime·timenow(SB), NOSPLIT, $0-0
+ B time·now(SB)
+
+// A Duff's device for zeroing memory.
+// The compiler jumps to computed addresses within
+// this routine to zero chunks of memory. Do not
+// change this code without also changing the code
+// in ../../cmd/5g/ggen.c:clearfat.
+// R0: zero
+// R1: ptr to memory to be zeroed
+// R1 is updated as a side effect.
+TEXT runtime·duffzero(SB), NOSPLIT, $0-0
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ RET
+
+// A Duff's device for copying memory.
+// The compiler jumps to computed addresses within
+// this routine to copy chunks of memory. Source
+// and destination must not overlap. Do not
+// change this code without also changing the code
+// in ../../cmd/5g/cgen.c:sgen.
+// R0: scratch space
+// R1: ptr to source memory
+// R2: ptr to destination memory
+// R1 and R2 are updated as a side effect
+TEXT runtime·duffcopy(SB), NOSPLIT, $0-0
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ RET
diff --git a/src/pkg/runtime/atomic_amd64.c b/src/pkg/runtime/atomic_amd64x.c
index 0bd4d906b..11b578936 100644
--- a/src/pkg/runtime/atomic_amd64.c
+++ b/src/pkg/runtime/atomic_amd64x.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.
+// +build amd64 amd64p32
+
#include "runtime.h"
#include "../../cmd/ld/textflag.h"
diff --git a/src/pkg/runtime/atomic_arm.c b/src/pkg/runtime/atomic_arm.c
index b1e97b27d..d914475c7 100644
--- a/src/pkg/runtime/atomic_arm.c
+++ b/src/pkg/runtime/atomic_arm.c
@@ -42,6 +42,19 @@ runtime·xchg(uint32 volatile* addr, uint32 v)
}
#pragma textflag NOSPLIT
+void*
+runtime·xchgp(void* volatile* addr, void* v)
+{
+ void *old;
+
+ for(;;) {
+ old = *addr;
+ if(runtime·casp(addr, old, v))
+ return old;
+ }
+}
+
+#pragma textflag NOSPLIT
void
runtime·procyield(uint32 cnt)
{
diff --git a/src/pkg/runtime/callback_windows.c b/src/pkg/runtime/callback_windows.c
index 88ee53bb5..285678fba 100644
--- a/src/pkg/runtime/callback_windows.c
+++ b/src/pkg/runtime/callback_windows.c
@@ -49,7 +49,7 @@ runtime·compilecallback(Eface fn, bool cleanstack)
runtime·cbctxts = &(cbs.ctxt[0]);
n = cbs.n;
for(i=0; i<n; i++) {
- if(cbs.ctxt[i]->gobody == fn.data) {
+ if(cbs.ctxt[i]->gobody == fn.data && cbs.ctxt[i]->cleanstack == cleanstack) {
runtime·unlock(&cbs);
// runtime·callbackasm is just a series of CALL instructions
// (each is 5 bytes long), and we want callback to arrive at
@@ -63,6 +63,7 @@ runtime·compilecallback(Eface fn, bool cleanstack)
c = runtime·mal(sizeof *c);
c->gobody = fn.data;
c->argsize = argsize;
+ c->cleanstack = cleanstack;
if(cleanstack && argsize!=0)
c->restorestack = argsize;
else
diff --git a/src/pkg/runtime/cgo/asm_nacl_amd64p32.s b/src/pkg/runtime/cgo/asm_nacl_amd64p32.s
new file mode 100644
index 000000000..377cf72a3
--- /dev/null
+++ b/src/pkg/runtime/cgo/asm_nacl_amd64p32.s
@@ -0,0 +1,13 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "../../../cmd/ld/textflag.h"
+
+/*
+ * void crosscall2(void (*fn)(void*, int32), void*, int32)
+ * Save registers and call fn with two arguments.
+ */
+TEXT crosscall2(SB),NOSPLIT,$0
+ INT $3
+ RET
diff --git a/src/pkg/runtime/cgo/gcc_dragonfly_386.c b/src/pkg/runtime/cgo/gcc_dragonfly_386.c
index 6797824c6..695c16634 100644
--- a/src/pkg/runtime/cgo/gcc_dragonfly_386.c
+++ b/src/pkg/runtime/cgo/gcc_dragonfly_386.c
@@ -36,14 +36,14 @@ _cgo_sys_thread_start(ThreadStart *ts)
int err;
SIGFILLSET(ign);
- sigprocmask(SIG_SETMASK, &ign, &oset);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
- sigprocmask(SIG_SETMASK, &oset, nil);
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_dragonfly_amd64.c b/src/pkg/runtime/cgo/gcc_dragonfly_amd64.c
index eb342a2ff..a46c121ad 100644
--- a/src/pkg/runtime/cgo/gcc_dragonfly_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_dragonfly_amd64.c
@@ -35,7 +35,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
int err;
SIGFILLSET(ign);
- sigprocmask(SIG_SETMASK, &ign, &oset);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
@@ -43,7 +43,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
- sigprocmask(SIG_SETMASK, &oset, nil);
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_freebsd_386.c b/src/pkg/runtime/cgo/gcc_freebsd_386.c
index 6797824c6..695c16634 100644
--- a/src/pkg/runtime/cgo/gcc_freebsd_386.c
+++ b/src/pkg/runtime/cgo/gcc_freebsd_386.c
@@ -36,14 +36,14 @@ _cgo_sys_thread_start(ThreadStart *ts)
int err;
SIGFILLSET(ign);
- sigprocmask(SIG_SETMASK, &ign, &oset);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
- sigprocmask(SIG_SETMASK, &oset, nil);
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_freebsd_amd64.c b/src/pkg/runtime/cgo/gcc_freebsd_amd64.c
index eb342a2ff..a46c121ad 100644
--- a/src/pkg/runtime/cgo/gcc_freebsd_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_freebsd_amd64.c
@@ -35,7 +35,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
int err;
SIGFILLSET(ign);
- sigprocmask(SIG_SETMASK, &ign, &oset);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
@@ -43,7 +43,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
- sigprocmask(SIG_SETMASK, &oset, nil);
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_freebsd_arm.c b/src/pkg/runtime/cgo/gcc_freebsd_arm.c
index 211dca75c..6175e1d9c 100644
--- a/src/pkg/runtime/cgo/gcc_freebsd_arm.c
+++ b/src/pkg/runtime/cgo/gcc_freebsd_arm.c
@@ -4,7 +4,9 @@
#include <sys/types.h>
#include <machine/sysarch.h>
+#include <sys/signalvar.h>
#include <pthread.h>
+#include <signal.h>
#include <string.h>
#include "libcgo.h"
@@ -39,10 +41,14 @@ void
_cgo_sys_thread_start(ThreadStart *ts)
{
pthread_attr_t attr;
+ sigset_t ign, oset;
pthread_t p;
size_t size;
int err;
+ SIGFILLSET(ign);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
+
// Not sure why the memset is necessary here,
// but without it, we get a bogus stack size
// out of pthread_attr_getstacksize. C'est la Linux.
@@ -52,6 +58,9 @@ _cgo_sys_thread_start(ThreadStart *ts)
pthread_attr_getstacksize(&attr, &size);
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
+
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
+
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
abort();
diff --git a/src/pkg/runtime/cgo/gcc_linux_386.c b/src/pkg/runtime/cgo/gcc_linux_386.c
index c25c7b70f..0a46c9b7a 100644
--- a/src/pkg/runtime/cgo/gcc_linux_386.c
+++ b/src/pkg/runtime/cgo/gcc_linux_386.c
@@ -34,7 +34,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
int err;
sigfillset(&ign);
- sigprocmask(SIG_SETMASK, &ign, &oset);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
// Not sure why the memset is necessary here,
// but without it, we get a bogus stack size
@@ -46,7 +46,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
- sigprocmask(SIG_SETMASK, &oset, nil);
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_linux_amd64.c b/src/pkg/runtime/cgo/gcc_linux_amd64.c
index bd7c88d99..c530183b7 100644
--- a/src/pkg/runtime/cgo/gcc_linux_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_linux_amd64.c
@@ -34,14 +34,14 @@ _cgo_sys_thread_start(ThreadStart *ts)
int err;
sigfillset(&ign);
- sigprocmask(SIG_SETMASK, &ign, &oset);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
- sigprocmask(SIG_SETMASK, &oset, nil);
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_linux_arm.c b/src/pkg/runtime/cgo/gcc_linux_arm.c
index 9a6e58594..032568155 100644
--- a/src/pkg/runtime/cgo/gcc_linux_arm.c
+++ b/src/pkg/runtime/cgo/gcc_linux_arm.c
@@ -4,6 +4,7 @@
#include <pthread.h>
#include <string.h>
+#include <signal.h>
#include "libcgo.h"
static void *threadentry(void*);
@@ -28,10 +29,14 @@ void
_cgo_sys_thread_start(ThreadStart *ts)
{
pthread_attr_t attr;
+ sigset_t ign, oset;
pthread_t p;
size_t size;
int err;
+ sigfillset(&ign);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
+
// Not sure why the memset is necessary here,
// but without it, we get a bogus stack size
// out of pthread_attr_getstacksize. C'est la Linux.
@@ -41,6 +46,9 @@ _cgo_sys_thread_start(ThreadStart *ts)
pthread_attr_getstacksize(&attr, &size);
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
+
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
+
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
abort();
diff --git a/src/pkg/runtime/cgo/gcc_netbsd_386.c b/src/pkg/runtime/cgo/gcc_netbsd_386.c
index b399e16dc..28690ccbd 100644
--- a/src/pkg/runtime/cgo/gcc_netbsd_386.c
+++ b/src/pkg/runtime/cgo/gcc_netbsd_386.c
@@ -35,14 +35,14 @@ _cgo_sys_thread_start(ThreadStart *ts)
int err;
sigfillset(&ign);
- sigprocmask(SIG_SETMASK, &ign, &oset);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
- sigprocmask(SIG_SETMASK, &oset, nil);
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_netbsd_amd64.c b/src/pkg/runtime/cgo/gcc_netbsd_amd64.c
index f27e142ce..6e0482d5b 100644
--- a/src/pkg/runtime/cgo/gcc_netbsd_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_netbsd_amd64.c
@@ -35,7 +35,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
int err;
sigfillset(&ign);
- sigprocmask(SIG_SETMASK, &ign, &oset);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
@@ -43,7 +43,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
- sigprocmask(SIG_SETMASK, &oset, nil);
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_netbsd_arm.c b/src/pkg/runtime/cgo/gcc_netbsd_arm.c
index 68c8b6e71..ba2ae2568 100644
--- a/src/pkg/runtime/cgo/gcc_netbsd_arm.c
+++ b/src/pkg/runtime/cgo/gcc_netbsd_arm.c
@@ -36,14 +36,14 @@ _cgo_sys_thread_start(ThreadStart *ts)
int err;
sigfillset(&ign);
- sigprocmask(SIG_SETMASK, &ign, &oset);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
- sigprocmask(SIG_SETMASK, &oset, nil);
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_openbsd_386.c b/src/pkg/runtime/cgo/gcc_openbsd_386.c
index 6422d1b93..e682c3725 100644
--- a/src/pkg/runtime/cgo/gcc_openbsd_386.c
+++ b/src/pkg/runtime/cgo/gcc_openbsd_386.c
@@ -122,14 +122,14 @@ _cgo_sys_thread_start(ThreadStart *ts)
int err;
sigfillset(&ign);
- sigprocmask(SIG_SETMASK, &ign, &oset);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
ts->g->stackguard = size;
err = sys_pthread_create(&p, &attr, threadentry, ts);
- sigprocmask(SIG_SETMASK, &oset, nil);
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_openbsd_amd64.c b/src/pkg/runtime/cgo/gcc_openbsd_amd64.c
index 5a5a17114..64d29a935 100644
--- a/src/pkg/runtime/cgo/gcc_openbsd_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_openbsd_amd64.c
@@ -122,7 +122,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
int err;
sigfillset(&ign);
- sigprocmask(SIG_SETMASK, &ign, &oset);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
@@ -130,7 +130,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
ts->g->stackguard = size;
err = sys_pthread_create(&p, &attr, threadentry, ts);
- sigprocmask(SIG_SETMASK, &oset, nil);
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_windows_386.c b/src/pkg/runtime/cgo/gcc_windows_386.c
index 02eab12e5..cdc866468 100644
--- a/src/pkg/runtime/cgo/gcc_windows_386.c
+++ b/src/pkg/runtime/cgo/gcc_windows_386.c
@@ -5,6 +5,8 @@
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <process.h>
+#include <stdlib.h>
+#include <stdio.h>
#include "libcgo.h"
static void threadentry(void*);
@@ -25,14 +27,19 @@ x_cgo_init(G *g)
void
_cgo_sys_thread_start(ThreadStart *ts)
{
- _beginthread(threadentry, 0, ts);
+ uintptr_t thandle;
+
+ thandle = _beginthread(threadentry, 0, ts);
+ if(thandle == -1) {
+ fprintf(stderr, "runtime: failed to create new OS thread (%d)\n", errno);
+ abort();
+ }
}
static void
threadentry(void *v)
{
ThreadStart ts;
- void *tls0;
ts = *(ThreadStart*)v;
free(v);
@@ -43,16 +50,13 @@ threadentry(void *v)
/*
* Set specific keys in thread local storage.
*/
- tls0 = (void*)LocalAlloc(LPTR, 32);
asm volatile (
"movl %0, %%fs:0x14\n" // MOVL tls0, 0x14(FS)
"movl %%fs:0x14, %%eax\n" // MOVL 0x14(FS), tmp
"movl %1, 0(%%eax)\n" // MOVL g, 0(FS)
"movl %2, 4(%%eax)\n" // MOVL m, 4(FS)
- :: "r"(tls0), "r"(ts.g), "r"(ts.m) : "%eax"
+ :: "r"(ts.tls), "r"(ts.g), "r"(ts.m) : "%eax"
);
crosscall_386(ts.fn);
-
- LocalFree(tls0);
}
diff --git a/src/pkg/runtime/cgo/gcc_windows_amd64.c b/src/pkg/runtime/cgo/gcc_windows_amd64.c
index f7695a1cc..d8dd69b4a 100644
--- a/src/pkg/runtime/cgo/gcc_windows_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_windows_amd64.c
@@ -5,6 +5,8 @@
#define WIN64_LEAN_AND_MEAN
#include <windows.h>
#include <process.h>
+#include <stdlib.h>
+#include <stdio.h>
#include "libcgo.h"
static void threadentry(void*);
@@ -25,14 +27,19 @@ x_cgo_init(G *g)
void
_cgo_sys_thread_start(ThreadStart *ts)
{
- _beginthread(threadentry, 0, ts);
+ uintptr_t thandle;
+
+ thandle = _beginthread(threadentry, 0, ts);
+ if(thandle == -1) {
+ fprintf(stderr, "runtime: failed to create new OS thread (%d)\n", errno);
+ abort();
+ }
}
static void
threadentry(void *v)
{
ThreadStart ts;
- void *tls0;
ts = *(ThreadStart*)v;
free(v);
@@ -43,13 +50,12 @@ threadentry(void *v)
/*
* Set specific keys in thread local storage.
*/
- tls0 = (void*)LocalAlloc(LPTR, 64);
asm volatile (
"movq %0, %%gs:0x28\n" // MOVL tls0, 0x28(GS)
"movq %%gs:0x28, %%rax\n" // MOVQ 0x28(GS), tmp
"movq %1, 0(%%rax)\n" // MOVQ g, 0(GS)
"movq %2, 8(%%rax)\n" // MOVQ m, 8(GS)
- :: "r"(tls0), "r"(ts.g), "r"(ts.m) : "%rax"
+ :: "r"(ts.tls), "r"(ts.g), "r"(ts.m) : "%rax"
);
crosscall_amd64(ts.fn);
diff --git a/src/pkg/runtime/cgo/libcgo.h b/src/pkg/runtime/cgo/libcgo.h
index 41a371c27..65ea3f372 100644
--- a/src/pkg/runtime/cgo/libcgo.h
+++ b/src/pkg/runtime/cgo/libcgo.h
@@ -34,6 +34,7 @@ struct ThreadStart
{
uintptr m;
G *g;
+ uintptr *tls;
void (*fn)(void);
};
diff --git a/src/pkg/runtime/cgocall.c b/src/pkg/runtime/cgocall.c
index 2a04453fd..7b2ec26f3 100644
--- a/src/pkg/runtime/cgocall.c
+++ b/src/pkg/runtime/cgocall.c
@@ -99,12 +99,7 @@ runtime·cgocall(void (*fn)(void*), void *arg)
{
Defer d;
- if(m->racecall) {
- runtime·asmcgocall(fn, arg);
- return;
- }
-
- if(!runtime·iscgo && !Windows)
+ if(!runtime·iscgo && !Solaris && !Windows)
runtime·throw("cgocall unavailable");
if(fn == 0)
@@ -127,11 +122,10 @@ runtime·cgocall(void (*fn)(void*), void *arg)
d.fn = &endcgoV;
d.siz = 0;
d.link = g->defer;
- d.argp = (void*)-1; // unused because unlockm never recovers
+ d.argp = NoArgs;
d.special = true;
- d.free = false;
g->defer = &d;
-
+
m->ncgo++;
/*
@@ -171,17 +165,6 @@ endcgo(void)
runtime·raceacquire(&cgosync);
}
-void
-runtime·NumCgoCall(int64 ret)
-{
- M *mp;
-
- ret = 0;
- for(mp=runtime·atomicloadp(&runtime·allm); mp; mp=mp->alllink)
- ret += mp->ncgocall;
- FLUSH(&ret);
-}
-
// Helper functions for cgo code.
void (*_cgo_malloc)(void*);
@@ -235,6 +218,11 @@ struct CallbackArgs
#define CBARGS (CallbackArgs*)((byte*)m->g0->sched.sp+2*sizeof(void*))
#endif
+// Unimplemented on amd64p32
+#ifdef GOARCH_amd64p32
+#define CBARGS (CallbackArgs*)(nil)
+#endif
+
// On 386, stack frame is three words, plus caller PC.
#ifdef GOARCH_386
#define CBARGS (CallbackArgs*)((byte*)m->g0->sched.sp+4*sizeof(void*))
@@ -251,21 +239,9 @@ runtime·cgocallbackg(void)
runtime·exit(2);
}
- if(m->racecall) {
- // We were not in syscall, so no need to call runtime·exitsyscall.
- // However we must set m->locks for the following reason.
- // Race detector runtime makes __tsan_symbolize cgo callback
- // holding internal mutexes. The mutexes are not cooperative with Go scheduler.
- // So if we deschedule a goroutine that holds race detector internal mutex
- // (e.g. preempt it), another goroutine will deadlock trying to acquire the same mutex.
- m->locks++;
- runtime·cgocallbackg1();
- m->locks--;
- } else {
- runtime·exitsyscall(); // coming out of cgo call
- runtime·cgocallbackg1();
- runtime·entersyscall(); // going back to cgo call
- }
+ runtime·exitsyscall(); // coming out of cgo call
+ runtime·cgocallbackg1();
+ runtime·entersyscall(); // going back to cgo call
}
void
@@ -283,19 +259,18 @@ runtime·cgocallbackg1(void)
d.fn = &unwindmf;
d.siz = 0;
d.link = g->defer;
- d.argp = (void*)-1; // unused because unwindm never recovers
+ d.argp = NoArgs;
d.special = true;
- d.free = false;
g->defer = &d;
- if(raceenabled && !m->racecall)
+ if(raceenabled)
runtime·raceacquire(&cgosync);
// Invoke callback.
cb = CBARGS;
runtime·newstackcall(cb->fn, cb->arg, cb->argsize);
- if(raceenabled && !m->racecall)
+ if(raceenabled)
runtime·racereleasemerge(&cgosync);
// Pop defer.
diff --git a/src/pkg/runtime/chan.c b/src/pkg/runtime/chan.goc
index 48cc41e20..7a584717b 100644
--- a/src/pkg/runtime/chan.c
+++ b/src/pkg/runtime/chan.goc
@@ -2,96 +2,25 @@
// 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_GOARCH.h"
#include "type.h"
#include "race.h"
#include "malloc.h"
+#include "chan.h"
#include "../../cmd/ld/textflag.h"
-#define MAXALIGN 8
-#define NOSELGEN 1
-
-typedef struct WaitQ WaitQ;
-typedef struct SudoG SudoG;
-typedef struct Select Select;
-typedef struct Scase Scase;
-
-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;
- uint16 pad; // ensures proper alignment of the buffer that follows Hchan in memory
- bool closed;
- Alg* elemalg; // interface for element type
- uintgo sendx; // send index
- uintgo recvx; // receive index
- WaitQ recvq; // list of recv waiters
- WaitQ sendq; // list of send waiters
- Lock;
-};
-
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
- byte* pc; // return pc
- uint16 kind;
- uint16 so; // vararg of selected bool
- 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 destroychan(Hchan*);
static void racesync(Hchan*, SudoG*);
-Hchan*
-runtime·makechan_c(ChanType *t, int64 hint)
+static Hchan*
+makechan(ChanType *t, int64 hint)
{
Hchan *c;
Type *elem;
@@ -104,13 +33,13 @@ runtime·makechan_c(ChanType *t, int64 hint)
if((sizeof(*c)%MAXALIGN) != 0 || elem->align > MAXALIGN)
runtime·throw("makechan: bad alignment");
- if(hint < 0 || (intgo)hint != hint || (elem->size > 0 && hint > MaxMem / elem->size))
+ if(hint < 0 || (intgo)hint != hint || (elem->size > 0 && hint > (MaxMem - sizeof(*c)) / elem->size))
runtime·panicstring("makechan: size out of range");
// allocate memory in one call
c = (Hchan*)runtime·mallocgc(sizeof(*c) + hint*elem->size, (uintptr)t | TypeInfo_Chan, 0);
c->elemsize = elem->size;
- c->elemalg = elem->alg;
+ c->elemtype = elem;
c->dataqsiz = hint;
if(debug)
@@ -120,21 +49,12 @@ runtime·makechan_c(ChanType *t, int64 hint)
return c;
}
-// For reflect
-// func makechan(typ *ChanType, size uint64) (chan)
-void
-reflect·makechan(ChanType *t, uint64 size, Hchan *c)
-{
- c = runtime·makechan_c(t, size);
- FLUSH(&c);
+func reflect·makechan(t *ChanType, size uint64) (c *Hchan) {
+ c = makechan(t, size);
}
-// makechan(t *ChanType, hint int64) (hchan *chan any);
-void
-runtime·makechan(ChanType *t, int64 hint, Hchan *ret)
-{
- ret = runtime·makechan_c(t, hint);
- FLUSH(&ret);
+func makechan(t *ChanType, size int64) (c *Hchan) {
+ c = makechan(t, size);
}
/*
@@ -151,27 +71,28 @@ runtime·makechan(ChanType *t, int64 hint, Hchan *ret)
* 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)
{
SudoG *sg;
SudoG mysg;
G* gp;
int64 t0;
+ if(raceenabled)
+ runtime·racereadobjectpc(ep, t->elem, runtime·getcallerpc(&t), chansend);
+
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(debug) {
runtime·printf("chansend: chan=%p; elem=", c);
- c->elemalg->print(c->elemsize, ep);
+ c->elemtype->alg->print(c->elemsize, ep);
runtime·prints("\n");
}
@@ -184,7 +105,7 @@ runtime·chansend(ChanType *t, Hchan *c, byte *ep, bool *pres, void *pc)
runtime·lock(c);
if(raceenabled)
- runtime·racereadpc(c, pc, runtime·chansend);
+ runtime·racereadpc(c, pc, chansend);
if(c->closed)
goto closed;
@@ -200,28 +121,24 @@ runtime·chansend(ChanType *t, Hchan *c, byte *ep, bool *pres, void *pc)
gp = sg->g;
gp->param = sg;
if(sg->elem != nil)
- c->elemalg->copy(c->elemsize, sg->elem, ep);
+ c->elemtype->alg->copy(c->elemsize, sg->elem, ep);
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);
@@ -233,32 +150,33 @@ 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)
+ if(raceenabled) {
+ runtime·raceacquire(chanbuf(c, c->sendx));
runtime·racerelease(chanbuf(c, c->sendx));
+ }
- c->elemalg->copy(c->elemsize, chanbuf(c, c->sendx), ep);
+ c->elemtype->alg->copy(c->elemsize, chanbuf(c, c->sendx), ep);
if(++c->sendx == c->dataqsiz)
c->sendx = 0;
c->qcount++;
@@ -272,37 +190,36 @@ 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;
G *gp;
int64 t0;
+ // raceenabled: don't need to check ep, as it is always on the stack.
+
if(debug)
runtime·printf("chanrecv: chan=%p\n", c);
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;
@@ -326,32 +243,29 @@ runtime·chanrecv(ChanType *t, Hchan* c, byte *ep, bool *selected, bool *receive
runtime·unlock(c);
if(ep != nil)
- c->elemalg->copy(c->elemsize, ep, sg->elem);
+ c->elemtype->alg->copy(c->elemsize, ep, sg->elem);
gp = sg->g;
gp->param = sg;
if(sg->releasetime)
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);
@@ -364,36 +278,37 @@ runtime·chanrecv(ChanType *t, Hchan* c, byte *ep, bool *selected, bool *receive
*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)
+ if(raceenabled) {
runtime·raceacquire(chanbuf(c, c->recvx));
+ runtime·racerelease(chanbuf(c, c->recvx));
+ }
if(ep != nil)
- c->elemalg->copy(c->elemsize, ep, chanbuf(c, c->recvx));
- c->elemalg->copy(c->elemsize, chanbuf(c, c->recvx), nil);
+ c->elemtype->alg->copy(c->elemsize, ep, chanbuf(c, c->recvx));
+ c->elemtype->alg->copy(c->elemsize, chanbuf(c, c->recvx), nil);
if(++c->recvx == c->dataqsiz)
c->recvx = 0;
c->qcount--;
@@ -408,19 +323,15 @@ 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)
- c->elemalg->copy(c->elemsize, ep, nil);
- if(selected != nil)
- *selected = true;
+ c->elemtype->alg->copy(c->elemsize, ep, nil);
if(received != nil)
*received = false;
if(raceenabled)
@@ -428,38 +339,25 @@ closed:
runtime·unlock(c);
if(mysg.releasetime > 0)
runtime·blockevent(mysg.releasetime - t0, 2);
+ return true;
}
-// chansend1(hchan *chan any, elem any);
#pragma textflag NOSPLIT
-void
-runtime·chansend1(ChanType *t, Hchan* c, ...)
-{
- runtime·chansend(t, c, (byte*)(&c+1), nil, runtime·getcallerpc(&t));
+func chansend1(t *ChanType, c *Hchan, elem *byte) {
+ chansend(t, c, elem, true, runtime·getcallerpc(&t));
}
-// chanrecv1(hchan *chan any) (elem any);
#pragma textflag NOSPLIT
-void
-runtime·chanrecv1(ChanType *t, Hchan* c, ...)
-{
- runtime·chanrecv(t, c, (byte*)(&c+1), nil, nil);
+func chanrecv1(t *ChanType, c *Hchan, elem *byte) {
+ chanrecv(t, c, elem, true, nil);
}
-// chanrecv2(hchan *chan any) (elem any, received bool);
+// chanrecv2(hchan *chan any, elem *any) (received bool);
#pragma textflag NOSPLIT
-void
-runtime·chanrecv2(ChanType *t, Hchan* c, ...)
-{
- byte *ae, *ap;
-
- ae = (byte*)(&c+1);
- ap = ae + t->elem->size;
- runtime·chanrecv(t, c, ae, nil, ap);
+func chanrecv2(t *ChanType, c *Hchan, elem *byte) (received bool) {
+ chanrecv(t, c, elem, true, &received);
}
-// func selectnbsend(c chan any, elem any) bool
-//
// compiler implements
//
// select {
@@ -478,18 +376,10 @@ runtime·chanrecv2(ChanType *t, Hchan* c, ...)
// }
//
#pragma textflag NOSPLIT
-void
-runtime·selectnbsend(ChanType *t, Hchan *c, ...)
-{
- byte *ae, *ap;
-
- ae = (byte*)(&c + 1);
- ap = ae + ROUND(t->elem->size, Structrnd);
- runtime·chansend(t, c, ae, ap, runtime·getcallerpc(&t));
+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 {
@@ -508,14 +398,10 @@ runtime·selectnbsend(ChanType *t, Hchan *c, ...)
// }
//
#pragma textflag NOSPLIT
-void
-runtime·selectnbrecv(ChanType *t, byte *v, Hchan *c, bool selected)
-{
- runtime·chanrecv(t, c, v, &selected, nil);
+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 {
@@ -534,89 +420,29 @@ runtime·selectnbrecv(ChanType *t, byte *v, Hchan *c, bool selected)
// }
//
#pragma textflag NOSPLIT
-void
-runtime·selectnbrecv2(ChanType *t, byte *v, bool *received, Hchan *c, bool selected)
-{
- runtime·chanrecv(t, c, v, &selected, received);
+func selectnbrecv2(t *ChanType, elem *byte, received *bool, c *Hchan) (selected bool) {
+ selected = chanrecv(t, c, elem, false, received);
}
-// 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.
-//
-// The "uintptr selected" is really "bool selected" but saying
-// uintptr gets us the right alignment for the output parameter block.
#pragma textflag NOSPLIT
-void
-reflect·chansend(ChanType *t, Hchan *c, uintptr val, bool nb, uintptr selected)
-{
- bool *sp;
- byte *vp;
-
- if(nb) {
- selected = false;
- sp = (bool*)&selected;
- } else {
- *(bool*)&selected = true;
- FLUSH(&selected);
- sp = nil;
- }
- if(t->elem->size <= sizeof(val))
- vp = (byte*)&val;
- else
- vp = (byte*)val;
- runtime·chansend(t, c, vp, sp, runtime·getcallerpc(&t));
+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.
-void
-reflect·chanrecv(ChanType *t, Hchan *c, bool nb, uintptr val, bool selected, bool received)
-{
- byte *vp;
- bool *sp;
-
- if(nb) {
- selected = false;
- sp = &selected;
- } else {
- selected = true;
- FLUSH(&selected);
- sp = nil;
- }
+func reflect·chanrecv(t *ChanType, c *Hchan, nb bool, elem *byte) (selected bool, received bool) {
received = false;
- FLUSH(&received);
- if(t->elem->size <= sizeof(val)) {
- val = 0;
- vp = (byte*)&val;
- } else {
- vp = runtime·mal(t->elem->size);
- val = (uintptr)vp;
- FLUSH(&val);
- }
- runtime·chanrecv(t, c, vp, sp, &received);
+ selected = chanrecv(t, c, elem, !nb, &received);
}
-static void newselect(int32, Select**);
+static Select* newselect(int32);
-// newselect(size uint32) (sel *byte);
#pragma textflag NOSPLIT
-void
-runtime·newselect(int32 size, ...)
-{
- int32 o;
- Select **selp;
-
- o = ROUND(sizeof(size), Structrnd);
- selp = (Select**)((byte*)&size + o);
- newselect(size, selp);
+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;
@@ -638,28 +464,22 @@ 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, void *pc, void *elem, int32 so);
-// selectsend(sel *byte, hchan *chan any, elem *any) (selected bool);
#pragma textflag NOSPLIT
-void
-runtime·selectsend(Select *sel, Hchan *c, void *elem, bool selected)
-{
+func selectsend(sel *Select, c *Hchan, elem *byte) (selected bool) {
selected = false;
- FLUSH(&selected);
// nil cases do not compete
- if(c == nil)
- return;
-
- selectsend(sel, c, runtime·getcallerpc(&sel), elem, (byte*)&selected - (byte*)&sel);
+ if(c != nil)
+ selectsend(sel, c, runtime·getcallerpc(&sel), elem, (byte*)&selected - (byte*)&sel);
}
static void
@@ -688,34 +508,22 @@ selectsend(Select *sel, Hchan *c, void *pc, void *elem, int32 so)
// cut in half to give stack a chance to split
static void selectrecv(Select *sel, Hchan *c, void *pc, void *elem, bool*, int32 so);
-// selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
#pragma textflag NOSPLIT
-void
-runtime·selectrecv(Select *sel, Hchan *c, void *elem, bool selected)
-{
+func selectrecv(sel *Select, c *Hchan, elem *byte) (selected bool) {
selected = false;
- FLUSH(&selected);
// nil cases do not compete
- if(c == nil)
- return;
-
- selectrecv(sel, c, runtime·getcallerpc(&sel), elem, nil, (byte*)&selected - (byte*)&sel);
+ if(c != nil)
+ selectrecv(sel, c, runtime·getcallerpc(&sel), elem, nil, (byte*)&selected - (byte*)&sel);
}
-// selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool);
#pragma textflag NOSPLIT
-void
-runtime·selectrecv2(Select *sel, Hchan *c, void *elem, bool *received, bool selected)
-{
+func selectrecv2(sel *Select, c *Hchan, elem *byte, received *bool) (selected bool) {
selected = false;
- FLUSH(&selected);
// nil cases do not compete
- if(c == nil)
- return;
-
- selectrecv(sel, c, runtime·getcallerpc(&sel), elem, received, (byte*)&selected - (byte*)&sel);
+ if(c != nil)
+ selectrecv(sel, c, runtime·getcallerpc(&sel), elem, received, (byte*)&selected - (byte*)&sel);
}
static void
@@ -745,14 +553,9 @@ selectrecv(Select *sel, Hchan *c, void *pc, void *elem, bool *received, int32 so
// cut in half to give stack a chance to split
static void selectdefault(Select*, void*, int32);
-// selectdefault(sel *byte) (selected bool);
#pragma textflag NOSPLIT
-void
-runtime·selectdefault(Select *sel, bool selected)
-{
+func selectdefault(sel *Select) (selected bool) {
selected = false;
- FLUSH(&selected);
-
selectdefault(sel, runtime·getcallerpc(&sel), (byte*)&selected - (byte*)&sel);
}
@@ -821,9 +624,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
}
@@ -834,9 +643,7 @@ static void* selectgo(Select**);
// overwrites return pc on stack to signal which case of the select
// to run, so cannot appear at the top of a split stack.
#pragma textflag NOSPLIT
-void
-runtime·selectgo(Select *sel)
-{
+func selectgo(sel *Select) {
runtime·setcallerpc(&sel, selectgo(&sel));
}
@@ -844,7 +651,7 @@ static void*
selectgo(Select **selp)
{
Select *sel;
- uint32 o, i, j, k;
+ uint32 o, i, j, k, done;
int64 t0;
Scase *cas, *dfl;
Hchan *c;
@@ -946,7 +753,7 @@ loop:
case CaseSend:
if(raceenabled)
- runtime·racereadpc(c, cas->pc, runtime·chansend);
+ runtime·racereadpc(c, cas->pc, chansend);
if(c->closed)
goto sclose;
if(c->dataqsiz > 0) {
@@ -973,13 +780,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:
@@ -993,7 +801,7 @@ loop:
}
g->param = nil;
- runtime·park((void(*)(Lock*))selunlock, (Lock*)sel, "select");
+ runtime·park(selparkcommit, sel, "select");
sellock(sel);
sg = g->param;
@@ -1029,18 +837,29 @@ loop:
*cas->receivedp = true;
}
+ if(raceenabled) {
+ if(cas->kind == CaseRecv && cas->sg.elem != nil)
+ runtime·racewriteobjectpc(cas->sg.elem, c->elemtype, cas->pc, chanrecv);
+ else if(cas->kind == CaseSend)
+ runtime·racereadobjectpc(cas->sg.elem, c->elemtype, cas->pc, chansend);
+ }
+
selunlock(sel);
goto retc;
asyncrecv:
// can receive from buffer
- if(raceenabled)
+ if(raceenabled) {
+ if(cas->sg.elem != nil)
+ runtime·racewriteobjectpc(cas->sg.elem, c->elemtype, cas->pc, chanrecv);
runtime·raceacquire(chanbuf(c, c->recvx));
+ runtime·racerelease(chanbuf(c, c->recvx));
+ }
if(cas->receivedp != nil)
*cas->receivedp = true;
if(cas->sg.elem != nil)
- c->elemalg->copy(c->elemsize, cas->sg.elem, chanbuf(c, c->recvx));
- c->elemalg->copy(c->elemsize, chanbuf(c, c->recvx), nil);
+ c->elemtype->alg->copy(c->elemsize, cas->sg.elem, chanbuf(c, c->recvx));
+ c->elemtype->alg->copy(c->elemsize, chanbuf(c, c->recvx), nil);
if(++c->recvx == c->dataqsiz)
c->recvx = 0;
c->qcount--;
@@ -1058,9 +877,12 @@ asyncrecv:
asyncsend:
// can send to buffer
- if(raceenabled)
+ if(raceenabled) {
+ runtime·raceacquire(chanbuf(c, c->sendx));
runtime·racerelease(chanbuf(c, c->sendx));
- c->elemalg->copy(c->elemsize, chanbuf(c, c->sendx), cas->sg.elem);
+ runtime·racereadobjectpc(cas->sg.elem, c->elemtype, cas->pc, chansend);
+ }
+ c->elemtype->alg->copy(c->elemsize, chanbuf(c, c->sendx), cas->sg.elem);
if(++c->sendx == c->dataqsiz)
c->sendx = 0;
c->qcount++;
@@ -1078,15 +900,18 @@ asyncsend:
syncrecv:
// can receive from sleeping sender (sg)
- if(raceenabled)
+ if(raceenabled) {
+ if(cas->sg.elem != nil)
+ runtime·racewriteobjectpc(cas->sg.elem, c->elemtype, cas->pc, chanrecv);
racesync(c, sg);
+ }
selunlock(sel);
if(debug)
runtime·printf("syncrecv: sel=%p c=%p o=%d\n", sel, c, o);
if(cas->receivedp != nil)
*cas->receivedp = true;
if(cas->sg.elem != nil)
- c->elemalg->copy(c->elemsize, cas->sg.elem, sg->elem);
+ c->elemtype->alg->copy(c->elemsize, cas->sg.elem, sg->elem);
gp = sg->g;
gp->param = sg;
if(sg->releasetime)
@@ -1100,20 +925,22 @@ rclose:
if(cas->receivedp != nil)
*cas->receivedp = false;
if(cas->sg.elem != nil)
- c->elemalg->copy(c->elemsize, cas->sg.elem, nil);
+ c->elemtype->alg->copy(c->elemsize, cas->sg.elem, nil);
if(raceenabled)
runtime·raceacquire(c);
goto retc;
syncsend:
// can send to sleeping receiver (sg)
- if(raceenabled)
+ if(raceenabled) {
+ runtime·racereadobjectpc(cas->sg.elem, c->elemtype, cas->pc, chansend);
racesync(c, sg);
+ }
selunlock(sel);
if(debug)
runtime·printf("syncsend: sel=%p c=%p o=%d\n", sel, c, o);
if(sg->elem != nil)
- c->elemalg->copy(c->elemsize, sg->elem, cas->sg.elem);
+ c->elemtype->alg->copy(c->elemsize, sg->elem, cas->sg.elem);
gp = sg->g;
gp->param = sg;
if(sg->releasetime)
@@ -1150,7 +977,7 @@ struct runtimeSelect
uintptr dir;
ChanType *typ;
Hchan *ch;
- uintptr val;
+ byte *val;
};
// This enum must match ../reflect/value.go:/SelectDir.
@@ -1160,34 +987,17 @@ enum SelectDir {
SelectDefault,
};
-// func rselect(cases []runtimeSelect) (chosen int, word uintptr, recvOK bool)
-void
-reflect·rselect(Slice cases, intgo chosen, uintptr word, bool recvOK)
-{
+func reflect·rselect(cases Slice) (chosen int, recvOK bool) {
int32 i;
Select *sel;
runtimeSelect* rcase, *rc;
- void *elem;
- void *recvptr;
- uintptr maxsize;
chosen = -1;
- word = 0;
recvOK = false;
- maxsize = 0;
rcase = (runtimeSelect*)cases.array;
- for(i=0; i<cases.len; i++) {
- rc = &rcase[i];
- if(rc->dir == SelectRecv && rc->ch != nil && maxsize < rc->typ->elem->size)
- maxsize = rc->typ->elem->size;
- }
-
- recvptr = nil;
- if(maxsize > sizeof(void*))
- recvptr = runtime·mal(maxsize);
- newselect(cases.len, &sel);
+ sel = newselect(cases.len);
for(i=0; i<cases.len; i++) {
rc = &rcase[i];
switch(rc->dir) {
@@ -1197,49 +1007,28 @@ reflect·rselect(Slice cases, intgo chosen, uintptr word, bool recvOK)
case SelectSend:
if(rc->ch == nil)
break;
- if(rc->typ->elem->size > sizeof(void*))
- elem = (void*)rc->val;
- else
- elem = (void*)&rc->val;
- selectsend(sel, rc->ch, (void*)i, elem, 0);
+ selectsend(sel, rc->ch, (void*)i, rc->val, 0);
break;
case SelectRecv:
if(rc->ch == nil)
break;
- if(rc->typ->elem->size > sizeof(void*))
- elem = recvptr;
- else
- elem = &word;
- selectrecv(sel, rc->ch, (void*)i, elem, &recvOK, 0);
+ selectrecv(sel, rc->ch, (void*)i, rc->val, &recvOK, 0);
break;
}
}
chosen = (intgo)(uintptr)selectgo(&sel);
- if(rcase[chosen].dir == SelectRecv && rcase[chosen].typ->elem->size > sizeof(void*))
- word = (uintptr)recvptr;
-
- FLUSH(&chosen);
- FLUSH(&word);
- FLUSH(&recvOK);
}
static void closechan(Hchan *c, void *pc);
-// closechan(sel *byte);
#pragma textflag NOSPLIT
-void
-runtime·closechan(Hchan *c)
-{
+func closechan(c *Hchan) {
closechan(c, runtime·getcallerpc(&c));
}
-// For reflect
-// func chanclose(c chan)
#pragma textflag NOSPLIT
-void
-reflect·chanclose(Hchan *c)
-{
+func reflect·chanclose(c *Hchan) {
closechan(c, runtime·getcallerpc(&c));
}
@@ -1292,28 +1081,18 @@ closechan(Hchan *c, void *pc)
runtime·unlock(c);
}
-// For reflect
-// func chanlen(c chan) (len int)
-void
-reflect·chanlen(Hchan *c, intgo len)
-{
+func reflect·chanlen(c *Hchan) (len int) {
if(c == nil)
len = 0;
else
len = c->qcount;
- FLUSH(&len);
}
-// For reflect
-// func chancap(c chan) int
-void
-reflect·chancap(Hchan *c, intgo cap)
-{
+func reflect·chancap(c *Hchan) (cap int) {
if(c == nil)
cap = 0;
else
cap = c->dataqsiz;
- FLUSH(&cap);
}
static SudoG*
@@ -1327,12 +1106,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;
diff --git a/src/pkg/runtime/chan.h b/src/pkg/runtime/chan.h
new file mode 100644
index 000000000..ce2eb9f4e
--- /dev/null
+++ b/src/pkg/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.
+
+#define MAXALIGN 8
+
+typedef struct WaitQ WaitQ;
+typedef struct SudoG SudoG;
+typedef struct Select Select;
+typedef struct Scase Scase;
+
+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;
+ 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
+ byte* pc; // return pc
+ uint16 kind;
+ uint16 so; // vararg of selected bool
+ 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/src/pkg/runtime/chan_test.go b/src/pkg/runtime/chan_test.go
index eb2c7c60d..ce4b39627 100644
--- a/src/pkg/runtime/chan_test.go
+++ b/src/pkg/runtime/chan_test.go
@@ -9,8 +9,327 @@ 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 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 +348,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 +430,106 @@ func TestMultiConsumer(t *testing.T) {
}
}
+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++ {
- 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
- }
- }
+ 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
}
- c <- true
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ }
+ })
}
func BenchmarkSelectContended(b *testing.B) {
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
+ 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:
- }
- }
+ b.RunParallel(func(pb *testing.PB) {
+ myc1 := make(chan int)
+ myc2 := make(chan int)
+ myc3 := make(chan int, 1)
+ myc4 := make(chan int, 1)
+ 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 +629,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/src/pkg/runtime/complex.c b/src/pkg/runtime/complex.goc
index 395e70fe3..40935cf1c 100644
--- a/src/pkg/runtime/complex.c
+++ b/src/pkg/runtime/complex.goc
@@ -2,13 +2,10 @@
// 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"
-typedef struct Complex128 Complex128;
-
-void
-runtime·complex128div(Complex128 n, Complex128 d, Complex128 q)
-{
+func complex128div(n Complex128, d Complex128) (q Complex128) {
int32 ninf, dinf, nnan, dnan;
float64 a, b, ratio, denom;
@@ -58,5 +55,4 @@ runtime·complex128div(Complex128 n, Complex128 d, Complex128 q)
q.imag = (n.imag - n.real*ratio) / denom;
}
}
- FLUSH(&q);
}
diff --git a/src/pkg/runtime/cpuprof.c b/src/pkg/runtime/cpuprof.goc
index 1c34b9e6f..faaea2943 100644
--- a/src/pkg/runtime/cpuprof.c
+++ b/src/pkg/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_GOARCH.h"
#include "malloc.h"
@@ -80,7 +81,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];
@@ -168,7 +168,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;
@@ -243,7 +243,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++;
@@ -307,6 +306,7 @@ flushlog(Profile *p)
*q++ = p->lost;
*q++ = 1;
*q++ = (uintptr)LostProfileData;
+ p->lost = 0;
}
p->nlog = q - log;
return true;
@@ -428,9 +428,6 @@ breakflush:
// CPUProfile returns the next cpu profile block as a []byte.
// The user documentation is in debug.go.
-void
-runtime·CPUProfile(Slice ret)
-{
+func CPUProfile() (ret Slice) {
ret = getprofile(prof);
- FLUSH(&ret);
}
diff --git a/src/pkg/runtime/crash_test.go b/src/pkg/runtime/crash_test.go
index 5476924bb..b0277f293 100644
--- a/src/pkg/runtime/crash_test.go
+++ b/src/pkg/runtime/crash_test.go
@@ -9,6 +9,7 @@ import (
"os"
"os/exec"
"path/filepath"
+ "runtime"
"strings"
"testing"
"text/template"
@@ -31,6 +32,10 @@ func testEnv(cmd *exec.Cmd) *exec.Cmd {
}
func executeTest(t *testing.T, templ string, data interface{}) string {
+ if runtime.GOOS == "nacl" {
+ t.Skip("skipping on nacl")
+ }
+
checkStaleRuntime(t)
st := template.Must(template.New("crashSource").Parse(templ))
@@ -111,8 +116,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)
}
}
@@ -132,6 +138,34 @@ 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 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)
+ }
+}
+
const crashSource = `
package main
@@ -272,3 +306,61 @@ 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{}
+}
+`
diff --git a/src/pkg/runtime/debug/garbage.go b/src/pkg/runtime/debug/garbage.go
index 8337d5d5b..edb364387 100644
--- a/src/pkg/runtime/debug/garbage.go
+++ b/src/pkg/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/src/pkg/runtime/debug/heapdump_test.go b/src/pkg/runtime/debug/heapdump_test.go
new file mode 100644
index 000000000..920190115
--- /dev/null
+++ b/src/pkg/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/src/pkg/runtime/debug/stack.go b/src/pkg/runtime/debug/stack.go
index 2896b2141..c29b0a226 100644
--- a/src/pkg/runtime/debug/stack.go
+++ b/src/pkg/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/src/pkg/runtime/defs.c b/src/pkg/runtime/defs.c
new file mode 100644
index 000000000..1c76198fc
--- /dev/null
+++ b/src/pkg/runtime/defs.c
@@ -0,0 +1,14 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file is compiled by cmd/dist to obtain debug information
+// about the given header files.
+
+#include "runtime.h"
+#include "arch_GOARCH.h"
+#include "malloc.h"
+#include "type.h"
+#include "race.h"
+#include "hashmap.h"
+#include "chan.h"
diff --git a/src/pkg/runtime/defs_freebsd.go b/src/pkg/runtime/defs_freebsd.go
index dad20f16d..2832583e0 100644
--- a/src/pkg/runtime/defs_freebsd.go
+++ b/src/pkg/runtime/defs_freebsd.go
@@ -49,8 +49,10 @@ const (
SA_RESTART = C.SA_RESTART
SA_ONSTACK = C.SA_ONSTACK
- UMTX_OP_WAIT_UINT = C.UMTX_OP_WAIT_UINT
- UMTX_OP_WAKE = C.UMTX_OP_WAKE
+ UMTX_OP_WAIT_UINT = C.UMTX_OP_WAIT_UINT
+ UMTX_OP_WAIT_UINT_PRIVATE = C.UMTX_OP_WAIT_UINT_PRIVATE
+ UMTX_OP_WAKE = C.UMTX_OP_WAKE
+ UMTX_OP_WAKE_PRIVATE = C.UMTX_OP_WAKE_PRIVATE
SIGHUP = C.SIGHUP
SIGINT = C.SIGINT
diff --git a/src/pkg/runtime/defs_freebsd_386.h b/src/pkg/runtime/defs_freebsd_386.h
index cf9c76eb1..fab938526 100644
--- a/src/pkg/runtime/defs_freebsd_386.h
+++ b/src/pkg/runtime/defs_freebsd_386.h
@@ -21,8 +21,10 @@ enum {
SA_RESTART = 0x2,
SA_ONSTACK = 0x1,
- UMTX_OP_WAIT_UINT = 0xb,
- UMTX_OP_WAKE = 0x3,
+ UMTX_OP_WAIT_UINT = 0xb,
+ UMTX_OP_WAIT_UINT_PRIVATE = 0xf,
+ UMTX_OP_WAKE = 0x3,
+ UMTX_OP_WAKE_PRIVATE = 0x10,
SIGHUP = 0x1,
SIGINT = 0x2,
diff --git a/src/pkg/runtime/defs_freebsd_amd64.h b/src/pkg/runtime/defs_freebsd_amd64.h
index 3fb33f38a..c1db91803 100644
--- a/src/pkg/runtime/defs_freebsd_amd64.h
+++ b/src/pkg/runtime/defs_freebsd_amd64.h
@@ -21,8 +21,10 @@ enum {
SA_RESTART = 0x2,
SA_ONSTACK = 0x1,
- UMTX_OP_WAIT_UINT = 0xb,
- UMTX_OP_WAKE = 0x3,
+ UMTX_OP_WAIT_UINT = 0xb,
+ UMTX_OP_WAIT_UINT_PRIVATE = 0xf,
+ UMTX_OP_WAKE = 0x3,
+ UMTX_OP_WAKE_PRIVATE = 0x10,
SIGHUP = 0x1,
SIGINT = 0x2,
diff --git a/src/pkg/runtime/defs_freebsd_arm.h b/src/pkg/runtime/defs_freebsd_arm.h
index d321f4249..4fc452e45 100644
--- a/src/pkg/runtime/defs_freebsd_arm.h
+++ b/src/pkg/runtime/defs_freebsd_arm.h
@@ -4,7 +4,7 @@
enum {
EINTR = 0x4,
- EFAULT = 0xe,
+ EFAULT = 0xe,
PROT_NONE = 0x0,
PROT_READ = 0x1,
@@ -21,8 +21,10 @@ enum {
SA_RESTART = 0x2,
SA_ONSTACK = 0x1,
- UMTX_OP_WAIT_UINT = 0xb,
- UMTX_OP_WAKE = 0x3,
+ UMTX_OP_WAIT_UINT = 0xb,
+ UMTX_OP_WAIT_UINT_PRIVATE = 0xf,
+ UMTX_OP_WAKE = 0x3,
+ UMTX_OP_WAKE_PRIVATE = 0x10,
SIGHUP = 0x1,
SIGINT = 0x2,
@@ -76,13 +78,13 @@ enum {
ITIMER_VIRTUAL = 0x1,
ITIMER_PROF = 0x2,
- EV_ADD = 0x1,
- EV_DELETE = 0x2,
- EV_CLEAR = 0x20,
- EV_RECEIPT = 0x40,
- EV_ERROR = 0x4000,
- EVFILT_READ = -0x1,
- EVFILT_WRITE = -0x2,
+ EV_ADD = 0x1,
+ EV_DELETE = 0x2,
+ EV_CLEAR = 0x20,
+ EV_RECEIPT = 0x40,
+ EV_ERROR = 0x4000,
+ EVFILT_READ = -0x1,
+ EVFILT_WRITE = -0x2,
};
typedef struct Rtprio Rtprio;
@@ -159,10 +161,12 @@ struct Ucontext {
struct Timespec {
int64 tv_sec;
int32 tv_nsec;
+ byte Pad_cgo_0[4];
};
struct Timeval {
int64 tv_sec;
int32 tv_usec;
+ byte Pad_cgo_0[4];
};
struct Itimerval {
Timeval it_interval;
@@ -170,12 +174,12 @@ struct Itimerval {
};
struct Kevent {
- uint32 ident;
- int16 filter;
- uint16 flags;
- uint32 fflags;
- int32 data;
- byte *udata;
+ uint32 ident;
+ int16 filter;
+ uint16 flags;
+ uint32 fflags;
+ int32 data;
+ byte *udata;
};
diff --git a/src/pkg/runtime/defs_nacl_386.h b/src/pkg/runtime/defs_nacl_386.h
new file mode 100644
index 000000000..e8fbb38e1
--- /dev/null
+++ b/src/pkg/runtime/defs_nacl_386.h
@@ -0,0 +1,63 @@
+// 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.
+
+// Created by hand, not machine generated.
+
+enum
+{
+ // These values are referred to in the source code
+ // but really don't matter. Even so, use the standard numbers.
+ SIGSEGV = 11,
+ SIGPROF = 27,
+};
+
+typedef struct Siginfo Siginfo;
+
+// native_client/src/trusted/service_runtime/include/machine/_types.h
+typedef struct Timespec Timespec;
+
+struct Timespec
+{
+ int64 tv_sec;
+ int32 tv_nsec;
+};
+
+// native_client/src/trusted/service_runtime/nacl_exception.h
+// native_client/src/include/nacl/nacl_exception.h
+
+typedef struct ExcContext ExcContext;
+typedef struct ExcPortable ExcPortable;
+typedef struct ExcRegs386 ExcRegs386;
+
+struct ExcRegs386
+{
+ uint32 eax;
+ uint32 ecx;
+ uint32 edx;
+ uint32 ebx;
+ uint32 esp;
+ uint32 ebp;
+ uint32 esi;
+ uint32 edi;
+ uint32 eip;
+ uint32 eflags;
+};
+
+struct ExcContext
+{
+ uint32 size;
+ uint32 portable_context_offset;
+ uint32 portable_context_size;
+ uint32 arch;
+ uint32 regs_size;
+ uint32 reserved[11];
+ ExcRegs386 regs;
+};
+
+struct ExcPortableContext
+{
+ uint32 pc;
+ uint32 sp;
+ uint32 fp;
+};
diff --git a/src/pkg/runtime/defs_nacl_amd64p32.h b/src/pkg/runtime/defs_nacl_amd64p32.h
new file mode 100644
index 000000000..8d3068bf8
--- /dev/null
+++ b/src/pkg/runtime/defs_nacl_amd64p32.h
@@ -0,0 +1,90 @@
+// 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.
+
+// Created by hand, not machine generated.
+
+enum
+{
+ // These values are referred to in the source code
+ // but really don't matter. Even so, use the standard numbers.
+ SIGSEGV = 11,
+ SIGPROF = 27,
+};
+
+typedef struct Siginfo Siginfo;
+
+
+// native_client/src/trusted/service_runtime/include/machine/_types.h
+typedef struct Timespec Timespec;
+
+struct Timespec
+{
+ int64 tv_sec;
+ int32 tv_nsec;
+};
+
+// native_client/src/trusted/service_runtime/nacl_exception.h
+// native_client/src/include/nacl/nacl_exception.h
+
+typedef struct ExcContext ExcContext;
+typedef struct ExcPortable ExcPortable;
+typedef struct ExcRegs386 ExcRegs386;
+typedef struct ExcRegsAmd64 ExcRegsAmd64;
+
+struct ExcRegs386
+{
+ uint32 eax;
+ uint32 ecx;
+ uint32 edx;
+ uint32 ebx;
+ uint32 esp;
+ uint32 ebp;
+ uint32 esi;
+ uint32 edi;
+ uint32 eip;
+ uint32 eflags;
+};
+
+struct ExcRegsAmd64
+{
+ uint64 rax;
+ uint64 rcx;
+ uint64 rdx;
+ uint64 rbx;
+ uint64 rsp;
+ uint64 rbp;
+ uint64 rsi;
+ uint64 rdi;
+ uint64 r8;
+ uint64 r9;
+ uint64 r10;
+ uint64 r11;
+ uint64 r12;
+ uint64 r13;
+ uint64 r14;
+ uint64 r15;
+ uint64 rip;
+ uint32 rflags;
+};
+
+struct ExcContext
+{
+ uint32 size;
+ uint32 portable_context_offset;
+ uint32 portable_context_size;
+ uint32 arch;
+ uint32 regs_size;
+ uint32 reserved[11];
+ union {
+ ExcRegs386 regs;
+ ExcRegsAmd64 regs64;
+ };
+};
+
+struct ExcPortableContext
+{
+ uint32 pc;
+ uint32 sp;
+ uint32 fp;
+};
diff --git a/src/pkg/runtime/defs_openbsd_386.h b/src/pkg/runtime/defs_openbsd_386.h
index a5b7f04b5..b8f993e2b 100644
--- a/src/pkg/runtime/defs_openbsd_386.h
+++ b/src/pkg/runtime/defs_openbsd_386.h
@@ -121,7 +121,7 @@ struct Sigcontext {
int32 sc_eflags;
int32 sc_esp;
int32 sc_ss;
- int32 sc_onstack;
+ int32 __sc_unused;
int32 sc_mask;
int32 sc_trapno;
int32 sc_err;
@@ -143,11 +143,11 @@ struct StackT {
};
struct Timespec {
- int32 tv_sec;
+ int64 tv_sec;
int32 tv_nsec;
};
struct Timeval {
- int32 tv_sec;
+ int64 tv_sec;
int32 tv_usec;
};
struct Itimerval {
@@ -160,7 +160,7 @@ struct Kevent {
int16 filter;
uint16 flags;
uint32 fflags;
- int32 data;
+ int64 data;
byte *udata;
};
diff --git a/src/pkg/runtime/defs_openbsd_amd64.h b/src/pkg/runtime/defs_openbsd_amd64.h
index eb47ec892..a1ae2ef65 100644
--- a/src/pkg/runtime/defs_openbsd_amd64.h
+++ b/src/pkg/runtime/defs_openbsd_amd64.h
@@ -133,7 +133,7 @@ struct Sigcontext {
int64 sc_rsp;
int64 sc_ss;
void *sc_fpstate;
- int32 sc_onstack;
+ int32 __sc_unused;
int32 sc_mask;
};
struct Siginfo {
@@ -154,8 +154,7 @@ struct StackT {
};
struct Timespec {
- int32 tv_sec;
- byte Pad_cgo_0[4];
+ int64 tv_sec;
int64 tv_nsec;
};
struct Timeval {
@@ -168,11 +167,11 @@ struct Itimerval {
};
struct Kevent {
- uint32 ident;
+ uint64 ident;
int16 filter;
uint16 flags;
uint32 fflags;
- int32 data;
+ int64 data;
byte *udata;
};
diff --git a/src/pkg/runtime/defs_solaris.go b/src/pkg/runtime/defs_solaris.go
new file mode 100644
index 000000000..8dcbb08b7
--- /dev/null
+++ b/src/pkg/runtime/defs_solaris.go
@@ -0,0 +1,156 @@
+// 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
+
+/*
+Input to cgo.
+
+GOARCH=amd64 go tool cgo -cdefs defs_solaris.go >defs_solaris_amd64.h
+*/
+
+package runtime
+
+/*
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/select.h>
+#include <sys/siginfo.h>
+#include <sys/signal.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/ucontext.h>
+#include <sys/regset.h>
+#include <sys/unistd.h>
+#include <sys/fork.h>
+#include <sys/port.h>
+#include <semaphore.h>
+#include <errno.h>
+#include <signal.h>
+#include <pthread.h>
+#include <netdb.h>
+*/
+import "C"
+
+const (
+ EINTR = C.EINTR
+ EBADF = C.EBADF
+ EFAULT = C.EFAULT
+ EAGAIN = C.EAGAIN
+ ETIMEDOUT = C.ETIMEDOUT
+ EWOULDBLOCK = C.EWOULDBLOCK
+ EINPROGRESS = C.EINPROGRESS
+
+ PROT_NONE = C.PROT_NONE
+ PROT_READ = C.PROT_READ
+ PROT_WRITE = C.PROT_WRITE
+ PROT_EXEC = C.PROT_EXEC
+
+ MAP_ANON = C.MAP_ANON
+ MAP_PRIVATE = C.MAP_PRIVATE
+ MAP_FIXED = C.MAP_FIXED
+
+ MADV_FREE = C.MADV_FREE
+
+ SA_SIGINFO = C.SA_SIGINFO
+ SA_RESTART = C.SA_RESTART
+ SA_ONSTACK = C.SA_ONSTACK
+
+ SIGHUP = C.SIGHUP
+ SIGINT = C.SIGINT
+ SIGQUIT = C.SIGQUIT
+ SIGILL = C.SIGILL
+ SIGTRAP = C.SIGTRAP
+ SIGABRT = C.SIGABRT
+ SIGEMT = C.SIGEMT
+ SIGFPE = C.SIGFPE
+ SIGKILL = C.SIGKILL
+ SIGBUS = C.SIGBUS
+ SIGSEGV = C.SIGSEGV
+ SIGSYS = C.SIGSYS
+ SIGPIPE = C.SIGPIPE
+ SIGALRM = C.SIGALRM
+ SIGTERM = C.SIGTERM
+ SIGURG = C.SIGURG
+ SIGSTOP = C.SIGSTOP
+ SIGTSTP = C.SIGTSTP
+ SIGCONT = C.SIGCONT
+ SIGCHLD = C.SIGCHLD
+ SIGTTIN = C.SIGTTIN
+ SIGTTOU = C.SIGTTOU
+ SIGIO = C.SIGIO
+ SIGXCPU = C.SIGXCPU
+ SIGXFSZ = C.SIGXFSZ
+ SIGVTALRM = C.SIGVTALRM
+ SIGPROF = C.SIGPROF
+ SIGWINCH = C.SIGWINCH
+ SIGUSR1 = C.SIGUSR1
+ SIGUSR2 = C.SIGUSR2
+
+ FPE_INTDIV = C.FPE_INTDIV
+ FPE_INTOVF = C.FPE_INTOVF
+ FPE_FLTDIV = C.FPE_FLTDIV
+ FPE_FLTOVF = C.FPE_FLTOVF
+ FPE_FLTUND = C.FPE_FLTUND
+ FPE_FLTRES = C.FPE_FLTRES
+ FPE_FLTINV = C.FPE_FLTINV
+ FPE_FLTSUB = C.FPE_FLTSUB
+
+ BUS_ADRALN = C.BUS_ADRALN
+ BUS_ADRERR = C.BUS_ADRERR
+ BUS_OBJERR = C.BUS_OBJERR
+
+ SEGV_MAPERR = C.SEGV_MAPERR
+ SEGV_ACCERR = C.SEGV_ACCERR
+
+ ITIMER_REAL = C.ITIMER_REAL
+ ITIMER_VIRTUAL = C.ITIMER_VIRTUAL
+ ITIMER_PROF = C.ITIMER_PROF
+
+ _SC_NPROCESSORS_ONLN = C._SC_NPROCESSORS_ONLN
+
+ PTHREAD_CREATE_DETACHED = C.PTHREAD_CREATE_DETACHED
+
+ FORK_NOSIGCHLD = C.FORK_NOSIGCHLD
+ FORK_WAITPID = C.FORK_WAITPID
+
+ MAXHOSTNAMELEN = C.MAXHOSTNAMELEN
+
+ O_NONBLOCK = C.O_NONBLOCK
+ FD_CLOEXEC = C.FD_CLOEXEC
+ F_GETFL = C.F_GETFL
+ F_SETFL = C.F_SETFL
+ F_SETFD = C.F_SETFD
+
+ POLLIN = C.POLLIN
+ POLLOUT = C.POLLOUT
+ POLLHUP = C.POLLHUP
+ POLLERR = C.POLLERR
+
+ PORT_SOURCE_FD = C.PORT_SOURCE_FD
+)
+
+type SemT C.sem_t
+
+type Sigaltstack C.struct_sigaltstack
+type Sigset C.sigset_t
+type StackT C.stack_t
+
+type Siginfo C.siginfo_t
+type Sigaction C.struct_sigaction
+
+type Fpregset C.fpregset_t
+type Mcontext C.mcontext_t
+type Ucontext C.ucontext_t
+
+type Timespec C.struct_timespec
+type Timeval C.struct_timeval
+type Itimerval C.struct_itimerval
+
+type PortEvent C.port_event_t
+type Pthread C.pthread_t
+type PthreadAttr C.pthread_attr_t
+
+// depends on Timespec, must appear below
+type Stat C.struct_stat
diff --git a/src/pkg/runtime/defs_solaris_amd64.go b/src/pkg/runtime/defs_solaris_amd64.go
new file mode 100644
index 000000000..049317888
--- /dev/null
+++ b/src/pkg/runtime/defs_solaris_amd64.go
@@ -0,0 +1,48 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+/*
+Input to cgo.
+
+GOARCH=amd64 go tool cgo -cdefs defs_solaris.go defs_solaris_amd64.go >defs_solaris_amd64.h
+*/
+
+package runtime
+
+/*
+#include <sys/types.h>
+#include <sys/regset.h>
+*/
+import "C"
+
+const (
+ REG_RDI = C.REG_RDI
+ REG_RSI = C.REG_RSI
+ REG_RDX = C.REG_RDX
+ REG_RCX = C.REG_RCX
+ REG_R8 = C.REG_R8
+ REG_R9 = C.REG_R9
+ REG_R10 = C.REG_R10
+ REG_R11 = C.REG_R11
+ REG_R12 = C.REG_R12
+ REG_R13 = C.REG_R13
+ REG_R14 = C.REG_R14
+ REG_R15 = C.REG_R15
+ REG_RBP = C.REG_RBP
+ REG_RBX = C.REG_RBX
+ REG_RAX = C.REG_RAX
+ REG_GS = C.REG_GS
+ REG_FS = C.REG_FS
+ REG_ES = C.REG_ES
+ REG_DS = C.REG_DS
+ REG_TRAPNO = C.REG_TRAPNO
+ REG_ERR = C.REG_ERR
+ REG_RIP = C.REG_RIP
+ REG_CS = C.REG_CS
+ REG_RFLAGS = C.REG_RFL
+ REG_RSP = C.REG_RSP
+ REG_SS = C.REG_SS
+)
diff --git a/src/pkg/runtime/defs_solaris_amd64.h b/src/pkg/runtime/defs_solaris_amd64.h
new file mode 100644
index 000000000..799724fad
--- /dev/null
+++ b/src/pkg/runtime/defs_solaris_amd64.h
@@ -0,0 +1,254 @@
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs_solaris.go defs_solaris_amd64.go
+
+
+enum {
+ EINTR = 0x4,
+ EBADF = 0x9,
+ EFAULT = 0xe,
+ EAGAIN = 0xb,
+ ETIMEDOUT = 0x91,
+ EWOULDBLOCK = 0xb,
+ EINPROGRESS = 0x96,
+
+ PROT_NONE = 0x0,
+ PROT_READ = 0x1,
+ PROT_WRITE = 0x2,
+ PROT_EXEC = 0x4,
+
+ MAP_ANON = 0x100,
+ MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
+
+ MADV_FREE = 0x5,
+
+ SA_SIGINFO = 0x8,
+ SA_RESTART = 0x4,
+ SA_ONSTACK = 0x1,
+
+ SIGHUP = 0x1,
+ SIGINT = 0x2,
+ SIGQUIT = 0x3,
+ SIGILL = 0x4,
+ SIGTRAP = 0x5,
+ SIGABRT = 0x6,
+ SIGEMT = 0x7,
+ SIGFPE = 0x8,
+ SIGKILL = 0x9,
+ SIGBUS = 0xa,
+ SIGSEGV = 0xb,
+ SIGSYS = 0xc,
+ SIGPIPE = 0xd,
+ SIGALRM = 0xe,
+ SIGTERM = 0xf,
+ SIGURG = 0x15,
+ SIGSTOP = 0x17,
+ SIGTSTP = 0x18,
+ SIGCONT = 0x19,
+ SIGCHLD = 0x12,
+ SIGTTIN = 0x1a,
+ SIGTTOU = 0x1b,
+ SIGIO = 0x16,
+ SIGXCPU = 0x1e,
+ SIGXFSZ = 0x1f,
+ SIGVTALRM = 0x1c,
+ SIGPROF = 0x1d,
+ SIGWINCH = 0x14,
+ SIGUSR1 = 0x10,
+ SIGUSR2 = 0x11,
+
+ FPE_INTDIV = 0x1,
+ FPE_INTOVF = 0x2,
+ FPE_FLTDIV = 0x3,
+ FPE_FLTOVF = 0x4,
+ FPE_FLTUND = 0x5,
+ FPE_FLTRES = 0x6,
+ FPE_FLTINV = 0x7,
+ FPE_FLTSUB = 0x8,
+
+ BUS_ADRALN = 0x1,
+ BUS_ADRERR = 0x2,
+ BUS_OBJERR = 0x3,
+
+ SEGV_MAPERR = 0x1,
+ SEGV_ACCERR = 0x2,
+
+ ITIMER_REAL = 0x0,
+ ITIMER_VIRTUAL = 0x1,
+ ITIMER_PROF = 0x2,
+
+ _SC_NPROCESSORS_ONLN = 0xf,
+
+ PTHREAD_CREATE_DETACHED = 0x40,
+
+ FORK_NOSIGCHLD = 0x1,
+ FORK_WAITPID = 0x2,
+
+ MAXHOSTNAMELEN = 0x100,
+
+ O_NONBLOCK = 0x80,
+ FD_CLOEXEC = 0x1,
+ F_GETFL = 0x3,
+ F_SETFL = 0x4,
+ F_SETFD = 0x2,
+
+ POLLIN = 0x1,
+ POLLOUT = 0x4,
+ POLLHUP = 0x10,
+ POLLERR = 0x8,
+
+ PORT_SOURCE_FD = 0x4,
+};
+
+typedef struct SemT SemT;
+typedef struct Sigaltstack Sigaltstack;
+typedef struct Sigset Sigset;
+typedef struct StackT StackT;
+typedef struct Siginfo Siginfo;
+typedef struct Sigaction Sigaction;
+typedef struct Fpregset Fpregset;
+typedef struct Mcontext Mcontext;
+typedef struct Ucontext Ucontext;
+typedef struct Timespec Timespec;
+typedef struct Timeval Timeval;
+typedef struct Itimerval Itimerval;
+typedef struct PortEvent PortEvent;
+typedef struct PthreadAttr PthreadAttr;
+typedef struct Stat Stat;
+
+#pragma pack on
+
+struct SemT {
+ uint32 sem_count;
+ uint16 sem_type;
+ uint16 sem_magic;
+ uint64 sem_pad1[3];
+ uint64 sem_pad2[2];
+};
+
+struct Sigaltstack {
+ byte *ss_sp;
+ uint64 ss_size;
+ int32 ss_flags;
+ byte Pad_cgo_0[4];
+};
+struct Sigset {
+ uint32 __sigbits[4];
+};
+struct StackT {
+ byte *ss_sp;
+ uint64 ss_size;
+ int32 ss_flags;
+ byte Pad_cgo_0[4];
+};
+
+struct Siginfo {
+ int32 si_signo;
+ int32 si_code;
+ int32 si_errno;
+ int32 si_pad;
+ byte __data[240];
+};
+struct Sigaction {
+ int32 sa_flags;
+ byte Pad_cgo_0[4];
+ byte _funcptr[8];
+ Sigset sa_mask;
+};
+
+struct Fpregset {
+ byte fp_reg_set[528];
+};
+struct Mcontext {
+ int64 gregs[28];
+ Fpregset fpregs;
+};
+struct Ucontext {
+ uint64 uc_flags;
+ Ucontext *uc_link;
+ Sigset uc_sigmask;
+ StackT uc_stack;
+ byte Pad_cgo_0[8];
+ Mcontext uc_mcontext;
+ int64 uc_filler[5];
+ byte Pad_cgo_1[8];
+};
+
+struct Timespec {
+ int64 tv_sec;
+ int64 tv_nsec;
+};
+struct Timeval {
+ int64 tv_sec;
+ int64 tv_usec;
+};
+struct Itimerval {
+ Timeval it_interval;
+ Timeval it_value;
+};
+
+struct PortEvent {
+ int32 portev_events;
+ uint16 portev_source;
+ uint16 portev_pad;
+ uint64 portev_object;
+ byte *portev_user;
+};
+typedef uint32 Pthread;
+struct PthreadAttr {
+ byte *__pthread_attrp;
+};
+
+struct Stat {
+ uint64 st_dev;
+ uint64 st_ino;
+ uint32 st_mode;
+ uint32 st_nlink;
+ uint32 st_uid;
+ uint32 st_gid;
+ uint64 st_rdev;
+ int64 st_size;
+ Timespec st_atim;
+ Timespec st_mtim;
+ Timespec st_ctim;
+ int32 st_blksize;
+ byte Pad_cgo_0[4];
+ int64 st_blocks;
+ int8 st_fstype[16];
+};
+
+
+#pragma pack off
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs_solaris.go defs_solaris_amd64.go
+
+
+enum {
+ REG_RDI = 0x8,
+ REG_RSI = 0x9,
+ REG_RDX = 0xc,
+ REG_RCX = 0xd,
+ REG_R8 = 0x7,
+ REG_R9 = 0x6,
+ REG_R10 = 0x5,
+ REG_R11 = 0x4,
+ REG_R12 = 0x3,
+ REG_R13 = 0x2,
+ REG_R14 = 0x1,
+ REG_R15 = 0x0,
+ REG_RBP = 0xa,
+ REG_RBX = 0xb,
+ REG_RAX = 0xe,
+ REG_GS = 0x17,
+ REG_FS = 0x16,
+ REG_ES = 0x18,
+ REG_DS = 0x19,
+ REG_TRAPNO = 0xf,
+ REG_ERR = 0x10,
+ REG_RIP = 0x11,
+ REG_CS = 0x12,
+ REG_RFLAGS = 0x13,
+ REG_RSP = 0x14,
+ REG_SS = 0x15,
+};
+
diff --git a/src/pkg/runtime/env_plan9.c b/src/pkg/runtime/env_plan9.c
index 599319c75..f732c9f29 100644
--- a/src/pkg/runtime/env_plan9.c
+++ b/src/pkg/runtime/env_plan9.c
@@ -12,6 +12,7 @@ runtime·getenv(int8 *s)
intgo len;
byte file[128];
byte *p;
+ static byte b[128];
len = runtime·findnull((byte*)s);
if(len > sizeof file-6)
@@ -25,7 +26,14 @@ runtime·getenv(int8 *s)
if(fd < 0)
return nil;
n = runtime·seek(fd, 0, 2);
- p = runtime·malloc(n+1);
+ if(runtime·strcmp((byte*)s, (byte*)"GOTRACEBACK") == 0){
+ // should not call malloc
+ if(n >= sizeof b)
+ return nil;
+ runtime·memclr(b, sizeof b);
+ p = b;
+ }else
+ p = runtime·malloc(n+1);
r = runtime·pread(fd, p, n, 0);
runtime·close(fd);
if(r < 0)
diff --git a/src/pkg/runtime/env_posix.c b/src/pkg/runtime/env_posix.c
index 00ce577d0..4c8288f6b 100644
--- a/src/pkg/runtime/env_posix.c
+++ b/src/pkg/runtime/env_posix.c
@@ -2,9 +2,11 @@
// 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 "arch_GOARCH.h"
+#include "malloc.h"
Slice syscall·envs;
@@ -44,15 +46,24 @@ void
syscall·setenv_c(String k, String v)
{
byte *arg[2];
+ uintptr len;
if(_cgo_setenv == nil)
return;
- arg[0] = runtime·malloc(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;
+ arg[0] = runtime·malloc(len);
runtime·memmove(arg[0], k.str, k.len);
arg[0][k.len] = 0;
- arg[1] = runtime·malloc(v.len + 1);
+ len = v.len + 1;
+ if(len < TinySize)
+ len = TinySize;
+ arg[1] = runtime·malloc(len);
runtime·memmove(arg[1], v.str, v.len);
arg[1][v.len] = 0;
diff --git a/src/pkg/runtime/error.go b/src/pkg/runtime/error.go
index bd7090883..e704ff872 100644
--- a/src/pkg/runtime/error.go
+++ b/src/pkg/runtime/error.go
@@ -75,19 +75,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/src/pkg/runtime/export_test.go b/src/pkg/runtime/export_test.go
index d170fa72a..7a31b63b3 100644
--- a/src/pkg/runtime/export_test.go
+++ b/src/pkg/runtime/export_test.go
@@ -31,11 +31,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
@@ -48,17 +48,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)
}
@@ -80,7 +80,13 @@ var BytesHash = bytesHash
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/src/pkg/runtime/extern.go b/src/pkg/runtime/extern.go
index 527e9cdf8..053dc1014 100644
--- a/src/pkg/runtime/extern.go
+++ b/src/pkg/runtime/extern.go
@@ -24,18 +24,28 @@ 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.
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 +79,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 +168,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 +190,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
}
diff --git a/src/pkg/runtime/funcdata.h b/src/pkg/runtime/funcdata.h
index 166263ef9..e20b6ae25 100644
--- a/src/pkg/runtime/funcdata.h
+++ b/src/pkg/runtime/funcdata.h
@@ -8,9 +8,11 @@
// as well as the compilers.
#define PCDATA_ArgSize 0 /* argument size at CALL instruction */
+#define PCDATA_StackMapIndex 1
-#define FUNCDATA_GCArgs 0 /* garbage collector blocks */
-#define FUNCDATA_GCLocals 1
+#define FUNCDATA_ArgsPointerMaps 2 /* garbage collector blocks */
+#define FUNCDATA_LocalsPointerMaps 3
+#define FUNCDATA_DeadValueMaps 4
// To be used in assembly.
#define ARGSIZE(n) PCDATA $PCDATA_ArgSize, $n
diff --git a/src/pkg/runtime/futex_test.go b/src/pkg/runtime/futex_test.go
index f4054b7e7..f57fc52b8 100644
--- a/src/pkg/runtime/futex_test.go
+++ b/src/pkg/runtime/futex_test.go
@@ -2,33 +2,76 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Futex is only available on Dragonfly, FreeBSD and Linux.
-// The race detector emits calls to split stack functions so it breaks the test.
+// Futex is only available on DragonFly BSD, FreeBSD and Linux.
+// The race detector emits calls to split stack functions so it breaks
+// the test.
+
// +build dragonfly freebsd linux
// +build !race
package runtime_test
import (
- . "runtime"
+ "runtime"
"testing"
"time"
)
+type futexsleepTest struct {
+ mtx uint32
+ ns int64
+ msg string
+ ch chan futexsleepTest
+}
+
+var futexsleepTests = []futexsleepTest{
+ beforeY2038: {mtx: 0, ns: 86400 * 1e9, msg: "before the year 2038", ch: make(chan futexsleepTest, 1)},
+ afterY2038: {mtx: 0, ns: (1<<31 + 100) * 1e9, msg: "after the year 2038", ch: make(chan futexsleepTest, 1)},
+}
+
+const (
+ beforeY2038 = iota
+ afterY2038
+)
+
func TestFutexsleep(t *testing.T) {
- ch := make(chan bool, 1)
- var dummy uint32
+ if runtime.GOMAXPROCS(0) > 1 {
+ // futexsleep doesn't handle EINTR or other signals,
+ // so spurious wakeups may happen.
+ t.Skip("skipping; GOMAXPROCS>1")
+ }
+
start := time.Now()
- go func() {
- Entersyscall()
- Futexsleep(&dummy, 0, (1<<31+100)*1e9)
- Exitsyscall()
- ch <- true
- }()
- select {
- case <-ch:
- t.Errorf("futexsleep finished early after %s!", time.Since(start))
- case <-time.After(time.Second):
- Futexwakeup(&dummy, 1)
+ for _, tt := range futexsleepTests {
+ go func(tt futexsleepTest) {
+ runtime.Entersyscall()
+ runtime.Futexsleep(&tt.mtx, tt.mtx, tt.ns)
+ runtime.Exitsyscall()
+ tt.ch <- tt
+ }(tt)
+ }
+loop:
+ for {
+ select {
+ case tt := <-futexsleepTests[beforeY2038].ch:
+ t.Errorf("futexsleep test %q finished early after %s", tt.msg, time.Since(start))
+ break loop
+ case tt := <-futexsleepTests[afterY2038].ch:
+ // Looks like FreeBSD 10 kernel has changed
+ // the semantics of timedwait on userspace
+ // mutex to make broken stuff look broken.
+ switch {
+ case runtime.GOOS == "freebsd" && runtime.GOARCH == "386":
+ t.Log("freebsd/386 may not work correctly after the year 2038, see golang.org/issue/7194")
+ default:
+ t.Errorf("futexsleep test %q finished early after %s", tt.msg, time.Since(start))
+ break loop
+ }
+ case <-time.After(time.Second):
+ break loop
+ }
+ }
+ for _, tt := range futexsleepTests {
+ runtime.Futexwakeup(&tt.mtx, 1)
}
}
diff --git a/src/pkg/runtime/gc_test.go b/src/pkg/runtime/gc_test.go
index dbd68c1c7..58717ecf7 100644
--- a/src/pkg/runtime/gc_test.go
+++ b/src/pkg/runtime/gc_test.go
@@ -9,6 +9,7 @@ import (
"runtime"
"runtime/debug"
"testing"
+ "time"
)
func TestGcSys(t *testing.T) {
@@ -151,3 +152,85 @@ 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)
+ }
+}
+
+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
+ }
+}
diff --git a/src/pkg/runtime/hash_test.go b/src/pkg/runtime/hash_test.go
index 312c4be8e..1c11e0538 100644
--- a/src/pkg/runtime/hash_test.go
+++ b/src/pkg/runtime/hash_test.go
@@ -397,10 +397,10 @@ func avalancheTest1(t *testing.T, k Key) {
// all sums inside those bounds with 99% probability.
N := n * hashSize
var c float64
- // find c such that Prob(mean-c*stddev < x < mean+c*stddev)^N > .99
- for c = 0.0; math.Pow(math.Erf(c/math.Sqrt(2)), float64(N)) < .99; c += .1 {
+ // find c such that Prob(mean-c*stddev < x < mean+c*stddev)^N > .9999
+ for c = 0.0; math.Pow(math.Erf(c/math.Sqrt(2)), float64(N)) < .9999; c += .1 {
}
- c *= 2.0 // allowed slack - we don't need to be perfectly random
+ c *= 4.0 // allowed slack - we don't need to be perfectly random
mean := .5 * REP
stddev := .5 * math.Sqrt(REP)
low := int(mean - c*stddev)
diff --git a/src/pkg/runtime/hashmap.c b/src/pkg/runtime/hashmap.goc
index 6d2ab2168..3327bed65 100644
--- a/src/pkg/runtime/hashmap.c
+++ b/src/pkg/runtime/hashmap.goc
@@ -2,125 +2,16 @@
// 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_GOARCH.h"
#include "malloc.h"
#include "type.h"
#include "race.h"
+#include "hashmap.h"
+#include "typekind.h"
#include "../../cmd/ld/textflag.h"
-// This file contains the implementation of Go's map type.
-//
-// The 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.
-
-// Maximum number of key/value pairs a bucket can hold.
-#define BUCKETSIZE 8
-
-// Maximum average load of a bucket that triggers growth.
-#define LOAD 6.5
-
-// Picking LOAD: 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)
-// LOAD %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.
-
-// 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.
-#define MAXKEYSIZE 128
-#define MAXVALUESIZE 128
-
-typedef struct Bucket Bucket;
-struct Bucket
-{
- // Note: the format of the Bucket is encoded in ../../cmd/gc/reflect.c and
- // ../reflect/type.go. Don't change this structure without also changing that code!
- uint8 tophash[BUCKETSIZE]; // top 8 bits of hash of each entry (0 = empty)
- Bucket *overflow; // overflow bucket, if any
- byte data[1]; // BUCKETSIZE keys followed by BUCKETSIZE 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.
-
-// Low-order bit of overflow field is used to mark a bucket as already evacuated
-// without destroying the overflow pointer.
-// Only buckets in oldbuckets will be marked as evacuated.
-// Evacuated bit will be set identically on the base bucket and any overflow buckets.
-#define evacuated(b) (((uintptr)(b)->overflow & 1) != 0)
-#define overflowptr(b) ((Bucket*)((uintptr)(b)->overflow & ~(uintptr)1))
-
-struct Hmap
-{
- // 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!
- uintgo count; // # live cells == size of map. Must be first (used by len() builtin)
- uint32 flags;
- uint32 hash0; // hash seed
- uint8 B; // log_2 of # of buckets (can hold up to LOAD * 2^B items)
- uint8 keysize; // key size in bytes
- uint8 valuesize; // value size in bytes
- uint16 bucketsize; // bucket size in bytes
-
- byte *buckets; // array of 2^B Buckets. may be nil if count==0.
- byte *oldbuckets; // previous bucket array of half the size, non-nil only when growing
- uintptr nevacuate; // progress counter for evacuation (buckets less than this have been evacuated)
-};
-
-// possible flags
-enum
-{
- IndirectKey = 1, // storing pointers to keys
- IndirectValue = 2, // storing pointers to values
- Iterator = 4, // there may be an iterator using buckets
- OldIterator = 8, // there may be an iterator using oldbuckets
-};
-
-// Macros for dereferencing indirect keys
-#define IK(h, p) (((h)->flags & IndirectKey) != 0 ? *(byte**)(p) : (p))
-#define IV(h, p) (((h)->flags & IndirectValue) != 0 ? *(byte**)(p) : (p))
-
enum
{
docheck = 0, // check invariants before and after every op. Slow!!!
@@ -143,16 +34,12 @@ check(MapType *t, Hmap *h)
// check buckets
for(bucket = 0; bucket < (uintptr)1 << h->B; bucket++) {
- if(h->oldbuckets != nil) {
- oldbucket = bucket & (((uintptr)1 << (h->B - 1)) - 1);
- b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
- if(!evacuated(b))
- continue; // b is still uninitialized
- }
for(b = (Bucket*)(h->buckets + bucket * h->bucketsize); b != nil; b = b->overflow) {
- for(i = 0, k = b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
- if(b->tophash[i] == 0)
+ for(i = 0, k = (byte*)b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
+ if(b->tophash[i] == Empty)
continue;
+ if(b->tophash[i] > Empty && b->tophash[i] < MinTopHash)
+ runtime·throw("evacuated cell in buckets");
cnt++;
t->key->alg->equal(&eq, t->key->size, IK(h, k), IK(h, k));
if(!eq)
@@ -160,8 +47,8 @@ check(MapType *t, Hmap *h)
hash = h->hash0;
t->key->alg->hash(&hash, t->key->size, IK(h, k));
top = hash >> (8*sizeof(uintptr) - 8);
- if(top == 0)
- top = 1;
+ if(top < MinTopHash)
+ top += MinTopHash;
if(top != b->tophash[i])
runtime·throw("bad hash");
}
@@ -172,14 +59,12 @@ check(MapType *t, Hmap *h)
if(h->oldbuckets != nil) {
for(oldbucket = 0; oldbucket < (uintptr)1 << (h->B - 1); oldbucket++) {
b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
- if(evacuated(b))
- continue;
- if(oldbucket < h->nevacuate)
- runtime·throw("bucket became unevacuated");
- for(; b != nil; b = overflowptr(b)) {
- for(i = 0, k = b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
- if(b->tophash[i] == 0)
+ for(; b != nil; b = b->overflow) {
+ for(i = 0, k = (byte*)b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
+ if(b->tophash[i] < MinTopHash)
continue;
+ if(oldbucket < h->nevacuate)
+ runtime·throw("unevacuated entry in an evacuated bucket");
cnt++;
t->key->alg->equal(&eq, t->key->size, IK(h, k), IK(h, k));
if(!eq)
@@ -187,8 +72,8 @@ check(MapType *t, Hmap *h)
hash = h->hash0;
t->key->alg->hash(&hash, t->key->size, IK(h, k));
top = hash >> (8*sizeof(uintptr) - 8);
- if(top == 0)
- top = 1;
+ if(top < MinTopHash)
+ top += MinTopHash;
if(top != b->tophash[i])
runtime·throw("bad hash (old)");
}
@@ -224,6 +109,10 @@ hash_init(MapType *t, Hmap *h, uint32 hint)
valuesize = sizeof(byte*);
}
bucketsize = offsetof(Bucket, data[0]) + (keysize + valuesize) * BUCKETSIZE;
+ if(bucketsize != t->bucket->size) {
+ runtime·printf("runtime: bucketsize=%p but t->bucket->size=%p; t=%S\n", bucketsize, t->bucket->size, *t->string);
+ runtime·throw("bucketsize wrong");
+ }
// invariants we depend on. We should probably check these at compile time
// somewhere, but for now we'll do it here.
@@ -237,9 +126,9 @@ hash_init(MapType *t, Hmap *h, uint32 hint)
runtime·throw("value size not a multiple of value align");
if(BUCKETSIZE < 8)
runtime·throw("bucketsize too small for proper alignment");
- if(sizeof(void*) == 4 && t->key->align > 4)
+ if((offsetof(Bucket, data[0]) & (t->key->align-1)) != 0)
runtime·throw("need padding in bucket (key)");
- if(sizeof(void*) == 4 && t->elem->align > 4)
+ if((offsetof(Bucket, data[0]) & (t->elem->align-1)) != 0)
runtime·throw("need padding in bucket (value)");
// find size parameter which will hold the requested # of elements
@@ -273,13 +162,12 @@ hash_init(MapType *t, Hmap *h, uint32 hint)
}
// Moves entries in oldbuckets[i] to buckets[i] and buckets[i+2^k].
-// We leave the original bucket intact, except for the evacuated marks, so that
-// iterators can still iterate through the old buckets.
+// We leave the original bucket intact, except for marking the topbits
+// entries as evacuated, so that iterators can still iterate through the old buckets.
static void
evacuate(MapType *t, Hmap *h, uintptr oldbucket)
{
Bucket *b;
- Bucket *nextb;
Bucket *x, *y;
Bucket *newx, *newy;
uintptr xi, yi;
@@ -302,15 +190,19 @@ evacuate(MapType *t, Hmap *h, uintptr oldbucket)
y = (Bucket*)(h->buckets + (oldbucket + newbit) * h->bucketsize);
xi = 0;
yi = 0;
- xk = x->data;
- yk = y->data;
+ xk = (byte*)x->data;
+ yk = (byte*)y->data;
xv = xk + h->keysize * BUCKETSIZE;
yv = yk + h->keysize * BUCKETSIZE;
- do {
- for(i = 0, k = b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
+ for(; b != nil; b = b->overflow) {
+ for(i = 0, k = (byte*)b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
top = b->tophash[i];
- if(top == 0)
+ if(top == Empty) {
+ b->tophash[i] = EvacuatedEmpty;
continue;
+ }
+ if(top < MinTopHash)
+ runtime·throw("bad state");
// Compute hash to make our evacuation decision (whether we need
// to send this key/value to bucket x or bucket y).
@@ -335,19 +227,20 @@ evacuate(MapType *t, Hmap *h, uintptr oldbucket)
else
hash &= ~newbit;
top = hash >> (8*sizeof(uintptr)-8);
- if(top == 0)
- top = 1;
+ if(top < MinTopHash)
+ top += MinTopHash;
}
}
if((hash & newbit) == 0) {
+ b->tophash[i] = EvacuatedX;
if(xi == BUCKETSIZE) {
if(checkgc) mstats.next_gc = mstats.heap_alloc;
newx = runtime·cnew(t->bucket);
x->overflow = newx;
x = newx;
xi = 0;
- xk = x->data;
+ xk = (byte*)x->data;
xv = xk + h->keysize * BUCKETSIZE;
}
x->tophash[xi] = top;
@@ -365,13 +258,14 @@ evacuate(MapType *t, Hmap *h, uintptr oldbucket)
xk += h->keysize;
xv += h->valuesize;
} else {
+ b->tophash[i] = EvacuatedY;
if(yi == BUCKETSIZE) {
if(checkgc) mstats.next_gc = mstats.heap_alloc;
newy = runtime·cnew(t->bucket);
y->overflow = newy;
y = newy;
yi = 0;
- yk = y->data;
+ yk = (byte*)y->data;
yv = yk + h->keysize * BUCKETSIZE;
}
y->tophash[yi] = top;
@@ -390,26 +284,21 @@ evacuate(MapType *t, Hmap *h, uintptr oldbucket)
yv += h->valuesize;
}
}
+ }
- // mark as evacuated so we don't do it again.
- // this also tells any iterators that this data isn't golden anymore.
- nextb = b->overflow;
- b->overflow = (Bucket*)((uintptr)nextb + 1);
-
- b = nextb;
- } while(b != nil);
-
- // Unlink the overflow buckets to help GC.
- b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
- if((h->flags & OldIterator) == 0)
- b->overflow = (Bucket*)1;
+ // Unlink the overflow buckets & clear key/value to help GC.
+ if((h->flags & OldIterator) == 0) {
+ b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
+ b->overflow = nil;
+ runtime·memclr((byte*)b->data, h->bucketsize - offsetof(Bucket, data[0]));
+ }
}
- // advance evacuation mark
+ // Advance evacuation mark
if(oldbucket == h->nevacuate) {
h->nevacuate = oldbucket + 1;
if(oldbucket + 1 == newbit) // newbit == # of oldbuckets
- // free main bucket array
+ // Growing is all done. Free old main bucket array.
h->oldbuckets = nil;
}
if(docheck)
@@ -443,7 +332,6 @@ hash_grow(MapType *t, Hmap *h)
if(h->oldbuckets != nil)
runtime·throw("evacuation not done in time");
old_buckets = h->buckets;
- // NOTE: this could be a big malloc, but since we don't need zeroing it is probably fast.
if(checkgc) mstats.next_gc = mstats.heap_alloc;
new_buckets = runtime·cnewarray(t->bucket, (uintptr)1 << (h->B + 1));
flags = (h->flags & ~(Iterator | OldIterator));
@@ -495,10 +383,10 @@ hash_lookup(MapType *t, Hmap *h, byte **keyp)
b = (Bucket*)(h->buckets + bucket * h->bucketsize);
}
top = hash >> (sizeof(uintptr)*8 - 8);
- if(top == 0)
- top = 1;
+ if(top < MinTopHash)
+ top += MinTopHash;
do {
- for(i = 0, k = b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
+ for(i = 0, k = (byte*)b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
if(b->tophash[i] == top) {
k2 = IK(h, k);
t->key->alg->equal(&eq, t->key->size, key, k2);
@@ -513,10 +401,6 @@ hash_lookup(MapType *t, Hmap *h, byte **keyp)
return nil;
}
-// When an item is not found, fast versions return a pointer to this zeroed memory.
-#pragma dataflag RODATA
-static uint8 empty_value[MAXVALUESIZE];
-
// Specialized versions of mapaccess1 for specific types.
// See ./hashmap_fast.c and ../../cmd/gc/walk.c.
#define HASH_LOOKUP1 runtime·mapaccess1_fast32
@@ -564,6 +448,9 @@ static uint8 empty_value[MAXVALUESIZE];
#ifdef GOARCH_amd64
#define CHECKTYPE uint64
#endif
+#ifdef GOARCH_amd64p32
+#define CHECKTYPE uint32
+#endif
#ifdef GOARCH_386
#define CHECKTYPE uint32
#endif
@@ -612,15 +499,15 @@ hash_insert(MapType *t, Hmap *h, void *key, void *value)
grow_work(t, h, bucket);
b = (Bucket*)(h->buckets + bucket * h->bucketsize);
top = hash >> (sizeof(uintptr)*8 - 8);
- if(top == 0)
- top = 1;
+ if(top < MinTopHash)
+ top += MinTopHash;
inserti = nil;
insertk = nil;
insertv = nil;
while(true) {
- for(i = 0, k = b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
+ for(i = 0, k = (byte*)b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
if(b->tophash[i] != top) {
- if(b->tophash[i] == 0 && inserti == nil) {
+ if(b->tophash[i] == Empty && inserti == nil) {
inserti = &b->tophash[i];
insertk = k;
insertv = v;
@@ -654,7 +541,7 @@ hash_insert(MapType *t, Hmap *h, void *key, void *value)
newb = runtime·cnew(t->bucket);
b->overflow = newb;
inserti = newb->tophash;
- insertk = newb->data;
+ insertk = (byte*)newb->data;
insertv = insertk + h->keysize * BUCKETSIZE;
}
@@ -701,10 +588,10 @@ hash_remove(MapType *t, Hmap *h, void *key)
grow_work(t, h, bucket);
b = (Bucket*)(h->buckets + bucket * h->bucketsize);
top = hash >> (sizeof(uintptr)*8 - 8);
- if(top == 0)
- top = 1;
+ if(top < MinTopHash)
+ top += MinTopHash;
do {
- for(i = 0, k = b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
+ for(i = 0, k = (byte*)b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
if(b->tophash[i] != top)
continue;
t->key->alg->equal(&eq, t->key->size, key, IK(h, k));
@@ -722,7 +609,7 @@ hash_remove(MapType *t, Hmap *h, void *key)
t->elem->alg->copy(t->elem->size, v, nil);
}
- b->tophash[i] = 0;
+ b->tophash[i] = Empty;
h->count--;
// TODO: consolidate buckets if they are mostly empty
@@ -737,42 +624,17 @@ hash_remove(MapType *t, Hmap *h, void *key)
// TODO: shrink the map, the same way we grow it.
-// If you modify hash_iter, also change cmd/gc/range.c to indicate
-// the size of this structure.
-struct hash_iter
-{
- uint8* key; // Must be in first position. Write nil to indicate iteration end (see cmd/gc/range.c).
- uint8* value;
-
- MapType *t;
- Hmap *h;
-
- // end point for iteration
- uintptr endbucket;
- bool wrapped;
-
- // state of table at time iterator is initialized
- uint8 B;
- byte *buckets;
-
- // iter state
- uintptr bucket;
- struct Bucket *bptr;
- uintptr i;
- intptr check_bucket;
-};
-
// iterator state:
// bucket: the current bucket ID
// b: the current Bucket in the chain
// i: the next offset to check in the current bucket
static void
-hash_iter_init(MapType *t, Hmap *h, struct hash_iter *it)
+hash_iter_init(MapType *t, Hmap *h, Hiter *it)
{
uint32 old;
- if(sizeof(struct hash_iter) / sizeof(uintptr) != 11) {
- runtime·throw("hash_iter size incorrect"); // see ../../cmd/gc/range.c
+ if(sizeof(Hiter) / sizeof(uintptr) != 10) {
+ runtime·throw("hash_iter size incorrect"); // see ../../cmd/gc/reflect.c
}
it->t = t;
it->h = h;
@@ -782,8 +644,9 @@ hash_iter_init(MapType *t, Hmap *h, struct hash_iter *it)
it->buckets = h->buckets;
// iterator state
- it->bucket = it->endbucket = runtime·fastrand1() & (((uintptr)1 << h->B) - 1);
- it->wrapped = false;
+ it->bucket = 0;
+ it->offset = runtime·fastrand1() & (BUCKETSIZE - 1);
+ it->done = false;
it->bptr = nil;
// Remember we have an iterator.
@@ -798,22 +661,22 @@ hash_iter_init(MapType *t, Hmap *h, struct hash_iter *it)
if(h->buckets == nil) {
// Empty map. Force next hash_next to exit without
- // evalulating h->bucket.
- it->wrapped = true;
+ // evaluating h->bucket.
+ it->done = true;
}
}
// initializes it->key and it->value to the next key/value pair
// in the iteration, or nil if we've reached the end.
static void
-hash_next(struct hash_iter *it)
+hash_next(Hiter *it)
{
Hmap *h;
MapType *t;
uintptr bucket, oldbucket;
uintptr hash;
Bucket *b;
- uintptr i;
+ uintptr i, offi;
intptr check_bucket;
bool eq;
byte *k, *v;
@@ -828,7 +691,7 @@ hash_next(struct hash_iter *it)
next:
if(b == nil) {
- if(bucket == it->endbucket && it->wrapped) {
+ if(it->done) {
// end of iteration
it->key = nil;
it->value = nil;
@@ -854,18 +717,20 @@ next:
bucket++;
if(bucket == ((uintptr)1 << it->B)) {
bucket = 0;
- it->wrapped = true;
+ it->done = true;
}
i = 0;
}
- k = b->data + h->keysize * i;
- v = b->data + h->keysize * BUCKETSIZE + h->valuesize * i;
- for(; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
- if(b->tophash[i] != 0) {
+ for(; i < BUCKETSIZE; i++) {
+ offi = (i + it->offset) & (BUCKETSIZE - 1);
+ k = (byte*)b->data + h->keysize * offi;
+ v = (byte*)b->data + h->keysize * BUCKETSIZE + h->valuesize * offi;
+ if(b->tophash[offi] != Empty && b->tophash[offi] != EvacuatedEmpty) {
if(check_bucket >= 0) {
// 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. So we're iterating
+ // 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).
@@ -883,12 +748,15 @@ next:
// 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.
- if(check_bucket >> (it->B - 1) != (b->tophash[i] & 1)) {
+ // NOTE: this case is why we need two evacuate tophash
+ // values, evacuatedX and evacuatedY, that differ in
+ // their low bit.
+ if(check_bucket >> (it->B - 1) != (b->tophash[offi] & 1)) {
continue;
}
}
}
- if(!evacuated(b)) {
+ if(b->tophash[offi] != EvacuatedX && b->tophash[offi] != EvacuatedY) {
// this is the golden data, we can return it.
it->key = IK(h, k);
it->value = IV(h, v);
@@ -924,7 +792,7 @@ next:
return;
}
}
- b = overflowptr(b);
+ b = b->overflow;
i = 0;
goto next;
}
@@ -933,15 +801,12 @@ next:
/// interfaces to go runtime
//
-void
-reflect·ismapkey(Type *typ, bool ret)
-{
+func reflect·ismapkey(typ *Type) (ret bool) {
ret = typ != nil && typ->alg->hash != runtime·nohash;
- FLUSH(&ret);
}
-Hmap*
-runtime·makemap_c(MapType *typ, int64 hint)
+static Hmap*
+makemap_c(MapType *typ, int64 hint)
{
Hmap *h;
Type *key;
@@ -971,235 +836,186 @@ runtime·makemap_c(MapType *typ, int64 hint)
return h;
}
-// makemap(key, val *Type, hint int64) (hmap *map[any]any);
-void
-runtime·makemap(MapType *typ, int64 hint, Hmap *ret)
-{
- ret = runtime·makemap_c(typ, hint);
- FLUSH(&ret);
+func makemap(typ *MapType, hint int64) (ret *Hmap) {
+ ret = makemap_c(typ, hint);
}
-// For reflect:
-// func makemap(Type *mapType) (hmap *map)
-void
-reflect·makemap(MapType *t, Hmap *ret)
-{
- ret = runtime·makemap_c(t, 0);
- FLUSH(&ret);
+func reflect·makemap(t *MapType) (ret *Hmap) {
+ ret = makemap_c(t, 0);
}
-void
-runtime·mapaccess(MapType *t, Hmap *h, byte *ak, byte *av, bool *pres)
-{
- byte *res;
- Type *elem;
-
- elem = t->elem;
- if(h == nil || h->count == 0) {
- elem->alg->copy(elem->size, av, nil);
- *pres = false;
- return;
- }
-
- res = hash_lookup(t, h, &ak);
-
- if(res != nil) {
- *pres = true;
- elem->alg->copy(elem->size, av, res);
- } else {
- *pres = false;
- elem->alg->copy(elem->size, av, nil);
- }
-}
-
-// mapaccess1(hmap *map[any]any, key any) (val any);
+// NOTE: The returned pointer may keep the whole map live, so don't
+// hold onto it for very long.
#pragma textflag NOSPLIT
-void
-runtime·mapaccess1(MapType *t, Hmap *h, ...)
-{
- byte *ak, *av;
- byte *res;
-
- if(raceenabled && h != nil)
+func mapaccess1(t *MapType, h *Hmap, key *byte) (val *byte) {
+ if(raceenabled && h != nil) {
runtime·racereadpc(h, runtime·getcallerpc(&t), runtime·mapaccess1);
-
- ak = (byte*)(&h + 1);
- av = ak + ROUND(t->key->size, Structrnd);
-
+ runtime·racereadobjectpc(key, t->key, runtime·getcallerpc(&t), runtime·mapaccess1);
+ }
if(h == nil || h->count == 0) {
- t->elem->alg->copy(t->elem->size, av, nil);
+ val = t->elem->zero;
} else {
- res = hash_lookup(t, h, &ak);
- t->elem->alg->copy(t->elem->size, av, res);
+ val = hash_lookup(t, h, &key);
+ if(val == nil)
+ val = t->elem->zero;
}
if(debug) {
runtime·prints("runtime.mapaccess1: map=");
runtime·printpointer(h);
runtime·prints("; key=");
- t->key->alg->print(t->key->size, ak);
+ t->key->alg->print(t->key->size, key);
runtime·prints("; val=");
- t->elem->alg->print(t->elem->size, av);
+ t->elem->alg->print(t->elem->size, val);
runtime·prints("\n");
}
}
-// mapaccess2(hmap *map[any]any, key any) (val any, pres bool);
+// NOTE: The returned pointer keeps the whole map live, so don't
+// hold onto it for very long.
#pragma textflag NOSPLIT
-void
-runtime·mapaccess2(MapType *t, Hmap *h, ...)
-{
- byte *ak, *av, *ap;
-
- if(raceenabled && h != nil)
+func mapaccess2(t *MapType, h *Hmap, key *byte) (val *byte, pres bool) {
+ if(raceenabled && h != nil) {
runtime·racereadpc(h, runtime·getcallerpc(&t), runtime·mapaccess2);
+ runtime·racereadobjectpc(key, t->key, runtime·getcallerpc(&t), runtime·mapaccess2);
+ }
- ak = (byte*)(&h + 1);
- av = ak + ROUND(t->key->size, Structrnd);
- ap = av + t->elem->size;
-
- runtime·mapaccess(t, h, ak, av, ap);
+ if(h == nil || h->count == 0) {
+ val = t->elem->zero;
+ pres = false;
+ } else {
+ val = hash_lookup(t, h, &key);
+ if(val == nil) {
+ val = t->elem->zero;
+ pres = false;
+ } else {
+ pres = true;
+ }
+ }
if(debug) {
runtime·prints("runtime.mapaccess2: map=");
runtime·printpointer(h);
runtime·prints("; key=");
- t->key->alg->print(t->key->size, ak);
+ t->key->alg->print(t->key->size, key);
runtime·prints("; val=");
- t->elem->alg->print(t->elem->size, av);
+ t->elem->alg->print(t->elem->size, val);
runtime·prints("; pres=");
- runtime·printbool(*ap);
+ runtime·printbool(pres);
runtime·prints("\n");
}
}
-// For reflect:
-// func mapaccess(t type, h map, key iword) (val iword, pres 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.
-void
-reflect·mapaccess(MapType *t, Hmap *h, uintptr key, uintptr val, bool pres)
-{
- byte *ak, *av;
-
- if(raceenabled && h != nil)
- runtime·racereadpc(h, runtime·getcallerpc(&t), reflect·mapaccess);
-
- if(t->key->size <= sizeof(key))
- ak = (byte*)&key;
- else
- ak = (byte*)key;
- val = 0;
- pres = false;
- if(t->elem->size <= sizeof(val))
- av = (byte*)&val;
+#pragma textflag NOSPLIT
+func reflect·mapaccess(t *MapType, h *Hmap, key *byte) (val *byte) {
+ if(h == nil)
+ val = nil;
else {
- av = runtime·mal(t->elem->size);
- val = (uintptr)av;
+ if(raceenabled) {
+ runtime·racereadpc(h, runtime·getcallerpc(&t), reflect·mapaccess);
+ runtime·racereadobjectpc(key, t->key, runtime·getcallerpc(&t), reflect·mapaccess);
+ }
+ val = hash_lookup(t, h, &key);
}
- runtime·mapaccess(t, h, ak, av, &pres);
- FLUSH(&val);
- FLUSH(&pres);
}
-void
-runtime·mapassign(MapType *t, Hmap *h, byte *ak, byte *av)
-{
+#pragma textflag NOSPLIT
+func mapassign1(t *MapType, h *Hmap, key *byte, val *byte) {
if(h == nil)
runtime·panicstring("assignment to entry in nil map");
- if(av == nil) {
- hash_remove(t, h, ak);
- } else {
- hash_insert(t, h, ak, av);
+ if(raceenabled) {
+ runtime·racewritepc(h, runtime·getcallerpc(&t), runtime·mapassign1);
+ runtime·racereadobjectpc(key, t->key, runtime·getcallerpc(&t), runtime·mapassign1);
+ runtime·racereadobjectpc(val, t->elem, runtime·getcallerpc(&t), runtime·mapassign1);
}
+ hash_insert(t, h, key, val);
+
if(debug) {
- runtime·prints("mapassign: map=");
+ runtime·prints("mapassign1: map=");
runtime·printpointer(h);
runtime·prints("; key=");
- t->key->alg->print(t->key->size, ak);
+ t->key->alg->print(t->key->size, key);
runtime·prints("; val=");
- if(av)
- t->elem->alg->print(t->elem->size, av);
- else
- runtime·prints("nil");
+ t->elem->alg->print(t->elem->size, val);
runtime·prints("\n");
}
}
-// mapassign1(mapType *type, hmap *map[any]any, key any, val any);
#pragma textflag NOSPLIT
-void
-runtime·mapassign1(MapType *t, Hmap *h, ...)
-{
- byte *ak, *av;
-
+func mapdelete(t *MapType, h *Hmap, key *byte) {
if(h == nil)
- runtime·panicstring("assignment to entry in nil map");
+ return;
- if(raceenabled)
- runtime·racewritepc(h, runtime·getcallerpc(&t), runtime·mapassign1);
- ak = (byte*)(&h + 1);
- av = ak + ROUND(t->key->size, t->elem->align);
+ if(raceenabled) {
+ runtime·racewritepc(h, runtime·getcallerpc(&t), runtime·mapdelete);
+ runtime·racereadobjectpc(key, t->key, runtime·getcallerpc(&t), runtime·mapdelete);
+ }
+
+ hash_remove(t, h, key);
- runtime·mapassign(t, h, ak, av);
+ if(debug) {
+ runtime·prints("mapdelete: map=");
+ runtime·printpointer(h);
+ runtime·prints("; key=");
+ t->key->alg->print(t->key->size, key);
+ runtime·prints("\n");
+ }
}
-// mapdelete(mapType *type, hmap *map[any]any, key any)
#pragma textflag NOSPLIT
-void
-runtime·mapdelete(MapType *t, Hmap *h, ...)
-{
- byte *ak;
-
+func reflect·mapassign(t *MapType, h *Hmap, key *byte, val *byte) {
if(h == nil)
- return;
+ runtime·panicstring("assignment to entry in nil map");
+ if(raceenabled) {
+ runtime·racewritepc(h, runtime·getcallerpc(&t), reflect·mapassign);
+ runtime·racereadobjectpc(key, t->key, runtime·getcallerpc(&t), reflect·mapassign);
+ runtime·racereadobjectpc(val, t->elem, runtime·getcallerpc(&t), reflect·mapassign);
+ }
- if(raceenabled)
- runtime·racewritepc(h, runtime·getcallerpc(&t), runtime·mapdelete);
- ak = (byte*)(&h + 1);
- runtime·mapassign(t, h, ak, nil);
+ hash_insert(t, h, key, val);
if(debug) {
- runtime·prints("mapdelete: map=");
+ runtime·prints("mapassign: map=");
runtime·printpointer(h);
runtime·prints("; key=");
- t->key->alg->print(t->key->size, ak);
+ t->key->alg->print(t->key->size, key);
+ runtime·prints("; val=");
+ t->elem->alg->print(t->elem->size, val);
runtime·prints("\n");
}
}
-// For reflect:
-// func mapassign(t type h map, key, val iword, pres 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.
-void
-reflect·mapassign(MapType *t, Hmap *h, uintptr key, uintptr val, bool pres)
-{
- byte *ak, *av;
-
+#pragma textflag NOSPLIT
+func reflect·mapdelete(t *MapType, h *Hmap, key *byte) {
if(h == nil)
- runtime·panicstring("assignment to entry in nil map");
- if(raceenabled)
- runtime·racewritepc(h, runtime·getcallerpc(&t), reflect·mapassign);
- if(t->key->size <= sizeof(key))
- ak = (byte*)&key;
- else
- ak = (byte*)key;
- if(t->elem->size <= sizeof(val))
- av = (byte*)&val;
- else
- av = (byte*)val;
- if(!pres)
- av = nil;
- runtime·mapassign(t, h, ak, av);
+ return; // see bug 8051
+ if(raceenabled) {
+ runtime·racewritepc(h, runtime·getcallerpc(&t), reflect·mapdelete);
+ runtime·racereadobjectpc(key, t->key, runtime·getcallerpc(&t), reflect·mapdelete);
+ }
+ hash_remove(t, h, key);
+
+ if(debug) {
+ runtime·prints("mapdelete: map=");
+ runtime·printpointer(h);
+ runtime·prints("; key=");
+ t->key->alg->print(t->key->size, key);
+ runtime·prints("\n");
+ }
}
-// mapiterinit(mapType *type, hmap *map[any]any, hiter *any);
-void
-runtime·mapiterinit(MapType *t, Hmap *h, struct hash_iter *it)
-{
+#pragma textflag NOSPLIT
+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(h == nil || h->count == 0) {
it->key = nil;
return;
@@ -1219,20 +1035,13 @@ runtime·mapiterinit(MapType *t, Hmap *h, struct hash_iter *it)
}
}
-// For reflect:
-// func mapiterinit(h map) (it iter)
-void
-reflect·mapiterinit(MapType *t, Hmap *h, struct hash_iter *it)
-{
+func reflect·mapiterinit(t *MapType, h *Hmap) (it *Hiter) {
it = runtime·mal(sizeof *it);
- FLUSH(&it);
runtime·mapiterinit(t, h, it);
}
-// mapiternext(hiter *any);
-void
-runtime·mapiternext(struct hash_iter *it)
-{
+#pragma textflag NOSPLIT
+func mapiternext(it *Hiter) {
if(raceenabled)
runtime·racereadpc(it->h, runtime·getcallerpc(&it), runtime·mapiternext);
@@ -1246,85 +1055,16 @@ runtime·mapiternext(struct hash_iter *it)
}
}
-// For reflect:
-// func mapiternext(it iter)
-void
-reflect·mapiternext(struct hash_iter *it)
-{
+func reflect·mapiternext(it *Hiter) {
runtime·mapiternext(it);
}
-// mapiter1(hiter *any) (key any);
-#pragma textflag NOSPLIT
-void
-runtime·mapiter1(struct hash_iter *it, ...)
-{
- byte *ak, *res;
- Type *key;
-
- ak = (byte*)(&it + 1);
-
- res = it->key;
- if(res == nil)
- runtime·throw("runtime.mapiter1: key:val nil pointer");
-
- key = it->t->key;
- key->alg->copy(key->size, ak, res);
-
- if(debug) {
- runtime·prints("mapiter1: iter=");
- runtime·printpointer(it);
- runtime·prints("; map=");
- runtime·printpointer(it->h);
- runtime·prints("\n");
- }
-}
-
-bool
-runtime·mapiterkey(struct hash_iter *it, void *ak)
-{
- byte *res;
- Type *key;
-
- res = it->key;
- if(res == nil)
- return false;
- key = it->t->key;
- key->alg->copy(key->size, ak, res);
- return true;
-}
-
-// For reflect:
-// func mapiterkey(h map) (key iword, ok 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.
-void
-reflect·mapiterkey(struct hash_iter *it, uintptr key, bool ok)
-{
- byte *res;
- Type *tkey;
-
- key = 0;
- ok = false;
- res = it->key;
- if(res != nil) {
- tkey = it->t->key;
- if(tkey->size <= sizeof(key))
- tkey->alg->copy(tkey->size, (byte*)&key, res);
- else
- key = (uintptr)res;
- ok = true;
- }
- FLUSH(&key);
- FLUSH(&ok);
+func reflect·mapiterkey(it *Hiter) (key *byte) {
+ key = it->key;
}
-// For reflect:
-// func maplen(h map) (len int)
-// Like len(m) in the actual language, we treat the nil map as length 0.
-void
-reflect·maplen(Hmap *h, intgo len)
-{
+#pragma textflag NOSPLIT
+func reflect·maplen(h *Hmap) (len int) {
if(h == nil)
len = 0;
else {
@@ -1332,35 +1072,6 @@ reflect·maplen(Hmap *h, intgo len)
if(raceenabled)
runtime·racereadpc(h, runtime·getcallerpc(&h), reflect·maplen);
}
- FLUSH(&len);
-}
-
-// mapiter2(hiter *any) (key any, val any);
-#pragma textflag NOSPLIT
-void
-runtime·mapiter2(struct hash_iter *it, ...)
-{
- byte *ak, *av, *res;
- MapType *t;
-
- t = it->t;
- ak = (byte*)(&it + 1);
- av = ak + ROUND(t->key->size, t->elem->align);
-
- res = it->key;
- if(res == nil)
- runtime·throw("runtime.mapiter2: key:val nil pointer");
-
- t->key->alg->copy(t->key->size, ak, res);
- t->elem->alg->copy(t->elem->size, av, it->value);
-
- if(debug) {
- runtime·prints("mapiter2: iter=");
- runtime·printpointer(it);
- runtime·prints("; map=");
- runtime·printpointer(it->h);
- runtime·prints("\n");
- }
}
// exported value for testing
diff --git a/src/pkg/runtime/hashmap.h b/src/pkg/runtime/hashmap.h
new file mode 100644
index 000000000..522d1ad01
--- /dev/null
+++ b/src/pkg/runtime/hashmap.h
@@ -0,0 +1,147 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains the implementation of Go's map type.
+//
+// The 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.
+
+// Maximum number of key/value pairs a bucket can hold.
+#define BUCKETSIZE 8
+
+// Maximum average load of a bucket that triggers growth.
+#define LOAD 6.5
+
+// Picking LOAD: 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)
+// LOAD %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.
+
+// 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.
+#define MAXKEYSIZE 128
+#define MAXVALUESIZE 128
+
+typedef struct Bucket Bucket;
+struct Bucket
+{
+ // Note: the format of the Bucket is encoded in ../../cmd/gc/reflect.c and
+ // ../reflect/type.go. Don't change this structure without also changing that code!
+ uint8 tophash[BUCKETSIZE]; // top 8 bits of hash of each entry (or special mark below)
+ Bucket *overflow; // overflow bucket, if any
+ uint64 data[1]; // BUCKETSIZE keys followed by BUCKETSIZE 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.
+
+// 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).
+enum
+{
+ 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.
+};
+#define evacuated(b) ((b)->tophash[0] > Empty && (b)->tophash[0] < MinTopHash)
+
+struct Hmap
+{
+ // 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!
+ uintgo count; // # live cells == size of map. Must be first (used by len() builtin)
+ uint32 flags;
+ uint32 hash0; // hash seed
+ uint8 B; // log_2 of # of buckets (can hold up to LOAD * 2^B items)
+ uint8 keysize; // key size in bytes
+ uint8 valuesize; // value size in bytes
+ uint16 bucketsize; // bucket size in bytes
+
+ byte *buckets; // array of 2^B Buckets. may be nil if count==0.
+ byte *oldbuckets; // previous bucket array of half the size, non-nil only when growing
+ uintptr nevacuate; // progress counter for evacuation (buckets less than this have been evacuated)
+};
+
+// possible flags
+enum
+{
+ IndirectKey = 1, // storing pointers to keys
+ IndirectValue = 2, // storing pointers to values
+ Iterator = 4, // there may be an iterator using buckets
+ OldIterator = 8, // there may be an iterator using oldbuckets
+};
+
+// Macros for dereferencing indirect keys
+#define IK(h, p) (((h)->flags & IndirectKey) != 0 ? *(byte**)(p) : (p))
+#define IV(h, p) (((h)->flags & IndirectValue) != 0 ? *(byte**)(p) : (p))
+
+// If you modify Hiter, also change cmd/gc/reflect.c to indicate
+// the layout of this structure.
+struct Hiter
+{
+ uint8* key; // Must be in first position. Write nil to indicate iteration end (see cmd/gc/range.c).
+ uint8* value; // Must be in second position (see cmd/gc/range.c).
+
+ MapType *t;
+ Hmap *h;
+ byte *buckets; // bucket ptr at hash_iter initialization time
+ struct Bucket *bptr; // current bucket
+
+ uint8 offset; // intra-bucket offset to start from during iteration (should be big enough to hold BUCKETSIZE-1)
+ bool done;
+
+ // state of table at time iterator is initialized
+ uint8 B;
+
+ // iter state
+ uintptr bucket;
+ uintptr i;
+ intptr check_bucket;
+};
+
diff --git a/src/pkg/runtime/hashmap_fast.c b/src/pkg/runtime/hashmap_fast.c
index 796582e2d..83bf6feb5 100644
--- a/src/pkg/runtime/hashmap_fast.c
+++ b/src/pkg/runtime/hashmap_fast.c
@@ -5,24 +5,23 @@
// Fast hashmap lookup specialized to a specific key type.
// Included by hashmap.c once for each specialized type.
-// Note that this code differs from hash_lookup in that
-// it returns a pointer to the result, not the result itself.
-// The returned pointer is only valid until the next GC
-// point, so the caller must dereference it before then.
-
// +build ignore
+// Because this file is #included, it cannot be processed by goc2c,
+// so we have to handle the Go resuts ourselves.
+
#pragma textflag NOSPLIT
void
-HASH_LOOKUP1(MapType *t, Hmap *h, KEYTYPE key, byte *value)
+HASH_LOOKUP1(MapType *t, Hmap *h, KEYTYPE key, GoOutput base, ...)
{
uintptr bucket, i;
Bucket *b;
KEYTYPE *k;
- byte *v;
+ byte *v, **valueptr;
uint8 top;
int8 keymaybe;
+ valueptr = (byte**)&base;
if(debug) {
runtime·prints("runtime.mapaccess1_fastXXX: map=");
runtime·printpointer(h);
@@ -31,8 +30,7 @@ HASH_LOOKUP1(MapType *t, Hmap *h, KEYTYPE key, byte *value)
runtime·prints("\n");
}
if(h == nil || h->count == 0) {
- value = empty_value;
- FLUSH(&value);
+ *valueptr = t->elem->zero;
return;
}
if(raceenabled)
@@ -45,26 +43,24 @@ HASH_LOOKUP1(MapType *t, Hmap *h, KEYTYPE key, byte *value)
b = (Bucket*)h->buckets;
if(FASTKEY(key)) {
for(i = 0, k = (KEYTYPE*)b->data, v = (byte*)(k + BUCKETSIZE); i < BUCKETSIZE; i++, k++, v += h->valuesize) {
- if(b->tophash[i] == 0)
+ if(b->tophash[i] == Empty)
continue;
if(QUICK_NE(key, *k))
continue;
if(QUICK_EQ(key, *k) || SLOW_EQ(key, *k)) {
- value = v;
- FLUSH(&value);
+ *valueptr = v;
return;
}
}
} else {
keymaybe = -1;
for(i = 0, k = (KEYTYPE*)b->data, v = (byte*)(k + BUCKETSIZE); i < BUCKETSIZE; i++, k++, v += h->valuesize) {
- if(b->tophash[i] == 0)
+ if(b->tophash[i] == Empty)
continue;
if(QUICK_NE(key, *k))
continue;
if(QUICK_EQ(key, *k)) {
- value = v;
- FLUSH(&value);
+ *valueptr = v;
return;
}
if(MAYBE_EQ(key, *k)) {
@@ -82,8 +78,7 @@ HASH_LOOKUP1(MapType *t, Hmap *h, KEYTYPE key, byte *value)
if(keymaybe >= 0) {
k = (KEYTYPE*)b->data + keymaybe;
if(SLOW_EQ(key, *k)) {
- value = (byte*)((KEYTYPE*)b->data + BUCKETSIZE) + keymaybe * h->valuesize;
- FLUSH(&value);
+ *valueptr = (byte*)((KEYTYPE*)b->data + BUCKETSIZE) + keymaybe * h->valuesize;
return;
}
}
@@ -93,8 +88,8 @@ dohash:
bucket = h->hash0;
HASHFUNC(&bucket, sizeof(KEYTYPE), &key);
top = bucket >> (sizeof(uintptr)*8 - 8);
- if(top == 0)
- top = 1;
+ if(top < MinTopHash)
+ top += MinTopHash;
bucket &= (((uintptr)1 << h->B) - 1);
if(h->oldbuckets != nil) {
i = bucket & (((uintptr)1 << (h->B - 1)) - 1);
@@ -112,29 +107,30 @@ dohash:
if(QUICK_NE(key, *k))
continue;
if(QUICK_EQ(key, *k) || SLOW_EQ(key, *k)) {
- value = v;
- FLUSH(&value);
+ *valueptr = v;
return;
}
}
b = b->overflow;
} while(b != nil);
}
- value = empty_value;
- FLUSH(&value);
+ *valueptr = t->elem->zero;
}
#pragma textflag NOSPLIT
void
-HASH_LOOKUP2(MapType *t, Hmap *h, KEYTYPE key, byte *value, bool res)
+HASH_LOOKUP2(MapType *t, Hmap *h, KEYTYPE key, GoOutput base, ...)
{
uintptr bucket, i;
Bucket *b;
KEYTYPE *k;
- byte *v;
+ byte *v, **valueptr;
uint8 top;
int8 keymaybe;
+ bool *okptr;
+ valueptr = (byte**)&base;
+ okptr = (bool*)(valueptr+1);
if(debug) {
runtime·prints("runtime.mapaccess2_fastXXX: map=");
runtime·printpointer(h);
@@ -143,10 +139,8 @@ HASH_LOOKUP2(MapType *t, Hmap *h, KEYTYPE key, byte *value, bool res)
runtime·prints("\n");
}
if(h == nil || h->count == 0) {
- value = empty_value;
- res = false;
- FLUSH(&value);
- FLUSH(&res);
+ *valueptr = t->elem->zero;
+ *okptr = false;
return;
}
if(raceenabled)
@@ -159,30 +153,26 @@ HASH_LOOKUP2(MapType *t, Hmap *h, KEYTYPE key, byte *value, bool res)
b = (Bucket*)h->buckets;
if(FASTKEY(key)) {
for(i = 0, k = (KEYTYPE*)b->data, v = (byte*)(k + BUCKETSIZE); i < BUCKETSIZE; i++, k++, v += h->valuesize) {
- if(b->tophash[i] == 0)
+ if(b->tophash[i] == Empty)
continue;
if(QUICK_NE(key, *k))
continue;
if(QUICK_EQ(key, *k) || SLOW_EQ(key, *k)) {
- value = v;
- res = true;
- FLUSH(&value);
- FLUSH(&res);
+ *valueptr = v;
+ *okptr = true;
return;
}
}
} else {
keymaybe = -1;
for(i = 0, k = (KEYTYPE*)b->data, v = (byte*)(k + BUCKETSIZE); i < BUCKETSIZE; i++, k++, v += h->valuesize) {
- if(b->tophash[i] == 0)
+ if(b->tophash[i] == Empty)
continue;
if(QUICK_NE(key, *k))
continue;
if(QUICK_EQ(key, *k)) {
- value = v;
- res = true;
- FLUSH(&value);
- FLUSH(&res);
+ *valueptr = v;
+ *okptr = true;
return;
}
if(MAYBE_EQ(key, *k)) {
@@ -200,10 +190,8 @@ HASH_LOOKUP2(MapType *t, Hmap *h, KEYTYPE key, byte *value, bool res)
if(keymaybe >= 0) {
k = (KEYTYPE*)b->data + keymaybe;
if(SLOW_EQ(key, *k)) {
- value = (byte*)((KEYTYPE*)b->data + BUCKETSIZE) + keymaybe * h->valuesize;
- res = true;
- FLUSH(&value);
- FLUSH(&res);
+ *valueptr = (byte*)((KEYTYPE*)b->data + BUCKETSIZE) + keymaybe * h->valuesize;
+ *okptr = true;
return;
}
}
@@ -213,8 +201,8 @@ dohash:
bucket = h->hash0;
HASHFUNC(&bucket, sizeof(KEYTYPE), &key);
top = bucket >> (sizeof(uintptr)*8 - 8);
- if(top == 0)
- top = 1;
+ if(top < MinTopHash)
+ top += MinTopHash;
bucket &= (((uintptr)1 << h->B) - 1);
if(h->oldbuckets != nil) {
i = bucket & (((uintptr)1 << (h->B - 1)) - 1);
@@ -232,18 +220,14 @@ dohash:
if(QUICK_NE(key, *k))
continue;
if(QUICK_EQ(key, *k) || SLOW_EQ(key, *k)) {
- value = v;
- res = true;
- FLUSH(&value);
- FLUSH(&res);
+ *valueptr = v;
+ *okptr = true;
return;
}
}
b = b->overflow;
} while(b != nil);
}
- value = empty_value;
- res = false;
- FLUSH(&value);
- FLUSH(&res);
+ *valueptr = t->elem->zero;
+ *okptr = false;
}
diff --git a/src/pkg/runtime/heapdump.c b/src/pkg/runtime/heapdump.c
new file mode 100644
index 000000000..744c59f9b
--- /dev/null
+++ b/src/pkg/runtime/heapdump.c
@@ -0,0 +1,981 @@
+// 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_GOARCH.h"
+#include "malloc.h"
+#include "mgc0.h"
+#include "type.h"
+#include "typekind.h"
+#include "funcdata.h"
+#include "zaexperiment.h"
+#include "../../cmd/ld/textflag.h"
+
+extern byte data[];
+extern byte edata[];
+extern byte bss[];
+extern byte ebss[];
+extern byte gcdata[];
+extern byte gcbss[];
+
+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, Type *type, uintptr kind);
+static void dumpbvtypes(BitVector *bv, byte *base);
+
+// fd to write the dump to.
+static uintptr dumpfd;
+
+// buffer of pending write data
+enum {
+ BufSize = 4096,
+};
+#pragma dataflag NOPTR
+static byte buf[BufSize];
+static uintptr nbuf;
+
+static void
+write(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 {
+ 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;
+ write(buf, n);
+}
+
+static void
+dumpbool(bool b)
+{
+ dumpint(b ? 1 : 0);
+}
+
+// dump varint uint64 length followed by memory contents
+static void
+dumpmemrange(byte *data, uintptr len)
+{
+ dumpint(len);
+ write(data, len);
+}
+
+static void
+dumpstr(String s)
+{
+ dumpmemrange(s.str, s.len);
+}
+
+static void
+dumpcstr(int8 *c)
+{
+ dumpmemrange((byte*)c, runtime·findnull((byte*)c));
+}
+
+// dump information for a type
+static void
+dumptype(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->x == nil || t->x->pkgPath == nil || t->x->name == nil) {
+ dumpstr(*t->string);
+ } else {
+ dumpint(t->x->pkgPath->len + 1 + t->x->name->len);
+ write(t->x->pkgPath->str, t->x->pkgPath->len);
+ write((byte*)".", 1);
+ write(t->x->name->str, t->x->name->len);
+ }
+ dumpbool(t->size > PtrSize || (t->kind & 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, 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(int8 *description, byte *to)
+{
+ dumpint(TagOtherRoot);
+ dumpcstr(description);
+ dumpint((uintptr)to);
+}
+
+static void
+dumpfinalizer(byte *obj, FuncVal *fn, Type* fint, PtrType *ot)
+{
+ dumpint(TagFinalizer);
+ dumpint((uintptr)obj);
+ dumpint((uintptr)fn);
+ dumpint((uintptr)fn->fn);
+ dumpint((uintptr)fint);
+ 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)
+};
+
+// dump kinds & offsets of interesting fields in bv
+static void
+dumpbv(BitVector *bv, uintptr offset)
+{
+ uintptr i;
+
+ for(i = 0; i < bv->n; i += BitsPerPointer) {
+ switch(bv->data[i/32] >> i%32 & 3) {
+ case BitsDead:
+ case BitsScalar:
+ break;
+ case BitsPointer:
+ dumpint(FieldKindPtr);
+ dumpint(offset + i / BitsPerPointer * PtrSize);
+ break;
+ case BitsMultiWord:
+ switch(bv->data[(i+BitsPerPointer)/32] >> (i+BitsPerPointer)%32 & 3) {
+ case BitsString:
+ dumpint(FieldKindString);
+ dumpint(offset + i / BitsPerPointer * PtrSize);
+ i += BitsPerPointer;
+ break;
+ case BitsSlice:
+ dumpint(FieldKindSlice);
+ dumpint(offset + i / BitsPerPointer * PtrSize);
+ i += 2 * BitsPerPointer;
+ break;
+ case BitsIface:
+ dumpint(FieldKindIface);
+ dumpint(offset + i / BitsPerPointer * PtrSize);
+ i += BitsPerPointer;
+ break;
+ case BitsEface:
+ dumpint(FieldKindEface);
+ dumpint(offset + i / BitsPerPointer * PtrSize);
+ i += BitsPerPointer;
+ break;
+ }
+ }
+ }
+}
+
+static bool
+dumpframe(Stkframe *s, void *arg)
+{
+ Func *f;
+ ChildInfo *child;
+ uintptr pc, off, size;
+ int32 pcdata;
+ StackMap *stackmap;
+ int8 *name;
+ BitVector bv;
+
+ child = (ChildInfo*)arg;
+ f = s->fn;
+
+ // Figure out what we can about our stack map
+ pc = s->pc;
+ if(pc != f->entry)
+ pc--;
+ pcdata = runtime·pcdatavalue(f, PCDATA_StackMapIndex, pc);
+ if(pcdata == -1) {
+ // We do not have a valid pcdata value but there might be a
+ // stackmap for this function. It is likely that we are looking
+ // at the function prologue, assume so and hope for the best.
+ pcdata = 0;
+ }
+ stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps);
+
+ // Dump any types we will need to resolve Efaces.
+ if(child->args.n >= 0)
+ dumpbvtypes(&child->args, (byte*)s->sp + child->argoff);
+ if(stackmap != nil && stackmap->n > 0) {
+ bv = runtime·stackmapdata(stackmap, pcdata);
+ dumpbvtypes(&bv, s->varp - bv.n / BitsPerPointer * PtrSize);
+ } else {
+ bv.n = -1;
+ }
+
+ // Dump main body of stack frame.
+ dumpint(TagStackFrame);
+ dumpint(s->sp); // lowest address in frame
+ dumpint(child->depth); // # of frames deep on the stack
+ dumpint((uintptr)child->sp); // sp of child, or 0 if bottom of stack
+ dumpmemrange((byte*)s->sp, s->fp - s->sp); // frame contents
+ dumpint(f->entry);
+ dumpint(s->pc);
+ dumpint(s->continpc);
+ name = runtime·funcname(f);
+ if(name == nil)
+ name = "unknown function";
+ dumpcstr(name);
+
+ // Dump fields in the outargs section
+ if(child->args.n >= 0) {
+ dumpbv(&child->args, child->argoff);
+ } else {
+ // conservative - everything might be a pointer
+ for(off = child->argoff; off < child->argoff + child->arglen; off += PtrSize) {
+ dumpint(FieldKindPtr);
+ dumpint(off);
+ }
+ }
+
+ // Dump fields in the local vars section
+ if(stackmap == nil) {
+ // No locals information, dump everything.
+ for(off = child->arglen; off < s->varp - (byte*)s->sp; off += PtrSize) {
+ dumpint(FieldKindPtr);
+ dumpint(off);
+ }
+ } else if(stackmap->n < 0) {
+ // Locals size information, dump just the locals.
+ size = -stackmap->n;
+ for(off = s->varp - size - (byte*)s->sp; off < s->varp - (byte*)s->sp; off += PtrSize) {
+ dumpint(FieldKindPtr);
+ dumpint(off);
+ }
+ } else if(stackmap->n > 0) {
+ // Locals bitmap information, scan just the pointers in
+ // locals.
+ dumpbv(&bv, s->varp - bv.n / BitsPerPointer * PtrSize - (byte*)s->sp);
+ }
+ dumpint(FieldKindEol);
+
+ // Record arg info for parent.
+ child->argoff = s->argp - (byte*)s->fp;
+ child->arglen = s->arglen;
+ child->sp = (byte*)s->sp;
+ child->depth++;
+ stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps);
+ if(stackmap != nil)
+ child->args = runtime·stackmapdata(stackmap, pcdata);
+ else
+ child->args.n = -1;
+ return true;
+}
+
+static void
+dumpgoroutine(G *gp)
+{
+ uintptr sp, pc, lr;
+ ChildInfo child;
+ Defer *d;
+ Panic *p;
+
+ if(gp->syscallstack != (uintptr)nil) {
+ sp = gp->syscallsp;
+ pc = gp->syscallpc;
+ lr = 0;
+ } else {
+ sp = gp->sched.sp;
+ pc = gp->sched.pc;
+ lr = gp->sched.lr;
+ }
+
+ dumpint(TagGoRoutine);
+ dumpint((uintptr)gp);
+ dumpint((uintptr)sp);
+ dumpint(gp->goid);
+ dumpint(gp->gopc);
+ dumpint(gp->status);
+ dumpbool(gp->issystem);
+ dumpbool(gp->isbackground);
+ dumpint(gp->waitsince);
+ dumpcstr(gp->waitreason);
+ dumpint((uintptr)gp->sched.ctxt);
+ 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->link) {
+ dumpint(TagDefer);
+ dumpint((uintptr)d);
+ dumpint((uintptr)gp);
+ dumpint((uintptr)d->argp);
+ dumpint((uintptr)d->pc);
+ dumpint((uintptr)d->fn);
+ dumpint((uintptr)d->fn->fn);
+ dumpint((uintptr)d->link);
+ }
+ for (p = gp->panic; p != nil; p = p->link) {
+ dumpint(TagPanic);
+ dumpint((uintptr)p);
+ dumpint((uintptr)gp);
+ dumpint((uintptr)p->arg.type);
+ dumpint((uintptr)p->arg.data);
+ dumpint((uintptr)p->defer);
+ dumpint((uintptr)p->link);
+ }
+}
+
+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, byte *obj, uintptr nret, Type *fint, PtrType *ot)
+{
+ dumpint(TagQueuedFinalizer);
+ dumpint((uintptr)obj);
+ dumpint((uintptr)fn);
+ dumpint((uintptr)fn->fn);
+ dumpint((uintptr)fint);
+ dumpint((uintptr)ot);
+ USED(&nret);
+}
+
+
+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->fint, 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 free[PageSize/8];
+
+static void
+dumpobjs(void)
+{
+ uintptr i, j, size, n, off, shift, *bitp, bits, ti, kind;
+ MSpan *s;
+ MLink *l;
+ byte *p;
+ 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) {
+ free[((byte*)l - p) / size] = true;
+ }
+ for(j = 0; j < n; j++, p += size) {
+ if(free[j]) {
+ free[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 = ((ChanType*)t)->elem; // 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(thechar);
+ dumpcstr(GOEXPERIMENT);
+ dumpint(runtime·ncpu);
+}
+
+static void
+itab_callback(Itab *tab)
+{
+ Type *t;
+
+ dumpint(TagItab);
+ dumpint((uintptr)tab);
+ t = tab->type;
+ dumpbool(t->size > PtrSize || (t->kind & KindNoPointers) == 0);
+}
+
+static void
+dumpitabs(void)
+{
+ runtime·iterate_itabs(itab_callback);
+}
+
+static void
+dumpms(void)
+{
+ M *mp;
+
+ for(mp = runtime·allm; mp != nil; mp = mp->alllink) {
+ dumpint(TagOSThread);
+ dumpint((uintptr)mp);
+ dumpint(mp->id);
+ dumpint(mp->procid);
+ }
+}
+
+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, uintptr *stk, uintptr size, uintptr allocs, uintptr frees)
+{
+ uintptr i, pc;
+ Func *f;
+ byte buf[20];
+ String file;
+ int32 line;
+
+ dumpint(TagMemProf);
+ dumpint((uintptr)b);
+ dumpint(size);
+ dumpint(nstk);
+ for(i = 0; i < nstk; i++) {
+ pc = stk[i];
+ f = runtime·findfunc(pc);
+ if(f == nil) {
+ runtime·snprintf(buf, sizeof(buf), "%X", (uint64)pc);
+ dumpcstr((int8*)buf);
+ dumpcstr("?");
+ dumpint(0);
+ } else {
+ dumpcstr(runtime·funcname(f));
+ // TODO: Why do we need to back up to a call instruction here?
+ // Maybe profiler should do this.
+ if(i > 0 && pc > f->entry) {
+ if(thechar == '6' || thechar == '8')
+ pc--;
+ else
+ pc -= 4; // arm, etc
+ }
+ line = runtime·funcline(f, pc, &file);
+ dumpstr(file);
+ dumpint(line);
+ }
+ }
+ 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)
+{
+ 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 = (byte*)"go1.3 heap dump\n";
+ write(hdr, runtime·findnull(hdr));
+ dumpparams();
+ dumpitabs();
+ dumpobjs();
+ dumpgs();
+ dumpms();
+ dumproots();
+ dumpmemstats();
+ dumpmemprof();
+ dumpint(TagEOF);
+ flush();
+
+ gp->param = nil;
+ gp->status = Grunning;
+ runtime·gogo(&gp->sched);
+}
+
+void
+runtime∕debug·WriteHeapDump(uintptr fd)
+{
+ // Stop the world.
+ runtime·semacquire(&runtime·worldsema, false);
+ 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->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);
+}
+
+// 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, uintptr size, 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;
+ }
+}
+
+// Dump all the types that appear in the type field of
+// any Eface described by this bit vector.
+static void
+dumpbvtypes(BitVector *bv, byte *base)
+{
+ uintptr i;
+
+ for(i = 0; i < bv->n; i += BitsPerPointer) {
+ if((bv->data[i/32] >> i%32 & 3) != BitsMultiWord)
+ continue;
+ switch(bv->data[(i+BitsPerPointer)/32] >> (i+BitsPerPointer)%32 & 3) {
+ case BitsString:
+ case BitsIface:
+ i += BitsPerPointer;
+ break;
+ case BitsSlice:
+ i += 2 * BitsPerPointer;
+ break;
+ case BitsEface:
+ dumptype(*(Type**)(base + i / BitsPerPointer * PtrSize));
+ i += BitsPerPointer;
+ break;
+ }
+ }
+}
diff --git a/src/pkg/runtime/iface.c b/src/pkg/runtime/iface.goc
index ecbdcc707..c0a17e303 100644
--- a/src/pkg/runtime/iface.c
+++ b/src/pkg/runtime/iface.goc
@@ -2,6 +2,7 @@
// 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_GOARCH.h"
#include "type.h"
@@ -9,15 +10,11 @@
#include "malloc.h"
#include "../../cmd/ld/textflag.h"
-void
-runtime·printiface(Iface i)
-{
+func printiface(i Iface) {
runtime·printf("(%p,%p)", i.tab, i.data);
}
-void
-runtime·printeface(Eface e)
-{
+func printeface(e Eface) {
runtime·printf("(%p,%p)", e.type, e.data);
}
@@ -137,6 +134,20 @@ out:
return m;
}
+// call the callback for every itab that is currently allocated.
+void
+runtime·iterate_itabs(void (*callback)(Itab*))
+{
+ int32 i;
+ Itab *tab;
+
+ for(i = 0; i < nelem(hash); i++) {
+ for(tab = hash[i]; tab != nil; tab = tab->link) {
+ callback(tab);
+ }
+ }
+}
+
static void
copyin(Type *t, void *src, void **dst)
{
@@ -150,7 +161,7 @@ copyin(Type *t, void *src, void **dst)
if(size <= sizeof(*dst))
alg->copy(size, dst, src);
else {
- p = runtime·mal(size);
+ p = runtime·cnew(t);
alg->copy(size, p, src);
*dst = p;
}
@@ -172,66 +183,45 @@ copyout(Type *t, void **src, void *dst)
}
#pragma textflag NOSPLIT
-void
-runtime·typ2Itab(Type *t, InterfaceType *inter, Itab **cache, Itab *ret)
-{
- Itab *tab;
-
+func typ2Itab(t *Type, inter *InterfaceType, cache **Itab) (tab *Itab) {
tab = itab(inter, t, 0);
runtime·atomicstorep(cache, tab);
- ret = tab;
- FLUSH(&ret);
}
-// func convT2I(typ *byte, typ2 *byte, cache **byte, elem any) (ret any)
#pragma textflag NOSPLIT
-void
-runtime·convT2I(Type *t, InterfaceType *inter, Itab **cache, ...)
-{
- byte *elem;
- Iface *ret;
+func convT2I(t *Type, inter *InterfaceType, cache **Itab, elem *byte) (ret Iface) {
Itab *tab;
- int32 wid;
- elem = (byte*)(&cache+1);
- wid = t->size;
- ret = (Iface*)(elem + ROUND(wid, Structrnd));
tab = runtime·atomicloadp(cache);
if(!tab) {
tab = itab(inter, t, 0);
runtime·atomicstorep(cache, tab);
}
- ret->tab = tab;
- copyin(t, elem, &ret->data);
+ ret.tab = tab;
+ copyin(t, elem, &ret.data);
}
-// func convT2E(typ *byte, elem any) (ret any)
#pragma textflag NOSPLIT
-void
-runtime·convT2E(Type *t, ...)
-{
- byte *elem;
- Eface *ret;
- int32 wid;
-
- elem = (byte*)(&t+1);
- wid = t->size;
- ret = (Eface*)(elem + ROUND(wid, Structrnd));
- ret->type = t;
- copyin(t, elem, &ret->data);
+func convT2E(t *Type, elem *byte) (ret Eface) {
+ ret.type = t;
+ copyin(t, elem, &ret.data);
}
static void assertI2Tret(Type *t, Iface i, byte *ret);
-// func ifaceI2T(typ *byte, iface any) (ret any)
+/*
+ * NOTE: Cannot use 'func' here, because we have to declare
+ * a return value, the only types we have are at least 1 byte large,
+ * goc2c will zero the return value, and the actual return value
+ * might have size 0 bytes, in which case the zeroing of the
+ * 1 or more bytes would be wrong.
+ * Using C lets us control (avoid) the initial zeroing.
+ */
#pragma textflag NOSPLIT
void
-runtime·assertI2T(Type *t, Iface i, ...)
+runtime·assertI2T(Type *t, Iface i, GoOutput retbase)
{
- byte *ret;
-
- ret = (byte*)(&i+1);
- assertI2Tret(t, i, ret);
+ assertI2Tret(t, i, (byte*)&retbase);
}
static void
@@ -256,47 +246,38 @@ assertI2Tret(Type *t, Iface i, byte *ret)
copyout(t, &i.data, ret);
}
-// func ifaceI2T2(typ *byte, iface any) (ret any, ok bool)
#pragma textflag NOSPLIT
-void
-runtime·assertI2T2(Type *t, Iface i, ...)
-{
- byte *ret;
+func assertI2T2(t *Type, i Iface) (ret byte, ...) {
bool *ok;
int32 wid;
- ret = (byte*)(&i+1);
wid = t->size;
- ok = (bool*)(ret + wid);
+ ok = (bool*)(&ret + wid);
if(i.tab == nil || i.tab->type != t) {
*ok = false;
- runtime·memclr(ret, wid);
+ runtime·memclr(&ret, wid);
return;
}
*ok = true;
- copyout(t, &i.data, ret);
+ copyout(t, &i.data, &ret);
}
-void
-runtime·assertI2TOK(Type *t, Iface i, bool ok)
-{
+func assertI2TOK(t *Type, i Iface) (ok bool) {
ok = i.tab!=nil && i.tab->type==t;
- FLUSH(&ok);
}
static void assertE2Tret(Type *t, Eface e, byte *ret);
-// func ifaceE2T(typ *byte, iface any) (ret any)
+/*
+ * NOTE: Cannot use 'func' here. See assertI2T above.
+ */
#pragma textflag NOSPLIT
void
-runtime·assertE2T(Type *t, Eface e, ...)
+runtime·assertE2T(Type *t, Eface e, GoOutput retbase)
{
- byte *ret;
-
- ret = (byte*)(&e+1);
- assertE2Tret(t, e, ret);
+ assertE2Tret(t, e, (byte*)&retbase);
}
static void
@@ -319,40 +300,29 @@ assertE2Tret(Type *t, Eface e, byte *ret)
copyout(t, &e.data, ret);
}
-// func ifaceE2T2(sigt *byte, iface any) (ret any, ok bool);
#pragma textflag NOSPLIT
-void
-runtime·assertE2T2(Type *t, Eface e, ...)
-{
- byte *ret;
+func assertE2T2(t *Type, e Eface) (ret byte, ...) {
bool *ok;
int32 wid;
- ret = (byte*)(&e+1);
wid = t->size;
- ok = (bool*)(ret + wid);
+ ok = (bool*)(&ret + wid);
if(t != e.type) {
*ok = false;
- runtime·memclr(ret, wid);
+ runtime·memclr(&ret, wid);
return;
}
*ok = true;
- copyout(t, &e.data, ret);
+ copyout(t, &e.data, &ret);
}
-void
-runtime·assertE2TOK(Type *t, Eface e, bool ok)
-{
+func assertE2TOK(t *Type, e Eface) (ok bool) {
ok = t==e.type;
- FLUSH(&ok);
}
-// func convI2E(elem any) (ret any)
-void
-runtime·convI2E(Iface i, Eface ret)
-{
+func convI2E(i Iface) (ret Eface) {
Itab *tab;
ret.data = i.data;
@@ -360,13 +330,9 @@ runtime·convI2E(Iface i, Eface ret)
ret.type = nil;
else
ret.type = tab->type;
- FLUSH(&ret);
}
-// func ifaceI2E(typ *byte, iface any) (ret any)
-void
-runtime·assertI2E(InterfaceType* inter, Iface i, Eface ret)
-{
+func assertI2E(inter *InterfaceType, i Iface) (ret Eface) {
Itab *tab;
Eface err;
@@ -380,13 +346,9 @@ runtime·assertI2E(InterfaceType* inter, Iface i, Eface ret)
}
ret.data = i.data;
ret.type = tab->type;
- FLUSH(&ret);
}
-// func ifaceI2E2(typ *byte, iface any) (ret any, ok bool)
-void
-runtime·assertI2E2(InterfaceType* inter, Iface i, Eface ret, bool ok)
-{
+func assertI2E2(inter *InterfaceType, i Iface) (ret Eface, ok bool) {
Itab *tab;
USED(inter);
@@ -399,14 +361,9 @@ runtime·assertI2E2(InterfaceType* inter, Iface i, Eface ret, bool ok)
ok = 1;
}
ret.data = i.data;
- FLUSH(&ret);
- FLUSH(&ok);
}
-// func convI2I(typ *byte, elem any) (ret any)
-void
-runtime·convI2I(InterfaceType* inter, Iface i, Iface ret)
-{
+func convI2I(inter *InterfaceType, i Iface) (ret Iface) {
Itab *tab;
ret.data = i.data;
@@ -416,7 +373,6 @@ runtime·convI2I(InterfaceType* inter, Iface i, Iface ret)
ret.tab = tab;
else
ret.tab = itab(inter, tab->type, 0);
- FLUSH(&ret);
}
void
@@ -437,17 +393,11 @@ runtime·ifaceI2I(InterfaceType *inter, Iface i, Iface *ret)
ret->tab = itab(inter, tab->type, 0);
}
-// func ifaceI2I(sigi *byte, iface any) (ret any)
-void
-runtime·assertI2I(InterfaceType* inter, Iface i, Iface ret)
-{
+func assertI2I(inter *InterfaceType, i Iface) (ret Iface) {
runtime·ifaceI2I(inter, i, &ret);
}
-// func ifaceI2I2(sigi *byte, iface any) (ret any, ok bool)
-void
-runtime·assertI2I2(InterfaceType *inter, Iface i, Iface ret, bool ok)
-{
+func assertI2I2(inter *InterfaceType, i Iface) (ret Iface, ok bool) {
Itab *tab;
tab = i.tab;
@@ -460,8 +410,6 @@ runtime·assertI2I2(InterfaceType *inter, Iface i, Iface ret, bool ok)
ret.tab = 0;
ok = 0;
}
- FLUSH(&ret);
- FLUSH(&ok);
}
void
@@ -492,25 +440,15 @@ runtime·ifaceE2I2(InterfaceType *inter, Eface e, Iface *ret)
return true;
}
-// For reflect
-// func ifaceE2I(t *InterfaceType, e interface{}, dst *Iface)
-void
-reflect·ifaceE2I(InterfaceType *inter, Eface e, Iface *dst)
-{
+func reflect·ifaceE2I(inter *InterfaceType, e Eface, dst *Iface) {
runtime·ifaceE2I(inter, e, dst);
}
-// func ifaceE2I(sigi *byte, iface any) (ret any)
-void
-runtime·assertE2I(InterfaceType* inter, Eface e, Iface ret)
-{
+func assertE2I(inter *InterfaceType, e Eface) (ret Iface) {
runtime·ifaceE2I(inter, e, &ret);
}
-// ifaceE2I2(sigi *byte, iface any) (ret any, ok bool)
-void
-runtime·assertE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok)
-{
+func assertE2I2(inter *InterfaceType, e Eface) (ret Iface, ok bool) {
if(e.type == nil) {
ok = 0;
ret.data = nil;
@@ -522,14 +460,9 @@ runtime·assertE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok)
ok = 1;
ret.data = e.data;
}
- FLUSH(&ret);
- FLUSH(&ok);
}
-// func ifaceE2E(typ *byte, iface any) (ret any)
-void
-runtime·assertE2E(InterfaceType* inter, Eface e, Eface ret)
-{
+func assertE2E(inter *InterfaceType, e Eface) (ret Eface) {
Type *t;
Eface err;
@@ -542,18 +475,12 @@ runtime·assertE2E(InterfaceType* inter, Eface e, Eface ret)
runtime·panic(err);
}
ret = e;
- FLUSH(&ret);
}
-// func ifaceE2E2(iface any) (ret any, ok bool)
-void
-runtime·assertE2E2(InterfaceType* inter, Eface e, Eface ret, bool ok)
-{
+func assertE2E2(inter *InterfaceType, e Eface) (ret Eface, ok bool) {
USED(inter);
ret = e;
ok = e.type != nil;
- FLUSH(&ret);
- FLUSH(&ok);
}
static uintptr
@@ -641,81 +568,53 @@ runtime·efaceeq_c(Eface e1, Eface e2)
return ifaceeq1(e1.data, e2.data, e1.type);
}
-// ifaceeq(i1 any, i2 any) (ret bool);
-void
-runtime·ifaceeq(Iface i1, Iface i2, bool ret)
-{
+func ifaceeq(i1 Iface, i2 Iface) (ret bool) {
ret = runtime·ifaceeq_c(i1, i2);
- FLUSH(&ret);
}
-// efaceeq(i1 any, i2 any) (ret bool)
-void
-runtime·efaceeq(Eface e1, Eface e2, bool ret)
-{
+func efaceeq(e1 Eface, e2 Eface) (ret bool) {
ret = runtime·efaceeq_c(e1, e2);
- FLUSH(&ret);
}
-// ifacethash(i1 any) (ret uint32);
-void
-runtime·ifacethash(Iface i1, uint32 ret)
-{
+func ifacethash(i1 Iface) (ret uint32) {
Itab *tab;
ret = 0;
tab = i1.tab;
if(tab != nil)
ret = tab->type->hash;
- FLUSH(&ret);
}
-// efacethash(e1 any) (ret uint32)
-void
-runtime·efacethash(Eface e1, uint32 ret)
-{
+func efacethash(e1 Eface) (ret uint32) {
Type *t;
ret = 0;
t = e1.type;
if(t != nil)
ret = t->hash;
- FLUSH(&ret);
}
-void
-reflect·unsafe_Typeof(Eface e, Eface ret)
-{
+func reflect·unsafe_Typeof(e Eface) (ret Eface) {
if(e.type == nil) {
ret.type = nil;
ret.data = nil;
} else {
ret = *(Eface*)(e.type);
}
- FLUSH(&ret);
}
-void
-reflect·unsafe_New(Type *t, void *ret)
-{
+func reflect·unsafe_New(t *Type) (ret *byte) {
ret = runtime·cnew(t);
- FLUSH(&ret);
}
-void
-reflect·unsafe_NewArray(Type *t, intgo n, void *ret)
-{
+func reflect·unsafe_NewArray(t *Type, n int) (ret *byte) {
ret = runtime·cnewarray(t, n);
- FLUSH(&ret);
}
-void
-reflect·typelinks(Slice ret)
-{
+func reflect·typelinks() (ret Slice) {
extern Type *typelink[], *etypelink[];
static int32 first = 1;
ret.array = (byte*)typelink;
ret.len = etypelink - typelink;
ret.cap = ret.len;
- FLUSH(&ret);
}
diff --git a/src/pkg/runtime/lfstack.c b/src/pkg/runtime/lfstack.goc
index 140384d3d..f7b8effa0 100644
--- a/src/pkg/runtime/lfstack.c
+++ b/src/pkg/runtime/lfstack.goc
@@ -4,6 +4,7 @@
// Lock-free stack.
+package runtime
#include "runtime.h"
#include "arch_GOARCH.h"
@@ -17,6 +18,20 @@
#define PTR_MASK ((1ull<<PTR_BITS)-1)
#define CNT_MASK (0ull-1)
+#ifdef _64BIT
+#ifdef GOOS_solaris
+// SPARC64 and Solaris on AMD64 uses all 64 bits of virtual addresses.
+// Use low-order three bits as ABA counter.
+// http://docs.oracle.com/cd/E19120-01/open.solaris/816-5138/6mba6ua5p/index.html
+#undef PTR_BITS
+#undef CNT_MASK
+#undef PTR_MASK
+#define PTR_BITS 0
+#define CNT_MASK 7
+#define PTR_MASK ((0ull-1)<<3)
+#endif
+#endif
+
void
runtime·lfstackpush(uint64 *head, LFNode *node)
{
@@ -57,9 +72,10 @@ runtime·lfstackpop(uint64 *head)
}
}
-void
-runtime·lfstackpop2(uint64 *head, LFNode *node)
-{
+func lfstackpush_go(head *uint64, node *LFNode) {
+ runtime·lfstackpush(head, node);
+}
+
+func lfstackpop_go(head *uint64) (node *LFNode) {
node = runtime·lfstackpop(head);
- FLUSH(&node);
}
diff --git a/src/pkg/runtime/lfstack_test.go b/src/pkg/runtime/lfstack_test.go
index 505aae605..e51877704 100644
--- a/src/pkg/runtime/lfstack_test.go
+++ b/src/pkg/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/src/pkg/runtime/lock_futex.c b/src/pkg/runtime/lock_futex.c
index e6e9be923..c16ac905d 100644
--- a/src/pkg/runtime/lock_futex.c
+++ b/src/pkg/runtime/lock_futex.c
@@ -130,8 +130,11 @@ runtime·notesleep(Note *n)
{
if(g != 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;
+ }
}
#pragma textflag NOSPLIT
@@ -143,8 +146,11 @@ notetsleep(Note *n, int64 ns, int64 deadline, int64 now)
// 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;
}
@@ -153,7 +159,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/src/pkg/runtime/lock_sema.c b/src/pkg/runtime/lock_sema.c
index 3d58cc87f..ff8fdfd42 100644
--- a/src/pkg/runtime/lock_sema.c
+++ b/src/pkg/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"
#include "stack.h"
@@ -161,7 +161,9 @@ runtime·notesleep(Note *n)
return;
}
// Queued. Sleep.
+ m->blocked = true;
runtime·semasleep(-1);
+ m->blocked = false;
}
#pragma textflag NOSPLIT
@@ -181,18 +183,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();
@@ -214,8 +221,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/src/pkg/runtime/malloc.goc b/src/pkg/runtime/malloc.goc
index c3ede4abd..7b7e350d8 100644
--- a/src/pkg/runtime/malloc.goc
+++ b/src/pkg/runtime/malloc.goc
@@ -19,6 +19,8 @@ package runtime
// Mark mheap as 'no pointers', it does not contain interesting pointers but occupies ~45K.
#pragma dataflag NOPTR
MHeap runtime·mheap;
+#pragma dataflag NOPTR
+MStats mstats;
int32 runtime·checking;
@@ -26,6 +28,10 @@ extern MStats mstats; // defined in zruntime_def_$GOOS_$GOARCH.go
extern volatile intgo 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.
@@ -34,12 +40,12 @@ void*
runtime·mallocgc(uintptr size, uintptr typ, uint32 flag)
{
int32 sizeclass;
+ uintptr tinysize, size1;
intgo rate;
MCache *c;
- MCacheList *l;
- uintptr npages;
MSpan *s;
- MLink *v;
+ MLink *v, *next;
+ byte *tiny;
if(size == 0) {
// All 0-length allocations use this pointer.
@@ -49,8 +55,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;
@@ -58,7 +64,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(m->locks == 0 && g->preempt) // restore the preemption request in case we've cleared it in newstack
+ g->stackguard0 = StackPreempt;
+ 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)
@@ -66,87 +147,117 @@ 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);
+
+ if(raceenabled)
+ runtime·racemalloc(v, size);
+
+ if(runtime·debug.allocfreetrace)
+ runtime·tracealloc(v, size, typ);
+
+ if(!(flag & FlagNoProfiling) && (rate = runtime·MemProfileRate) > 0) {
+ if(size < rate && size < c->next_sample)
+ c->next_sample -= size;
+ else
+ profilealloc(v, size);
}
- m->mallocing = 0;
- if(UseSpanType && !(flag & FlagNoScan) && typ != 0 && m->settype_bufsize == nelem(m->settype_buf))
- runtime·settype_flush(m);
m->locks--;
if(m->locks == 0 && g->preempt) // restore the preemption request in case we've cleared it in newstack
g->stackguard0 = StackPreempt;
- if(!(flag & FlagNoProfiling) && (rate = runtime·MemProfileRate) > 0) {
- if(size >= rate)
- goto profile;
- if(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(!(flag & FlagNoInvokeGC) && mstats.heap_alloc >= mstats.next_gc)
runtime·gc(0);
- if(raceenabled)
- runtime·racemalloc(v, size);
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 = 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*
runtime·malloc(uintptr size)
{
@@ -160,7 +271,6 @@ runtime·free(void *v)
int32 sizeclass;
MSpan *s;
MCache *c;
- uint32 prof;
uintptr size;
if(v == nil)
@@ -177,39 +287,73 @@ runtime·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;
}
@@ -261,37 +405,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)
{
@@ -314,33 +427,42 @@ runtime·purgecachedstats(MCache *c)
}
}
-uintptr runtime·sizeof_C_MStats = sizeof(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.
+uintptr runtime·sizeof_C_MStats = sizeof(MStats) - (NumSizeClasses - 61) * sizeof(mstats.by_size[0]);
#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;
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.
@@ -380,7 +502,8 @@ runtime·mallocinit(void)
spans_size = ROUND(spans_size, PageSize);
for(i = 0; i <= 0x7f; i++) {
p = (void*)(i<<40 | 0x00c0ULL<<32);
- p = runtime·SysReserve(p, bitmap_size + spans_size + arena_size);
+ p_size = bitmap_size + spans_size + arena_size + PageSize;
+ p = runtime·SysReserve(p, p_size, &reserved);
if(p != nil)
break;
}
@@ -422,91 +545,119 @@ 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);
- 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);
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 > 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 <= 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(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 || p+n - h->arena_start >= MaxArena32) {
+ if(p < h->arena_start || 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;
}
@@ -534,7 +685,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
@@ -562,95 +713,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;
- if(sizeof(void*) == 8)
- 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
@@ -683,9 +806,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;
}
@@ -701,11 +822,8 @@ runtime·mal(uintptr n)
}
#pragma textflag NOSPLIT
-void
-runtime·new(Type *typ, uint8 *ret)
-{
+func new(typ *Type) (ret *uint8) {
ret = runtime·mallocgc(typ->size, (uintptr)typ | TypeInfo_SingleObject, typ->kind&KindNoPointers ? FlagNoScan : 0);
- FLUSH(&ret);
}
static void*
@@ -732,7 +850,7 @@ runtime·cnewarray(Type *typ, intgo n)
}
func GC() {
- runtime·gc(1);
+ runtime·gc(2); // force GC and do eager sweep
}
func SetFinalizer(obj Eface, finalizer Eface) {
@@ -754,14 +872,30 @@ func SetFinalizer(obj Eface, finalizer Eface) {
runtime·printf("runtime.SetFinalizer: first argument is %S, not pointer\n", *obj.type->string);
goto throw;
}
+ ot = (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->elem != nil && ot->elem->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.data < runtime·mheap.arena_start || runtime·mheap.arena_used <= (byte*)obj.data)
+ return;
if(!runtime·mlookup(obj.data, &base, &size, nil) || obj.data != 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->elem == nil || (ot->elem->kind&KindNoPointers) == 0 || ot->elem->size >= TinySize) {
+ runtime·printf("runtime.SetFinalizer: pointer not at beginning of allocated block (%p)\n", obj.data);
+ goto throw;
+ }
}
- nret = 0;
- ot = (PtrType*)obj.type;
- fint = nil;
if(finalizer.type != nil) {
+ runtime·createfing();
if(finalizer.type->kind != KindFunc)
goto badfunc;
ft = (FuncType*)finalizer.type;
@@ -781,16 +915,20 @@ func SetFinalizer(obj Eface, finalizer Eface) {
goto badfunc;
// compute size needed for return parameters
+ nret = 0;
for(i=0; i<ft->out.len; i++) {
t = ((Type**)ft->out.array)[i];
nret = ROUND(nret, t->align) + t->size;
}
nret = ROUND(nret, sizeof(void*));
- }
-
- if(!runtime·addfinalizer(obj.data, finalizer.data, nret, fint, ot)) {
- runtime·printf("runtime.SetFinalizer: finalizer already set\n");
- goto throw;
+ ot = (PtrType*)obj.type;
+ if(!runtime·addfinalizer(obj.data, finalizer.data, nret, fint, 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.data);
}
return;
diff --git a/src/pkg/runtime/malloc.h b/src/pkg/runtime/malloc.h
index 2c66c6fa7..798c130ad 100644
--- a/src/pkg/runtime/malloc.h
+++ b/src/pkg/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
@@ -255,8 +275,9 @@ struct MStats
} by_size[NumSizeClasses];
};
-#define mstats runtime·memStats /* name shared with Go */
+#define mstats runtime·memStats
extern MStats mstats;
+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,44 @@ 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;
+ uintptr nret;
+ Type* fint;
+ 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 +421,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 +452,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 +461,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 +479,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 +499,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 +512,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 +524,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 +533,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(Type*);
void* runtime·cnewarray(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
@@ -477,13 +568,25 @@ enum
};
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·iterate_memprof(void (*callback)(Bucket*, uintptr, uintptr*, 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·walkfintab(void (*fn)(void*));
+void runtime·setprofilebucket(void *p, Bucket *b);
+
+bool runtime·addfinalizer(void*, FuncVal *fn, uintptr, Type*, PtrType*);
+void runtime·removefinalizer(void*);
+void runtime·queuefinalizer(byte *p, FuncVal *fn, uintptr nret, Type *fint, PtrType *ot);
+
+void runtime·freeallspecials(MSpan *span, void *p, uintptr size);
+bool runtime·freespecial(Special *s, void *p, uintptr size, bool freed);
enum
{
@@ -495,8 +598,46 @@ 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)
diff --git a/src/pkg/runtime/map_test.go b/src/pkg/runtime/map_test.go
index a221cb28c..e4e838349 100644
--- a/src/pkg/runtime/map_test.go
+++ b/src/pkg/runtime/map_test.go
@@ -409,3 +409,69 @@ func TestMapNanGrowIterator(t *testing.T) {
t.Fatalf("missing value")
}
}
+
+func TestMapIterOrder(t *testing.T) {
+ for _, n := range [...]int{3, 7, 9, 15} {
+ // Make m be {0: true, 1: true, ..., n-1: true}.
+ m := make(map[int]bool)
+ for i := 0; i < n; i++ {
+ m[i] = true
+ }
+ // Check that iterating over the map produces at least two different orderings.
+ ord := func() []int {
+ var s []int
+ for key := range m {
+ s = append(s, key)
+ }
+ 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)
+ }
+ }
+}
+
+func TestMapStringBytesLookup(t *testing.T) {
+ // Use large string keys to avoid small-allocation coalescing,
+ // which can cause AllocsPerRun to report lower counts than it should.
+ 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)
+ }
+}
diff --git a/src/pkg/runtime/mapspeed_test.go b/src/pkg/runtime/mapspeed_test.go
index d643d9898..da45ea11e 100644
--- a/src/pkg/runtime/mapspeed_test.go
+++ b/src/pkg/runtime/mapspeed_test.go
@@ -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/src/pkg/runtime/mcache.c b/src/pkg/runtime/mcache.c
index 863030e74..26e3db2dc 100644
--- a/src/pkg/runtime/mcache.c
+++ b/src/pkg/runtime/mcache.c
@@ -10,69 +10,118 @@
#include "arch_GOARCH.h"
#include "malloc.h"
+extern volatile intgo 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");
-}
+ 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;
+ 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/src/pkg/runtime/mcentral.c b/src/pkg/runtime/mcentral.c
index 735a7e6a9..203558fca 100644
--- a/src/pkg/runtime/mcentral.c
+++ b/src/pkg/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 *
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/src/pkg/runtime/mem.go b/src/pkg/runtime/mem.go
index dc735e4a6..fa308b5d9 100644
--- a/src/pkg/runtime/mem.go
+++ b/src/pkg/runtime/mem.go
@@ -60,9 +60,8 @@ type MemStats struct {
var sizeof_C_MStats uintptr // filled in by malloc.goc
-var memStats MemStats
-
func init() {
+ var memStats MemStats
if sizeof_C_MStats != unsafe.Sizeof(memStats) {
println(sizeof_C_MStats, unsafe.Sizeof(memStats))
panic("MStats vs MemStatsType size mismatch")
diff --git a/src/pkg/runtime/mem_darwin.c b/src/pkg/runtime/mem_darwin.c
index a75c46d9d..878c4e1c5 100644
--- a/src/pkg/runtime/mem_darwin.c
+++ b/src/pkg/runtime/mem_darwin.c
@@ -41,11 +41,18 @@ runtime·SysFree(void *v, uintptr n, uint64 *stat)
runtime·munmap(v, n);
}
+void
+runtime·SysFault(void *v, uintptr n)
+{
+ runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
+}
+
void*
-runtime·SysReserve(void *v, uintptr n)
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
{
void *p;
+ *reserved = true;
p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
if(p < (void*)4096)
return nil;
@@ -58,10 +65,12 @@ enum
};
void
-runtime·SysMap(void *v, uintptr n, uint64 *stat)
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
{
void *p;
+ USED(reserved);
+
runtime·xadd64(stat, n);
p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
if(p == (void*)ENOMEM)
diff --git a/src/pkg/runtime/mem_dragonfly.c b/src/pkg/runtime/mem_dragonfly.c
index 025b62ea6..c270332cb 100644
--- a/src/pkg/runtime/mem_dragonfly.c
+++ b/src/pkg/runtime/mem_dragonfly.c
@@ -45,17 +45,26 @@ runtime·SysFree(void *v, uintptr n, uint64 *stat)
runtime·munmap(v, n);
}
+void
+runtime·SysFault(void *v, uintptr n)
+{
+ runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
+}
+
void*
-runtime·SysReserve(void *v, uintptr n)
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
{
void *p;
// On 64-bit, people with ulimit -v set complain if we reserve too
// much address space. Instead, assume that the reservation is okay
// and check the assumption in SysMap.
- if(sizeof(void*) == 8)
+ if(sizeof(void*) == 8 && n > 1LL<<32) {
+ *reserved = false;
return v;
-
+ }
+
+ *reserved = true;
p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
if(p < (void*)4096)
return nil;
@@ -63,14 +72,14 @@ runtime·SysReserve(void *v, uintptr n)
}
void
-runtime·SysMap(void *v, uintptr n, uint64 *stat)
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
{
void *p;
runtime·xadd64(stat, n);
// On 64-bit, we don't actually have v reserved, so tread carefully.
- if(sizeof(void*) == 8) {
+ if(!reserved) {
// TODO(jsing): For some reason DragonFly seems to return
// memory at a different address than we requested, even when
// there should be no reason for it to do so. This can be
diff --git a/src/pkg/runtime/mem_freebsd.c b/src/pkg/runtime/mem_freebsd.c
index 1ee2a555e..586947a2d 100644
--- a/src/pkg/runtime/mem_freebsd.c
+++ b/src/pkg/runtime/mem_freebsd.c
@@ -45,17 +45,26 @@ runtime·SysFree(void *v, uintptr n, uint64 *stat)
runtime·munmap(v, n);
}
+void
+runtime·SysFault(void *v, uintptr n)
+{
+ runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
+}
+
void*
-runtime·SysReserve(void *v, uintptr n)
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
{
void *p;
// On 64-bit, people with ulimit -v set complain if we reserve too
// much address space. Instead, assume that the reservation is okay
// and check the assumption in SysMap.
- if(sizeof(void*) == 8)
+ if(sizeof(void*) == 8 && n > 1LL<<32) {
+ *reserved = false;
return v;
-
+ }
+
+ *reserved = true;
p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
if(p < (void*)4096)
return nil;
@@ -63,14 +72,14 @@ runtime·SysReserve(void *v, uintptr n)
}
void
-runtime·SysMap(void *v, uintptr n, uint64 *stat)
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
{
void *p;
runtime·xadd64(stat, n);
// On 64-bit, we don't actually have v reserved, so tread carefully.
- if(sizeof(void*) == 8) {
+ if(!reserved) {
p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
if(p == (void*)ENOMEM)
runtime·throw("runtime: out of memory");
diff --git a/src/pkg/runtime/mem_linux.c b/src/pkg/runtime/mem_linux.c
index b0f295633..635594c36 100644
--- a/src/pkg/runtime/mem_linux.c
+++ b/src/pkg/runtime/mem_linux.c
@@ -11,6 +11,7 @@
enum
{
_PAGE_SIZE = 4096,
+ EACCES = 13,
};
static int32
@@ -19,15 +20,22 @@ addrspace_free(void *v, uintptr n)
int32 errval;
uintptr chunk;
uintptr off;
- static byte vec[4096];
+
+ // 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];
for(off = 0; off < n; off += chunk) {
chunk = _PAGE_SIZE * sizeof vec;
if(chunk > (n - off))
chunk = n - off;
errval = runtime·mincore((int8*)v + off, chunk, vec);
- // errval is 0 if success, or -(error_code) if error.
- if (errval == 0 || errval != -ENOMEM)
+ // ENOMEM means unmapped, which is what we want.
+ // Anything else we assume means the pages are mapped.
+ if (errval != -ENOMEM)
return 0;
}
return 1;
@@ -91,8 +99,14 @@ runtime·SysFree(void *v, uintptr n, uint64 *stat)
runtime·munmap(v, n);
}
+void
+runtime·SysFault(void *v, uintptr n)
+{
+ runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
+}
+
void*
-runtime·SysReserve(void *v, uintptr n)
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
{
void *p;
@@ -100,7 +114,7 @@ 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 > 1LL<<32) {
p = mmap_fixed(v, 64<<10, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
if (p != v) {
if(p >= (void*)4096)
@@ -108,24 +122,26 @@ runtime·SysReserve(void *v, uintptr n)
return nil;
}
runtime·munmap(p, 64<<10);
+ *reserved = false;
return v;
}
p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
if((uintptr)p < 4096)
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;
runtime·xadd64(stat, n);
// 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, -1, 0);
if(p == (void*)ENOMEM)
runtime·throw("runtime: out of memory");
diff --git a/src/pkg/runtime/mem_nacl.c b/src/pkg/runtime/mem_nacl.c
new file mode 100644
index 000000000..e2bca40a4
--- /dev/null
+++ b/src/pkg/runtime/mem_nacl.c
@@ -0,0 +1,118 @@
+// 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_GOARCH.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "malloc.h"
+
+enum
+{
+ Debug = 0,
+};
+
+void*
+runtime·SysAlloc(uintptr n, uint64 *stat)
+{
+ void *v;
+
+ v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(v < (void*)4096) {
+ if(Debug)
+ runtime·printf("SysAlloc(%p): %p\n", n, v);
+ return nil;
+ }
+ runtime·xadd64(stat, n);
+ if(Debug)
+ runtime·printf("SysAlloc(%p) = %p\n", n, v);
+ return v;
+}
+
+void
+runtime·SysUnused(void *v, uintptr n)
+{
+ if(Debug)
+ runtime·printf("SysUnused(%p, %p)\n", v, n);
+}
+
+void
+runtime·SysUsed(void *v, uintptr n)
+{
+ USED(v);
+ USED(n);
+}
+
+void
+runtime·SysFree(void *v, uintptr n, uint64 *stat)
+{
+ if(Debug)
+ runtime·printf("SysFree(%p, %p)\n", v, n);
+ runtime·xadd64(stat, -(uint64)n);
+ runtime·munmap(v, n);
+}
+
+void
+runtime·SysFault(void *v, uintptr n)
+{
+ runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
+}
+
+void*
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
+{
+ void *p;
+
+ // On 64-bit, people with ulimit -v set complain if we reserve too
+ // much address space. Instead, assume that the reservation is okay
+ // and check the assumption in SysMap.
+ if(NaCl || sizeof(void*) == 8) {
+ *reserved = false;
+ return v;
+ }
+
+ p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(p < (void*)4096)
+ return nil;
+ *reserved = true;
+ return p;
+}
+
+void
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
+{
+ void *p;
+
+ runtime·xadd64(stat, n);
+
+ // On 64-bit, we don't actually have v reserved, so tread carefully.
+ if(!reserved) {
+ p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(p == (void*)ENOMEM) {
+ runtime·printf("SysMap(%p, %p): %p\n", v, n, p);
+ runtime·throw("runtime: out of memory");
+ }
+ if(p != v) {
+ runtime·printf("SysMap(%p, %p): %p\n", v, n, p);
+ runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
+ runtime·throw("runtime: address space conflict");
+ }
+ if(Debug)
+ runtime·printf("SysMap(%p, %p) = %p\n", v, n, p);
+ return;
+ }
+
+ p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
+ if(p == (void*)ENOMEM) {
+ runtime·printf("SysMap(%p, %p): %p\n", v, n, p);
+ runtime·throw("runtime: out of memory");
+ }
+ if(p != v) {
+ runtime·printf("SysMap(%p, %p): %p\n", v, n, p);
+ runtime·printf("mmap MAP_FIXED %p returned %p\n", v, p);
+ runtime·throw("runtime: cannot map pages in arena address space");
+ }
+ if(Debug)
+ runtime·printf("SysMap(%p, %p) = %p\n", v, n, p);
+}
diff --git a/src/pkg/runtime/mem_netbsd.c b/src/pkg/runtime/mem_netbsd.c
index 91e36eb60..861ae90c7 100644
--- a/src/pkg/runtime/mem_netbsd.c
+++ b/src/pkg/runtime/mem_netbsd.c
@@ -45,32 +45,41 @@ runtime·SysFree(void *v, uintptr n, uint64 *stat)
runtime·munmap(v, n);
}
+void
+runtime·SysFault(void *v, uintptr n)
+{
+ runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
+}
+
void*
-runtime·SysReserve(void *v, uintptr n)
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
{
void *p;
// On 64-bit, people with ulimit -v set complain if we reserve too
// much address space. Instead, assume that the reservation is okay
// and check the assumption in SysMap.
- if(sizeof(void*) == 8)
+ if(sizeof(void*) == 8 && n > 1LL<<32) {
+ *reserved = false;
return v;
+ }
p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
if(p < (void*)4096)
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;
runtime·xadd64(stat, n);
// On 64-bit, we don't actually have v reserved, so tread carefully.
- if(sizeof(void*) == 8) {
+ if(!reserved) {
p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
if(p == (void*)ENOMEM)
runtime·throw("runtime: out of memory");
diff --git a/src/pkg/runtime/mem_openbsd.c b/src/pkg/runtime/mem_openbsd.c
index 91e36eb60..861ae90c7 100644
--- a/src/pkg/runtime/mem_openbsd.c
+++ b/src/pkg/runtime/mem_openbsd.c
@@ -45,32 +45,41 @@ runtime·SysFree(void *v, uintptr n, uint64 *stat)
runtime·munmap(v, n);
}
+void
+runtime·SysFault(void *v, uintptr n)
+{
+ runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
+}
+
void*
-runtime·SysReserve(void *v, uintptr n)
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
{
void *p;
// On 64-bit, people with ulimit -v set complain if we reserve too
// much address space. Instead, assume that the reservation is okay
// and check the assumption in SysMap.
- if(sizeof(void*) == 8)
+ if(sizeof(void*) == 8 && n > 1LL<<32) {
+ *reserved = false;
return v;
+ }
p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
if(p < (void*)4096)
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;
runtime·xadd64(stat, n);
// On 64-bit, we don't actually have v reserved, so tread carefully.
- if(sizeof(void*) == 8) {
+ if(!reserved) {
p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
if(p == (void*)ENOMEM)
runtime·throw("runtime: out of memory");
diff --git a/src/pkg/runtime/mem_plan9.c b/src/pkg/runtime/mem_plan9.c
index edf970b2f..bbf04c7ed 100644
--- a/src/pkg/runtime/mem_plan9.c
+++ b/src/pkg/runtime/mem_plan9.c
@@ -62,14 +62,21 @@ runtime·SysUsed(void *v, uintptr nbytes)
}
void
-runtime·SysMap(void *v, uintptr nbytes, uint64 *stat)
+runtime·SysMap(void *v, uintptr nbytes, bool reserved, uint64 *stat)
{
- USED(v, nbytes, stat);
+ USED(v, nbytes, reserved, stat);
+}
+
+void
+runtime·SysFault(void *v, uintptr nbytes)
+{
+ USED(v, nbytes);
}
void*
-runtime·SysReserve(void *v, uintptr nbytes)
+runtime·SysReserve(void *v, uintptr nbytes, bool *reserved)
{
USED(v);
+ *reserved = true;
return runtime·SysAlloc(nbytes, &mstats.heap_sys);
}
diff --git a/src/pkg/runtime/mem_solaris.c b/src/pkg/runtime/mem_solaris.c
new file mode 100644
index 000000000..034222887
--- /dev/null
+++ b/src/pkg/runtime/mem_solaris.c
@@ -0,0 +1,99 @@
+// 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_GOARCH.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "malloc.h"
+
+enum
+{
+ ENOMEM = 12,
+};
+
+void*
+runtime·SysAlloc(uintptr n, uint64 *stat)
+{
+ void *v;
+
+ v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(v < (void*)4096)
+ return nil;
+ runtime·xadd64(stat, n);
+ return v;
+}
+
+void
+runtime·SysUnused(void *v, uintptr n)
+{
+ USED(v);
+ USED(n);
+}
+
+void
+runtime·SysUsed(void *v, uintptr n)
+{
+ USED(v);
+ USED(n);
+}
+
+void
+runtime·SysFree(void *v, uintptr n, uint64 *stat)
+{
+ runtime·xadd64(stat, -(uint64)n);
+ runtime·munmap(v, n);
+}
+
+void
+runtime·SysFault(void *v, uintptr n)
+{
+ runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
+}
+
+void*
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
+{
+ void *p;
+
+ // On 64-bit, people with ulimit -v set complain if we reserve too
+ // much address space. Instead, assume that the reservation is okay
+ // and check the assumption in SysMap.
+ if(sizeof(void*) == 8 && n > 1LL<<32) {
+ *reserved = false;
+ return v;
+ }
+
+ p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(p < (void*)4096)
+ return nil;
+ *reserved = true;
+ return p;
+}
+
+void
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
+{
+ void *p;
+
+ runtime·xadd64(stat, n);
+
+ // On 64-bit, we don't actually have v reserved, so tread carefully.
+ if(!reserved) {
+ p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(p == (void*)ENOMEM)
+ runtime·throw("runtime: out of memory");
+ if(p != v) {
+ runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
+ runtime·throw("runtime: address space conflict");
+ }
+ return;
+ }
+
+ p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
+ if(p == (void*)ENOMEM)
+ runtime·throw("runtime: out of memory");
+ if(p != v)
+ runtime·throw("runtime: cannot map pages in arena address space");
+}
diff --git a/src/pkg/runtime/mem_windows.c b/src/pkg/runtime/mem_windows.c
index abdc72ad8..77ec6e926 100644
--- a/src/pkg/runtime/mem_windows.c
+++ b/src/pkg/runtime/mem_windows.c
@@ -15,12 +15,15 @@ enum {
MEM_RELEASE = 0x8000,
PAGE_READWRITE = 0x0004,
+ PAGE_NOACCESS = 0x0001,
};
#pragma dynimport runtime·VirtualAlloc VirtualAlloc "kernel32.dll"
#pragma dynimport runtime·VirtualFree VirtualFree "kernel32.dll"
+#pragma dynimport runtime·VirtualProtect VirtualProtect "kernel32.dll"
extern void *runtime·VirtualAlloc;
extern void *runtime·VirtualFree;
+extern void *runtime·VirtualProtect;
void*
runtime·SysAlloc(uintptr n, uint64 *stat)
@@ -33,10 +36,30 @@ void
runtime·SysUnused(void *v, uintptr n)
{
void *r;
+ uintptr small;
r = runtime·stdcall(runtime·VirtualFree, 3, v, n, (uintptr)MEM_DECOMMIT);
- if(r == nil)
- runtime·throw("runtime: failed to decommit pages");
+ if(r != nil)
+ return;
+
+ // Decommit failed. Usual reason is that we've merged memory from two different
+ // VirtualAlloc calls, and Windows will only let each VirtualFree handle pages from
+ // a single VirtualAlloc. It is okay to specify a subset of the pages from a single alloc,
+ // just not pages from multiple allocs. This is a rare case, arising only when we're
+ // trying to give memory back to the operating system, which happens on a time
+ // scale of minutes. It doesn't have to be terribly fast. Instead of extra bookkeeping
+ // on all our VirtualAlloc calls, try freeing successively smaller pieces until
+ // we manage to free something, and then repeat. This ends up being O(n log n)
+ // in the worst case, but that's fast enough.
+ while(n > 0) {
+ small = n;
+ while(small >= 4096 && runtime·stdcall(runtime·VirtualFree, 3, v, small, (uintptr)MEM_DECOMMIT) == nil)
+ small = (small / 2) & ~(4096-1);
+ if(small < 4096)
+ runtime·throw("runtime: failed to decommit pages");
+ v = (byte*)v + small;
+ n -= small;
+ }
}
void
@@ -60,9 +83,17 @@ runtime·SysFree(void *v, uintptr n, uint64 *stat)
runtime·throw("runtime: failed to release pages");
}
+void
+runtime·SysFault(void *v, uintptr n)
+{
+ // SysUnused makes the memory inaccessible and prevents its reuse
+ runtime·SysUnused(v, n);
+}
+
void*
-runtime·SysReserve(void *v, uintptr n)
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
{
+ *reserved = true;
// v is just a hint.
// First try at v.
v = runtime·stdcall(runtime·VirtualAlloc, 4, v, n, (uintptr)MEM_RESERVE, (uintptr)PAGE_READWRITE);
@@ -74,10 +105,12 @@ runtime·SysReserve(void *v, uintptr n)
}
void
-runtime·SysMap(void *v, uintptr n, uint64 *stat)
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
{
void *p;
-
+
+ USED(reserved);
+
runtime·xadd64(stat, n);
p = runtime·stdcall(runtime·VirtualAlloc, 4, v, n, (uintptr)MEM_COMMIT, (uintptr)PAGE_READWRITE);
if(p != v)
diff --git a/src/pkg/runtime/memclr_386.s b/src/pkg/runtime/memclr_386.s
new file mode 100644
index 000000000..4b7580cb4
--- /dev/null
+++ b/src/pkg/runtime/memclr_386.s
@@ -0,0 +1,127 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !plan9
+
+#include "../../cmd/ld/textflag.h"
+
+// void runtime·memclr(void*, uintptr)
+TEXT runtime·memclr(SB), NOSPLIT, $0-8
+ MOVL ptr+0(FP), DI
+ MOVL n+4(FP), BX
+ XORL AX, AX
+
+ // MOVOU seems always faster than REP STOSL.
+clr_tail:
+ TESTL BX, BX
+ JEQ clr_0
+ CMPL BX, $2
+ JBE clr_1or2
+ CMPL BX, $4
+ JBE clr_3or4
+ CMPL BX, $8
+ JBE clr_5through8
+ CMPL BX, $16
+ JBE clr_9through16
+ TESTL $0x4000000, runtime·cpuid_edx(SB) // check for sse2
+ JEQ nosse2
+ PXOR X0, X0
+ CMPL BX, $32
+ JBE clr_17through32
+ CMPL BX, $64
+ JBE clr_33through64
+ CMPL BX, $128
+ JBE clr_65through128
+ CMPL BX, $256
+ JBE clr_129through256
+ // TODO: use branch table and BSR to make this just a single dispatch
+
+clr_loop:
+ MOVOU X0, 0(DI)
+ MOVOU X0, 16(DI)
+ MOVOU X0, 32(DI)
+ MOVOU X0, 48(DI)
+ MOVOU X0, 64(DI)
+ MOVOU X0, 80(DI)
+ MOVOU X0, 96(DI)
+ MOVOU X0, 112(DI)
+ MOVOU X0, 128(DI)
+ MOVOU X0, 144(DI)
+ MOVOU X0, 160(DI)
+ MOVOU X0, 176(DI)
+ MOVOU X0, 192(DI)
+ MOVOU X0, 208(DI)
+ MOVOU X0, 224(DI)
+ MOVOU X0, 240(DI)
+ SUBL $256, BX
+ ADDL $256, DI
+ CMPL BX, $256
+ JAE clr_loop
+ JMP clr_tail
+
+clr_1or2:
+ MOVB AX, (DI)
+ MOVB AX, -1(DI)(BX*1)
+clr_0:
+ RET
+clr_3or4:
+ MOVW AX, (DI)
+ MOVW AX, -2(DI)(BX*1)
+ RET
+clr_5through8:
+ MOVL AX, (DI)
+ MOVL AX, -4(DI)(BX*1)
+ RET
+clr_9through16:
+ MOVL AX, (DI)
+ MOVL AX, 4(DI)
+ MOVL AX, -8(DI)(BX*1)
+ MOVL AX, -4(DI)(BX*1)
+ RET
+clr_17through32:
+ MOVOU X0, (DI)
+ MOVOU X0, -16(DI)(BX*1)
+ RET
+clr_33through64:
+ MOVOU X0, (DI)
+ MOVOU X0, 16(DI)
+ MOVOU X0, -32(DI)(BX*1)
+ MOVOU X0, -16(DI)(BX*1)
+ RET
+clr_65through128:
+ MOVOU X0, (DI)
+ MOVOU X0, 16(DI)
+ MOVOU X0, 32(DI)
+ MOVOU X0, 48(DI)
+ MOVOU X0, -64(DI)(BX*1)
+ MOVOU X0, -48(DI)(BX*1)
+ MOVOU X0, -32(DI)(BX*1)
+ MOVOU X0, -16(DI)(BX*1)
+ RET
+clr_129through256:
+ MOVOU X0, (DI)
+ MOVOU X0, 16(DI)
+ MOVOU X0, 32(DI)
+ MOVOU X0, 48(DI)
+ MOVOU X0, 64(DI)
+ MOVOU X0, 80(DI)
+ MOVOU X0, 96(DI)
+ MOVOU X0, 112(DI)
+ MOVOU X0, -128(DI)(BX*1)
+ MOVOU X0, -112(DI)(BX*1)
+ MOVOU X0, -96(DI)(BX*1)
+ MOVOU X0, -80(DI)(BX*1)
+ MOVOU X0, -64(DI)(BX*1)
+ MOVOU X0, -48(DI)(BX*1)
+ MOVOU X0, -32(DI)(BX*1)
+ MOVOU X0, -16(DI)(BX*1)
+ RET
+nosse2:
+ MOVL BX, CX
+ SHRL $2, CX
+ REP
+ STOSL
+ ANDL $3, BX
+ JNE clr_tail
+ RET
diff --git a/src/pkg/runtime/memclr_amd64.s b/src/pkg/runtime/memclr_amd64.s
new file mode 100644
index 000000000..6b79363b2
--- /dev/null
+++ b/src/pkg/runtime/memclr_amd64.s
@@ -0,0 +1,116 @@
+// 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 !plan9
+
+#include "../../cmd/ld/textflag.h"
+
+// void runtime·memclr(void*, uintptr)
+TEXT runtime·memclr(SB), NOSPLIT, $0-16
+ MOVQ ptr+0(FP), DI
+ MOVQ n+8(FP), BX
+ XORQ AX, AX
+
+ // MOVOU seems always faster than REP STOSQ.
+clr_tail:
+ TESTQ BX, BX
+ JEQ clr_0
+ CMPQ BX, $2
+ JBE clr_1or2
+ CMPQ BX, $4
+ JBE clr_3or4
+ CMPQ BX, $8
+ JBE clr_5through8
+ CMPQ BX, $16
+ JBE clr_9through16
+ PXOR X0, X0
+ CMPQ BX, $32
+ JBE clr_17through32
+ CMPQ BX, $64
+ JBE clr_33through64
+ CMPQ BX, $128
+ JBE clr_65through128
+ CMPQ BX, $256
+ JBE clr_129through256
+ // TODO: use branch table and BSR to make this just a single dispatch
+ // TODO: for really big clears, use MOVNTDQ.
+
+clr_loop:
+ MOVOU X0, 0(DI)
+ MOVOU X0, 16(DI)
+ MOVOU X0, 32(DI)
+ MOVOU X0, 48(DI)
+ MOVOU X0, 64(DI)
+ MOVOU X0, 80(DI)
+ MOVOU X0, 96(DI)
+ MOVOU X0, 112(DI)
+ MOVOU X0, 128(DI)
+ MOVOU X0, 144(DI)
+ MOVOU X0, 160(DI)
+ MOVOU X0, 176(DI)
+ MOVOU X0, 192(DI)
+ MOVOU X0, 208(DI)
+ MOVOU X0, 224(DI)
+ MOVOU X0, 240(DI)
+ SUBQ $256, BX
+ ADDQ $256, DI
+ CMPQ BX, $256
+ JAE clr_loop
+ JMP clr_tail
+
+clr_1or2:
+ MOVB AX, (DI)
+ MOVB AX, -1(DI)(BX*1)
+clr_0:
+ RET
+clr_3or4:
+ MOVW AX, (DI)
+ MOVW AX, -2(DI)(BX*1)
+ RET
+clr_5through8:
+ MOVL AX, (DI)
+ MOVL AX, -4(DI)(BX*1)
+ RET
+clr_9through16:
+ MOVQ AX, (DI)
+ MOVQ AX, -8(DI)(BX*1)
+ RET
+clr_17through32:
+ MOVOU X0, (DI)
+ MOVOU X0, -16(DI)(BX*1)
+ RET
+clr_33through64:
+ MOVOU X0, (DI)
+ MOVOU X0, 16(DI)
+ MOVOU X0, -32(DI)(BX*1)
+ MOVOU X0, -16(DI)(BX*1)
+ RET
+clr_65through128:
+ MOVOU X0, (DI)
+ MOVOU X0, 16(DI)
+ MOVOU X0, 32(DI)
+ MOVOU X0, 48(DI)
+ MOVOU X0, -64(DI)(BX*1)
+ MOVOU X0, -48(DI)(BX*1)
+ MOVOU X0, -32(DI)(BX*1)
+ MOVOU X0, -16(DI)(BX*1)
+ RET
+clr_129through256:
+ MOVOU X0, (DI)
+ MOVOU X0, 16(DI)
+ MOVOU X0, 32(DI)
+ MOVOU X0, 48(DI)
+ MOVOU X0, 64(DI)
+ MOVOU X0, 80(DI)
+ MOVOU X0, 96(DI)
+ MOVOU X0, 112(DI)
+ MOVOU X0, -128(DI)(BX*1)
+ MOVOU X0, -112(DI)(BX*1)
+ MOVOU X0, -96(DI)(BX*1)
+ MOVOU X0, -80(DI)(BX*1)
+ MOVOU X0, -64(DI)(BX*1)
+ MOVOU X0, -48(DI)(BX*1)
+ MOVOU X0, -32(DI)(BX*1)
+ MOVOU X0, -16(DI)(BX*1)
+ RET
diff --git a/src/pkg/runtime/memclr_arm.s b/src/pkg/runtime/memclr_arm.s
index d5ff75d7a..b19ea72a3 100644
--- a/src/pkg/runtime/memclr_arm.s
+++ b/src/pkg/runtime/memclr_arm.s
@@ -40,12 +40,6 @@ TEXT runtime·memclr(SB),NOSPLIT,$0-8
CMP $4, R(N) /* need at least 4 bytes to copy */
BLT _1tail
- AND $0xFF, R(0) /* it's a byte */
- SLL $8, R(0), R(TMP) /* replicate to a word */
- ORR R(TMP), R(0)
- SLL $16, R(0), R(TMP)
- ORR R(TMP), R(0)
-
_4align: /* align on 4 */
AND.S $3, R(TO), R(TMP)
BEQ _4aligned
diff --git a/src/pkg/runtime/memclr_plan9_386.s b/src/pkg/runtime/memclr_plan9_386.s
new file mode 100644
index 000000000..9b496785a
--- /dev/null
+++ b/src/pkg/runtime/memclr_plan9_386.s
@@ -0,0 +1,50 @@
+// 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 "../../cmd/ld/textflag.h"
+
+// void runtime·memclr(void*, uintptr)
+TEXT runtime·memclr(SB), NOSPLIT, $0-8
+ MOVL ptr+0(FP), DI
+ MOVL n+4(FP), BX
+ XORL AX, AX
+
+clr_tail:
+ TESTL BX, BX
+ JEQ clr_0
+ CMPL BX, $2
+ JBE clr_1or2
+ CMPL BX, $4
+ JBE clr_3or4
+ CMPL BX, $8
+ JBE clr_5through8
+ CMPL BX, $16
+ JBE clr_9through16
+ MOVL BX, CX
+ SHRL $2, CX
+ REP
+ STOSL
+ ANDL $3, BX
+ JNE clr_tail
+ RET
+
+clr_1or2:
+ MOVB AX, (DI)
+ MOVB AX, -1(DI)(BX*1)
+clr_0:
+ RET
+clr_3or4:
+ MOVW AX, (DI)
+ MOVW AX, -2(DI)(BX*1)
+ RET
+clr_5through8:
+ MOVL AX, (DI)
+ MOVL AX, -4(DI)(BX*1)
+ RET
+clr_9through16:
+ MOVL AX, (DI)
+ MOVL AX, 4(DI)
+ MOVL AX, -8(DI)(BX*1)
+ MOVL AX, -4(DI)(BX*1)
+ RET
diff --git a/src/pkg/runtime/memclr_plan9_amd64.s b/src/pkg/runtime/memclr_plan9_amd64.s
new file mode 100644
index 000000000..6b33054f5
--- /dev/null
+++ b/src/pkg/runtime/memclr_plan9_amd64.s
@@ -0,0 +1,48 @@
+// 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 "../../cmd/ld/textflag.h"
+
+// void runtime·memclr(void*, uintptr)
+TEXT runtime·memclr(SB), NOSPLIT, $0-16
+ MOVQ ptr+0(FP), DI
+ MOVQ n+8(FP), BX
+ XORQ AX, AX
+
+clr_tail:
+ TESTQ BX, BX
+ JEQ clr_0
+ CMPQ BX, $2
+ JBE clr_1or2
+ CMPQ BX, $4
+ JBE clr_3or4
+ CMPQ BX, $8
+ JBE clr_5through8
+ CMPQ BX, $16
+ JBE clr_9through16
+ MOVQ BX, CX
+ SHRQ $2, CX
+ REP
+ STOSQ
+ ANDQ $3, BX
+ JNE clr_tail
+ RET
+
+clr_1or2:
+ MOVB AX, (DI)
+ MOVB AX, -1(DI)(BX*1)
+clr_0:
+ RET
+clr_3or4:
+ MOVW AX, (DI)
+ MOVW AX, -2(DI)(BX*1)
+ RET
+clr_5through8:
+ MOVL AX, (DI)
+ MOVL AX, -4(DI)(BX*1)
+ RET
+clr_9through16:
+ MOVQ AX, (DI)
+ MOVQ AX, -8(DI)(BX*1)
+ RET
diff --git a/src/pkg/runtime/memmove_386.s b/src/pkg/runtime/memmove_386.s
index 13d575973..3aed8ad07 100644
--- a/src/pkg/runtime/memmove_386.s
+++ b/src/pkg/runtime/memmove_386.s
@@ -23,6 +23,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// +build !plan9
+
#include "../../cmd/ld/textflag.h"
TEXT runtime·memmove(SB), NOSPLIT, $0-12
diff --git a/src/pkg/runtime/memmove_amd64.s b/src/pkg/runtime/memmove_amd64.s
index f1641cdb2..5895846db 100644
--- a/src/pkg/runtime/memmove_amd64.s
+++ b/src/pkg/runtime/memmove_amd64.s
@@ -23,6 +23,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// +build !plan9
+
#include "../../cmd/ld/textflag.h"
// void runtime·memmove(void*, void*, uintptr)
diff --git a/src/pkg/runtime/memmove_nacl_amd64p32.s b/src/pkg/runtime/memmove_nacl_amd64p32.s
new file mode 100644
index 000000000..1b5733112
--- /dev/null
+++ b/src/pkg/runtime/memmove_nacl_amd64p32.s
@@ -0,0 +1,46 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "../../cmd/ld/textflag.h"
+
+TEXT runtime·memmove(SB), NOSPLIT, $0-12
+ MOVL to+0(FP), DI
+ MOVL fr+4(FP), SI
+ MOVL n+8(FP), BX
+
+ CMPL SI, DI
+ JLS back
+
+forward:
+ MOVL BX, CX
+ SHRL $3, CX
+ ANDL $7, BX
+ REP; MOVSQ
+ MOVL BX, CX
+ REP; MOVSB
+ RET
+
+back:
+ MOVL SI, CX
+ ADDL BX, CX
+ CMPL CX, DI
+ JLS forward
+
+ ADDL BX, DI
+ ADDL BX, SI
+ STD
+
+ MOVL BX, CX
+ SHRL $3, CX
+ ANDL $7, BX
+ SUBL $8, DI
+ SUBL $8, SI
+ REP; MOVSQ
+ ADDL $7, DI
+ ADDL $7, SI
+ MOVL BX, CX
+ REP; MOVSB
+ CLD
+
+ RET
diff --git a/src/pkg/runtime/memmove_plan9_386.s b/src/pkg/runtime/memmove_plan9_386.s
new file mode 100644
index 000000000..187616cd0
--- /dev/null
+++ b/src/pkg/runtime/memmove_plan9_386.s
@@ -0,0 +1,127 @@
+// Inferno's libkern/memmove-386.s
+// http://code.google.com/p/inferno-os/source/browse/libkern/memmove-386.s
+//
+// 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.
+
+#include "../../cmd/ld/textflag.h"
+
+TEXT runtime·memmove(SB), NOSPLIT, $0-12
+ MOVL to+0(FP), DI
+ MOVL fr+4(FP), SI
+ MOVL n+8(FP), BX
+
+ // REP instructions have a high startup cost, so we handle small sizes
+ // with some straightline code. The REP MOVSL instruction is really fast
+ // for large sizes. The cutover is approximately 1K.
+tail:
+ TESTL BX, BX
+ JEQ move_0
+ CMPL BX, $2
+ JBE move_1or2
+ CMPL BX, $4
+ JBE move_3or4
+ CMPL BX, $8
+ JBE move_5through8
+ CMPL BX, $16
+ JBE move_9through16
+
+/*
+ * check and set for backwards
+ */
+ CMPL SI, DI
+ JLS back
+
+/*
+ * forward copy loop
+ */
+forward:
+ MOVL BX, CX
+ SHRL $2, CX
+ ANDL $3, BX
+
+ REP; MOVSL
+ JMP tail
+/*
+ * check overlap
+ */
+back:
+ MOVL SI, CX
+ ADDL BX, CX
+ CMPL CX, DI
+ JLS forward
+/*
+ * whole thing backwards has
+ * adjusted addresses
+ */
+
+ ADDL BX, DI
+ ADDL BX, SI
+ STD
+
+/*
+ * copy
+ */
+ MOVL BX, CX
+ SHRL $2, CX
+ ANDL $3, BX
+
+ SUBL $4, DI
+ SUBL $4, SI
+ REP; MOVSL
+
+ CLD
+ ADDL $4, DI
+ ADDL $4, SI
+ SUBL BX, DI
+ SUBL BX, SI
+ JMP tail
+
+move_1or2:
+ MOVB (SI), AX
+ MOVB -1(SI)(BX*1), CX
+ MOVB AX, (DI)
+ MOVB CX, -1(DI)(BX*1)
+move_0:
+ RET
+move_3or4:
+ MOVW (SI), AX
+ MOVW -2(SI)(BX*1), CX
+ MOVW AX, (DI)
+ MOVW CX, -2(DI)(BX*1)
+ RET
+move_5through8:
+ MOVL (SI), AX
+ MOVL -4(SI)(BX*1), CX
+ MOVL AX, (DI)
+ MOVL CX, -4(DI)(BX*1)
+ RET
+move_9through16:
+ MOVL (SI), AX
+ MOVL 4(SI), CX
+ MOVL -8(SI)(BX*1), DX
+ MOVL -4(SI)(BX*1), BP
+ MOVL AX, (DI)
+ MOVL CX, 4(DI)
+ MOVL DX, -8(DI)(BX*1)
+ MOVL BP, -4(DI)(BX*1)
+ RET
diff --git a/src/pkg/runtime/memmove_plan9_amd64.s b/src/pkg/runtime/memmove_plan9_amd64.s
new file mode 100644
index 000000000..60108273c
--- /dev/null
+++ b/src/pkg/runtime/memmove_plan9_amd64.s
@@ -0,0 +1,126 @@
+// Derived from Inferno's libkern/memmove-386.s (adapted for amd64)
+// http://code.google.com/p/inferno-os/source/browse/libkern/memmove-386.s
+//
+// 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.
+
+#include "../../cmd/ld/textflag.h"
+
+// void runtime·memmove(void*, void*, uintptr)
+TEXT runtime·memmove(SB), NOSPLIT, $0-24
+
+ MOVQ to+0(FP), DI
+ MOVQ fr+8(FP), SI
+ MOVQ n+16(FP), BX
+
+ // REP instructions have a high startup cost, so we handle small sizes
+ // with some straightline code. The REP MOVSQ instruction is really fast
+ // for large sizes. The cutover is approximately 1K.
+tail:
+ TESTQ BX, BX
+ JEQ move_0
+ CMPQ BX, $2
+ JBE move_1or2
+ CMPQ BX, $4
+ JBE move_3or4
+ CMPQ BX, $8
+ JBE move_5through8
+ CMPQ BX, $16
+ JBE move_9through16
+
+/*
+ * check and set for backwards
+ */
+ CMPQ SI, DI
+ JLS back
+
+/*
+ * forward copy loop
+ */
+forward:
+ MOVQ BX, CX
+ SHRQ $3, CX
+ ANDQ $7, BX
+
+ REP; MOVSQ
+ JMP tail
+
+back:
+/*
+ * check overlap
+ */
+ MOVQ SI, CX
+ ADDQ BX, CX
+ CMPQ CX, DI
+ JLS forward
+
+/*
+ * whole thing backwards has
+ * adjusted addresses
+ */
+ ADDQ BX, DI
+ ADDQ BX, SI
+ STD
+
+/*
+ * copy
+ */
+ MOVQ BX, CX
+ SHRQ $3, CX
+ ANDQ $7, BX
+
+ SUBQ $8, DI
+ SUBQ $8, SI
+ REP; MOVSQ
+
+ CLD
+ ADDQ $8, DI
+ ADDQ $8, SI
+ SUBQ BX, DI
+ SUBQ BX, SI
+ JMP tail
+
+move_1or2:
+ MOVB (SI), AX
+ MOVB -1(SI)(BX*1), CX
+ MOVB AX, (DI)
+ MOVB CX, -1(DI)(BX*1)
+move_0:
+ RET
+move_3or4:
+ MOVW (SI), AX
+ MOVW -2(SI)(BX*1), CX
+ MOVW AX, (DI)
+ MOVW CX, -2(DI)(BX*1)
+ RET
+move_5through8:
+ MOVL (SI), AX
+ MOVL -4(SI)(BX*1), CX
+ MOVL AX, (DI)
+ MOVL CX, -4(DI)(BX*1)
+ RET
+move_9through16:
+ MOVQ (SI), AX
+ MOVQ -8(SI)(BX*1), CX
+ MOVQ AX, (DI)
+ MOVQ CX, -8(DI)(BX*1)
+ RET
diff --git a/src/pkg/runtime/memmove_test.go b/src/pkg/runtime/memmove_test.go
index 9525f0682..540f0feb5 100644
--- a/src/pkg/runtime/memmove_test.go
+++ b/src/pkg/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,154 @@ 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 BenchmarkClearFat32(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ var x [32]byte
+ _ = x
+ }
+}
+func BenchmarkClearFat64(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ var x [64]byte
+ _ = x
+ }
+}
+func BenchmarkClearFat128(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ var x [128]byte
+ _ = x
+ }
+}
+func BenchmarkClearFat256(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ var x [256]byte
+ _ = x
+ }
+}
+func BenchmarkClearFat512(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ var x [512]byte
+ _ = x
+ }
+}
+func BenchmarkClearFat1024(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ var x [1024]byte
+ _ = x
+ }
+}
+
+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/src/pkg/runtime/mfinal.c b/src/pkg/runtime/mfinal.c
deleted file mode 100644
index 3e524d3e0..000000000
--- a/src/pkg/runtime/mfinal.c
+++ /dev/null
@@ -1,219 +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_GOARCH.h"
-#include "malloc.h"
-#include "type.h"
-
-enum { debug = 0 };
-
-typedef struct Fin Fin;
-struct Fin
-{
- FuncVal *fn;
- uintptr nret;
- Type *fint;
- PtrType *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 **key;
- 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[CacheLineSize - sizeof(Fintab)];
-} fintab[TABSZ];
-
-static void
-addfintab(Fintab *t, void *k, FuncVal *fn, uintptr nret, Type *fint, PtrType *ot)
-{
- int32 i, j;
-
- i = (uintptr)k % (uintptr)t->max;
- for(j=0; j<t->max; j++) {
- if(t->key[i] == nil) {
- t->nkey++;
- goto ret;
- }
- if(t->key[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->key[i] = k;
- t->val[i].fn = fn;
- t->val[i].nret = nret;
- t->val[i].fint = fint;
- 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->key[i] == nil)
- return false;
- if(t->key[i] == k) {
- if(f)
- *f = t->val[i];
- if(del) {
- t->key[i] = (void*)-1;
- t->val[i].fn = nil;
- t->val[i].nret = 0;
- 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.key = runtime·mallocgc(newtab.max*sizeof newtab.key[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->key[i];
- if(k != nil && k != (void*)-1)
- addfintab(&newtab, k, tab->val[i].fn, tab->val[i].nret, tab->val[i].fint, tab->val[i].ot);
- }
-
- runtime·free(tab->key);
- runtime·free(tab->val);
-
- tab->key = newtab.key;
- tab->val = newtab.val;
- tab->nkey = newtab.nkey;
- tab->ndead = newtab.ndead;
- tab->max = newtab.max;
-}
-
-bool
-runtime·addfinalizer(void *p, FuncVal *f, uintptr nret, Type *fint, PtrType *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, nret, fint, 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, uintptr *nret, Type **fint, PtrType **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;
- *nret = f.nret;
- *fint = f.fint;
- *ot = f.ot;
- return true;
-}
-
-void
-runtime·walkfintab(void (*fn)(void*))
-{
- void **key;
- void **ekey;
- int32 i;
-
- for(i=0; i<TABSZ; i++) {
- runtime·lock(&fintab[i]);
- key = fintab[i].key;
- ekey = key + fintab[i].max;
- for(; key < ekey; key++)
- if(*key != nil && *key != ((void*)-1))
- fn(*key);
- runtime·unlock(&fintab[i]);
- }
-}
diff --git a/src/pkg/runtime/mfinal_test.go b/src/pkg/runtime/mfinal_test.go
index 6efef9bb0..6b53888ab 100644
--- a/src/pkg/runtime/mfinal_test.go
+++ b/src/pkg/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
@@ -46,13 +45,15 @@ func TestFinalizerType(t *testing.T) {
}
for _, tt := range finalizerTests {
+ done := make(chan bool, 1)
go func() {
v := new(int)
*v = 97531
runtime.SetFinalizer(tt.convert(v), tt.finalizer)
v = nil
+ done <- true
}()
- time.Sleep(1 * time.Second)
+ <-done
runtime.GC()
select {
case <-ch:
@@ -73,6 +74,7 @@ func TestFinalizerInterfaceBig(t *testing.T) {
t.Skipf("Skipping on non-amd64 machine")
}
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 +89,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 +103,137 @@ 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)
+ }
+}
+
+// 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
+ }
+ 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) {
+ 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")
}
- wg.Wait()
+ 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/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c
index 761f128a8..392da535b 100644
--- a/src/pkg/runtime/mgc0.c
+++ b/src/pkg/runtime/mgc0.c
@@ -2,13 +2,60 @@
// 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 "runtime.h"
#include "arch_GOARCH.h"
#include "malloc.h"
#include "stack.h"
#include "mgc0.h"
+#include "chan.h"
#include "race.h"
#include "type.h"
#include "typekind.h"
@@ -17,14 +64,11 @@
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,
@@ -34,46 +78,50 @@ 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 *f)
+{
+ poolcleanup = f;
+}
+
+static void
+clearpools(void)
+{
+ P *p, **pp;
+ MCache *c;
+ int32 i;
+
+ // clear sync.Pool's
+ if(poolcleanup != nil)
+ reflect·call(poolcleanup, nil, 0, 0);
-#define bitMask (bitBlockBoundary | bitAllocated | bitMarked | bitSpecial)
+ for(pp=runtime·allp; p=*pp; pp++) {
+ // clear tinyalloc pool
+ c = p->mcache;
+ if(c != nil) {
+ c->tiny = nil;
+ c->tinysize = 0;
+ }
+ // clear defer pools
+ for(i=0; i<nelem(p->deferpool); i++)
+ p->deferpool[i] = nil;
+ }
+}
// Holding worldsema grants an M the right to try to stop the world.
// The procedure is:
@@ -98,11 +146,10 @@ struct Obj
uintptr ti; // type info
};
-// 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];
@@ -138,39 +185,44 @@ extern byte ebss[];
extern byte gcdata[];
extern byte gcbss[];
-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 Lock gclock;
+static G* fing;
-static void runfinq(void);
+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 bool scanframe(Stkframe *frame, void *wbufp);
+static void addstackroots(G *gp, Workbuf **wbufp);
+
+static FuncVal runfinqv = {runfinq};
+static FuncVal bgsweepv = {bgsweep};
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;
enum {
@@ -207,6 +259,8 @@ static struct {
uint64 foundword;
uint64 foundspan;
} markonly;
+ uint32 nbgsweep;
+ uint32 npausesweep;
} gcstats;
// markonly marks an object. It returns true if the object
@@ -260,8 +314,7 @@ markonly(void *obj)
// (Manually inlined copy of MHeap_LookupMaybe.)
k = (uintptr)obj>>PageShift;
x = k;
- if(sizeof(void*) == 8)
- x -= (uintptr)runtime·mheap.arena_start>>PageShift;
+ x -= (uintptr)runtime·mheap.arena_start>>PageShift;
s = runtime·mheap.spans[x];
if(s == nil || k < s->start || obj >= s->limit || s->state != MSpanInUse)
return false;
@@ -317,6 +370,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
{
@@ -350,7 +421,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;
@@ -358,17 +429,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);
@@ -387,152 +460,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++;
+
+ // 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");
+ }
- while(ptrbuf < ptrbuf_end) {
- obj = ptrbuf->p;
- ti = ptrbuf->ti;
- ptrbuf++;
+ // obj may be a pointer to a live object.
+ // Try to find the beginning of the object.
- // 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");
- }
+ // Round down to word boundary.
+ if(((uintptr)obj & ((uintptr)PtrSize-1)) != 0) {
+ obj = (void*)((uintptr)obj & ~((uintptr)PtrSize-1));
+ ti = 0;
+ }
- // obj may be a pointer to a live object.
- // Try to find the beginning of the object.
+ // 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;
- // Round down to word boundary.
- if(((uintptr)obj & ((uintptr)PtrSize-1)) != 0) {
- obj = (void*)((uintptr)obj & ~((uintptr)PtrSize-1));
- ti = 0;
- }
+ // 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;
- if(sizeof(void*) == 8)
- 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;
- if(sizeof(void*) == 8)
- 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++;
@@ -570,9 +637,9 @@ 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
@@ -607,8 +674,7 @@ checkptr(void *obj, uintptr objti)
if(t == nil)
return;
x = (uintptr)obj >> PageShift;
- if(sizeof(void*) == 8)
- x -= (uintptr)(runtime·mheap.arena_start)>>PageShift;
+ x -= (uintptr)(runtime·mheap.arena_start)>>PageShift;
s = runtime·mheap.spans[x];
objstart = (byte*)((uintptr)s->start<<PageShift);
if(s->sizeclass != 0) {
@@ -636,8 +702,8 @@ checkptr(void *obj, uintptr objti)
// 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 ? (int8*)t->string->str : (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 ? (int8*)t->string->str : (int8*)"?", pc1, (int32)j, pc1[j], pc2, (int32)j, pc2[j]);
runtime·throw("invalid gc type info");
}
}
@@ -650,30 +716,27 @@ 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 n, i, end_b, elemsize, size, ti, objti, count, type, nobj;
uintptr *pc, precise_type, nominal_size;
uintptr *chan_ret, chancap;
void *obj;
- Type *t;
+ 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;
Hchan *chan;
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.
@@ -681,21 +744,30 @@ 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[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[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)
chan = nil;
@@ -707,17 +779,17 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
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) {
+ 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];
@@ -773,14 +845,22 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
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);
}
} else {
pc = defaultProg;
+ if(Debug > 1)
+ runtime·printf("scanblock %p %D no span types\n", b, (int64)n);
}
if(IgnorePreciseGC)
@@ -788,7 +868,6 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
pc++;
stack_top.b = (uintptr)b;
-
end_b = (uintptr)b + n - PtrSize;
for(;;) {
@@ -801,6 +880,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);
@@ -808,6 +889,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->len, (int64)sliceptr->cap);
if(sliceptr->cap != 0) {
obj = sliceptr->array;
// Can't use slice element type for scanning,
@@ -821,27 +904,34 @@ 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(Debug > 2)
+ runtime·printf("gc_eface @%p: %p %p\n", stack_top.b+pc[1], eface->type, eface->data);
if(eface->type == nil)
continue;
// eface->type
t = eface->type;
if((void*)t >= arena_start && (void*)t < arena_used) {
- *ptrbufpos++ = (PtrTarget){t, 0};
- if(ptrbufpos == ptrbuf_end)
- flushptrbuf(ptrbuf, &ptrbufpos, &wp, &wbuf, &nobj);
+ *sbuf.ptr.pos++ = (PtrTarget){t, 0};
+ if(sbuf.ptr.pos == sbuf.ptr.end)
+ flushptrbuf(&sbuf);
}
// eface->data
@@ -851,8 +941,14 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
continue;
obj = eface->data;
- if((t->kind & ~KindNoPointers) == KindPtr)
- objti = (uintptr)((PtrType*)t)->elem->gc;
+ if((t->kind & ~KindNoPointers) == 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 = ((PtrType*)t)->elem;
+ if(!(et->kind & KindNoPointers))
+ objti = (uintptr)((PtrType*)t)->elem->gc;
+ }
} else {
obj = eface->data;
objti = (uintptr)t->gc;
@@ -863,14 +959,16 @@ 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->tab, nil, iface->data);
if(iface->tab == nil)
continue;
// iface->tab
if((void*)iface->tab >= arena_start && (void*)iface->tab < arena_used) {
- *ptrbufpos++ = (PtrTarget){iface->tab, (uintptr)itabtype->gc};
- if(ptrbufpos == ptrbuf_end)
- flushptrbuf(ptrbuf, &ptrbufpos, &wp, &wbuf, &nobj);
+ *sbuf.ptr.pos++ = (PtrTarget){iface->tab, (uintptr)itabtype->gc};
+ if(sbuf.ptr.pos == sbuf.ptr.end)
+ flushptrbuf(&sbuf);
}
// iface->data
@@ -881,8 +979,14 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
continue;
obj = iface->data;
- if((t->kind & ~KindNoPointers) == KindPtr)
- objti = (uintptr)((PtrType*)t)->elem->gc;
+ if((t->kind & ~KindNoPointers) == 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 = ((PtrType*)t)->elem;
+ if(!(et->kind & KindNoPointers))
+ objti = (uintptr)((PtrType*)t)->elem->gc;
+ }
} else {
obj = iface->data;
objti = (uintptr)t->gc;
@@ -893,11 +997,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(obj >= arena_start && obj < arena_used) {
- *ptrbufpos++ = (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;
@@ -926,7 +1032,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);
@@ -972,13 +1078,17 @@ 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;
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;
@@ -1007,10 +1117,10 @@ 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,
+ *sbuf.obj.pos++ = (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);
+ if(sbuf.obj.pos == sbuf.obj.end)
+ flushobjbuf(&sbuf);
}
}
if(chan_ret == nil)
@@ -1019,14 +1129,15 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
continue;
default:
+ runtime·printf("runtime: invalid GC instruction %p at %p\n", pc[0], pc);
runtime·throw("scanblock: invalid GC instruction");
return;
}
if(obj >= arena_start && obj < arena_used) {
- *ptrbufpos++ = (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);
}
}
@@ -1034,109 +1145,31 @@ 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--;
- }
-
-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<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;
-
- debug_scanblock(obj, size);
+ --sbuf.wp;
+ b = sbuf.wp->p;
+ n = sbuf.wp->n;
+ ti = sbuf.wp->ti;
+ sbuf.nobj--;
}
}
@@ -1196,18 +1229,102 @@ 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:
+ enqueue1(&wbuf, (Obj){data, edata - data, (uintptr)gcdata});
+ break;
+
+ case RootBss:
+ enqueue1(&wbuf, (Obj){bss, ebss - bss, (uintptr)gcbss});
+ 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->fint, 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,
@@ -1304,43 +1421,20 @@ handoff(Workbuf *b)
return b1;
}
-static void
-addroot(Obj obj)
-{
- 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;
- }
- work.roots[work.nroot] = obj;
- work.nroot++;
-}
-
extern byte pclntab[]; // base for f->ptrsoff
-typedef struct BitVector BitVector;
-struct BitVector
+BitVector
+runtime·stackmapdata(StackMap *stackmap, int32 n)
{
- int32 n;
- uint32 data[];
-};
+ if(n < 0 || n >= stackmap->n)
+ runtime·throw("stackmapdata: index out of range");
+ return (BitVector){stackmap->nbit, stackmap->data + n*((stackmap->nbit+31)/32)};
+}
// Scans an interface data value when the interface type indicates
// that it is a pointer.
static void
-scaninterfacedata(uintptr bits, byte *scanp, bool afterprologue)
+scaninterfacedata(uintptr bits, byte *scanp, bool afterprologue, void *wbufp)
{
Itab *tab;
Type *type;
@@ -1356,16 +1450,17 @@ scaninterfacedata(uintptr bits, byte *scanp, bool afterprologue)
return;
}
}
- addroot((Obj){scanp+PtrSize, PtrSize, 0});
+ enqueue1(wbufp, (Obj){scanp+PtrSize, PtrSize, 0});
}
// Starting from scanp, scans words corresponding to set bits.
static void
-scanbitvector(byte *scanp, BitVector *bv, bool afterprologue)
+scanbitvector(Func *f, bool precise, byte *scanp, BitVector *bv, bool afterprologue, void *wbufp)
{
uintptr word, bits;
uint32 *wordp;
int32 i, remptrs;
+ byte *p;
wordp = bv->data;
for(remptrs = bv->n; remptrs > 0; remptrs -= 32) {
@@ -1377,11 +1472,88 @@ scanbitvector(byte *scanp, BitVector *bv, bool afterprologue)
i /= BitsPerPointer;
for(; i > 0; i--) {
bits = word & 3;
- if(bits != BitsNoPointer && *(void**)scanp != nil)
- if(bits == BitsPointer)
- addroot((Obj){scanp, PtrSize, 0});
- else
- scaninterfacedata(bits, scanp, afterprologue);
+ switch(bits) {
+ case BitsDead:
+ if(runtime·debug.gcdead)
+ *(uintptr*)scanp = PoisonGC;
+ break;
+ case BitsScalar:
+ break;
+ case BitsPointer:
+ p = *(byte**)scanp;
+ if(p != nil) {
+ if(Debug > 2)
+ runtime·printf("frame %s @%p: ptr %p\n", runtime·funcname(f), scanp, p);
+ if(precise && (p < (byte*)PageSize || (uintptr)p == PoisonGC || (uintptr)p == PoisonStack)) {
+ // Looks like a junk value in a pointer slot.
+ // Liveness analysis wrong?
+ m->traceback = 2;
+ runtime·printf("bad pointer in frame %s at %p: %p\n", runtime·funcname(f), scanp, p);
+ runtime·throw("bad pointer in scanbitvector");
+ }
+ enqueue1(wbufp, (Obj){scanp, PtrSize, 0});
+ }
+ break;
+ case BitsMultiWord:
+ p = scanp;
+ word >>= BitsPerPointer;
+ scanp += PtrSize;
+ i--;
+ if(i == 0) {
+ // Get next chunk of bits
+ remptrs -= 32;
+ word = *wordp++;
+ if(remptrs < 32)
+ i = remptrs;
+ else
+ i = 32;
+ i /= BitsPerPointer;
+ }
+ switch(word & 3) {
+ case BitsString:
+ if(Debug > 2)
+ runtime·printf("frame %s @%p: string %p/%D\n", runtime·funcname(f), p, ((String*)p)->str, (int64)((String*)p)->len);
+ if(((String*)p)->len != 0)
+ markonly(((String*)p)->str);
+ break;
+ case BitsSlice:
+ word >>= BitsPerPointer;
+ scanp += PtrSize;
+ i--;
+ if(i == 0) {
+ // Get next chunk of bits
+ remptrs -= 32;
+ word = *wordp++;
+ if(remptrs < 32)
+ i = remptrs;
+ else
+ i = 32;
+ i /= BitsPerPointer;
+ }
+ if(Debug > 2)
+ runtime·printf("frame %s @%p: slice %p/%D/%D\n", runtime·funcname(f), p, ((Slice*)p)->array, (int64)((Slice*)p)->len, (int64)((Slice*)p)->cap);
+ if(((Slice*)p)->cap < ((Slice*)p)->len) {
+ m->traceback = 2;
+ runtime·printf("bad slice in frame %s at %p: %p/%p/%p\n", runtime·funcname(f), p, ((byte**)p)[0], ((byte**)p)[1], ((byte**)p)[2]);
+ runtime·throw("slice capacity smaller than length");
+ }
+ if(((Slice*)p)->cap != 0)
+ enqueue1(wbufp, (Obj){p, PtrSize, 0});
+ break;
+ case BitsIface:
+ case BitsEface:
+ if(*(byte**)p != nil) {
+ if(Debug > 2) {
+ if((word&3) == BitsEface)
+ runtime·printf("frame %s @%p: eface %p %p\n", runtime·funcname(f), p, ((uintptr*)p)[0], ((uintptr*)p)[1]);
+ else
+ runtime·printf("frame %s @%p: iface %p %p\n", runtime·funcname(f), p, ((uintptr*)p)[0], ((uintptr*)p)[1]);
+ }
+ scaninterfacedata(word & 3, p, afterprologue, wbufp);
+ }
+ break;
+ }
+ }
word >>= BitsPerPointer;
scanp += PtrSize;
}
@@ -1389,64 +1561,111 @@ scanbitvector(byte *scanp, BitVector *bv, bool afterprologue)
}
// Scan a stack frame: local variables and function arguments/results.
-static void
-addframeroots(Stkframe *frame, void*)
+static bool
+scanframe(Stkframe *frame, void *wbufp)
{
Func *f;
- BitVector *args, *locals;
+ StackMap *stackmap;
+ BitVector bv;
uintptr size;
+ uintptr targetpc;
+ int32 pcdata;
bool afterprologue;
+ bool precise;
f = frame->fn;
+ targetpc = frame->continpc;
+ if(targetpc == 0) {
+ // Frame is dead.
+ return true;
+ }
+ if(targetpc != f->entry)
+ targetpc--;
+ pcdata = runtime·pcdatavalue(f, PCDATA_StackMapIndex, targetpc);
+ if(pcdata == -1) {
+ // We do not have a valid pcdata value but there might be a
+ // stackmap for this function. It is likely that we are looking
+ // at the function prologue, assume so and hope for the best.
+ pcdata = 0;
+ }
// Scan local variables if stack frame has been allocated.
// Use pointer information if known.
afterprologue = (frame->varp > (byte*)frame->sp);
+ precise = false;
if(afterprologue) {
- locals = runtime·funcdata(f, FUNCDATA_GCLocals);
- if(locals == nil) {
+ stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps);
+ if(stackmap == nil) {
// No locals information, scan everything.
size = frame->varp - (byte*)frame->sp;
- addroot((Obj){frame->varp - size, size, 0});
- } else if(locals->n < 0) {
- // Locals size information, scan just the
+ if(Debug > 2)
+ runtime·printf("frame %s unsized locals %p+%p\n", runtime·funcname(f), frame->varp-size, size);
+ enqueue1(wbufp, (Obj){frame->varp - size, size, 0});
+ } else if(stackmap->n < 0) {
+ // Locals size information, scan just the locals.
+ size = -stackmap->n;
+ if(Debug > 2)
+ runtime·printf("frame %s conservative locals %p+%p\n", runtime·funcname(f), frame->varp-size, size);
+ enqueue1(wbufp, (Obj){frame->varp - size, size, 0});
+ } else if(stackmap->n > 0) {
+ // Locals bitmap information, scan just the pointers in
// locals.
- size = -locals->n;
- addroot((Obj){frame->varp - size, size, 0});
- } else if(locals->n > 0) {
- // Locals bitmap information, scan just the
- // pointers in locals.
- size = (locals->n*PtrSize) / BitsPerPointer;
- scanbitvector(frame->varp - size, locals, afterprologue);
+ if(pcdata < 0 || pcdata >= stackmap->n) {
+ // don't know where we are
+ runtime·printf("pcdata is %d and %d stack map entries for %s (targetpc=%p)\n",
+ pcdata, stackmap->n, runtime·funcname(f), targetpc);
+ runtime·throw("scanframe: bad symbol table");
+ }
+ bv = runtime·stackmapdata(stackmap, pcdata);
+ size = (bv.n * PtrSize) / BitsPerPointer;
+ precise = true;
+ scanbitvector(f, true, frame->varp - size, &bv, afterprologue, wbufp);
}
}
// Scan arguments.
// Use pointer information if known.
- args = runtime·funcdata(f, FUNCDATA_GCArgs);
- if(args != nil && args->n > 0)
- scanbitvector(frame->argp, args, false);
- else
- addroot((Obj){frame->argp, frame->arglen, 0});
+ stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps);
+ if(stackmap != nil) {
+ bv = runtime·stackmapdata(stackmap, pcdata);
+ scanbitvector(f, precise, frame->argp, &bv, true, wbufp);
+ } else {
+ if(Debug > 2)
+ runtime·printf("frame %s conservative args %p+%p\n", runtime·funcname(f), frame->argp, (uintptr)frame->arglen);
+ enqueue1(wbufp, (Obj){frame->argp, frame->arglen, 0});
+ }
+ return true;
}
static void
-addstackroots(G *gp)
+addstackroots(G *gp, Workbuf **wbufp)
{
M *mp;
int32 n;
Stktop *stk;
- uintptr sp, guard, pc, lr;
+ uintptr sp, guard;
void *base;
uintptr size;
- stk = (Stktop*)gp->stackbase;
- guard = gp->stackguard;
+ 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;
+ }
if(gp == g)
runtime·throw("can't scan our own stack");
if((mp = gp->m) != nil && mp->helpgc)
runtime·throw("can't scan gchelper stack");
+
if(gp->syscallstack != (uintptr)nil) {
// Scanning another goroutine that is about to enter or might
// have just exited a system call. It may be executing code such
@@ -1454,35 +1673,33 @@ addstackroots(G *gp)
// Use the stack segment and stack pointer at the time of
// the system call instead, since that won't change underfoot.
sp = gp->syscallsp;
- pc = gp->syscallpc;
- lr = 0;
stk = (Stktop*)gp->syscallstack;
guard = gp->syscallguard;
} else {
// Scanning another goroutine's stack.
// The goroutine is usually asleep (the world is stopped).
sp = gp->sched.sp;
- pc = gp->sched.pc;
- lr = gp->sched.lr;
-
+ stk = (Stktop*)gp->stackbase;
+ guard = gp->stackguard;
// For function about to start, context argument is a root too.
if(gp->sched.ctxt != 0 && runtime·mlookup(gp->sched.ctxt, &base, &size, nil))
- addroot((Obj){base, size, 0});
+ enqueue1(wbufp, (Obj){base, size, 0});
}
if(ScanStackByFrames) {
+ USED(sp);
USED(stk);
USED(guard);
- runtime·gentraceback(pc, sp, lr, gp, 0, nil, 0x7fffffff, addframeroots, nil, false);
+ runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff, scanframe, wbufp, false);
} else {
- USED(lr);
- USED(pc);
n = 0;
while(stk) {
if(sp < guard-StackGuard || (uintptr)stk < sp) {
runtime·printf("scanstack inconsistent: g%D#%d sp=%p not in [%p,%p]\n", gp->goid, n, sp, guard-StackGuard, stk);
runtime·throw("scanstack");
}
- addroot((Obj){(byte*)sp, (uintptr)stk - sp, (uintptr)defaultProg | PRECISE | LOOP});
+ if(Debug > 2)
+ runtime·printf("conservative stack %p+%p\n", (byte*)sp, (uintptr)stk-sp);
+ enqueue1(wbufp, (Obj){(byte*)sp, (uintptr)stk - sp, (uintptr)defaultProg | PRECISE | LOOP});
sp = stk->gobuf.sp;
guard = stk->stackguard;
stk = (Stktop*)stk->stackbase;
@@ -1491,101 +1708,17 @@ addstackroots(G *gp)
}
}
-static void
-addfinroots(void *v)
-{
- uintptr size;
- void *base;
-
- size = 0;
- if(!runtime·mlookup(v, &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 void
-addroots(void)
-{
- G *gp;
- FinBlock *fb;
- MSpan *s, **allspans;
- uint32 spanidx;
-
- work.nroot = 0;
-
- // data & bss
- // TODO(atom): load balancing
- addroot((Obj){data, edata - data, (uintptr)gcdata});
- addroot((Obj){bss, ebss - bss, (uintptr)gcbss});
-
- // 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);
-
- for(fb=allfin; fb; fb=fb->alllink)
- addroot((Obj){(byte*)fb->fin, fb->cnt*sizeof(fb->fin[0]), 0});
-}
-
-static bool
-handlespecial(byte *p, uintptr size)
+void
+runtime·queuefinalizer(byte *p, FuncVal *fn, uintptr nret, Type *fint, PtrType *ot)
{
- FuncVal *fn;
- uintptr nret;
- PtrType *ot;
- Type *fint;
FinBlock *block;
Finalizer *f;
- if(!runtime·getfinalizer(p, true, &fn, &nret, &fint, &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;
}
@@ -1601,33 +1734,79 @@ handlespecial(byte *p, uintptr size)
f->fint = fint;
f->ot = ot;
f->arg = p;
+ runtime·fingwake = true;
runtime·unlock(&finlock);
- return true;
+}
+
+void
+runtime·iterate_finq(void (*callback)(FuncVal*, byte*, uintptr, Type*, PtrType*))
+{
+ FinBlock *fb;
+ Finalizer *f;
+ uintptr 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->nret, f->fint, f->ot);
+ }
+ }
+}
+
+void
+runtime·MSpan_EnsureSwept(MSpan *s)
+{
+ 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)
{
- 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;
-
- USED(&desc);
- s = runtime·mheap.allspans[idx];
- if(s->state != MSpanInUse)
- return;
+ MLink *x;
+ Special *special, **specialp, *y;
+ bool res, sweepgenset;
+
+ // 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 && 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) {
@@ -1637,10 +1816,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;
@@ -1654,9 +1875,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;
@@ -1666,33 +1886,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) {
@@ -1703,19 +1922,113 @@ 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.
+// Pretected by gclock.
+static struct
+{
+ G* g;
+ bool parked;
+
+ MSpan** spans;
+ uint32 nspan;
+ uint32 spanidx;
+} sweep;
+
+// background sweeping goroutine
+static void
+bgsweep(void)
+{
+ g->issystem = 1;
+ for(;;) {
+ while(runtime·sweepone() != -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;
+ g->isbackground = true;
+ runtime·parkunlock(&gclock, "GC sweep wait");
+ 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)
+{
+ 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 -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;
}
}
@@ -1727,7 +2040,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)
@@ -1754,7 +2067,6 @@ dumpspan(uint32 idx)
bits = *bitp>>shift;
allocated = ((bits & bitAllocated) != 0);
- special = ((bits & bitSpecial) != 0);
for(i=0; i<size; i+=sizeof(void*)) {
if(column == 0) {
@@ -1762,7 +2074,6 @@ dumpspan(uint32 idx)
}
if(i == 0) {
runtime·printf(allocated ? "(" : "[");
- runtime·printf(special ? "@" : "");
runtime·printf("%p: ", p+i);
} else {
runtime·printf(" ");
@@ -1798,42 +2109,24 @@ runtime·memorydump(void)
void
runtime·gchelper(void)
{
- int32 nproc;
+ uint32 nproc;
+ 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);
-
- if(DebugMark) {
- // wait while the main thread executes mark(debug_scanblock)
- while(runtime·atomicload(&work.debugmarkdone) == 0)
- runtime·usleep(10);
- }
+ scanblock(nil, true);
- runtime·parfordo(work.sweepfor);
bufferList[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);
+ 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)
{
@@ -1849,12 +2142,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; 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;
int32 i;
uint64 stacks_inuse, smallfree;
uint64 *src, *dst;
@@ -1895,12 +2201,7 @@ updatememstats(GCStats *stats)
}
// Flush MCache's to MCentral.
- for(pp=runtime·allp; p=*pp; pp++) {
- c = p->mcache;
- if(c==nil)
- continue;
- runtime·MCache_ReleaseAll(c);
- }
+ flushallmcaches();
// Aggregate local stats.
cachestats();
@@ -1942,6 +2243,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);
@@ -1960,8 +2262,8 @@ readgogc(void)
return runtime·atoi(p);
}
-static FuncVal runfinqv = {runfinq};
-
+// force = 1 - do GC regardless of current heap usage
+// force = 2 - go GC and eager sweep
void
runtime·gc(int32 force)
{
@@ -1997,7 +2299,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);
@@ -2006,22 +2308,25 @@ 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->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();
}
// all done
@@ -2032,19 +2337,10 @@ 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 = runtime·newproc1(&runfinqv, nil, 0, 0, runtime·gc);
- 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();
}
- // give the queued finalizers, if any, a chance to run
- runtime·gosched();
}
static void
@@ -2060,33 +2356,24 @@ static void
gc(struct gc_args *args)
{
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;
+ 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) {
@@ -2095,43 +2382,49 @@ gc(struct gc_args *args)
itabtype = ((PtrType*)eface.type)->elem;
}
+ t1 = 0;
+ if(runtime·debug.gctrace)
+ t1 = runtime·nanotime();
+
+ // Sweep what is not sweeped by bgsweep.
+ while(runtime·sweepone() != -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++;
@@ -2139,22 +2432,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);
@@ -2181,9 +2481,49 @@ 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 = runtime·newproc1(&bgsweepv, nil, 0, 0, runtime·gc);
+ else if(sweep.parked) {
+ sweep.parked = false;
+ runtime·ready(sweep.g);
+ }
+ runtime·unlock(&gclock);
+ } else {
+ // Sweep all spans eagerly.
+ while(runtime·sweepone() != -1)
+ gcstats.npausesweep++;
+ }
+
+ // Shrink a stack if not much of it is being used.
+ // TODO: do in a parfor
+ for(i = 0; i < runtime·allglen; i++)
+ runtime·shrinkstack(runtime·allg[i]);
+
runtime·MProf_GC();
+ m->traceback = 0;
}
+extern uintptr runtime·sizeof_C_MStats;
+
void
runtime·ReadMemStats(MStats *stats)
{
@@ -2194,8 +2534,10 @@ runtime·ReadMemStats(MStats *stats)
runtime·semacquire(&runtime·worldsema, false);
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·memcopy(runtime·sizeof_C_MStats, stats, &mstats);
m->gcing = 0;
m->locks++;
runtime·semrelease(&runtime·worldsema);
@@ -2234,9 +2576,10 @@ runtime∕debug·readGCStats(Slice *pauses)
pauses->len = n+3;
}
-void
-runtime∕debug·setGCPercent(intgo in, intgo out)
-{
+int32
+runtime·setgcpercent(int32 in) {
+ int32 out;
+
runtime·lock(&runtime·mheap);
if(gcpercent == GcpercentUnknown)
gcpercent = readgogc();
@@ -2245,7 +2588,7 @@ runtime∕debug·setGCPercent(intgo in, intgo out)
in = -1;
gcpercent = in;
runtime·unlock(&runtime·mheap);
- FLUSH(&out);
+ return out;
}
static void
@@ -2268,15 +2611,38 @@ runfinq(void)
uint32 framesz, framecap, i;
Eface *ef, ef1;
+ // 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;
frame = nil;
framecap = 0;
+ framesz = 0;
+ i = 0;
+ ef = nil;
+ ef1.type = nil;
+ ef1.data = nil;
+
+ // force flush to memory
+ USED(&f);
+ USED(&fb);
+ USED(&next);
+ USED(&framesz);
+ USED(&i);
+ USED(&ef);
+ USED(&ef1);
+
for(;;) {
runtime·lock(&finlock);
fb = finq;
finq = nil;
if(fb == nil) {
- fingwait = 1;
- runtime·park(runtime·unlock, &finlock, "finalizer wait");
+ runtime·fingwait = true;
+ g->isbackground = true;
+ runtime·parkunlock(&finlock, "finalizer wait");
+ g->isbackground = false;
continue;
}
runtime·unlock(&finlock);
@@ -2290,7 +2656,7 @@ runfinq(void)
if(framecap < framesz) {
runtime·free(frame);
// The frame does not contain pointers interesting for GC,
- // all not yet finalized objects are stored in finc.
+ // 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 = runtime·mallocgc(framesz, 0, FlagNoScan|FlagNoInvokeGC);
@@ -2313,80 +2679,99 @@ runfinq(void)
if(!runtime·ifaceE2I2((InterfaceType*)f->fint, ef1, (Iface*)frame))
runtime·throw("invalid type conversion in runfinq");
}
- reflect·call(f->fn, frame, framesz);
+ reflect·call(f->fn, frame, framesz, framesz);
f->fn = nil;
f->arg = nil;
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 = nil;
+ ef1.type = nil;
+ ef1.data = 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 = runtime·newproc1(&runfinqv, nil, 0, 0, runtime·gc);
+ 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.
@@ -2418,15 +2803,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
@@ -2435,8 +2833,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.
@@ -2465,50 +2870,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)
{
@@ -2522,9 +2883,10 @@ runtime·MHeap_MapBits(MHeap *h)
n = (h->arena_used - h->arena_start) / wordsPerBitmapWord;
n = ROUND(n, bitmapChunk);
+ n = ROUND(n, PhysPageSize);
if(h->bitmap_mapped >= n)
return;
- 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/src/pkg/runtime/mgc0.go b/src/pkg/runtime/mgc0.go
index b15054662..624485d18 100644
--- a/src/pkg/runtime/mgc0.go
+++ b/src/pkg/runtime/mgc0.go
@@ -9,7 +9,19 @@ 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 timenow() (sec int64, nsec int32)
+
+func gc_unixnanotime(now *int64) {
+ sec, nsec := timenow()
+ *now = sec*1e9 + int64(nsec)
+}
diff --git a/src/pkg/runtime/mgc0.h b/src/pkg/runtime/mgc0.h
index f8abe6c9c..16000d1ae 100644
--- a/src/pkg/runtime/mgc0.h
+++ b/src/pkg/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/src/pkg/runtime/mheap.c b/src/pkg/runtime/mheap.c
index fc80c2600..7e83eb283 100644
--- a/src/pkg/runtime/mheap.c
+++ b/src/pkg/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);
}
@@ -72,20 +80,95 @@ runtime·MHeap_MapSpans(MHeap *h)
// Map spans array, PageSize at a time.
n = (uintptr)h->arena_used;
- if(sizeof(void*) == 8)
- n -= (uintptr)h->arena_start;
+ n -= (uintptr)h->arena_start;
n = n / PageSize * sizeof(h->spans[0]);
- n = ROUND(n, PageSize);
+ n = ROUND(n, PhysPageSize);
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 == -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;
@@ -95,14 +178,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;
}
@@ -113,6 +204,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])) {
@@ -136,29 +232,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) {
@@ -167,13 +246,13 @@ HaveSpan:
runtime·MSpan_Init(t, s->start + npage, s->npages - npage);
s->npages = npage;
p = t->start;
- if(sizeof(void*) == 8)
- p -= ((uintptr)h->arena_start>>PageShift);
+ p -= ((uintptr)h->arena_start>>PageShift);
if(p > 0)
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
@@ -186,8 +265,7 @@ HaveSpan:
s->elemsize = (sizeclass==0 ? s->npages<<PageShift : runtime·class_to_size[sizeclass]);
s->types.compression = MTypes_Empty;
p = s->start;
- if(sizeof(void*) == 8)
- p -= ((uintptr)h->arena_start>>PageShift);
+ p -= ((uintptr)h->arena_start>>PageShift);
for(n=0; n<npage; n++)
h->spans[p+n] = s;
return s;
@@ -197,7 +275,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.
@@ -255,10 +333,10 @@ MHeap_Grow(MHeap *h, uintptr npage)
s = runtime·FixAlloc_Alloc(&h->spanalloc);
runtime·MSpan_Init(s, (uintptr)v>>PageShift, ask>>PageShift);
p = s->start;
- if(sizeof(void*) == 8)
- p -= ((uintptr)h->arena_start>>PageShift);
+ 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;
@@ -273,8 +351,7 @@ runtime·MHeap_Lookup(MHeap *h, void *v)
uintptr p;
p = (uintptr)v;
- if(sizeof(void*) == 8)
- p -= (uintptr)h->arena_start;
+ p -= (uintptr)h->arena_start;
return h->spans[p >> PageShift];
}
@@ -295,8 +372,7 @@ runtime·MHeap_LookupMaybe(MHeap *h, void *v)
return nil;
p = (uintptr)v>>PageShift;
q = p;
- if(sizeof(void*) == 8)
- q -= (uintptr)h->arena_start >> PageShift;
+ q -= (uintptr)h->arena_start >> PageShift;
s = h->spans[q];
if(s == nil || p < s->start || v >= s->limit || s->state != MSpanInUse)
return nil;
@@ -322,20 +398,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();
@@ -343,16 +418,12 @@ MHeap_FreeLocked(MHeap *h, MSpan *s)
// Coalesce with earlier, later spans.
p = s->start;
- if(sizeof(void*) == 8)
- p -= (uintptr)h->arena_start >> PageShift;
+ 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);
@@ -360,12 +431,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;
@@ -376,7 +444,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
@@ -419,7 +487,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)
@@ -440,6 +508,7 @@ runtime·MHeap_Scavenger(void)
{
MHeap *h;
uint64 tick, now, forcegc, limit;
+ int64 unixnow;
int32 k;
Note note, *notep;
@@ -463,8 +532,8 @@ runtime·MHeap_Scavenger(void)
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.
@@ -476,8 +545,8 @@ runtime·MHeap_Scavenger(void)
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);
}
@@ -486,7 +555,7 @@ runtime·MHeap_Scavenger(void)
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);
@@ -503,11 +572,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.
@@ -549,4 +623,310 @@ 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.
+ 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);
+ 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);
+ 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.
+ 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);
+ m->locks--;
+ return s;
+ }
+ t = &s->next;
+ }
+ runtime·unlock(&span->specialLock);
+ m->locks--;
+ return nil;
+}
+
+// Adds a finalizer to the object p. Returns true if it succeeded.
+bool
+runtime·addfinalizer(void *p, FuncVal *f, uintptr nret, Type *fint, 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->nret = nret;
+ s->fint = fint;
+ 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->nret, sf->fint, 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/src/pkg/runtime/mknacl.sh b/src/pkg/runtime/mknacl.sh
new file mode 100644
index 000000000..47fb7bd88
--- /dev/null
+++ b/src/pkg/runtime/mknacl.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+# 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.
+
+cat /Users/rsc/pub/native_client/src/trusted/service_runtime/include/bits/nacl_syscalls.h |
+ awk '
+ BEGIN {
+ printf("// generated by mknacl.sh - do not edit\n")
+ }
+ NF==3 && $1=="#define" && $2~/^NACL_sys_/ {
+ name=$2
+ sub(/^NACL_sys_/, "SYS_", name)
+ printf("#define %s %s\n", name, $3)
+ }' >syscall_nacl.h
diff --git a/src/pkg/runtime/mprof.goc b/src/pkg/runtime/mprof.goc
index 4ae74f0c2..9c23a16f8 100644
--- a/src/pkg/runtime/mprof.goc
+++ b/src/pkg/runtime/mprof.goc
@@ -22,7 +22,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
@@ -34,14 +33,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
{
@@ -49,7 +67,8 @@ struct Bucket
int64 cycles;
};
};
- uintptr hash;
+ uintptr hash; // hash of size + stk
+ uintptr size;
uintptr nstk;
uintptr stk[1];
};
@@ -63,7 +82,7 @@ static uintptr bucketmem;
// Return the bucket for stk[0:nstk], allocating new bucket if needed.
static Bucket*
-stkbucket(int32 typ, uintptr *stk, int32 nstk, bool alloc)
+stkbucket(int32 typ, uintptr size, uintptr *stk, int32 nstk, bool alloc)
{
int32 i;
uintptr h;
@@ -82,12 +101,17 @@ stkbucket(int32 typ, uintptr *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 == nstk &&
+ if(b->typ == typ && b->hash == h && b->size == size && b->nstk == nstk &&
runtime·mcmp((byte*)b->stk, (byte*)stk, nstk*sizeof stk[0]) == 0)
return b;
@@ -99,6 +123,7 @@ stkbucket(int32 typ, uintptr *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;
@@ -118,10 +143,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;
@@ -138,143 +169,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;
uintptr stk[32];
Bucket *b;
+ int32 nstk;
- nstk = runtime·callers(1, stk, 32);
+ nstk = runtime·callers(1, stk, nelem(stk));
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);
}
@@ -311,9 +238,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));
runtime·lock(&proflock);
- b = stkbucket(BProf, stk, nstk, true);
+ b = stkbucket(BProf, 0, stk, nstk, true);
b->count++;
b->cycles += cycles;
runtime·unlock(&proflock);
@@ -365,6 +292,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)
@@ -381,6 +309,18 @@ func MemProfile(p Slice, include_inuse_zero bool) (n int, ok bool) {
runtime·unlock(&proflock);
}
+void
+runtime·iterate_memprof(void (*callback)(Bucket*, uintptr, uintptr*, 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.
typedef struct BRecord BRecord;
struct BRecord {
@@ -483,7 +423,7 @@ saveg(uintptr pc, uintptr sp, G *gp, TRecord *r)
}
func GoroutineProfile(b Slice) (n int, ok bool) {
- uintptr pc, sp;
+ uintptr pc, sp, i;
TRecord *r;
G *gp;
@@ -502,7 +442,8 @@ func GoroutineProfile(b Slice) (n int, ok bool) {
ok = true;
r = (TRecord*)b.array;
saveg(pc, sp, 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(~(uintptr)0, ~(uintptr)0, gp, r++);
@@ -515,8 +456,72 @@ func GoroutineProfile(b Slice) (n int, ok bool) {
}
}
+// Tracing of alloc/free/gc.
+
+static Lock tracelock;
+
+static int8*
+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)
+{
+ int8 *name;
+ Type *type;
+
+ runtime·lock(&tracelock);
+ 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->string);
+ if(m->curg == nil || g == m->curg) {
+ runtime·goroutineheader(g);
+ runtime·traceback((uintptr)runtime·getcallerpc(&p), (uintptr)runtime·getcallersp(&p), 0, g);
+ } else {
+ runtime·goroutineheader(m->curg);
+ runtime·traceback(~(uintptr)0, ~(uintptr)0, 0, m->curg);
+ }
+ runtime·printf("\n");
+ m->traceback = 0;
+ runtime·unlock(&tracelock);
+}
+
+void
+runtime·tracefree(void *p, uintptr size)
+{
+ runtime·lock(&tracelock);
+ m->traceback = 2;
+ runtime·printf("tracefree(%p, %p)\n", p, size);
+ runtime·goroutineheader(g);
+ runtime·traceback((uintptr)runtime·getcallerpc(&p), (uintptr)runtime·getcallersp(&p), 0, g);
+ runtime·printf("\n");
+ 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);
+ m->traceback = 2;
+ runtime·printf("tracegc()\n");
+ // running on m->g0 stack; show all non-g0 goroutines
+ runtime·tracebackothers(g);
+ runtime·printf("end tracegc\n");
+ runtime·printf("\n");
+ m->traceback = 0;
+ runtime·unlock(&tracelock);
}
diff --git a/src/pkg/runtime/msize.c b/src/pkg/runtime/msize.c
index 50b372b61..2fbd5e104 100644
--- a/src/pkg/runtime/msize.c
+++ b/src/pkg/runtime/msize.c
@@ -28,8 +28,11 @@
#include "runtime.h"
#include "arch_GOARCH.h"
#include "malloc.h"
+#include "../../cmd/ld/textflag.h"
+#pragma dataflag NOPTR
int32 runtime·class_to_size[NumSizeClasses];
+#pragma dataflag NOPTR
int32 runtime·class_to_allocnpages[NumSizeClasses];
// The SizeToClass lookup is implemented using two arrays,
@@ -41,11 +44,15 @@ int32 runtime·class_to_allocnpages[NumSizeClasses];
// size divided by 128 (rounded up). The arrays are filled in
// by InitSizes.
+#pragma dataflag NOPTR
int8 runtime·size_to_class8[1024/8 + 1];
+#pragma dataflag NOPTR
int8 runtime·size_to_class128[(MaxSmallSize-1024)/128 + 1];
-static int32
-SizeToClass(int32 size)
+void runtime·testdefersizes(void);
+
+int32
+runtime·SizeToClass(int32 size)
{
if(size > MaxSmallSize)
runtime·throw("SizeToClass - invalid size");
@@ -90,9 +97,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
- && npages == runtime·class_to_allocnpages[sizeclass-1]
- && allocsize/size == allocsize/runtime·class_to_size[sizeclass-1]) {
+ if(sizeclass > 1 &&
+ 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 +126,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");
@@ -133,6 +140,8 @@ runtime·InitSizes(void)
}
}
+ runtime·testdefersizes();
+
// Copy out for statistics table.
for(i=0; i<nelem(runtime·class_to_size); i++)
mstats.by_size[i].size = runtime·class_to_size[i];
@@ -158,3 +167,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/src/pkg/runtime/netpoll.goc b/src/pkg/runtime/netpoll.goc
index d27bef167..7b3d16d02 100644
--- a/src/pkg/runtime/netpoll.goc
+++ b/src/pkg/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
@@ -19,21 +19,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
@@ -47,7 +72,7 @@ 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);
@@ -59,6 +84,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();
}
@@ -97,7 +127,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;
@@ -106,14 +135,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;
@@ -122,15 +152,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) {
@@ -185,7 +213,7 @@ func runtime_pollSetDeadline(pd *PollDesc, d int64, mode int) {
}
// 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)
@@ -205,6 +233,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) {
@@ -228,6 +257,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)
@@ -235,12 +288,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;
@@ -261,51 +312,75 @@ 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 = g;
- runtime·park(runtime·unlock, &pd->Lock, "IO wait");
- runtime·lock(pd);
- if(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*)ioready;
- *gpp = nil;
- return old;
+ if(old > WAIT)
+ return old; // must be G*
+ return nil;
}
static void
@@ -331,14 +406,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);
@@ -374,7 +449,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/src/pkg/runtime/netpoll_epoll.c b/src/pkg/runtime/netpoll_epoll.c
index 885ac5e4d..9ea5e1a59 100644
--- a/src/pkg/runtime/netpoll_epoll.c
+++ b/src/pkg/runtime/netpoll_epoll.c
@@ -52,6 +52,13 @@ runtime·netpollclose(uintptr fd)
return -res;
}
+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*
diff --git a/src/pkg/runtime/netpoll_kqueue.c b/src/pkg/runtime/netpoll_kqueue.c
index afc8d6859..171346cce 100644
--- a/src/pkg/runtime/netpoll_kqueue.c
+++ b/src/pkg/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*
diff --git a/src/pkg/runtime/netpoll_nacl.c b/src/pkg/runtime/netpoll_nacl.c
new file mode 100644
index 000000000..b75753a23
--- /dev/null
+++ b/src/pkg/runtime/netpoll_nacl.c
@@ -0,0 +1,37 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+
+// Fake network poller for NaCl.
+// Should never be used, because NaCl network connections do not honor "SetNonblock".
+
+void
+runtime·netpollinit(void)
+{
+}
+
+int32
+runtime·netpollopen(uintptr fd, PollDesc *pd)
+{
+ USED(fd);
+ USED(pd);
+ return 0;
+}
+
+int32
+runtime·netpollclose(uintptr fd)
+{
+ USED(fd);
+ return 0;
+}
+
+G*
+runtime·netpoll(bool block)
+{
+ USED(block);
+ return nil;
+}
diff --git a/src/pkg/runtime/netpoll_solaris.c b/src/pkg/runtime/netpoll_solaris.c
new file mode 100644
index 000000000..a2631a8ab
--- /dev/null
+++ b/src/pkg/runtime/netpoll_solaris.c
@@ -0,0 +1,268 @@
+// 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 "arch_GOARCH.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+
+// Solaris runtime-integrated network poller.
+//
+// Solaris uses event ports for scalable network I/O. Event
+// ports are level-triggered, unlike epoll and kqueue which
+// can be configured in both level-triggered and edge-triggered
+// mode. Level triggering means we have to keep track of a few things
+// ourselves. After we receive an event for a file descriptor,
+// it's our responsibility to ask again to be notified for future
+// events for that descriptor. When doing this we must keep track of
+// what kind of events the goroutines are currently interested in,
+// for example a fd may be open both for reading and writing.
+//
+// A description of the high level operation of this code
+// follows. Networking code will get a file descriptor by some means
+// and will register it with the netpolling mechanism by a code path
+// that eventually calls runtime·netpollopen. runtime·netpollopen
+// calls port_associate with an empty event set. That means that we
+// will not receive any events at this point. The association needs
+// to be done at this early point because we need to process the I/O
+// readiness notification at some point in the future. If I/O becomes
+// ready when nobody is listening, when we finally care about it,
+// nobody will tell us anymore.
+//
+// Beside calling runtime·netpollopen, the networking code paths
+// will call runtime·netpollarm each time goroutines are interested
+// in doing network I/O. Because now we know what kind of I/O we
+// are interested in (reading/writting), we can call port_associate
+// passing the correct type of event set (POLLIN/POLLOUT). As we made
+// sure to have already associated the file descriptor with the port,
+// when we now call port_associate, we will unblock the main poller
+// loop (in runtime·netpoll) right away if the socket is actually
+// ready for I/O.
+//
+// The main poller loop runs in its own thread waiting for events
+// using port_getn. When an event happens, it will tell the scheduler
+// about it using runtime·netpollready. Besides doing this, it must
+// also re-associate the events that were not part of this current
+// notification with the file descriptor. Failing to do this would
+// mean each notification will prevent concurrent code using the
+// same file descriptor in parallel.
+//
+// The logic dealing with re-associations is encapsulated in
+// runtime·netpollupdate. This function takes care to associate the
+// descriptor only with the subset of events that were previously
+// part of the association, except the one that just happened. We
+// can't re-associate with that right away, because event ports
+// are level triggered so it would cause a busy loop. Instead, that
+// association is effected only by the runtime·netpollarm code path,
+// when Go code actually asks for I/O.
+//
+// The open and arming mechanisms are serialized using the lock
+// inside PollDesc. This is required because the netpoll loop runs
+// asynchonously in respect to other Go code and by the time we get
+// to call port_associate to update the association in the loop, the
+// file descriptor might have been closed and reopened already. The
+// lock allows runtime·netpollupdate to be called synchronously from
+// the loop thread while preventing other threads operating to the
+// same PollDesc, so once we unblock in the main loop, until we loop
+// again we know for sure we are always talking about the same file
+// descriptor and can safely access the data we want (the event set).
+
+#pragma dynimport libc·fcntl fcntl "libc.so"
+#pragma dynimport libc·port_create port_create "libc.so"
+#pragma dynimport libc·port_associate port_associate "libc.so"
+#pragma dynimport libc·port_dissociate port_dissociate "libc.so"
+#pragma dynimport libc·port_getn port_getn "libc.so"
+extern uintptr libc·fcntl;
+extern uintptr libc·port_create;
+extern uintptr libc·port_associate;
+extern uintptr libc·port_dissociate;
+extern uintptr libc·port_getn;
+
+#define errno (*m->perrno)
+
+int32
+runtime·fcntl(int32 fd, int32 cmd, uintptr arg)
+{
+ return runtime·sysvicall6(libc·fcntl, 3,
+ (uintptr)fd, (uintptr)cmd, (uintptr)arg);
+}
+
+int32
+runtime·port_create(void)
+{
+ return runtime·sysvicall6(libc·port_create, 0);
+}
+
+int32
+runtime·port_associate(int32 port, int32 source, uintptr object, int32 events, uintptr user)
+{
+ return runtime·sysvicall6(libc·port_associate,
+ 5, (uintptr)port, (uintptr)source, object, (uintptr)events, user);
+}
+
+int32
+runtime·port_dissociate(int32 port, int32 source, uintptr object)
+{
+ return runtime·sysvicall6(libc·port_dissociate,
+ 3, (uintptr)port, (uintptr)source, object);
+}
+
+int32
+runtime·port_getn(int32 port, PortEvent *evs, uint32 max, uint32 *nget, Timespec *timeout)
+{
+ return runtime·sysvicall6(libc·port_getn, 5, (uintptr)port,
+ (uintptr)evs, (uintptr)max, (uintptr)nget, (uintptr)timeout);
+}
+
+static int32 portfd = -1;
+
+void
+runtime·netpollinit(void)
+{
+ if((portfd = runtime·port_create()) >= 0) {
+ runtime·fcntl(portfd, F_SETFD, FD_CLOEXEC);
+ return;
+ }
+
+ runtime·printf("netpollinit: failed to create port (%d)\n", errno);
+ runtime·throw("netpollinit: failed to create port");
+}
+
+int32
+runtime·netpollopen(uintptr fd, PollDesc *pd)
+{
+ int32 r;
+
+ runtime·netpolllock(pd);
+ // We don't register for any specific type of events yet, that's
+ // netpollarm's job. We merely ensure we call port_associate before
+ // asynchonous connect/accept completes, so when we actually want
+ // to do any I/O, the call to port_associate (from netpollarm,
+ // with the interested event set) will unblock port_getn right away
+ // because of the I/O readiness notification.
+ *runtime·netpolluser(pd) = 0;
+ r = runtime·port_associate(portfd, PORT_SOURCE_FD, fd, 0, (uintptr)pd);
+ runtime·netpollunlock(pd);
+ return r;
+}
+
+int32
+runtime·netpollclose(uintptr fd)
+{
+ return runtime·port_dissociate(portfd, PORT_SOURCE_FD, fd);
+}
+
+// Updates the association with a new set of interested events. After
+// this call, port_getn will return one and only one event for that
+// particular descriptor, so this function needs to be called again.
+void
+runtime·netpollupdate(PollDesc* pd, uint32 set, uint32 clear)
+{
+ uint32 *ep, old, events;
+ uintptr fd = runtime·netpollfd(pd);
+ ep = (uint32*)runtime·netpolluser(pd);
+
+ if(runtime·netpollclosing(pd))
+ return;
+
+ old = *ep;
+ events = (old & ~clear) | set;
+ if(old == events)
+ return;
+
+ if(events && runtime·port_associate(portfd, PORT_SOURCE_FD, fd, events, (uintptr)pd) != 0) {
+ runtime·printf("netpollupdate: failed to associate (%d)\n", errno);
+ runtime·throw("netpollupdate: failed to associate");
+ }
+ *ep = events;
+}
+
+// subscribe the fd to the port such that port_getn will return one event.
+void
+runtime·netpollarm(PollDesc* pd, int32 mode)
+{
+ runtime·netpolllock(pd);
+ switch(mode) {
+ case 'r':
+ runtime·netpollupdate(pd, POLLIN, 0);
+ break;
+ case 'w':
+ runtime·netpollupdate(pd, POLLOUT, 0);
+ break;
+ default:
+ runtime·throw("netpollarm: bad mode");
+ }
+ runtime·netpollunlock(pd);
+}
+
+// polls for ready network connections
+// returns list of goroutines that become runnable
+G*
+runtime·netpoll(bool block)
+{
+ static int32 lasterr;
+ PortEvent events[128], *ev;
+ PollDesc *pd;
+ int32 i, mode, clear;
+ uint32 n;
+ Timespec *wait = nil, zero;
+ G *gp;
+
+ if(portfd == -1)
+ return (nil);
+
+ if(!block) {
+ zero.tv_sec = 0;
+ zero.tv_nsec = 0;
+ wait = &zero;
+ }
+
+retry:
+ n = 1;
+ if(runtime·port_getn(portfd, events, nelem(events), &n, wait) < 0) {
+ if(errno != EINTR && errno != lasterr) {
+ lasterr = errno;
+ runtime·printf("runtime: port_getn on fd %d failed with %d\n", portfd, errno);
+ }
+ goto retry;
+ }
+
+ gp = nil;
+ for(i = 0; i < n; i++) {
+ ev = &events[i];
+
+ if(ev->portev_events == 0)
+ continue;
+ pd = (PollDesc *)ev->portev_user;
+
+ mode = 0;
+ clear = 0;
+ if(ev->portev_events & (POLLIN|POLLHUP|POLLERR)) {
+ mode += 'r';
+ clear |= POLLIN;
+ }
+ if(ev->portev_events & (POLLOUT|POLLHUP|POLLERR)) {
+ mode += 'w';
+ clear |= POLLOUT;
+ }
+ // To effect edge-triggered events, we need to be sure to
+ // update our association with whatever events were not
+ // set with the event. For example if we are registered
+ // for POLLIN|POLLOUT, and we get POLLIN, besides waking
+ // the goroutine interested in POLLIN we have to not forget
+ // about the one interested in POLLOUT.
+ if(clear != 0) {
+ runtime·netpolllock(pd);
+ runtime·netpollupdate(pd, 0, clear);
+ runtime·netpollunlock(pd);
+ }
+
+ if(mode)
+ runtime·netpollready(&gp, pd, mode);
+ }
+
+ if(block && gp == nil)
+ goto retry;
+ return gp;
+}
diff --git a/src/pkg/runtime/netpoll_windows.c b/src/pkg/runtime/netpoll_windows.c
index b510a41e2..f3cd15c7a 100644
--- a/src/pkg/runtime/netpoll_windows.c
+++ b/src/pkg/runtime/netpoll_windows.c
@@ -72,6 +72,13 @@ runtime·netpollclose(uintptr fd)
return 0;
}
+void
+runtime·netpollarm(PollDesc* pd, int32 mode)
+{
+ USED(pd, mode);
+ runtime·throw("unused");
+}
+
// Polls for completed network IO.
// Returns list of goroutines that become runnable.
G*
@@ -94,13 +101,17 @@ retry:
n = nelem(entries) / runtime·gomaxprocs;
if(n < 8)
n = 8;
+ if(block)
+ m->blocked = true;
if(runtime·stdcall(runtime·GetQueuedCompletionStatusEx, 6, iocphandle, entries, (uintptr)n, &n, (uintptr)wait, (uintptr)0) == 0) {
+ m->blocked = false;
errno = runtime·getlasterror();
if(!block && errno == WAIT_TIMEOUT)
return nil;
runtime·printf("netpoll: GetQueuedCompletionStatusEx failed (errno=%d)\n", errno);
runtime·throw("netpoll: GetQueuedCompletionStatusEx failed");
}
+ m->blocked = false;
for(i = 0; i < n; i++) {
op = entries[i].op;
errno = 0;
@@ -113,7 +124,10 @@ retry:
op = nil;
errno = 0;
qty = 0;
+ if(block)
+ m->blocked = true;
if(runtime·stdcall(runtime·GetQueuedCompletionStatus, 5, iocphandle, &qty, &key, &op, (uintptr)wait) == 0) {
+ m->blocked = false;
errno = runtime·getlasterror();
if(!block && errno == WAIT_TIMEOUT)
return nil;
@@ -123,6 +137,7 @@ retry:
}
// dequeued failed IO packet, so report that
}
+ m->blocked = false;
handlecompletion(&gp, op, errno, qty);
}
if(block && gp == nil)
diff --git a/src/pkg/runtime/norace_test.go b/src/pkg/runtime/norace_test.go
index a3d5b0086..3b171877a 100644
--- a/src/pkg/runtime/norace_test.go
+++ b/src/pkg/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/src/pkg/runtime/os_darwin.c b/src/pkg/runtime/os_darwin.c
index 9eb1b4626..33a2df958 100644
--- a/src/pkg/runtime/os_darwin.c
+++ b/src/pkg/runtime/os_darwin.c
@@ -59,6 +59,7 @@ runtime·osinit(void)
void
runtime·get_random_data(byte **rnd, int32 *rnd_len)
{
+ #pragma dataflag NOPTR
static byte urandom_data[HashRandomBytes];
int32 fd;
fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
@@ -434,9 +435,12 @@ runtime·mach_semrelease(uint32 sem)
void
runtime·sigpanic(void)
{
+ if(!runtime·canpanic(g))
+ runtime·throw("unexpected signal during runtime execution");
+
switch(g->sig) {
case SIGBUS:
- if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
+ if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -444,7 +448,7 @@ runtime·sigpanic(void)
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGSEGV:
- if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
+ if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -517,3 +521,9 @@ runtime·signalstack(byte *p, int32 n)
st.ss_flags = SS_DISABLE;
runtime·sigaltstack(&st, nil);
}
+
+void
+runtime·unblocksignals(void)
+{
+ runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
+}
diff --git a/src/pkg/runtime/os_darwin.h b/src/pkg/runtime/os_darwin.h
index b4f49e023..91a405f21 100644
--- a/src/pkg/runtime/os_darwin.h
+++ b/src/pkg/runtime/os_darwin.h
@@ -23,6 +23,7 @@ int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
typedef uint32 Sigset;
void runtime·sigprocmask(int32, Sigset*, Sigset*);
+void runtime·unblocksignals(void);
struct Sigaction;
void runtime·sigaction(uintptr, struct Sigaction*, struct Sigaction*);
@@ -39,4 +40,3 @@ void runtime·setitimer(int32, Itimerval*, Itimerval*);
#define SIG_BLOCK 1
#define SIG_UNBLOCK 2
#define SIG_SETMASK 3
-
diff --git a/src/pkg/runtime/os_dragonfly.c b/src/pkg/runtime/os_dragonfly.c
index cf427b78c..e7fd2cc06 100644
--- a/src/pkg/runtime/os_dragonfly.c
+++ b/src/pkg/runtime/os_dragonfly.c
@@ -122,6 +122,7 @@ runtime·osinit(void)
void
runtime·get_random_data(byte **rnd, int32 *rnd_len)
{
+ #pragma dataflag NOPTR
static byte urandom_data[HashRandomBytes];
int32 fd;
fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
@@ -169,9 +170,12 @@ runtime·unminit(void)
void
runtime·sigpanic(void)
{
+ if(!runtime·canpanic(g))
+ runtime·throw("unexpected signal during runtime execution");
+
switch(g->sig) {
case SIGBUS:
- if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
+ if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -179,7 +183,7 @@ runtime·sigpanic(void)
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGSEGV:
- if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
+ if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -280,3 +284,9 @@ runtime·signalstack(byte *p, int32 n)
st.ss_flags = SS_DISABLE;
runtime·sigaltstack(&st, nil);
}
+
+void
+runtime·unblocksignals(void)
+{
+ runtime·sigprocmask(&sigset_none, nil);
+}
diff --git a/src/pkg/runtime/os_dragonfly.h b/src/pkg/runtime/os_dragonfly.h
index ebbd0eb15..fddeede85 100644
--- a/src/pkg/runtime/os_dragonfly.h
+++ b/src/pkg/runtime/os_dragonfly.h
@@ -12,6 +12,7 @@ void runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
struct sigaction;
void runtime·sigaction(int32, struct sigaction*, struct sigaction*);
void runtime·sigprocmask(Sigset *, Sigset *);
+void runtime·unblocksignals(void);
void runtime·setitimer(int32, Itimerval*, Itimerval*);
int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
diff --git a/src/pkg/runtime/os_freebsd.c b/src/pkg/runtime/os_freebsd.c
index 042097bdd..02b13472c 100644
--- a/src/pkg/runtime/os_freebsd.c
+++ b/src/pkg/runtime/os_freebsd.c
@@ -50,7 +50,7 @@ runtime·futexsleep(uint32 *addr, uint32 val, int64 ns)
Timespec ts;
if(ns < 0) {
- ret = runtime·sys_umtx_op(addr, UMTX_OP_WAIT_UINT, val, nil, nil);
+ ret = runtime·sys_umtx_op(addr, UMTX_OP_WAIT_UINT_PRIVATE, val, nil, nil);
if(ret >= 0 || ret == -EINTR)
return;
goto fail;
@@ -58,7 +58,7 @@ runtime·futexsleep(uint32 *addr, uint32 val, int64 ns)
// NOTE: tv_nsec is int64 on amd64, so this assumes a little-endian system.
ts.tv_nsec = 0;
ts.tv_sec = runtime·timediv(ns, 1000000000, (int32*)&ts.tv_nsec);
- ret = runtime·sys_umtx_op(addr, UMTX_OP_WAIT_UINT, val, nil, &ts);
+ ret = runtime·sys_umtx_op(addr, UMTX_OP_WAIT_UINT_PRIVATE, val, nil, &ts);
if(ret >= 0 || ret == -EINTR)
return;
@@ -78,7 +78,7 @@ runtime·futexwakeup(uint32 *addr, uint32 cnt)
{
int32 ret;
- ret = runtime·sys_umtx_op(addr, UMTX_OP_WAKE, cnt, nil, nil);
+ ret = runtime·sys_umtx_op(addr, UMTX_OP_WAKE_PRIVATE, cnt, nil, nil);
if(ret >= 0)
return;
@@ -130,6 +130,7 @@ runtime·osinit(void)
void
runtime·get_random_data(byte **rnd, int32 *rnd_len)
{
+ #pragma dataflag NOPTR
static byte urandom_data[HashRandomBytes];
int32 fd;
fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
@@ -177,9 +178,12 @@ runtime·unminit(void)
void
runtime·sigpanic(void)
{
+ if(!runtime·canpanic(g))
+ runtime·throw("unexpected signal during runtime execution");
+
switch(g->sig) {
case SIGBUS:
- if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
+ if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -187,7 +191,7 @@ runtime·sigpanic(void)
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGSEGV:
- if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
+ if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -288,3 +292,9 @@ runtime·signalstack(byte *p, int32 n)
st.ss_flags = SS_DISABLE;
runtime·sigaltstack(&st, nil);
}
+
+void
+runtime·unblocksignals(void)
+{
+ runtime·sigprocmask(&sigset_none, nil);
+}
diff --git a/src/pkg/runtime/os_freebsd.h b/src/pkg/runtime/os_freebsd.h
index c1853e65d..4b2c25330 100644
--- a/src/pkg/runtime/os_freebsd.h
+++ b/src/pkg/runtime/os_freebsd.h
@@ -12,6 +12,7 @@ void runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
struct sigaction;
void runtime·sigaction(int32, struct sigaction*, struct sigaction*);
void runtime·sigprocmask(Sigset *, Sigset *);
+void runtime·unblocksignals(void);
void runtime·setitimer(int32, Itimerval*, Itimerval*);
int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
diff --git a/src/pkg/runtime/os_linux.c b/src/pkg/runtime/os_linux.c
index cb45fe8ce..8a945242b 100644
--- a/src/pkg/runtime/os_linux.c
+++ b/src/pkg/runtime/os_linux.c
@@ -218,9 +218,12 @@ runtime·unminit(void)
void
runtime·sigpanic(void)
{
+ if(!runtime·canpanic(g))
+ runtime·throw("unexpected signal during runtime execution");
+
switch(g->sig) {
case SIGBUS:
- if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
+ if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -228,7 +231,7 @@ runtime·sigpanic(void)
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGSEGV:
- if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
+ if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -331,3 +334,9 @@ runtime·signalstack(byte *p, int32 n)
st.ss_flags = SS_DISABLE;
runtime·sigaltstack(&st, nil);
}
+
+void
+runtime·unblocksignals(void)
+{
+ runtime·rtsigprocmask(SIG_SETMASK, &sigset_none, nil, sizeof sigset_none);
+}
diff --git a/src/pkg/runtime/os_linux.h b/src/pkg/runtime/os_linux.h
index b2d3f6f2a..d4b1902c3 100644
--- a/src/pkg/runtime/os_linux.h
+++ b/src/pkg/runtime/os_linux.h
@@ -28,6 +28,7 @@ struct Sigset
uint32 mask[2];
};
void runtime·rtsigprocmask(int32, Sigset*, Sigset*, int32);
+void runtime·unblocksignals(void);
#define SIG_SETMASK 2
#define RLIMIT_AS 9
diff --git a/src/pkg/runtime/os_linux_arm.c b/src/pkg/runtime/os_linux_arm.c
index 570b3f0be..aad08b989 100644
--- a/src/pkg/runtime/os_linux_arm.c
+++ b/src/pkg/runtime/os_linux_arm.c
@@ -16,7 +16,7 @@
static uint32 runtime·randomNumber;
uint8 runtime·armArch = 6; // we default to ARMv6
uint32 runtime·hwcap; // set by setup_auxv
-uint8 runtime·goarm; // set by 5l
+extern uint8 runtime·goarm; // set by 5l
void
runtime·checkgoarm(void)
diff --git a/src/pkg/runtime/os_nacl.c b/src/pkg/runtime/os_nacl.c
new file mode 100644
index 000000000..3196e2ce3
--- /dev/null
+++ b/src/pkg/runtime/os_nacl.c
@@ -0,0 +1,278 @@
+// 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 "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "arch_GOARCH.h"
+#include "../../cmd/ld/textflag.h"
+#include "stack.h"
+
+int8 *goos = "nacl";
+extern SigTab runtime·sigtab[];
+
+void runtime·sigtramp(void);
+
+// 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
+runtime·mpreinit(M *mp)
+{
+ mp->gsignal = runtime·malg(32*1024); // OS X wants >=8K, Linux >=2K
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+void
+runtime·minit(void)
+{
+ int32 ret;
+
+ // Initialize signal handling
+ ret = runtime·nacl_exception_stack((byte*)m->gsignal->stackguard - StackGuard, 32*1024);
+ if(ret < 0)
+ runtime·printf("runtime: nacl_exception_stack: error %d\n", -ret);
+
+ ret = runtime·nacl_exception_handler(runtime·sigtramp, nil);
+ if(ret < 0)
+ runtime·printf("runtime: nacl_exception_handler: error %d\n", -ret);
+}
+
+// Called from dropm to undo the effect of an minit.
+void
+runtime·unminit(void)
+{
+}
+
+int8 runtime·sigtrampf[] = "runtime: signal at PC=%X AX=%X CX=%X DX=%X BX=%X DI=%X R15=%X *SP=%X\n";
+int8 runtime·sigtrampp[] = "runtime: sigtramp";
+
+extern byte runtime·tls0[];
+
+void
+runtime·osinit(void)
+{
+ runtime·ncpu = 1;
+ m->procid = 2;
+//runtime·nacl_exception_handler(runtime·sigtramp, nil);
+}
+
+void
+runtime·crash(void)
+{
+ *(int32*)0 = 0;
+}
+
+void
+runtime·get_random_data(byte **rnd, int32 *rnd_len)
+{
+ *rnd = nil;
+ *rnd_len = 0;
+}
+
+void
+runtime·goenvs(void)
+{
+ runtime·goenvs_unix();
+}
+
+void
+runtime·initsig(void)
+{
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·usleep(uint32 us)
+{
+ Timespec ts;
+
+ ts.tv_sec = us/1000000;
+ ts.tv_nsec = (us%1000000)*1000;
+ runtime·nacl_nanosleep(&ts, nil);
+}
+
+void runtime·mstart_nacl(void);
+
+void
+runtime·newosproc(M *mp, void *stk)
+{
+ int32 ret;
+ void **tls;
+
+ tls = (void**)mp->tls;
+ tls[0] = mp->g0;
+ tls[1] = mp;
+ ret = runtime·nacl_thread_create(runtime·mstart_nacl, stk, tls+2, 0);
+ if(ret < 0) {
+ runtime·printf("nacl_thread_create: error %d\n", -ret);
+ runtime·throw("newosproc");
+ }
+}
+
+uintptr
+runtime·semacreate(void)
+{
+ int32 mu, cond;
+
+ mu = runtime·nacl_mutex_create(0);
+ if(mu < 0) {
+ runtime·printf("nacl_mutex_create: error %d\n", -mu);
+ runtime·throw("semacreate");
+ }
+ cond = runtime·nacl_cond_create(0);
+ if(cond < 0) {
+ runtime·printf("nacl_cond_create: error %d\n", -cond);
+ runtime·throw("semacreate");
+ }
+ m->waitsemalock = mu;
+ return cond; // assigned to m->waitsema
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·semasleep(int64 ns)
+{
+ int32 ret;
+
+ ret = runtime·nacl_mutex_lock(m->waitsemalock);
+ if(ret < 0) {
+ //runtime·printf("nacl_mutex_lock: error %d\n", -ret);
+ runtime·throw("semasleep");
+ }
+ if(m->waitsemacount > 0) {
+ m->waitsemacount = 0;
+ runtime·nacl_mutex_unlock(m->waitsemalock);
+ return 0;
+ }
+
+ while(m->waitsemacount == 0) {
+ if(ns < 0) {
+ ret = runtime·nacl_cond_wait(m->waitsema, m->waitsemalock);
+ if(ret < 0) {
+ //runtime·printf("nacl_cond_wait: error %d\n", -ret);
+ runtime·throw("semasleep");
+ }
+ } else {
+ Timespec ts;
+
+ ns += runtime·nanotime();
+ ts.tv_sec = runtime·timediv(ns, 1000000000, (int32*)&ts.tv_nsec);
+ ret = runtime·nacl_cond_timed_wait_abs(m->waitsema, m->waitsemalock, &ts);
+ if(ret == -ETIMEDOUT) {
+ runtime·nacl_mutex_unlock(m->waitsemalock);
+ return -1;
+ }
+ if(ret < 0) {
+ //runtime·printf("nacl_cond_timed_wait_abs: error %d\n", -ret);
+ runtime·throw("semasleep");
+ }
+ }
+ }
+
+ m->waitsemacount = 0;
+ runtime·nacl_mutex_unlock(m->waitsemalock);
+ return 0;
+}
+
+void
+runtime·semawakeup(M *mp)
+{
+ int32 ret;
+
+ ret = runtime·nacl_mutex_lock(mp->waitsemalock);
+ if(ret < 0) {
+ //runtime·printf("nacl_mutex_lock: error %d\n", -ret);
+ runtime·throw("semawakeup");
+ }
+ if(mp->waitsemacount != 0) {
+ //runtime·printf("semawakeup: double wakeup\n");
+ runtime·throw("semawakeup");
+ }
+ mp->waitsemacount = 1;
+ runtime·nacl_cond_signal(mp->waitsema);
+ runtime·nacl_mutex_unlock(mp->waitsemalock);
+}
+
+void
+os·sigpipe(void)
+{
+ runtime·throw("too many writes on closed pipe");
+}
+
+uintptr
+runtime·memlimit(void)
+{
+ runtime·printf("memlimit\n");
+ return 0;
+}
+
+#pragma dataflag NOPTR
+static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+#pragma textflag NOSPLIT
+void
+runtime·badsignal2(void)
+{
+ runtime·write(2, badsignal, sizeof badsignal - 1);
+ runtime·exit(2);
+}
+
+void runtime·madvise(byte*, uintptr, int32) { }
+void runtime·munmap(byte*, uintptr) {}
+
+void
+runtime·resetcpuprofiler(int32 hz)
+{
+ USED(hz);
+}
+
+void
+runtime·sigdisable(uint32)
+{
+}
+
+void
+runtime·sigenable(uint32)
+{
+}
+
+void
+runtime·closeonexec(int32)
+{
+}
+
+void
+runtime·sigpanic(void)
+{
+ if(!runtime·canpanic(g))
+ runtime·throw("unexpected signal during runtime execution");
+
+ // Native Client only invokes the exception handler for memory faults.
+ g->sig = SIGSEGV;
+ if(g->sigpc == 0)
+ runtime·panicstring("call of nil func value");
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+}
+
+uint32 runtime·writelock; // test-and-set spin lock for runtime.write
+
+/*
+An attempt at IRT. Doesn't work. See end of sys_nacl_amd64.s.
+
+void (*runtime·nacl_irt_query)(void);
+
+int8 runtime·nacl_irt_basic_v0_1_str[] = "nacl-irt-basic-0.1";
+void *runtime·nacl_irt_basic_v0_1[6]; // exit, gettod, clock, nanosleep, sched_yield, sysconf
+int32 runtime·nacl_irt_basic_v0_1_size = sizeof(runtime·nacl_irt_basic_v0_1);
+
+int8 runtime·nacl_irt_memory_v0_3_str[] = "nacl-irt-memory-0.3";
+void *runtime·nacl_irt_memory_v0_3[3]; // mmap, munmap, mprotect
+int32 runtime·nacl_irt_memory_v0_3_size = sizeof(runtime·nacl_irt_memory_v0_3);
+
+int8 runtime·nacl_irt_thread_v0_1_str[] = "nacl-irt-thread-0.1";
+void *runtime·nacl_irt_thread_v0_1[3]; // thread_create, thread_exit, thread_nice
+int32 runtime·nacl_irt_thread_v0_1_size = sizeof(runtime·nacl_irt_thread_v0_1);
+*/ \ No newline at end of file
diff --git a/src/pkg/runtime/os_nacl.h b/src/pkg/runtime/os_nacl.h
new file mode 100644
index 000000000..7c9d9c242
--- /dev/null
+++ b/src/pkg/runtime/os_nacl.h
@@ -0,0 +1,162 @@
+enum {
+ NSIG = 32,
+ SI_USER = 1,
+
+ // native_client/src/trusted/service_runtime/include/sys/errno.h
+ // The errors are mainly copied from Linux.
+ EPERM = 1, /* Operation not permitted */
+ ENOENT = 2, /* No such file or directory */
+ ESRCH = 3, /* No such process */
+ EINTR = 4, /* Interrupted system call */
+ EIO = 5, /* I/O error */
+ ENXIO = 6, /* No such device or address */
+ E2BIG = 7, /* Argument list too long */
+ ENOEXEC = 8, /* Exec format error */
+ EBADF = 9, /* Bad file number */
+ ECHILD = 10, /* No child processes */
+ EAGAIN = 11, /* Try again */
+ ENOMEM = 12, /* Out of memory */
+ EACCES = 13, /* Permission denied */
+ EFAULT = 14, /* Bad address */
+ EBUSY = 16, /* Device or resource busy */
+ EEXIST = 17, /* File exists */
+ EXDEV = 18, /* Cross-device link */
+ ENODEV = 19, /* No such device */
+ ENOTDIR = 20, /* Not a directory */
+ EISDIR = 21, /* Is a directory */
+ EINVAL = 22, /* Invalid argument */
+ ENFILE = 23, /* File table overflow */
+ EMFILE = 24, /* Too many open files */
+ ENOTTY = 25, /* Not a typewriter */
+ EFBIG = 27, /* File too large */
+ ENOSPC = 28, /* No space left on device */
+ ESPIPE = 29, /* Illegal seek */
+ EROFS = 30, /* Read-only file system */
+ EMLINK = 31, /* Too many links */
+ EPIPE = 32, /* Broken pipe */
+ ENAMETOOLONG = 36, /* File name too long */
+ ENOSYS = 38, /* Function not implemented */
+ EDQUOT = 122, /* Quota exceeded */
+ EDOM = 33, /* Math arg out of domain of func */
+ ERANGE = 34, /* Math result not representable */
+ EDEADLK = 35, /* Deadlock condition */
+ ENOLCK = 37, /* No record locks available */
+ ENOTEMPTY = 39, /* Directory not empty */
+ ELOOP = 40, /* Too many symbolic links */
+ ENOMSG = 42, /* No message of desired type */
+ EIDRM = 43, /* Identifier removed */
+ ECHRNG = 44, /* Channel number out of range */
+ EL2NSYNC = 45, /* Level 2 not synchronized */
+ EL3HLT = 46, /* Level 3 halted */
+ EL3RST = 47, /* Level 3 reset */
+ ELNRNG = 48, /* Link number out of range */
+ EUNATCH = 49, /* Protocol driver not attached */
+ ENOCSI = 50, /* No CSI structure available */
+ EL2HLT = 51, /* Level 2 halted */
+ EBADE = 52, /* Invalid exchange */
+ EBADR = 53, /* Invalid request descriptor */
+ EXFULL = 54, /* Exchange full */
+ ENOANO = 55, /* No anode */
+ EBADRQC = 56, /* Invalid request code */
+ EBADSLT = 57, /* Invalid slot */
+ EDEADLOCK = EDEADLK, /* File locking deadlock error */
+ EBFONT = 59, /* Bad font file fmt */
+ ENOSTR = 60, /* Device not a stream */
+ ENODATA = 61, /* No data (for no delay io) */
+ ETIME = 62, /* Timer expired */
+ ENOSR = 63, /* Out of streams resources */
+ ENONET = 64, /* Machine is not on the network */
+ ENOPKG = 65, /* Package not installed */
+ EREMOTE = 66, /* The object is remote */
+ ENOLINK = 67, /* The link has been severed */
+ EADV = 68, /* Advertise error */
+ ESRMNT = 69, /* Srmount error */
+ ECOMM = 70, /* Communication error on send */
+ EPROTO = 71, /* Protocol error */
+ EMULTIHOP = 72, /* Multihop attempted */
+ EDOTDOT = 73, /* Cross mount point (not really error) */
+ EBADMSG = 74, /* Trying to read unreadable message */
+ EOVERFLOW = 75, /* Value too large for defined data type */
+ ENOTUNIQ = 76, /* Given log. name not unique */
+ EBADFD = 77, /* f.d. invalid for this operation */
+ EREMCHG = 78, /* Remote address changed */
+ ELIBACC = 79, /* Can't access a needed shared lib */
+ ELIBBAD = 80, /* Accessing a corrupted shared lib */
+ ELIBSCN = 81, /* .lib section in a.out corrupted */
+ ELIBMAX = 82, /* Attempting to link in too many libs */
+ ELIBEXEC = 83, /* Attempting to exec a shared library */
+ EILSEQ = 84,
+ EUSERS = 87,
+ ENOTSOCK = 88, /* Socket operation on non-socket */
+ EDESTADDRREQ = 89, /* Destination address required */
+ EMSGSIZE = 90, /* Message too long */
+ EPROTOTYPE = 91, /* Protocol wrong type for socket */
+ ENOPROTOOPT = 92, /* Protocol not available */
+ EPROTONOSUPPORT = 93, /* Unknown protocol */
+ ESOCKTNOSUPPORT = 94, /* Socket type not supported */
+ EOPNOTSUPP = 95, /* Operation not supported on transport endpoint */
+ EPFNOSUPPORT = 96, /* Protocol family not supported */
+ EAFNOSUPPORT = 97, /* Address family not supported by protocol family */
+ EADDRINUSE = 98, /* Address already in use */
+ EADDRNOTAVAIL = 99, /* Address not available */
+ ENETDOWN = 100, /* Network interface is not configured */
+ ENETUNREACH = 101, /* Network is unreachable */
+ ENETRESET = 102,
+ ECONNABORTED = 103, /* Connection aborted */
+ ECONNRESET = 104, /* Connection reset by peer */
+ ENOBUFS = 105, /* No buffer space available */
+ EISCONN = 106, /* Socket is already connected */
+ ENOTCONN = 107, /* Socket is not connected */
+ ESHUTDOWN = 108, /* Can't send after socket shutdown */
+ ETOOMANYREFS = 109,
+ ETIMEDOUT = 110, /* Connection timed out */
+ ECONNREFUSED = 111, /* Connection refused */
+ EHOSTDOWN = 112, /* Host is down */
+ EHOSTUNREACH = 113, /* Host is unreachable */
+ EALREADY = 114, /* Socket already connected */
+ EINPROGRESS = 115, /* Connection already in progress */
+ ESTALE = 116,
+ ENOTSUP = EOPNOTSUPP, /* Not supported */
+ ENOMEDIUM = 123, /* No medium (in tape drive) */
+ ECANCELED = 125, /* Operation canceled. */
+ ELBIN = 2048, /* Inode is remote (not really error) */
+ EFTYPE = 2049, /* Inappropriate file type or format */
+ ENMFILE = 2050, /* No more files */
+ EPROCLIM = 2051,
+ ENOSHARE = 2052, /* No such host or network path */
+ ECASECLASH = 2053, /* Filename exists with different case */
+ EWOULDBLOCK = EAGAIN, /* Operation would block */
+
+ // native_client/src/trusted/service_runtime/include/bits/mman.h.
+ // NOTE: DO NOT USE native_client/src/shared/imc/nacl_imc_c.h.
+ // Those MAP_*values are different from these.
+ PROT_NONE = 0x0,
+ PROT_READ = 0x1,
+ PROT_WRITE = 0x2,
+ PROT_EXEC = 0x4,
+
+ MAP_SHARED = 0x1,
+ MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
+ MAP_ANON = 0x20,
+};
+typedef byte* kevent_udata;
+
+int32 runtime·nacl_exception_stack(byte*, int32);
+int32 runtime·nacl_exception_handler(void*, void*);
+int32 runtime·nacl_sem_create(int32);
+int32 runtime·nacl_sem_wait(int32);
+int32 runtime·nacl_sem_post(int32);
+int32 runtime·nacl_mutex_create(int32);
+int32 runtime·nacl_mutex_lock(int32);
+int32 runtime·nacl_mutex_trylock(int32);
+int32 runtime·nacl_mutex_unlock(int32);
+int32 runtime·nacl_cond_create(int32);
+int32 runtime·nacl_cond_wait(int32, int32);
+int32 runtime·nacl_cond_signal(int32);
+int32 runtime·nacl_cond_broadcast(int32);
+int32 runtime·nacl_cond_timed_wait_abs(int32, int32, Timespec*);
+int32 runtime·nacl_thread_create(void*, void*, void*, void*);
+int32 runtime·nacl_nanosleep(Timespec*, Timespec*);
+
+void runtime·sigpanic(void);
diff --git a/src/pkg/runtime/os_netbsd.c b/src/pkg/runtime/os_netbsd.c
index a49dca295..93229bffe 100644
--- a/src/pkg/runtime/os_netbsd.c
+++ b/src/pkg/runtime/os_netbsd.c
@@ -188,6 +188,7 @@ runtime·osinit(void)
void
runtime·get_random_data(byte **rnd, int32 *rnd_len)
{
+ #pragma dataflag NOPTR
static byte urandom_data[HashRandomBytes];
int32 fd;
fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
@@ -237,9 +238,12 @@ runtime·unminit(void)
void
runtime·sigpanic(void)
{
+ if(!runtime·canpanic(g))
+ runtime·throw("unexpected signal during runtime execution");
+
switch(g->sig) {
case SIGBUS:
- if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
+ if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -247,7 +251,7 @@ runtime·sigpanic(void)
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGSEGV:
- if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
+ if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -326,3 +330,9 @@ runtime·signalstack(byte *p, int32 n)
st.ss_flags = SS_DISABLE;
runtime·sigaltstack(&st, nil);
}
+
+void
+runtime·unblocksignals(void)
+{
+ runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
+}
diff --git a/src/pkg/runtime/os_netbsd.h b/src/pkg/runtime/os_netbsd.h
index 55743c8d5..16e9833af 100644
--- a/src/pkg/runtime/os_netbsd.h
+++ b/src/pkg/runtime/os_netbsd.h
@@ -18,6 +18,7 @@ void runtime·setitimer(int32, Itimerval*, Itimerval*);
void runtime·sigaction(int32, struct sigaction*, struct sigaction*);
void runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
void runtime·sigprocmask(int32, Sigset*, Sigset*);
+void runtime·unblocksignals(void);
int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
extern void runtime·lwp_tramp(void);
diff --git a/src/pkg/runtime/os_openbsd.c b/src/pkg/runtime/os_openbsd.c
index 18377a047..08a290a05 100644
--- a/src/pkg/runtime/os_openbsd.c
+++ b/src/pkg/runtime/os_openbsd.c
@@ -82,7 +82,7 @@ runtime·semasleep(int64 ns)
// NOTE: tv_nsec is int64 on amd64, so this assumes a little-endian system.
ts.tv_nsec = 0;
ts.tv_sec = runtime·timediv(ns, 1000000000, (int32*)&ts.tv_nsec);
- runtime·thrsleep(&m->waitsemacount, CLOCK_REALTIME, &ts, &m->waitsemalock, nil);
+ runtime·thrsleep(&m->waitsemacount, CLOCK_MONOTONIC, &ts, &m->waitsemalock, nil);
}
// reacquire lock
while(runtime·xchg(&m->waitsemalock, 1))
@@ -167,6 +167,7 @@ runtime·osinit(void)
void
runtime·get_random_data(byte **rnd, int32 *rnd_len)
{
+ #pragma dataflag NOPTR
static byte urandom_data[HashRandomBytes];
int32 fd;
fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
@@ -214,9 +215,12 @@ runtime·unminit(void)
void
runtime·sigpanic(void)
{
+ if(!runtime·canpanic(g))
+ runtime·throw("unexpected signal during runtime execution");
+
switch(g->sig) {
case SIGBUS:
- if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
+ if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -224,7 +228,7 @@ runtime·sigpanic(void)
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGSEGV:
- if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
+ if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -300,3 +304,9 @@ runtime·signalstack(byte *p, int32 n)
st.ss_flags = SS_DISABLE;
runtime·sigaltstack(&st, nil);
}
+
+void
+runtime·unblocksignals(void)
+{
+ runtime·sigprocmask(SIG_SETMASK, sigset_none);
+}
diff --git a/src/pkg/runtime/os_openbsd.h b/src/pkg/runtime/os_openbsd.h
index 4746b314f..bbfde39e2 100644
--- a/src/pkg/runtime/os_openbsd.h
+++ b/src/pkg/runtime/os_openbsd.h
@@ -18,6 +18,7 @@ void runtime·setitimer(int32, Itimerval*, Itimerval*);
void runtime·sigaction(int32, struct sigaction*, struct sigaction*);
void runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
Sigset runtime·sigprocmask(int32, Sigset);
+void runtime·unblocksignals(void);
int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
#define NSIG 33
diff --git a/src/pkg/runtime/os_plan9.c b/src/pkg/runtime/os_plan9.c
index 07db2c305..14d4fae48 100644
--- a/src/pkg/runtime/os_plan9.c
+++ b/src/pkg/runtime/os_plan9.c
@@ -102,8 +102,18 @@ runtime·crash(void)
void
runtime·get_random_data(byte **rnd, int32 *rnd_len)
{
- *rnd = nil;
- *rnd_len = 0;
+ static byte random_data[HashRandomBytes];
+ int32 fd;
+
+ fd = runtime·open("/dev/random", 0 /* O_RDONLY */, 0);
+ if(runtime·read(fd, random_data, HashRandomBytes) == HashRandomBytes) {
+ *rnd = random_data;
+ *rnd_len = HashRandomBytes;
+ } else {
+ *rnd = nil;
+ *rnd_len = 0;
+ }
+ runtime·close(fd);
}
void
@@ -183,13 +193,15 @@ runtime·itoa(int32 n, byte *p, uint32 len)
void
runtime·goexitsall(int8 *status)
{
+ int8 buf[ERRMAX];
M *mp;
int32 pid;
+ runtime·snprintf((byte*)buf, sizeof buf, "go: exit %s", status);
pid = getpid();
for(mp=runtime·atomicloadp(&runtime·allm); mp; mp=mp->alllink)
if(mp->procid != pid)
- runtime·postnote(mp->procid, status);
+ runtime·postnote(mp->procid, buf);
}
int32
@@ -271,6 +283,8 @@ runtime·semasleep(int64 ns)
if(ns >= 0) {
ms = runtime·timediv(ns, 1000000, nil);
+ if(ms == 0)
+ ms = 1;
ret = runtime·plan9_tsemacquire(&m->waitsemacount, ms);
if(ret == 1)
return 0; // success
@@ -295,15 +309,82 @@ os·sigpipe(void)
runtime·throw("too many writes on closed pipe");
}
+static int64
+atolwhex(byte *p)
+{
+ int64 n;
+ int32 f;
+
+ n = 0;
+ f = 0;
+ while(*p == ' ' || *p == '\t')
+ p++;
+ if(*p == '-' || *p == '+') {
+ if(*p++ == '-')
+ f = 1;
+ while(*p == ' ' || *p == '\t')
+ p++;
+ }
+ if(p[0] == '0' && p[1]) {
+ if(p[1] == 'x' || p[1] == 'X') {
+ p += 2;
+ for(;;) {
+ if('0' <= *p && *p <= '9')
+ n = n*16 + *p++ - '0';
+ else if('a' <= *p && *p <= 'f')
+ n = n*16 + *p++ - 'a' + 10;
+ else if('A' <= *p && *p <= 'F')
+ n = n*16 + *p++ - 'A' + 10;
+ else
+ break;
+ }
+ } else
+ while('0' <= *p && *p <= '7')
+ n = n*8 + *p++ - '0';
+ } else
+ while('0' <= *p && *p <= '9')
+ n = n*10 + *p++ - '0';
+ if(f)
+ n = -n;
+ return n;
+}
+
void
runtime·sigpanic(void)
{
- if(g->sigpc == 0)
- runtime·panicstring("call of nil func value");
- runtime·panicstring(m->notesig);
-
- if(g->sig == 1 || g->sig == 2)
+ byte *p;
+
+ if(!runtime·canpanic(g))
+ runtime·throw("unexpected signal during runtime execution");
+
+ switch(g->sig) {
+ case SIGRFAULT:
+ case SIGWFAULT:
+ p = runtime·strstr((byte*)m->notesig, (byte*)"addr=")+5;
+ g->sigcode1 = atolwhex(p);
+ if(g->sigcode1 < 0x1000 || g->paniconfault) {
+ if(g->sigpc == 0)
+ runtime·panicstring("call of nil func value");
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ }
+ runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
+ break;
+ case SIGTRAP:
+ if(g->paniconfault)
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ runtime·throw(m->notesig);
+ break;
+ case SIGINTDIV:
+ runtime·panicstring("integer divide by zero");
+ break;
+ case SIGFLOAT:
+ runtime·panicstring("floating point error");
+ break;
+ default:
+ runtime·panicstring(m->notesig);
+ break;
+ }
}
int32
@@ -313,9 +394,9 @@ runtime·read(int32 fd, void *buf, int32 nbytes)
}
int32
-runtime·write(int32 fd, void *buf, int32 nbytes)
+runtime·write(uintptr fd, void *buf, int32 nbytes)
{
- return runtime·pwrite(fd, buf, nbytes, -1LL);
+ return runtime·pwrite((int32)fd, buf, nbytes, -1LL);
}
uintptr
diff --git a/src/pkg/runtime/os_plan9.h b/src/pkg/runtime/os_plan9.h
index f0474cda5..00ea8366d 100644
--- a/src/pkg/runtime/os_plan9.h
+++ b/src/pkg/runtime/os_plan9.h
@@ -78,5 +78,12 @@ struct Tos {
/* top of stack is here */
};
-#define NSIG 5 /* number of signals in runtime·SigTab array */
+#define NSIG 14 /* number of signals in runtime·SigTab array */
#define ERRMAX 128 /* max length of note string */
+
+/* Notes in runtime·sigtab that are handled by runtime·sigpanic. */
+#define SIGRFAULT 2
+#define SIGWFAULT 3
+#define SIGINTDIV 4
+#define SIGFLOAT 5
+#define SIGTRAP 6
diff --git a/src/pkg/runtime/os_plan9_386.c b/src/pkg/runtime/os_plan9_386.c
index 0844d726b..80d711f33 100644
--- a/src/pkg/runtime/os_plan9_386.c
+++ b/src/pkg/runtime/os_plan9_386.c
@@ -10,71 +10,80 @@
void
runtime·dumpregs(Ureg *u)
{
- runtime·printf("ax %X\n", u->ax);
- runtime·printf("bx %X\n", u->bx);
- runtime·printf("cx %X\n", u->cx);
- runtime·printf("dx %X\n", u->dx);
- runtime·printf("di %X\n", u->di);
- runtime·printf("si %X\n", u->si);
- runtime·printf("bp %X\n", u->bp);
- runtime·printf("sp %X\n", u->sp);
- runtime·printf("pc %X\n", u->pc);
- runtime·printf("flags %X\n", u->flags);
- runtime·printf("cs %X\n", u->cs);
- runtime·printf("fs %X\n", u->fs);
- runtime·printf("gs %X\n", u->gs);
+ runtime·printf("ax %x\n", u->ax);
+ runtime·printf("bx %x\n", u->bx);
+ runtime·printf("cx %x\n", u->cx);
+ runtime·printf("dx %x\n", u->dx);
+ runtime·printf("di %x\n", u->di);
+ runtime·printf("si %x\n", u->si);
+ runtime·printf("bp %x\n", u->bp);
+ runtime·printf("sp %x\n", u->sp);
+ runtime·printf("pc %x\n", u->pc);
+ runtime·printf("flags %x\n", u->flags);
+ runtime·printf("cs %x\n", u->cs);
+ runtime·printf("fs %x\n", u->fs);
+ runtime·printf("gs %x\n", u->gs);
}
int32
-runtime·sighandler(void *v, int8 *s, G *gp)
+runtime·sighandler(void *v, int8 *note, G *gp)
{
+ uintptr *sp;
+ SigTab *t;
bool crash;
Ureg *ureg;
- uintptr *sp;
- SigTab *sig, *nsig;
- intgo len, i;
+ intgo len, n;
+ int32 sig, flags;
- if(!s)
- return NCONT;
-
- len = runtime·findnull((byte*)s);
- if(len <= 4 || runtime·mcmp((byte*)s, (byte*)"sys:", 4) != 0)
- return NDFLT;
-
- nsig = nil;
- sig = runtime·sigtab;
- for(i=0; i < NSIG; i++) {
- if(runtime·strstr((byte*)s, (byte*)sig->name)) {
- nsig = sig;
+ ureg = (Ureg*)v;
+
+ // The kernel will never pass us a nil note or ureg so we probably
+ // made a mistake somewhere in runtime·sigtramp.
+ if(ureg == nil || note == nil) {
+ runtime·printf("sighandler: ureg %p note %p\n", ureg, note);
+ goto Throw;
+ }
+
+ // Check that the note is no more than ERRMAX bytes (including
+ // the trailing NUL). We should never receive a longer note.
+ len = runtime·findnull((byte*)note);
+ if(len > ERRMAX-1) {
+ runtime·printf("sighandler: note is longer than ERRMAX\n");
+ goto Throw;
+ }
+
+ // See if the note matches one of the patterns in runtime·sigtab.
+ // Notes that do not match any pattern can be handled at a higher
+ // level by the program but will otherwise be ignored.
+ flags = SigNotify;
+ for(sig = 0; sig < nelem(runtime·sigtab); sig++) {
+ t = &runtime·sigtab[sig];
+ n = runtime·findnull((byte*)t->name);
+ if(len < n)
+ continue;
+ if(runtime·strncmp((byte*)note, (byte*)t->name, n) == 0) {
+ flags = t->flags;
break;
}
- sig++;
}
- if(nsig == nil)
- return NDFLT;
-
- ureg = v;
- if(nsig->flags & SigPanic) {
- if(gp == nil || m->notesig == 0)
- goto Throw;
+ if(flags & SigGoExit)
+ runtime·exits(note+9); // Strip "go: exit " prefix.
- // Save error string from sigtramp's stack,
- // into gsignal->sigcode0, so we can reliably
- // access it from the panic routines.
- if(len > ERRMAX)
- len = ERRMAX;
- runtime·memmove((void*)m->notesig, (void*)s, len);
+ if(flags & SigPanic) {
+ // Copy the error string from sigtramp's stack into m->notesig so
+ // we can reliably access it from the panic routines.
+ runtime·memmove(m->notesig, note, len+1);
- gp->sig = i;
+ gp->sig = sig;
gp->sigpc = ureg->pc;
- // Only push runtime·sigpanic if ureg->pc != 0.
- // If ureg->pc == 0, probably panicked because of a
- // call to a nil func. Not pushing that onto sp will
- // make the trace look like a call to runtime·sigpanic instead.
- // (Otherwise the trace will end at runtime·sigpanic and we
- // won't get to see who faulted.)
+ // Only push runtime·sigpanic if PC != 0.
+ //
+ // If PC == 0, probably panicked because of a call to a nil func.
+ // Not pushing that onto SP will make the trace look like a call
+ // to runtime·sigpanic instead. (Otherwise the trace will end at
+ // runtime·sigpanic and we won't get to see who faulted).
if(ureg->pc != 0) {
sp = (uintptr*)ureg->sp;
*--sp = ureg->pc;
@@ -84,34 +93,42 @@ runtime·sighandler(void *v, int8 *s, G *gp)
return NCONT;
}
- if(!(nsig->flags & SigThrow))
- return NDFLT;
+ if(flags & SigNotify) {
+ // TODO(ality): See if os/signal wants it.
+ //if(runtime·sigsend(...))
+ // return NCONT;
+ }
+ if(flags & SigKill)
+ goto Exit;
+ if(!(flags & SigThrow))
+ return NCONT;
Throw:
m->throwing = 1;
m->caughtsig = gp;
runtime·startpanic();
- runtime·printf("%s\n", s);
- runtime·printf("PC=%X\n", ureg->pc);
+ runtime·printf("%s\n", note);
+ runtime·printf("PC=%x\n", ureg->pc);
runtime·printf("\n");
if(runtime·gotraceback(&crash)) {
+ runtime·goroutineheader(gp);
runtime·traceback(ureg->pc, ureg->sp, 0, gp);
runtime·tracebackothers(gp);
+ runtime·printf("\n");
runtime·dumpregs(ureg);
}
if(crash)
runtime·crash();
- runtime·goexitsall("");
- runtime·exits(s);
-
- return 0;
+Exit:
+ runtime·goexitsall(note);
+ runtime·exits(note);
+ return NDFLT; // not reached
}
-
void
runtime·sigenable(uint32 sig)
{
diff --git a/src/pkg/runtime/os_plan9_amd64.c b/src/pkg/runtime/os_plan9_amd64.c
index 58822ff84..a4e5ba819 100644
--- a/src/pkg/runtime/os_plan9_amd64.c
+++ b/src/pkg/runtime/os_plan9_amd64.c
@@ -34,55 +34,64 @@ runtime·dumpregs(Ureg *u)
}
int32
-runtime·sighandler(void *v, int8 *s, G *gp)
+runtime·sighandler(void *v, int8 *note, G *gp)
{
+ uintptr *sp;
+ SigTab *t;
bool crash;
Ureg *ureg;
- uintptr *sp;
- SigTab *sig, *nsig;
- intgo i, len;
+ intgo len, n;
+ int32 sig, flags;
- if(!s)
- return NCONT;
-
- len = runtime·findnull((byte*)s);
- if(len <= 4 || runtime·mcmp((byte*)s, (byte*)"sys:", 4) != 0)
- return NDFLT;
-
- nsig = nil;
- sig = runtime·sigtab;
- for(i=0; i < NSIG; i++) {
- if(runtime·strstr((byte*)s, (byte*)sig->name)) {
- nsig = sig;
+ ureg = (Ureg*)v;
+
+ // The kernel will never pass us a nil note or ureg so we probably
+ // made a mistake somewhere in runtime·sigtramp.
+ if(ureg == nil || note == nil) {
+ runtime·printf("sighandler: ureg %p note %p\n", ureg, note);
+ goto Throw;
+ }
+
+ // Check that the note is no more than ERRMAX bytes (including
+ // the trailing NUL). We should never receive a longer note.
+ len = runtime·findnull((byte*)note);
+ if(len > ERRMAX-1) {
+ runtime·printf("sighandler: note is longer than ERRMAX\n");
+ goto Throw;
+ }
+
+ // See if the note matches one of the patterns in runtime·sigtab.
+ // Notes that do not match any pattern can be handled at a higher
+ // level by the program but will otherwise be ignored.
+ flags = SigNotify;
+ for(sig = 0; sig < nelem(runtime·sigtab); sig++) {
+ t = &runtime·sigtab[sig];
+ n = runtime·findnull((byte*)t->name);
+ if(len < n)
+ continue;
+ if(runtime·strncmp((byte*)note, (byte*)t->name, n) == 0) {
+ flags = t->flags;
break;
}
- sig++;
}
- if(nsig == nil)
- return NDFLT;
-
- ureg = v;
- if(nsig->flags & SigPanic) {
- if(gp == nil || m->notesig == 0)
- goto Throw;
+ if(flags & SigGoExit)
+ runtime·exits(note+9); // Strip "go: exit " prefix.
- // Save error string from sigtramp's stack,
- // into gsignal->sigcode0, so we can reliably
- // access it from the panic routines.
- if(len > ERRMAX)
- len = ERRMAX;
- runtime·memmove((void*)m->notesig, (void*)s, len);
+ if(flags & SigPanic) {
+ // Copy the error string from sigtramp's stack into m->notesig so
+ // we can reliably access it from the panic routines.
+ runtime·memmove(m->notesig, note, len+1);
- gp->sig = i;
+ gp->sig = sig;
gp->sigpc = ureg->ip;
- // Only push runtime·sigpanic if ureg->ip != 0.
- // If ureg->ip == 0, probably panicked because of a
- // call to a nil func. Not pushing that onto sp will
- // make the trace look like a call to runtime·sigpanic instead.
- // (Otherwise the trace will end at runtime·sigpanic and we
- // won't get to see who faulted.)
+ // Only push runtime·sigpanic if PC != 0.
+ //
+ // If PC == 0, probably panicked because of a call to a nil func.
+ // Not pushing that onto SP will make the trace look like a call
+ // to runtime·sigpanic instead. (Otherwise the trace will end at
+ // runtime·sigpanic and we won't get to see who faulted).
if(ureg->ip != 0) {
sp = (uintptr*)ureg->sp;
*--sp = ureg->ip;
@@ -92,31 +101,40 @@ runtime·sighandler(void *v, int8 *s, G *gp)
return NCONT;
}
- if(!(nsig->flags & SigThrow))
- return NDFLT;
+ if(flags & SigNotify) {
+ // TODO(ality): See if os/signal wants it.
+ //if(runtime·sigsend(...))
+ // return NCONT;
+ }
+ if(flags & SigKill)
+ goto Exit;
+ if(!(flags & SigThrow))
+ return NCONT;
Throw:
m->throwing = 1;
m->caughtsig = gp;
runtime·startpanic();
- runtime·printf("%s\n", s);
+ runtime·printf("%s\n", note);
runtime·printf("PC=%X\n", ureg->ip);
runtime·printf("\n");
if(runtime·gotraceback(&crash)) {
+ runtime·goroutineheader(gp);
runtime·traceback(ureg->ip, ureg->sp, 0, gp);
runtime·tracebackothers(gp);
+ runtime·printf("\n");
runtime·dumpregs(ureg);
}
if(crash)
runtime·crash();
- runtime·goexitsall("");
- runtime·exits(s);
-
- return 0;
+Exit:
+ runtime·goexitsall(note);
+ runtime·exits(note);
+ return NDFLT; // not reached
}
void
diff --git a/src/pkg/runtime/os_solaris.c b/src/pkg/runtime/os_solaris.c
new file mode 100644
index 000000000..c6bbea311
--- /dev/null
+++ b/src/pkg/runtime/os_solaris.c
@@ -0,0 +1,583 @@
+// 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.
+
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "signal_unix.h"
+#include "stack.h"
+#include "../../cmd/ld/textflag.h"
+
+#pragma dynexport end _end
+#pragma dynexport etext _etext
+#pragma dynexport edata _edata
+
+#pragma dynimport libc·___errno ___errno "libc.so"
+#pragma dynimport libc·clock_gettime clock_gettime "libc.so"
+#pragma dynimport libc·close close "libc.so"
+#pragma dynimport libc·exit exit "libc.so"
+#pragma dynimport libc·fstat fstat "libc.so"
+#pragma dynimport libc·getcontext getcontext "libc.so"
+#pragma dynimport libc·getrlimit getrlimit "libc.so"
+#pragma dynimport libc·malloc malloc "libc.so"
+#pragma dynimport libc·mmap mmap "libc.so"
+#pragma dynimport libc·munmap munmap "libc.so"
+#pragma dynimport libc·open open "libc.so"
+#pragma dynimport libc·pthread_attr_destroy pthread_attr_destroy "libc.so"
+#pragma dynimport libc·pthread_attr_getstack pthread_attr_getstack "libc.so"
+#pragma dynimport libc·pthread_attr_init pthread_attr_init "libc.so"
+#pragma dynimport libc·pthread_attr_setdetachstate pthread_attr_setdetachstate "libc.so"
+#pragma dynimport libc·pthread_attr_setstack pthread_attr_setstack "libc.so"
+#pragma dynimport libc·pthread_create pthread_create "libc.so"
+#pragma dynimport libc·raise raise "libc.so"
+#pragma dynimport libc·read read "libc.so"
+#pragma dynimport libc·select select "libc.so"
+#pragma dynimport libc·sched_yield sched_yield "libc.so"
+#pragma dynimport libc·sem_init sem_init "libc.so"
+#pragma dynimport libc·sem_post sem_post "libc.so"
+#pragma dynimport libc·sem_reltimedwait_np sem_reltimedwait_np "libc.so"
+#pragma dynimport libc·sem_wait sem_wait "libc.so"
+#pragma dynimport libc·setitimer setitimer "libc.so"
+#pragma dynimport libc·sigaction sigaction "libc.so"
+#pragma dynimport libc·sigaltstack sigaltstack "libc.so"
+#pragma dynimport libc·sigprocmask sigprocmask "libc.so"
+#pragma dynimport libc·sysconf sysconf "libc.so"
+#pragma dynimport libc·usleep usleep "libc.so"
+#pragma dynimport libc·write write "libc.so"
+
+extern uintptr libc·___errno;
+extern uintptr libc·clock_gettime;
+extern uintptr libc·close;
+extern uintptr libc·exit;
+extern uintptr libc·fstat;
+extern uintptr libc·getcontext;
+extern uintptr libc·getrlimit;
+extern uintptr libc·malloc;
+extern uintptr libc·mmap;
+extern uintptr libc·munmap;
+extern uintptr libc·open;
+extern uintptr libc·pthread_attr_destroy;
+extern uintptr libc·pthread_attr_getstack;
+extern uintptr libc·pthread_attr_init;
+extern uintptr libc·pthread_attr_setdetachstate;
+extern uintptr libc·pthread_attr_setstack;
+extern uintptr libc·pthread_create;
+extern uintptr libc·raise;
+extern uintptr libc·read;
+extern uintptr libc·sched_yield;
+extern uintptr libc·select;
+extern uintptr libc·sem_init;
+extern uintptr libc·sem_post;
+extern uintptr libc·sem_reltimedwait_np;
+extern uintptr libc·sem_wait;
+extern uintptr libc·setitimer;
+extern uintptr libc·sigaction;
+extern uintptr libc·sigaltstack;
+extern uintptr libc·sigprocmask;
+extern uintptr libc·sysconf;
+extern uintptr libc·usleep;
+extern uintptr libc·write;
+
+void runtime·getcontext(Ucontext *context);
+int32 runtime·pthread_attr_destroy(PthreadAttr* attr);
+int32 runtime·pthread_attr_init(PthreadAttr* attr);
+int32 runtime·pthread_attr_getstack(PthreadAttr* attr, void** addr, uint64* size);
+int32 runtime·pthread_attr_setdetachstate(PthreadAttr* attr, int32 state);
+int32 runtime·pthread_attr_setstack(PthreadAttr* attr, void* addr, uint64 size);
+int32 runtime·pthread_create(Pthread* thread, PthreadAttr* attr, void(*fn)(void), void *arg);
+uint32 runtime·tstart_sysvicall(M *newm);
+int32 runtime·sem_init(SemT* sem, int32 pshared, uint32 value);
+int32 runtime·sem_post(SemT* sem);
+int32 runtime·sem_reltimedwait_np(SemT* sem, Timespec* timeout);
+int32 runtime·sem_wait(SemT* sem);
+int64 runtime·sysconf(int32 name);
+
+extern SigTab runtime·sigtab[];
+static Sigset sigset_none;
+static Sigset sigset_all = { ~(uint32)0, ~(uint32)0, ~(uint32)0, ~(uint32)0, };
+
+// Calling sysvcall on os stack.
+#pragma textflag NOSPLIT
+uintptr
+runtime·sysvicall6(uintptr fn, int32 count, ...)
+{
+ runtime·memclr((byte*)&m->scratch, sizeof(m->scratch));
+ m->libcall.fn = (void*)fn;
+ m->libcall.n = (uintptr)count;
+ for(;count; count--)
+ m->scratch.v[count - 1] = *((uintptr*)&count + count);
+ m->libcall.args = (uintptr*)&m->scratch.v[0];
+ runtime·asmcgocall(runtime·asmsysvicall6, &m->libcall);
+ return m->libcall.r1;
+}
+
+static int32
+getncpu(void)
+{
+ int32 n;
+
+ n = (int32)runtime·sysconf(_SC_NPROCESSORS_ONLN);
+ if(n < 1)
+ return 1;
+ return n;
+}
+
+void
+runtime·osinit(void)
+{
+ runtime·ncpu = getncpu();
+}
+
+void
+runtime·newosproc(M *mp, void *stk)
+{
+ PthreadAttr attr;
+ Sigset oset;
+ Pthread tid;
+ int32 ret;
+
+ USED(stk);
+ if(runtime·pthread_attr_init(&attr) != 0)
+ runtime·throw("pthread_attr_init");
+ if(runtime·pthread_attr_setstack(&attr, 0, 0x200000) != 0)
+ runtime·throw("pthread_attr_setstack");
+ if(runtime·pthread_attr_getstack(&attr, (void**)&mp->g0->stackbase, &mp->g0->stacksize) != 0)
+ runtime·throw("pthread_attr_getstack");
+ if(runtime·pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0)
+ runtime·throw("pthread_attr_setdetachstate");
+
+ // Disable signals during create, so that the new thread starts
+ // with signals disabled. It will enable them in minit.
+ runtime·sigprocmask(SIG_SETMASK, &sigset_all, &oset);
+ ret = runtime·pthread_create(&tid, &attr, (void (*)(void))runtime·tstart_sysvicall, mp);
+ runtime·sigprocmask(SIG_SETMASK, &oset, nil);
+ if(ret != 0) {
+ runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), ret);
+ runtime·throw("runtime.newosproc");
+ }
+}
+
+void
+runtime·get_random_data(byte **rnd, int32 *rnd_len)
+{
+ #pragma dataflag NOPTR
+ static byte urandom_data[HashRandomBytes];
+ int32 fd;
+ fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
+ if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) {
+ *rnd = urandom_data;
+ *rnd_len = HashRandomBytes;
+ } else {
+ *rnd = nil;
+ *rnd_len = 0;
+ }
+ runtime·close(fd);
+}
+
+void
+runtime·goenvs(void)
+{
+ runtime·goenvs_unix();
+}
+
+// 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
+runtime·mpreinit(M *mp)
+{
+ mp->gsignal = runtime·malg(32*1024);
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+void
+runtime·minit(void)
+{
+ runtime·asmcgocall(runtime·miniterrno, (void *)libc·___errno);
+ // Initialize signal handling
+ runtime·signalstack((byte*)m->gsignal->stackguard - StackGuard, 32*1024);
+ runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
+}
+
+// Called from dropm to undo the effect of an minit.
+void
+runtime·unminit(void)
+{
+ runtime·signalstack(nil, 0);
+}
+
+void
+runtime·sigpanic(void)
+{
+ if(!runtime·canpanic(g))
+ runtime·throw("unexpected signal during runtime execution");
+
+ switch(g->sig) {
+ case SIGBUS:
+ if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
+ if(g->sigpc == 0)
+ runtime·panicstring("call of nil func value");
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ }
+ runtime·printf("unexpected fault address %p\n", g->sigcode1);
+ runtime·throw("fault");
+ case SIGSEGV:
+ if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
+ if(g->sigpc == 0)
+ runtime·panicstring("call of nil func value");
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ }
+ runtime·printf("unexpected fault address %p\n", g->sigcode1);
+ runtime·throw("fault");
+ case SIGFPE:
+ switch(g->sigcode0) {
+ case FPE_INTDIV:
+ runtime·panicstring("integer divide by zero");
+ case FPE_INTOVF:
+ runtime·panicstring("integer overflow");
+ }
+ runtime·panicstring("floating point error");
+ }
+ runtime·panicstring(runtime·sigtab[g->sig].name);
+}
+
+uintptr
+runtime·memlimit(void)
+{
+ Rlimit rl;
+ extern byte text[], end[];
+ uintptr used;
+
+ if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
+ return 0;
+ if(rl.rlim_cur >= 0x7fffffff)
+ return 0;
+
+ // Estimate our VM footprint excluding the heap.
+ // Not an exact science: use size of binary plus
+ // some room for thread stacks.
+ used = end - text + (64<<20);
+ if(used >= rl.rlim_cur)
+ return 0;
+
+ // If there's not at least 16 MB left, we're probably
+ // not going to be able to do much. Treat as no limit.
+ rl.rlim_cur -= used;
+ if(rl.rlim_cur < (16<<20))
+ return 0;
+
+ return rl.rlim_cur - used;
+}
+
+void
+runtime·setprof(bool on)
+{
+ USED(on);
+}
+
+extern void runtime·sigtramp(void);
+
+void
+runtime·setsig(int32 i, GoSighandler *fn, bool restart)
+{
+ Sigaction sa;
+
+ runtime·memclr((byte*)&sa, sizeof sa);
+ sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
+ if(restart)
+ sa.sa_flags |= SA_RESTART;
+ sa.sa_mask.__sigbits[0] = ~(uint32)0;
+ sa.sa_mask.__sigbits[1] = ~(uint32)0;
+ sa.sa_mask.__sigbits[2] = ~(uint32)0;
+ sa.sa_mask.__sigbits[3] = ~(uint32)0;
+ if(fn == runtime·sighandler)
+ fn = (void*)runtime·sigtramp;
+ *((void**)&sa._funcptr[0]) = (void*)fn;
+ runtime·sigaction(i, &sa, nil);
+}
+
+GoSighandler*
+runtime·getsig(int32 i)
+{
+ Sigaction sa;
+
+ runtime·memclr((byte*)&sa, sizeof sa);
+ runtime·sigaction(i, nil, &sa);
+ if(*((void**)&sa._funcptr[0]) == runtime·sigtramp)
+ return runtime·sighandler;
+ return *((void**)&sa._funcptr[0]);
+}
+
+void
+runtime·signalstack(byte *p, int32 n)
+{
+ StackT st;
+
+ st.ss_sp = (void*)p;
+ st.ss_size = n;
+ st.ss_flags = 0;
+ if(p == nil)
+ st.ss_flags = SS_DISABLE;
+ runtime·sigaltstack(&st, nil);
+}
+
+void
+runtime·unblocksignals(void)
+{
+ runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
+}
+
+#pragma textflag NOSPLIT
+uintptr
+runtime·semacreate(void)
+{
+ SemT* sem;
+
+ // Call libc's malloc rather than runtime·malloc. This will
+ // allocate space on the C heap. We can't call runtime·malloc
+ // here because it could cause a deadlock.
+ m->libcall.fn = (void*)libc·malloc;
+ m->libcall.n = 1;
+ runtime·memclr((byte*)&m->scratch, sizeof(m->scratch));
+ m->scratch.v[0] = (uintptr)sizeof(*sem);
+ m->libcall.args = (uintptr*)&m->scratch;
+ runtime·asmcgocall(runtime·asmsysvicall6, &m->libcall);
+ sem = (void*)m->libcall.r1;
+ if(runtime·sem_init(sem, 0, 0) != 0)
+ runtime·throw("sem_init");
+ return (uintptr)sem;
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·semasleep(int64 ns)
+{
+ if(ns >= 0) {
+ m->ts.tv_sec = ns / 1000000000LL;
+ m->ts.tv_nsec = ns % 1000000000LL;
+
+ m->libcall.fn = (void*)libc·sem_reltimedwait_np;
+ m->libcall.n = 2;
+ runtime·memclr((byte*)&m->scratch, sizeof(m->scratch));
+ m->scratch.v[0] = m->waitsema;
+ m->scratch.v[1] = (uintptr)&m->ts;
+ m->libcall.args = (uintptr*)&m->scratch;
+ runtime·asmcgocall(runtime·asmsysvicall6, &m->libcall);
+ if(*m->perrno != 0) {
+ if(*m->perrno == ETIMEDOUT || *m->perrno == EAGAIN || *m->perrno == EINTR)
+ return -1;
+ runtime·throw("sem_reltimedwait_np");
+ }
+ return 0;
+ }
+ for(;;) {
+ m->libcall.fn = (void*)libc·sem_wait;
+ m->libcall.n = 1;
+ runtime·memclr((byte*)&m->scratch, sizeof(m->scratch));
+ m->scratch.v[0] = m->waitsema;
+ m->libcall.args = (uintptr*)&m->scratch;
+ runtime·asmcgocall(runtime·asmsysvicall6, &m->libcall);
+ if(m->libcall.r1 == 0)
+ break;
+ if(*m->perrno == EINTR)
+ continue;
+ runtime·throw("sem_wait");
+ }
+ return 0;
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·semawakeup(M *mp)
+{
+ SemT* sem = (SemT*)mp->waitsema;
+ if(runtime·sem_post(sem) != 0)
+ runtime·throw("sem_post");
+}
+
+int32
+runtime·close(int32 fd)
+{
+ return runtime·sysvicall6(libc·close, 1, (uintptr)fd);
+}
+
+void
+runtime·exit(int32 r)
+{
+ runtime·sysvicall6(libc·exit, 1, (uintptr)r);
+}
+
+/* int32 */ void
+runtime·getcontext(Ucontext* context)
+{
+ runtime·sysvicall6(libc·getcontext, 1, (uintptr)context);
+}
+
+int32
+runtime·getrlimit(int32 res, Rlimit* rlp)
+{
+ return runtime·sysvicall6(libc·getrlimit, 2, (uintptr)res, (uintptr)rlp);
+}
+
+uint8*
+runtime·mmap(byte* addr, uintptr len, int32 prot, int32 flags, int32 fildes, uint32 off)
+{
+ return (uint8*)runtime·sysvicall6(libc·mmap, 6, (uintptr)addr, (uintptr)len, (uintptr)prot, (uintptr)flags, (uintptr)fildes, (uintptr)off);
+}
+
+void
+runtime·munmap(byte* addr, uintptr len)
+{
+ runtime·sysvicall6(libc·munmap, 2, (uintptr)addr, (uintptr)len);
+}
+
+extern int64 runtime·nanotime1(void);
+#pragma textflag NOSPLIT
+int64
+runtime·nanotime(void)
+{
+ return runtime·sysvicall6((uintptr)runtime·nanotime1, 0);
+}
+
+void
+time·now(int64 sec, int32 usec)
+{
+ int64 ns;
+
+ ns = runtime·nanotime();
+ sec = ns / 1000000000LL;
+ usec = ns - sec * 1000000000LL;
+ FLUSH(&sec);
+ FLUSH(&usec);
+}
+
+int32
+runtime·open(int8* path, int32 oflag, int32 mode)
+{
+ return runtime·sysvicall6(libc·open, 3, (uintptr)path, (uintptr)oflag, (uintptr)mode);
+}
+
+int32
+runtime·pthread_attr_destroy(PthreadAttr* attr)
+{
+ return runtime·sysvicall6(libc·pthread_attr_destroy, 1, (uintptr)attr);
+}
+
+int32
+runtime·pthread_attr_getstack(PthreadAttr* attr, void** addr, uint64* size)
+{
+ return runtime·sysvicall6(libc·pthread_attr_getstack, 3, (uintptr)attr, (uintptr)addr, (uintptr)size);
+}
+
+int32
+runtime·pthread_attr_init(PthreadAttr* attr)
+{
+ return runtime·sysvicall6(libc·pthread_attr_init, 1, (uintptr)attr);
+}
+
+int32
+runtime·pthread_attr_setdetachstate(PthreadAttr* attr, int32 state)
+{
+ return runtime·sysvicall6(libc·pthread_attr_setdetachstate, 2, (uintptr)attr, (uintptr)state);
+}
+
+int32
+runtime·pthread_attr_setstack(PthreadAttr* attr, void* addr, uint64 size)
+{
+ return runtime·sysvicall6(libc·pthread_attr_setstack, 3, (uintptr)attr, (uintptr)addr, (uintptr)size);
+}
+
+int32
+runtime·pthread_create(Pthread* thread, PthreadAttr* attr, void(*fn)(void), void *arg)
+{
+ return runtime·sysvicall6(libc·pthread_create, 4, (uintptr)thread, (uintptr)attr, (uintptr)fn, (uintptr)arg);
+}
+
+/* int32 */ void
+runtime·raise(int32 sig)
+{
+ runtime·sysvicall6(libc·raise, 1, (uintptr)sig);
+}
+
+int32
+runtime·read(int32 fd, void* buf, int32 nbyte)
+{
+ return runtime·sysvicall6(libc·read, 3, (uintptr)fd, (uintptr)buf, (uintptr)nbyte);
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·sem_init(SemT* sem, int32 pshared, uint32 value)
+{
+ return runtime·sysvicall6(libc·sem_init, 3, (uintptr)sem, (uintptr)pshared, (uintptr)value);
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·sem_post(SemT* sem)
+{
+ return runtime·sysvicall6(libc·sem_post, 1, (uintptr)sem);
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·sem_reltimedwait_np(SemT* sem, Timespec* timeout)
+{
+ return runtime·sysvicall6(libc·sem_reltimedwait_np, 2, (uintptr)sem, (uintptr)timeout);
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·sem_wait(SemT* sem)
+{
+ return runtime·sysvicall6(libc·sem_wait, 1, (uintptr)sem);
+}
+
+/* int32 */ void
+runtime·setitimer(int32 which, Itimerval* value, Itimerval* ovalue)
+{
+ runtime·sysvicall6(libc·setitimer, 3, (uintptr)which, (uintptr)value, (uintptr)ovalue);
+}
+
+/* int32 */ void
+runtime·sigaction(int32 sig, struct Sigaction* act, struct Sigaction* oact)
+{
+ runtime·sysvicall6(libc·sigaction, 3, (uintptr)sig, (uintptr)act, (uintptr)oact);
+}
+
+/* int32 */ void
+runtime·sigaltstack(Sigaltstack* ss, Sigaltstack* oss)
+{
+ runtime·sysvicall6(libc·sigaltstack, 2, (uintptr)ss, (uintptr)oss);
+}
+
+/* int32 */ void
+runtime·sigprocmask(int32 how, Sigset* set, Sigset* oset)
+{
+ runtime·sysvicall6(libc·sigprocmask, 3, (uintptr)how, (uintptr)set, (uintptr)oset);
+}
+
+int64
+runtime·sysconf(int32 name)
+{
+ return runtime·sysvicall6(libc·sysconf, 1, (uintptr)name);
+}
+
+void
+runtime·usleep(uint32 us)
+{
+ runtime·sysvicall6(libc·usleep, 1, (uintptr)us);
+}
+
+int32
+runtime·write(uintptr fd, void* buf, int32 nbyte)
+{
+ return runtime·sysvicall6(libc·write, 3, (uintptr)fd, (uintptr)buf, (uintptr)nbyte);
+}
+
+void
+runtime·osyield(void)
+{
+ runtime·sysvicall6(libc·sched_yield, 0);
+}
diff --git a/src/pkg/runtime/os_solaris.h b/src/pkg/runtime/os_solaris.h
new file mode 100644
index 000000000..f3fae5da2
--- /dev/null
+++ b/src/pkg/runtime/os_solaris.h
@@ -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.
+
+#define SS_DISABLE 2
+
+#define SIG_BLOCK 1
+#define SIG_UNBLOCK 2
+#define SIG_SETMASK 3
+
+typedef uintptr kevent_udata;
+
+struct sigaction;
+
+void runtime·sigpanic(void);
+
+void runtime·setitimer(int32, Itimerval*, Itimerval*);
+void runtime·sigaction(int32, struct Sigaction*, struct Sigaction*);
+void runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
+void runtime·sigprocmask(int32, Sigset*, Sigset*);
+void runtime·unblocksignals(void);
+int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
+
+#define NSIG 73 /* number of signals in runtime·SigTab array */
+#define SI_USER 0
+
+void runtime·raisesigpipe(void);
+void runtime·setsig(int32, void(*)(int32, Siginfo*, void*, G*), bool);
+void runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp);
+void runtime·sigpanic(void);
+
+#define _UC_SIGMASK 0x01
+#define _UC_CPU 0x04
+
+#define RLIMIT_AS 10
+typedef struct Rlimit Rlimit;
+struct Rlimit {
+ int64 rlim_cur;
+ int64 rlim_max;
+};
+int32 runtime·getrlimit(int32, Rlimit*);
+
+// Call a library function with SysV conventions,
+// and switch to os stack during the call.
+#pragma varargck countpos runtime·sysvicall6 2
+#pragma varargck type runtime·sysvicall6 uintptr
+#pragma varargck type runtime·sysvicall6 int32
+void runtime·asmsysvicall6(void *c);
+uintptr runtime·sysvicall6(uintptr fn, int32 count, ...);
+
+void runtime·miniterrno(void *fn);
diff --git a/src/pkg/runtime/os_windows.c b/src/pkg/runtime/os_windows.c
index c3e296aa6..0dd44ed1b 100644
--- a/src/pkg/runtime/os_windows.c
+++ b/src/pkg/runtime/os_windows.c
@@ -8,6 +8,7 @@
#include "os_GOOS.h"
#include "../../cmd/ld/textflag.h"
+#pragma dynimport runtime·AddVectoredExceptionHandler AddVectoredExceptionHandler "kernel32.dll"
#pragma dynimport runtime·CloseHandle CloseHandle "kernel32.dll"
#pragma dynimport runtime·CreateEvent CreateEventA "kernel32.dll"
#pragma dynimport runtime·CreateThread CreateThread "kernel32.dll"
@@ -26,20 +27,20 @@
#pragma dynimport runtime·GetThreadContext GetThreadContext "kernel32.dll"
#pragma dynimport runtime·LoadLibrary LoadLibraryW "kernel32.dll"
#pragma dynimport runtime·LoadLibraryA LoadLibraryA "kernel32.dll"
+#pragma dynimport runtime·NtWaitForSingleObject NtWaitForSingleObject "ntdll.dll"
#pragma dynimport runtime·ResumeThread ResumeThread "kernel32.dll"
#pragma dynimport runtime·SetConsoleCtrlHandler SetConsoleCtrlHandler "kernel32.dll"
#pragma dynimport runtime·SetEvent SetEvent "kernel32.dll"
+#pragma dynimport runtime·SetProcessPriorityBoost SetProcessPriorityBoost "kernel32.dll"
#pragma dynimport runtime·SetThreadPriority SetThreadPriority "kernel32.dll"
#pragma dynimport runtime·SetWaitableTimer SetWaitableTimer "kernel32.dll"
#pragma dynimport runtime·Sleep Sleep "kernel32.dll"
#pragma dynimport runtime·SuspendThread SuspendThread "kernel32.dll"
-#pragma dynimport runtime·timeBeginPeriod timeBeginPeriod "winmm.dll"
#pragma dynimport runtime·WaitForSingleObject WaitForSingleObject "kernel32.dll"
#pragma dynimport runtime·WriteFile WriteFile "kernel32.dll"
-#pragma dynimport runtime·NtWaitForSingleObject NtWaitForSingleObject "ntdll.dll"
-
-extern void *runtime·NtWaitForSingleObject;
+#pragma dynimport runtime·timeBeginPeriod timeBeginPeriod "winmm.dll"
+extern void *runtime·AddVectoredExceptionHandler;
extern void *runtime·CloseHandle;
extern void *runtime·CreateEvent;
extern void *runtime·CreateThread;
@@ -58,19 +59,25 @@ extern void *runtime·GetSystemTimeAsFileTime;
extern void *runtime·GetThreadContext;
extern void *runtime·LoadLibrary;
extern void *runtime·LoadLibraryA;
+extern void *runtime·NtWaitForSingleObject;
extern void *runtime·ResumeThread;
extern void *runtime·SetConsoleCtrlHandler;
extern void *runtime·SetEvent;
+extern void *runtime·SetProcessPriorityBoost;
extern void *runtime·SetThreadPriority;
extern void *runtime·SetWaitableTimer;
extern void *runtime·Sleep;
extern void *runtime·SuspendThread;
-extern void *runtime·timeBeginPeriod;
extern void *runtime·WaitForSingleObject;
extern void *runtime·WriteFile;
+extern void *runtime·timeBeginPeriod;
void *runtime·GetQueuedCompletionStatusEx;
+extern uintptr runtime·externalthreadhandlerp;
+void runtime·externalthreadhandler(void);
+void runtime·sigtramp(void);
+
static int32
getproccount(void)
{
@@ -84,25 +91,22 @@ void
runtime·osinit(void)
{
void *kernel32;
- void *SetProcessPriorityBoost;
- // -1 = current process, -2 = current thread
- runtime·stdcall(runtime·DuplicateHandle, 7,
- (uintptr)-1, (uintptr)-2, (uintptr)-1, &m->thread,
- (uintptr)0, (uintptr)0, (uintptr)DUPLICATE_SAME_ACCESS);
+ runtime·externalthreadhandlerp = (uintptr)runtime·externalthreadhandler;
+
+ runtime·stdcall(runtime·AddVectoredExceptionHandler, 2, (uintptr)1, (uintptr)runtime·sigtramp);
runtime·stdcall(runtime·SetConsoleCtrlHandler, 2, runtime·ctrlhandler, (uintptr)1);
runtime·stdcall(runtime·timeBeginPeriod, 1, (uintptr)1);
runtime·ncpu = getproccount();
+
+ // Windows dynamic priority boosting assumes that a process has different types
+ // of dedicated threads -- GUI, IO, computational, etc. Go processes use
+ // equivalent threads that all do a mix of GUI, IO, computations, etc.
+ // In such context dynamic priority boosting does nothing but harm, so we turn it off.
+ runtime·stdcall(runtime·SetProcessPriorityBoost, 2, (uintptr)-1, (uintptr)1);
kernel32 = runtime·stdcall(runtime·LoadLibraryA, 1, "kernel32.dll");
if(kernel32 != nil) {
- // Windows dynamic priority boosting assumes that a process has different types
- // of dedicated threads -- GUI, IO, computational, etc. Go processes use
- // equivalent threads that all do a mix of GUI, IO, computations, etc.
- // In such context dynamic priority boosting does nothing but harm, so we turn it off.
- SetProcessPriorityBoost = runtime·stdcall(runtime·GetProcAddress, 2, kernel32, "SetProcessPriorityBoost");
- if(SetProcessPriorityBoost != nil) // supported since Windows XP
- runtime·stdcall(SetProcessPriorityBoost, 2, (uintptr)-1, (uintptr)1);
runtime·GetQueuedCompletionStatusEx = runtime·stdcall(runtime·GetProcAddress, 2, kernel32, "GetQueuedCompletionStatusEx");
}
}
@@ -162,7 +166,7 @@ runtime·exit(int32 code)
}
int32
-runtime·write(int32 fd, void *buf, int32 n)
+runtime·write(uintptr fd, void *buf, int32 n)
{
void *handle;
uint32 written;
@@ -176,7 +180,9 @@ runtime·write(int32 fd, void *buf, int32 n)
handle = runtime·stdcall(runtime·GetStdHandle, 1, (uintptr)-12);
break;
default:
- return -1;
+ // assume fd is real windows handle.
+ handle = (void*)fd;
+ break;
}
runtime·stdcall(runtime·WriteFile, 5, handle, buf, (uintptr)n, &written, (uintptr)0);
return written;
@@ -229,7 +235,6 @@ runtime·newosproc(M *mp, void *stk)
runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), runtime·getlasterror());
runtime·throw("runtime.newosproc");
}
- runtime·atomicstorep(&mp->thread, thandle);
}
// Called to initialize a new m (including the bootstrap m).
@@ -245,14 +250,19 @@ runtime·mpreinit(M *mp)
void
runtime·minit(void)
{
- runtime·install_exception_handler();
+ void *thandle;
+
+ // -1 = current process, -2 = current thread
+ runtime·stdcall(runtime·DuplicateHandle, 7,
+ (uintptr)-1, (uintptr)-2, (uintptr)-1, &thandle,
+ (uintptr)0, (uintptr)0, (uintptr)DUPLICATE_SAME_ACCESS);
+ runtime·atomicstorep(&m->thread, thandle);
}
// Called from dropm to undo the effect of an minit.
void
runtime·unminit(void)
{
- runtime·remove_exception_handler();
}
#pragma textflag NOSPLIT
@@ -285,11 +295,20 @@ time·now(int64 sec, int32 usec)
void *
runtime·stdcall(void *fn, int32 count, ...)
{
- m->wincall.fn = fn;
- m->wincall.n = count;
- m->wincall.args = (uintptr*)&count + 1;
- runtime·asmcgocall(runtime·asmstdcall, &m->wincall);
- return (void*)m->wincall.r1;
+ m->libcall.fn = fn;
+ m->libcall.n = count;
+ m->libcall.args = (uintptr*)&count + 1;
+ if(m->profilehz != 0) {
+ // leave pc/sp for cpu profiler
+ m->libcallg = g;
+ m->libcallpc = (uintptr)runtime·getcallerpc(&fn);
+ // sp must be the last, because once async cpu profiler finds
+ // all three values to be non-zero, it will use them
+ m->libcallsp = (uintptr)runtime·getcallersp(&fn);
+ }
+ runtime·asmcgocall(runtime·asmstdcall, &m->libcall);
+ m->libcallsp = 0;
+ return (void*)m->libcall.r1;
}
extern void runtime·usleep1(uint32);
@@ -329,9 +348,12 @@ runtime·issigpanic(uint32 code)
void
runtime·sigpanic(void)
{
+ if(!runtime·canpanic(g))
+ runtime·throw("unexpected signal during runtime execution");
+
switch(g->sig) {
case EXCEPTION_ACCESS_VIOLATION:
- if(g->sigcode1 < 0x1000) {
+ if(g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -352,8 +374,6 @@ runtime·sigpanic(void)
runtime·throw("fault");
}
-extern void *runtime·sigtramp;
-
void
runtime·initsig(void)
{
@@ -383,7 +403,7 @@ runtime·ctrlhandler1(uint32 type)
return 0;
}
-extern void runtime·dosigprof(Context *r, G *gp);
+extern void runtime·dosigprof(Context *r, G *gp, M *mp);
extern void runtime·profileloop(void);
static void *profiletimer;
@@ -402,13 +422,11 @@ profilem(M *mp)
tls = runtime·tls0;
gp = *(G**)tls;
- if(gp != nil && gp != mp->g0 && gp->status != Gsyscall) {
- // align Context to 16 bytes
- r = (Context*)((uintptr)(&rbuf[15]) & ~15);
- r->ContextFlags = CONTEXT_CONTROL;
- runtime·stdcall(runtime·GetThreadContext, 2, mp->thread, r);
- runtime·dosigprof(r, gp);
- }
+ // align Context to 16 bytes
+ r = (Context*)((uintptr)(&rbuf[15]) & ~15);
+ r->ContextFlags = CONTEXT_CONTROL;
+ runtime·stdcall(runtime·GetThreadContext, 2, mp->thread, r);
+ runtime·dosigprof(r, gp, mp);
}
void
@@ -425,10 +443,13 @@ runtime·profileloop1(void)
allm = runtime·atomicloadp(&runtime·allm);
for(mp = allm; mp != nil; mp = mp->alllink) {
thread = runtime·atomicloadp(&mp->thread);
- if(thread == nil)
+ // Do not profile threads blocked on Notes,
+ // this includes idle worker threads,
+ // idle timer thread, idle heap scavenger, etc.
+ if(thread == nil || mp->profilehz == 0 || mp->blocked)
continue;
runtime·stdcall(runtime·SuspendThread, 1, thread);
- if(mp->profilehz != 0)
+ if(mp->profilehz != 0 && !mp->blocked)
profilem(mp);
runtime·stdcall(runtime·ResumeThread, 1, thread);
}
diff --git a/src/pkg/runtime/os_windows_386.c b/src/pkg/runtime/os_windows_386.c
index c377e5b6c..c36a00114 100644
--- a/src/pkg/runtime/os_windows_386.c
+++ b/src/pkg/runtime/os_windows_386.c
@@ -24,16 +24,47 @@ runtime·dumpregs(Context *r)
runtime·printf("gs %x\n", r->SegGs);
}
+#define DBG_PRINTEXCEPTION_C 0x40010006
+
+// Called by sigtramp from Windows VEH handler.
+// Return value signals whether the exception has been handled (-1)
+// or should be made available to other handlers in the chain (0).
uint32
runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
{
bool crash;
uintptr *sp;
+ extern byte text[], etext[];
+
+ if(info->ExceptionCode == DBG_PRINTEXCEPTION_C) {
+ // This exception is intended to be caught by debuggers.
+ // There is a not-very-informational message like
+ // "Invalid parameter passed to C runtime function"
+ // sitting at info->ExceptionInformation[0] (a wchar_t*),
+ // with length info->ExceptionInformation[1].
+ // The default behavior is to ignore this exception,
+ // but somehow returning 0 here (meaning keep going)
+ // makes the program crash instead. Maybe Windows has no
+ // other handler registered? In any event, ignore it.
+ return -1;
+ }
+
+ // Only handle exception if executing instructions in Go binary
+ // (not Windows library code).
+ if(r->Eip < (uint32)text || (uint32)etext < r->Eip)
+ return 0;
switch(info->ExceptionCode) {
case EXCEPTION_BREAKPOINT:
- r->Eip--; // because 8l generates 2 bytes for INT3
- return 1;
+ // It is unclear whether this is needed, unclear whether it
+ // would work, and unclear how to test it. Leave out for now.
+ // This only handles breakpoint instructions written in the
+ // assembly sources, not breakpoints set by a debugger, and
+ // there are very few of the former.
+ //
+ // r->Eip--; // because 8l generates 2 bytes for INT3
+ // return 0;
+ break;
}
if(gp != nil && runtime·issigpanic(info->ExceptionCode)) {
@@ -58,15 +89,15 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
r->Esp = (uintptr)sp;
}
r->Eip = (uintptr)runtime·sigpanic;
- return 0;
+ return -1;
}
if(runtime·panicking) // traceback already printed
runtime·exit(2);
runtime·panicking = 1;
- runtime·printf("Exception %x %p %p\n", info->ExceptionCode,
- info->ExceptionInformation[0], info->ExceptionInformation[1]);
+ runtime·printf("Exception %x %p %p %p\n", info->ExceptionCode,
+ info->ExceptionInformation[0], info->ExceptionInformation[1], r->Eip);
runtime·printf("PC=%x\n", r->Eip);
if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
@@ -84,9 +115,8 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
if(crash)
runtime·crash();
-
runtime·exit(2);
- return 0;
+ return -1; // not reached
}
void
@@ -102,7 +132,7 @@ runtime·sigdisable(uint32 sig)
}
void
-runtime·dosigprof(Context *r, G *gp)
+runtime·dosigprof(Context *r, G *gp, M *mp)
{
- runtime·sigprof((uint8*)r->Eip, (uint8*)r->Esp, nil, gp);
+ runtime·sigprof((uint8*)r->Eip, (uint8*)r->Esp, nil, gp, mp);
}
diff --git a/src/pkg/runtime/os_windows_amd64.c b/src/pkg/runtime/os_windows_amd64.c
index 97c48feb0..7fb973cde 100644
--- a/src/pkg/runtime/os_windows_amd64.c
+++ b/src/pkg/runtime/os_windows_amd64.c
@@ -32,15 +32,44 @@ runtime·dumpregs(Context *r)
runtime·printf("gs %X\n", (uint64)r->SegGs);
}
+#define DBG_PRINTEXCEPTION_C 0x40010006
+
+// Called by sigtramp from Windows VEH handler.
+// Return value signals whether the exception has been handled (-1)
+// or should be made available to other handlers in the chain (0).
uint32
runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
{
bool crash;
uintptr *sp;
+ extern byte text[], etext[];
+
+ if(info->ExceptionCode == DBG_PRINTEXCEPTION_C) {
+ // This exception is intended to be caught by debuggers.
+ // There is a not-very-informational message like
+ // "Invalid parameter passed to C runtime function"
+ // sitting at info->ExceptionInformation[0] (a wchar_t*),
+ // with length info->ExceptionInformation[1].
+ // The default behavior is to ignore this exception,
+ // but somehow returning 0 here (meaning keep going)
+ // makes the program crash instead. Maybe Windows has no
+ // other handler registered? In any event, ignore it.
+ return -1;
+ }
+
+ // Only handle exception if executing instructions in Go binary
+ // (not Windows library code).
+ if(r->Rip < (uint64)text || (uint64)etext < r->Rip)
+ return 0;
switch(info->ExceptionCode) {
case EXCEPTION_BREAKPOINT:
- return 1;
+ // It is unclear whether this is needed, unclear whether it
+ // would work, and unclear how to test it. Leave out for now.
+ // This only handles breakpoint instructions written in the
+ // assembly sources, not breakpoints set by a debugger, and
+ // there are very few of the former.
+ break;
}
if(gp != nil && runtime·issigpanic(info->ExceptionCode)) {
@@ -65,15 +94,16 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
r->Rsp = (uintptr)sp;
}
r->Rip = (uintptr)runtime·sigpanic;
- return 0;
+ return -1;
}
if(runtime·panicking) // traceback already printed
runtime·exit(2);
runtime·panicking = 1;
- runtime·printf("Exception %x %p %p\n", info->ExceptionCode,
- info->ExceptionInformation[0], info->ExceptionInformation[1]);
+ runtime·printf("Exception %x %p %p %p\n", info->ExceptionCode,
+ info->ExceptionInformation[0], info->ExceptionInformation[1], r->Rip);
+
runtime·printf("PC=%X\n", r->Rip);
if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
@@ -92,7 +122,7 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
runtime·crash();
runtime·exit(2);
- return 0;
+ return -1; // not reached
}
void
@@ -108,7 +138,7 @@ runtime·sigdisable(uint32 sig)
}
void
-runtime·dosigprof(Context *r, G *gp)
+runtime·dosigprof(Context *r, G *gp, M *mp)
{
- runtime·sigprof((uint8*)r->Rip, (uint8*)r->Rsp, nil, gp);
+ runtime·sigprof((uint8*)r->Rip, (uint8*)r->Rsp, nil, gp, mp);
}
diff --git a/src/pkg/runtime/panic.c b/src/pkg/runtime/panic.c
index 8227a444d..f577b37b5 100644
--- a/src/pkg/runtime/panic.c
+++ b/src/pkg/runtime/panic.c
@@ -13,108 +13,63 @@
uint32 runtime·panicking;
static Lock paniclk;
-enum
-{
- DeferChunkSize = 2048
-};
+// Each P holds pool for defers with arg sizes 8, 24, 40, 56 and 72 bytes.
+// Memory block is 40 (24 for 32 bits) bytes larger due to Defer header.
+// This maps exactly to malloc size classes.
+
+// defer size class for arg size sz
+#define DEFERCLASS(sz) (((sz)+7)>>4)
+// total size of memory block for defer with arg size sz
+#define TOTALSIZE(sz) (sizeof(Defer) - sizeof(((Defer*)nil)->args) + ROUND(sz, sizeof(uintptr)))
-// Allocate a Defer, usually as part of the larger frame of deferred functions.
-// Each defer must be released with both popdefer and freedefer.
+// Allocate a Defer, usually using per-P pool.
+// Each defer must be released with freedefer.
static Defer*
newdefer(int32 siz)
{
- int32 total;
- DeferChunk *c;
+ int32 total, sc;
Defer *d;
-
- c = g->dchunk;
- total = sizeof(*d) + ROUND(siz, sizeof(uintptr)) - sizeof(d->args);
- if(c == nil || total > DeferChunkSize - c->off) {
- if(total > DeferChunkSize / 2) {
- // Not worth putting in any chunk.
- // Allocate a separate block.
- d = runtime·malloc(total);
- d->siz = siz;
- d->special = 1;
- d->free = 1;
- d->link = g->defer;
- g->defer = d;
- return d;
- }
-
- // Cannot fit in current chunk.
- // Switch to next chunk, allocating if necessary.
- c = g->dchunknext;
- if(c == nil)
- c = runtime·malloc(DeferChunkSize);
- c->prev = g->dchunk;
- c->off = sizeof(*c);
- g->dchunk = c;
- g->dchunknext = nil;
+ P *p;
+
+ d = nil;
+ sc = DEFERCLASS(siz);
+ if(sc < nelem(p->deferpool)) {
+ p = m->p;
+ d = p->deferpool[sc];
+ if(d)
+ p->deferpool[sc] = d->link;
+ }
+ if(d == nil) {
+ // deferpool is empty or just a big defer
+ total = TOTALSIZE(siz);
+ d = runtime·malloc(total);
}
-
- d = (Defer*)((byte*)c + c->off);
- c->off += total;
d->siz = siz;
d->special = 0;
- d->free = 0;
d->link = g->defer;
g->defer = d;
- return d;
-}
-
-// Pop the current defer from the defer stack.
-// Its contents are still valid until the goroutine begins executing again.
-// In particular it is safe to call reflect.call(d->fn, d->argp, d->siz) after
-// popdefer returns.
-static void
-popdefer(void)
-{
- Defer *d;
- DeferChunk *c;
- int32 total;
-
- d = g->defer;
- if(d == nil)
- runtime·throw("runtime: popdefer nil");
- g->defer = d->link;
- if(d->special) {
- // Nothing else to do.
- return;
- }
- total = sizeof(*d) + ROUND(d->siz, sizeof(uintptr)) - sizeof(d->args);
- c = g->dchunk;
- if(c == nil || (byte*)d+total != (byte*)c+c->off)
- runtime·throw("runtime: popdefer phase error");
- c->off -= total;
- if(c->off == sizeof(*c)) {
- // Chunk now empty, so pop from stack.
- // Save in dchunknext both to help with pingponging between frames
- // and to make sure d is still valid on return.
- if(g->dchunknext != nil)
- runtime·free(g->dchunknext);
- g->dchunknext = c;
- g->dchunk = c->prev;
- }
+ return d;
}
// Free the given defer.
-// For defers in the per-goroutine chunk this just clears the saved arguments.
-// For large defers allocated on the heap, this frees them.
// The defer cannot be used after this call.
static void
freedefer(Defer *d)
{
- int32 total;
+ int32 sc;
+ P *p;
- if(d->special) {
- if(d->free)
- runtime·free(d);
- } else {
- // Wipe out any possible pointers in argp/pc/fn/args.
- total = sizeof(*d) + ROUND(d->siz, sizeof(uintptr)) - sizeof(d->args);
- runtime·memclr((byte*)d, total);
- }
+ if(d->special)
+ return;
+ sc = DEFERCLASS(d->siz);
+ if(sc < nelem(p->deferpool)) {
+ p = m->p;
+ d->link = p->deferpool[sc];
+ p->deferpool[sc] = d;
+ // No need to wipe out pointers in argp/pc/fn/args,
+ // because we empty the pool before GC.
+ } else
+ runtime·free(d);
}
// Create a new deferred function fn with siz bytes of arguments.
@@ -157,14 +112,12 @@ runtime·deferproc(int32 siz, FuncVal *fn, ...)
// 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 ... in the prototype keeps the compiler from declaring
-// an argument frame size. deferreturn is a very special function,
-// and if the runtime ever asks for its frame size, that means
-// the traceback routines are probably broken.
+
+// The single argument isn't actually used - it just has its address
+// taken so it can be matched against pending defers.
#pragma textflag NOSPLIT
void
-runtime·deferreturn(uintptr arg0, ...)
+runtime·deferreturn(uintptr arg0)
{
Defer *d;
byte *argp;
@@ -184,7 +137,7 @@ runtime·deferreturn(uintptr arg0, ...)
m->locks++;
runtime·memmove(argp, d->args, d->siz);
fn = d->fn;
- popdefer();
+ g->defer = d->link;
freedefer(d);
m->locks--;
if(m->locks == 0 && g->preempt)
@@ -192,6 +145,37 @@ runtime·deferreturn(uintptr arg0, ...)
runtime·jmpdefer(fn, argp);
}
+// Ensure that defer arg sizes that map to the same defer size class
+// also map to the same malloc size class.
+void
+runtime·testdefersizes(void)
+{
+ P *p;
+ int32 i, siz, defersc, mallocsc;
+ int32 map[nelem(p->deferpool)];
+
+ for(i=0; i<nelem(p->deferpool); i++)
+ map[i] = -1;
+ for(i=0;; i++) {
+ defersc = DEFERCLASS(i);
+ if(defersc >= nelem(p->deferpool))
+ break;
+ siz = TOTALSIZE(i);
+ mallocsc = runtime·SizeToClass(siz);
+ siz = runtime·class_to_size[mallocsc];
+ // runtime·printf("defer class %d: arg size %d, block size %d(%d)\n", defersc, i, siz, mallocsc);
+ if(map[defersc] < 0) {
+ map[defersc] = mallocsc;
+ continue;
+ }
+ if(map[defersc] != mallocsc) {
+ runtime·printf("bad defer size class: i=%d siz=%d mallocsc=%d/%d\n",
+ i, siz, map[defersc], mallocsc);
+ runtime·throw("bad defer size class");
+ }
+ }
+}
+
// Run all deferred functions for the current goroutine.
static void
rundefer(void)
@@ -199,8 +183,8 @@ rundefer(void)
Defer *d;
while((d = g->defer) != nil) {
- popdefer();
- reflect·call(d->fn, (byte*)d->args, d->siz);
+ g->defer = d->link;
+ reflect·call(d->fn, (byte*)d->args, d->siz, d->siz);
freedefer(d);
}
}
@@ -221,37 +205,65 @@ printpanics(Panic *p)
}
static void recovery(G*);
+static void abortpanic(Panic*);
+static FuncVal abortpanicV = { (void(*)(void))abortpanic };
// The implementation of the predeclared function panic.
void
runtime·panic(Eface e)
{
- Defer *d;
- Panic *p;
+ Defer *d, dabort;
+ Panic p;
void *pc, *argp;
-
- p = runtime·mal(sizeof *p);
- p->arg = e;
- p->link = g->panic;
- p->stackbase = g->stackbase;
- g->panic = p;
+
+ runtime·memclr((byte*)&p, sizeof p);
+ p.arg = e;
+ p.link = g->panic;
+ p.stackbase = g->stackbase;
+ g->panic = &p;
+
+ dabort.fn = &abortpanicV;
+ dabort.siz = sizeof(&p);
+ dabort.args[0] = &p;
+ dabort.argp = NoArgs;
+ dabort.special = true;
for(;;) {
d = g->defer;
if(d == nil)
break;
// take defer off list in case of recursive panic
- popdefer();
- g->ispanic = true; // rock for newstack, where reflect.newstackcall ends up
+ g->defer = d->link;
+ g->ispanic = true; // rock for runtime·newstack, where runtime·newstackcall ends up
argp = d->argp;
pc = d->pc;
+
+ // The deferred function may cause another panic,
+ // so newstackcall may not return. Set up a defer
+ // to mark this panic aborted if that happens.
+ dabort.link = g->defer;
+ g->defer = &dabort;
+ p.defer = d;
+
runtime·newstackcall(d->fn, (byte*)d->args, d->siz);
+
+ // Newstackcall did not panic. Remove dabort.
+ if(g->defer != &dabort)
+ runtime·throw("bad defer entry in panic");
+ g->defer = dabort.link;
+
freedefer(d);
- if(p->recovered) {
- g->panic = p->link;
+ if(p.recovered) {
+ g->panic = p.link;
+ // Aborted panics are marked but remain on the g->panic list.
+ // Recovery will unwind the stack frames containing their Panic structs.
+ // Remove them from the list and free the associated defers.
+ while(g->panic && g->panic->aborted) {
+ freedefer(g->panic->defer);
+ g->panic = g->panic->link;
+ }
if(g->panic == nil) // must be done with signal
g->sig = 0;
- runtime·free(p);
// Pass information about recovering frame to recovery.
g->sigcode0 = (uintptr)argp;
g->sigcode1 = (uintptr)pc;
@@ -263,7 +275,14 @@ runtime·panic(Eface e)
// ran out of deferred calls - old-school panic now
runtime·startpanic();
printpanics(g->panic);
- runtime·dopanic(0);
+ runtime·dopanic(0); // should not return
+ runtime·exit(1); // not reached
+}
+
+static void
+abortpanic(Panic *p)
+{
+ p->aborted = true;
}
// Unwind the stack after a deferred function calls recover
@@ -320,10 +339,7 @@ runtime·unwindstack(G *gp, byte *sp)
gp->stackbase = top->stackbase;
gp->stackguard = top->stackguard;
gp->stackguard0 = gp->stackguard;
- if(top->free != 0) {
- gp->stacksize -= top->free;
- runtime·stackfree(stk, top->free);
- }
+ runtime·stackfree(gp, stk, top);
}
if(sp != nil && (sp < (byte*)gp->stackguard - StackGuard || (byte*)gp->stackbase < sp)) {
@@ -337,10 +353,11 @@ runtime·unwindstack(G *gp, byte *sp)
// find the stack segment of its caller.
#pragma textflag NOSPLIT
void
-runtime·recover(byte *argp, Eface ret)
+runtime·recover(byte *argp, GoOutput retbase, ...)
{
Panic *p;
Stktop *top;
+ Eface *ret;
// Must be an unrecovered panic in progress.
// Must be on a stack segment created for a deferred call during a panic.
@@ -351,16 +368,16 @@ runtime·recover(byte *argp, Eface ret)
// do not count as official calls to adjust what we consider the top frame
// while they are active on the stack. The linker emits adjustments of
// g->panicwrap in the prologue and epilogue of functions marked as wrappers.
+ ret = (Eface*)&retbase;
top = (Stktop*)g->stackbase;
p = g->panic;
if(p != nil && !p->recovered && top->panic && argp == (byte*)top - top->argsize - g->panicwrap) {
p->recovered = 1;
- ret = p->arg;
+ *ret = p->arg;
} else {
- ret.type = nil;
- ret.data = nil;
+ ret->type = nil;
+ ret->data = nil;
}
- FLUSH(&ret);
}
void
@@ -371,18 +388,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(g != nil)
+ 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(g != nil)
- 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
@@ -453,6 +486,29 @@ runtime·throwinit(void)
runtime·throw("recursive call during initialization - linker skew");
}
+bool
+runtime·canpanic(G *gp)
+{
+ 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 || gp->syscallsp != 0)
+ return false;
+#ifdef GOOS_windows
+ if(m->libcallsp != 0)
+ return false;
+#endif
+ return true;
+}
+
void
runtime·throw(int8 *s)
{
@@ -470,6 +526,16 @@ runtime·panicstring(int8 *s)
{
Eface err;
+ // m->softfloat is set during software floating point,
+ // which might cause a fault during a memory load.
+ // It increments m->locks to avoid preemption.
+ // If we're panicking, the software floating point frames
+ // will be unwound, so decrement m->locks as they would.
+ if(m->softfloat) {
+ m->locks--;
+ m->softfloat = 0;
+ }
+
if(m->mallocing) {
runtime·printf("panic: %s\n", s);
runtime·throw("panic during malloc");
@@ -478,6 +544,10 @@ runtime·panicstring(int8 *s)
runtime·printf("panic: %s\n", s);
runtime·throw("panic during gc");
}
+ if(m->locks) {
+ runtime·printf("panic: %s\n", s);
+ runtime·throw("panic holding locks");
+ }
runtime·newErrorCString(s, &err);
runtime·panic(err);
}
@@ -488,3 +558,9 @@ runtime·Goexit(void)
rundefer();
runtime·goexit();
}
+
+void
+runtime·panicdivide(void)
+{
+ runtime·panicstring("integer divide by zero");
+}
diff --git a/src/pkg/runtime/parfor.c b/src/pkg/runtime/parfor.c
index ceaac8bc9..4706e0a43 100644
--- a/src/pkg/runtime/parfor.c
+++ b/src/pkg/runtime/parfor.c
@@ -33,15 +33,6 @@ runtime·parforalloc(uint32 nthrmax)
return desc;
}
-// For testing from Go
-// func parforalloc2(nthrmax uint32) *ParFor
-void
-runtime·parforalloc2(uint32 nthrmax, ParFor *desc)
-{
- desc = runtime·parforalloc(nthrmax);
- FLUSH(&desc);
-}
-
void
runtime·parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait, void (*body)(ParFor*, uint32))
{
@@ -75,14 +66,6 @@ runtime·parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait,
}
}
-// For testing from Go
-// func parforsetup2(desc *ParFor, nthr, n uint32, ctx *byte, wait bool, body func(*ParFor, uint32))
-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)
{
@@ -207,13 +190,10 @@ exit:
me->nsleep = 0;
}
-// For testing from Go
-// func parforiters(desc *ParFor, tid uintptr) (uintptr, uintptr)
+// For testing from Go.
void
-runtime·parforiters(ParFor *desc, uintptr tid, uintptr start, uintptr end)
+runtime·parforiters(ParFor *desc, uintptr tid, uintptr *start, uintptr *end)
{
- start = (uint32)desc->thr[tid].pos;
- end = (uint32)(desc->thr[tid].pos>>32);
- FLUSH(&start);
- FLUSH(&end);
+ *start = (uint32)desc->thr[tid].pos;
+ *end = (uint32)(desc->thr[tid].pos>>32);
}
diff --git a/src/pkg/runtime/pprof/pprof.go b/src/pkg/runtime/pprof/pprof.go
index 3b8428519..26aa0b8be 100644
--- a/src/pkg/runtime/pprof/pprof.go
+++ b/src/pkg/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
diff --git a/src/pkg/runtime/pprof/pprof_test.go b/src/pkg/runtime/pprof/pprof_test.go
index eb76b93c4..aba538e75 100644
--- a/src/pkg/runtime/pprof/pprof_test.go
+++ b/src/pkg/runtime/pprof/pprof_test.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build !nacl
+
package pprof_test
import (
@@ -138,7 +140,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 +195,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 +220,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") {
return
}
}
@@ -264,9 +267,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) {
@@ -278,31 +281,31 @@ 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\.chanrecv1\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.goc:[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]+
`},
{"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\.chansend1\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.goc:[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]+
`},
{"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\.chanrecv1\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.goc:[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]+
`},
{"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\.selectgo\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.goc:[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]+
`},
{"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\.selectgo\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.goc:[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]+
`},
diff --git a/src/pkg/runtime/print.c b/src/pkg/runtime/print.c
index 8de3ae4fa..a04708fae 100644
--- a/src/pkg/runtime/print.c
+++ b/src/pkg/runtime/print.c
@@ -63,67 +63,85 @@ runtime·printf(int8 *s, ...)
vprintf(s, arg);
}
+#pragma textflag NOSPLIT
+int32
+runtime·snprintf(byte *buf, int32 n, int8 *s, ...)
+{
+ byte *arg;
+ int32 m;
+
+ arg = (byte*)(&s+1);
+ g->writebuf = buf;
+ g->writenbuf = n-1;
+ vprintf(s, arg);
+ *g->writebuf = '\0';
+ m = g->writebuf - buf;
+ g->writenbuf = 0;
+ g->writebuf = nil;
+ return m;
+}
+
// Very simple printf. Only for debugging prints.
// Do not add to this without checking with Rob.
static void
vprintf(int8 *s, byte *base)
{
int8 *p, *lp;
- uintptr arg, narg;
+ uintptr arg, siz;
byte *v;
//runtime·lock(&debuglock);
lp = p = s;
- arg = 0;
+ arg = (uintptr)base;
for(; *p; p++) {
if(*p != '%')
continue;
if(p > lp)
gwrite(lp, p-lp);
p++;
- narg = 0;
+ siz = 0;
switch(*p) {
case 't':
case 'c':
- narg = arg + 1;
+ siz = 1;
break;
case 'd': // 32-bit
case 'x':
arg = ROUND(arg, 4);
- narg = arg + 4;
+ siz = 4;
break;
case 'D': // 64-bit
case 'U':
case 'X':
case 'f':
- arg = ROUND(arg, sizeof(uintptr));
- narg = arg + 8;
+ arg = ROUND(arg, sizeof(uintreg));
+ siz = 8;
break;
case 'C':
- arg = ROUND(arg, sizeof(uintptr));
- narg = arg + 16;
+ arg = ROUND(arg, sizeof(uintreg));
+ siz = 16;
break;
case 'p': // pointer-sized
case 's':
arg = ROUND(arg, sizeof(uintptr));
- narg = arg + sizeof(uintptr);
+ siz = sizeof(uintptr);
break;
case 'S': // pointer-aligned but bigger
arg = ROUND(arg, sizeof(uintptr));
- narg = arg + sizeof(String);
+ siz = sizeof(String);
break;
case 'a': // pointer-aligned but bigger
arg = ROUND(arg, sizeof(uintptr));
- narg = arg + sizeof(Slice);
+ siz = sizeof(Slice);
break;
case 'i': // pointer-aligned but bigger
case 'e':
arg = ROUND(arg, sizeof(uintptr));
- narg = arg + sizeof(Eface);
+ siz = sizeof(Eface);
break;
}
- v = base+arg;
+ v = (byte*)arg;
switch(*p) {
case 'a':
runtime·printslice(*(Slice*)v);
@@ -171,7 +189,7 @@ vprintf(int8 *s, byte *base)
runtime·printhex(*(uint64*)v);
break;
}
- arg = narg;
+ arg += siz;
lp = p+1;
}
if(p > lp)
@@ -236,7 +254,10 @@ runtime·printfloat(float64 v)
n = 7; // digits printed
e = 0; // exp
s = 0; // sign
- if(v != 0) {
+ if(v == 0) {
+ if(1/v == runtime·neginf)
+ s = 1;
+ } else {
// sign
if(v < 0) {
v = -v;
@@ -345,7 +366,7 @@ runtime·printhex(uint64 v)
void
runtime·printpointer(void *p)
{
- runtime·printhex((uint64)p);
+ runtime·printhex((uintptr)p);
}
void
@@ -370,11 +391,3 @@ runtime·printnl(void)
{
gwrite("\n", 1);
}
-
-void
-runtime·typestring(Eface e, String s)
-{
- s = *e.type->string;
- FLUSH(&s);
-}
-
diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c
index ed3e1e73e..914a02e0b 100644
--- a/src/pkg/runtime/proc.c
+++ b/src/pkg/runtime/proc.c
@@ -58,17 +58,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;
bool runtime·iscgo;
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;
M* runtime·extram;
@@ -76,10 +82,15 @@ int8* runtime·goos;
int32 runtime·ncpu;
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);
@@ -106,6 +117,7 @@ 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*);
@@ -114,6 +126,7 @@ static bool preemptall(void);
static bool preemptone(P*);
static bool exitsyscallfast(void);
static bool haveexperiment(int8*);
+static void allgadd(G*);
// The bootstrap sequence is:
//
@@ -131,9 +144,9 @@ runtime·schedinit(void)
Eface i;
runtime·sched.maxmcount = 10000;
- runtime·precisestack = haveexperiment("precisestack");
+ runtime·precisestack = true; // haveexperiment("precisestack");
- runtime·mprofinit();
+ runtime·symtabinit();
runtime·mallocinit();
mcommoninit(m);
@@ -142,14 +155,15 @@ 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();
runtime·parsedebugvars();
- // Allocate internal symbol table representation now, we need it for GC anyway.
- runtime·symtabinit();
-
runtime·sched.lastpoll = runtime·nanotime();
procs = 1;
p = runtime·getenv("GOMAXPROCS");
@@ -161,6 +175,11 @@ runtime·schedinit(void)
runtime·allp = runtime·malloc((MaxGomaxprocs+1)*sizeof(runtime·allp[0]));
procresize(procs);
+ runtime·copystack = runtime·precisestack;
+ p = runtime·getenv("GOCOPYSTACK");
+ if(p != nil && !runtime·strcmp(p, (byte*)"0"))
+ runtime·copystack = false;
+
mstats.enablegc = 1;
if(raceenabled)
@@ -175,6 +194,15 @@ static FuncVal scavenger = {runtime·MHeap_Scavenger};
static FuncVal initDone = { runtime·unlockOSThread };
// The main goroutine.
+// Note: C frames in general are not copyable during stack growth, for two reasons:
+// 1) We don't know where in a frame to find pointers to other stack locations.
+// 2) There's no guarantee that globals or heap values do not point into the frame.
+//
+// The C frame for runtime.main is copyable, because:
+// 1) There are no pointers to other stack locations in the frame
+// (d.fn points at a global, d.link is nil, d.argp is -1).
+// 2) The only pointer into this frame is from the defer chain,
+// which is explicitly handled during stack copying.
void
runtime·main(void)
{
@@ -202,9 +230,8 @@ runtime·main(void)
d.fn = &initDone;
d.siz = 0;
d.link = g->defer;
- d.argp = (void*)-1;
+ d.argp = NoArgs;
d.special = true;
- d.free = false;
g->defer = &d;
if(m != &runtime·m0)
@@ -237,6 +264,7 @@ void
runtime·goroutineheader(G *gp)
{
int8 *status;
+ int64 waitfor;
switch(gp->status) {
case Gidle:
@@ -261,7 +289,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
@@ -269,6 +306,7 @@ runtime·tracebackothers(G *me)
{
G *gp;
int32 traceback;
+ uintptr i;
traceback = runtime·gotraceback(nil);
@@ -279,7 +317,9 @@ runtime·tracebackothers(G *me)
runtime·traceback(~(uintptr)0, ~(uintptr)0, 0, 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)
@@ -292,6 +332,7 @@ runtime·tracebackothers(G *me)
} else
runtime·traceback(~(uintptr)0, ~(uintptr)0, 0, gp);
}
+ runtime·unlock(&allglock);
}
static void
@@ -562,15 +603,6 @@ runtime·starttheworld(void)
void
runtime·mstart(void)
{
-#ifdef GOOS_windows
-#ifdef GOARCH_386
- // It is used by windows-386 only. Unfortunately, seh needs
- // to be located on os stack, and mstart runs on os stack
- // for both m0 and m.
- SEH seh;
-#endif
-#endif
-
if(g != m->g0)
runtime·throw("bad runtime·mstart");
@@ -580,11 +612,6 @@ runtime·mstart(void)
runtime·gosave(&m->g0->sched);
m->g0->sched.pc = (uintptr)-1; // make sure it is never used
m->g0->stackguard = m->g0->stackguard0; // cgo sets only stackguard0, copy it to stackguard
-#ifdef GOOS_windows
-#ifdef GOARCH_386
- m->seh = &seh;
-#endif
-#endif
runtime·asminit();
runtime·minit();
@@ -620,6 +647,7 @@ struct CgoThreadStart
{
M *m;
G *g;
+ uintptr *tls;
void (*fn)(void);
};
@@ -643,9 +671,9 @@ runtime·allocm(P *p)
mp = runtime·cnew(mtype);
mcommoninit(mp);
- // In case of cgo, pthread_create will make us a stack.
+ // In case of cgo or Solaris, pthread_create will make us a stack.
// Windows will layout sched stack on OS stack.
- if(runtime·iscgo || Windows)
+ if(runtime·iscgo || Solaris || Windows)
mp->g0 = runtime·malg(-1);
else
mp->g0 = runtime·malg(8192);
@@ -659,6 +687,21 @@ runtime·allocm(P *p)
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)->elem;
+ }
+ gp = runtime·cnew(gtype);
+ return gp;
+}
+
static M* lockextra(bool nilokay);
static void unlockextra(M*);
@@ -735,16 +778,6 @@ runtime·needm(byte x)
g->stackguard = (uintptr)(&x - 32*1024);
g->stackguard0 = g->stackguard;
-#ifdef GOOS_windows
-#ifdef GOARCH_386
- // On windows/386, we need to put an SEH frame (two words)
- // somewhere on the current stack. We are called from cgocallback_gofunc
- // and we know that it will leave two unused words below m->curg->sched.sp.
- // Use those.
- m->seh = (SEH*)((uintptr*)&x + 1);
-#endif
-#endif
-
// Initialize this thread to use the m.
runtime·asminit();
runtime·minit();
@@ -783,13 +816,7 @@ runtime·newextram(void)
if(raceenabled)
gp->racectx = runtime·racegostart(runtime·newextram);
// 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);
+ allgadd(gp);
// Add m to the extra list.
mnext = lockextra(true);
@@ -828,12 +855,6 @@ runtime·dropm(void)
// Undo whatever initialization minit did during needm.
runtime·unminit();
-#ifdef GOOS_windows
-#ifdef GOARCH_386
- m->seh = nil; // reset dangling typed pointer
-#endif
-#endif
-
// Clear m and g, and return m to the extra list.
// After the call to setmg we can only call nosplit functions.
mp = m;
@@ -904,6 +925,7 @@ newm(void(*fn)(void), P *p)
runtime·throw("_cgo_thread_start missing");
ts.m = mp;
ts.g = mp->g0;
+ ts.tls = mp->tls;
ts.fn = runtime·mstart;
runtime·asmcgocall(_cgo_thread_start, &ts);
return;
@@ -948,7 +970,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)
{
@@ -1112,6 +1134,7 @@ execute(G *gp)
runtime·throw("execute: bad g status");
}
gp->status = Grunning;
+ gp->waitsince = 0;
gp->preempt = false;
gp->stackguard0 = gp->stackguard;
m->p->schedtick++;
@@ -1140,6 +1163,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)
@@ -1331,28 +1356,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, int8 *reason)
+runtime·park(bool(*unlockf)(G*, void*), void *lock, int8 *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, int8 *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();
@@ -1365,6 +1414,8 @@ park0(G *gp)
void
runtime·gosched(void)
{
+ if(g->status != Grunning)
+ runtime·throw("bad g status");
runtime·mcall(runtime·gosched0);
}
@@ -1393,6 +1444,8 @@ runtime·gosched0(G *gp)
void
runtime·goexit(void)
{
+ if(g->status != Grunning)
+ runtime·throw("bad g status");
if(raceenabled)
runtime·racegoend();
runtime·mcall(goexit0);
@@ -1405,6 +1458,13 @@ goexit0(G *gp)
gp->status = Gdead;
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) {
@@ -1535,6 +1595,7 @@ runtime·exitsyscall(void)
if(g->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++;
@@ -1640,6 +1701,7 @@ exitsyscall0(G *gp)
}
// Called from syscall package before fork.
+#pragma textflag NOSPLIT
void
syscall·runtime_BeforeFork(void)
{
@@ -1648,14 +1710,28 @@ syscall·runtime_BeforeFork(void)
m->locks++;
if(m->profilehz != 0)
runtime·resetcpuprofiler(0);
+
+ // This function is called before fork in syscall package.
+ // Code between fork and exec must not allocate memory nor even try to grow stack.
+ // Here we spoil g->stackguard to reliably detect any attempts to grow stack.
+ // runtime_AfterFork will undo this in parent process, but not in child.
+ m->forkstackguard = g->stackguard;
+ g->stackguard0 = StackPreempt-1;
+ g->stackguard = StackPreempt-1;
}
// Called from syscall package after fork in parent.
+#pragma textflag NOSPLIT
void
syscall·runtime_AfterFork(void)
{
int32 hz;
+ // See the comment in runtime_BeforeFork.
+ g->stackguard0 = m->forkstackguard;
+ g->stackguard = m->forkstackguard;
+ m->forkstackguard = 0;
+
hz = runtime·sched.profilehz;
if(hz != 0)
runtime·resetcpuprofiler(hz);
@@ -1669,7 +1745,13 @@ syscall·runtime_AfterFork(void)
static void
mstackalloc(G *gp)
{
- gp->param = runtime·stackalloc((uintptr)gp->param);
+ G *newg;
+ uintptr size;
+
+ newg = (G*)gp->param;
+ size = newg->stacksize;
+ newg->stacksize = 0;
+ gp->param = runtime·stackalloc(newg, size);
runtime·gogo(&gp->sched);
}
@@ -1685,24 +1767,24 @@ runtime·malg(int32 stacksize)
runtime·throw("runtime: bad stack.h");
}
- newg = runtime·malloc(sizeof(G));
+ newg = allocg();
if(stacksize >= 0) {
+ stacksize = runtime·round2(StackSystem + stacksize);
if(g == m->g0) {
// running on scheduler stack already.
- stk = runtime·stackalloc(StackSystem + stacksize);
+ stk = runtime·stackalloc(newg, stacksize);
} else {
// have to call stackalloc on scheduler stack.
- g->param = (void*)(StackSystem + stacksize);
+ newg->stacksize = stacksize;
+ g->param = newg;
runtime·mcall(mstackalloc);
stk = g->param;
g->param = nil;
}
- newg->stacksize = StackSystem + stacksize;
newg->stack0 = (uintptr)stk;
newg->stackguard = (uintptr)stk + StackGuard;
newg->stackguard0 = newg->stackguard;
- newg->stackbase = (uintptr)stk + StackSystem + stacksize - sizeof(Stktop);
- runtime·memclr((byte*)newg->stackbase, sizeof(Stktop));
+ newg->stackbase = (uintptr)stk + stacksize - sizeof(Stktop);
}
return newg;
}
@@ -1736,9 +1818,14 @@ runtime·newproc1(FuncVal *fn, byte *argp, int32 narg, int32 nret, void *callerp
{
byte *sp;
G *newg;
+ P *p;
int32 siz;
//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
siz = narg + nret;
siz = (siz+7) & ~7;
@@ -1750,18 +1837,13 @@ runtime·newproc1(FuncVal *fn, byte *argp, int32 narg, int32 nret, void *callerp
if(siz > StackMin - 1024)
runtime·throw("runtime.newproc: function arguments too large for new goroutine");
- if((newg = gfget(m->p)) != nil) {
+ p = m->p;
+ if((newg = gfget(p)) != nil) {
if(newg->stackguard - StackGuard != newg->stack0)
runtime·throw("invalid stack in newg");
} else {
newg = runtime·malg(StackMin);
- 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);
}
sp = (byte*)newg->stackbase;
@@ -1780,11 +1862,15 @@ runtime·newproc1(FuncVal *fn, byte *argp, int32 narg, int32 nret, void *callerp
runtime·gostartcallfn(&newg->sched, fn);
newg->gopc = (uintptr)callerpc;
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++;
newg->panicwrap = 0;
if(raceenabled)
newg->racectx = runtime·racegostart((void*)callerpc);
- runqput(m->p, newg);
+ runqput(p, newg);
if(runtime·atomicload(&runtime·sched.npidle) != 0 && runtime·atomicload(&runtime·sched.nmspinning) == 0 && fn->fn != runtime·main) // TODO: fast atomic
wakep();
@@ -1794,13 +1880,56 @@ runtime·newproc1(FuncVal *fn, byte *argp, int32 narg, int32 nret, void *callerp
return newg;
}
+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
gfput(P *p, G *gp)
{
+ uintptr stksize;
+ Stktop *top;
+
if(gp->stackguard - StackGuard != gp->stack0)
runtime·throw("invalid stack in gfput");
+ stksize = gp->stackbase + sizeof(Stktop) - gp->stack0;
+ if(stksize != gp->stacksize) {
+ runtime·printf("runtime: bad stacksize, goroutine %D, remain=%d, last=%d\n",
+ gp->goid, (int32)gp->stacksize, (int32)stksize);
+ runtime·throw("gfput: bad stacksize");
+ }
+ top = (Stktop*)gp->stackbase;
+ if(top->malloced) {
+ // non-standard stack size - free it.
+ runtime·stackfree(gp, (void*)gp->stack0, top);
+ gp->stack0 = 0;
+ gp->stackguard = 0;
+ gp->stackguard0 = 0;
+ gp->stackbase = 0;
+ }
gp->schedlink = p->gfree;
p->gfree = gp;
p->gfreecnt++;
@@ -1823,6 +1952,7 @@ static G*
gfget(P *p)
{
G *gp;
+ byte *stk;
retry:
gp = p->gfree;
@@ -1841,6 +1971,23 @@ retry:
if(gp) {
p->gfree = gp->schedlink;
p->gfreecnt--;
+
+ if(gp->stack0 == 0) {
+ // Stack was deallocated in gfput. Allocate a new one.
+ if(g == m->g0) {
+ stk = runtime·stackalloc(gp, FixedStack);
+ } else {
+ gp->stacksize = FixedStack;
+ g->param = gp;
+ runtime·mcall(mstackalloc);
+ stk = g->param;
+ g->param = nil;
+ }
+ gp->stack0 = (uintptr)stk;
+ gp->stackbase = (uintptr)stk + FixedStack - sizeof(Stktop);
+ gp->stackguard = (uintptr)stk + StackGuard;
+ gp->stackguard0 = gp->stackguard;
+ }
}
return gp;
}
@@ -1963,39 +2110,26 @@ runtime·lockedOSThread(void)
return g->lockedm != nil && m->lockedg != nil;
}
-// for testing of callbacks
-void
-runtime·golockedOSThread(bool ret)
-{
- ret = runtime·lockedOSThread();
- FLUSH(&ret);
-}
-
-void
-runtime·NumGoroutine(intgo ret)
-{
- ret = runtime·gcount();
- FLUSH(&ret);
-}
-
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;
}
@@ -2032,25 +2166,30 @@ static struct {
uintptr pcbuf[100];
} prof;
-static void
-System(void)
-{
-}
+static void System(void) {}
+static void ExternalCode(void) {}
+static void GC(void) {}
+extern byte etext[];
// Called if we receive a SIGPROF signal.
void
-runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp)
+runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp, M *mp)
{
int32 n;
bool traceback;
+ // Do not use global m in this function, use mp instead.
+ // On windows one m is sending reports about all the g's, so m means a wrong thing.
+ byte m;
+
+ m = 0;
+ USED(m);
if(prof.fn == nil || prof.hz == 0)
return;
- traceback = true;
- // Windows does profiling in a dedicated thread w/o m.
- if(!Windows && (m == nil || m->mcache == nil))
- traceback = false;
-
+
+ // Profiling runs concurrently with GC, so it must not allocate.
+ mp->mallocing++;
+
// Define that a "user g" is a user-created goroutine, and a "system g"
// is one that is m->g0 or m->gsignal. We've only made sure that we
// can unwind user g's, so exclude the system g's.
@@ -2123,36 +2262,55 @@ runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp)
// To recap, there are no constraints on the assembly being used for the
// transition. We simply require that g and SP match and that the PC is not
// in runtime.gogo.
- //
- // On Windows, one m is sending reports about all the g's, so gp == m->curg
- // is not a useful comparison. The profilem function in os_windows.c has
- // already checked that gp is a user g.
- if(gp == nil ||
- (!Windows && gp != m->curg) ||
+ traceback = true;
+ if(gp == nil || gp != mp->curg ||
(uintptr)sp < gp->stackguard - StackGuard || gp->stackbase < (uintptr)sp ||
((uint8*)runtime·gogo <= pc && pc < (uint8*)runtime·gogo + RuntimeGogoBytes))
traceback = false;
- // Race detector calls asmcgocall w/o entersyscall/exitsyscall,
- // we can not currently unwind through asmcgocall.
- if(m != nil && m->racecall)
- traceback = false;
-
runtime·lock(&prof);
if(prof.fn == nil) {
runtime·unlock(&prof);
+ mp->mallocing--;
return;
}
n = 0;
if(traceback)
n = runtime·gentraceback((uintptr)pc, (uintptr)sp, (uintptr)lr, gp, 0, prof.pcbuf, nelem(prof.pcbuf), nil, nil, false);
if(!traceback || n <= 0) {
- n = 2;
- prof.pcbuf[0] = (uintptr)pc;
- prof.pcbuf[1] = (uintptr)System + 1;
+ // Normal traceback is impossible or has failed.
+ // See if it falls into several common cases.
+ n = 0;
+ if(mp->ncgo > 0 && mp->curg != nil &&
+ mp->curg->syscallpc != 0 && mp->curg->syscallsp != 0) {
+ // Cgo, we can't unwind and symbolize arbitrary C code,
+ // so instead collect Go stack that leads to the cgo call.
+ // This is especially important on windows, since all syscalls are cgo calls.
+ n = runtime·gentraceback(mp->curg->syscallpc, mp->curg->syscallsp, 0, mp->curg, 0, prof.pcbuf, nelem(prof.pcbuf), nil, nil, false);
+ }
+#ifdef GOOS_windows
+ if(n == 0 && mp->libcallg != nil && mp->libcallpc != 0 && mp->libcallsp != 0) {
+ // Libcall, i.e. runtime syscall on windows.
+ // Collect Go stack that leads to the call.
+ n = runtime·gentraceback(mp->libcallpc, mp->libcallsp, 0, mp->libcallg, 0, prof.pcbuf, nelem(prof.pcbuf), nil, nil, false);
+ }
+#endif
+ if(n == 0) {
+ // If all of the above has failed, account it against abstract "System" or "GC".
+ n = 2;
+ // "ExternalCode" is better than "etext".
+ if((uintptr)pc > (uintptr)etext)
+ pc = (byte*)ExternalCode + PCQuantum;
+ prof.pcbuf[0] = (uintptr)pc;
+ if(mp->gcing || mp->helpgc)
+ prof.pcbuf[1] = (uintptr)GC + PCQuantum;
+ else
+ prof.pcbuf[1] = (uintptr)System + PCQuantum;
+ }
}
prof.fn(prof.pcbuf, n);
runtime·unlock(&prof);
+ mp->mallocing--;
}
// Arrange to call fn with a traceback hz times a second.
@@ -2195,6 +2353,7 @@ static void
procresize(int32 new)
{
int32 i, old;
+ bool empty;
G *gp;
P *p;
@@ -2216,27 +2375,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))
- 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; i < 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++) {
@@ -2318,30 +2492,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;
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!");
}
@@ -2418,6 +2603,7 @@ struct Pdesc
uint32 syscalltick;
int64 syscallwhen;
};
+#pragma dataflag NOPTR
static Pdesc pdesc[MaxGomaxprocs];
static uint32
@@ -2436,16 +2622,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.
@@ -2525,7 +2714,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;
int8 *fmt;
M *mp, *lockedm;
G *gp, *lockedg;
@@ -2552,15 +2742,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]
@@ -2571,7 +2757,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) {
@@ -2592,18 +2778,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);
}
@@ -2646,6 +2835,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*
@@ -2661,6 +2864,8 @@ globrunqget(P *p, int32 max)
n = runtime·sched.runqsize;
if(max > 0 && n > max)
n = max;
+ if(n > nelem(p->runq)/2)
+ n = nelem(p->runq)/2;
runtime·sched.runqsize -= n;
if(runtime·sched.runqsize == 0)
runtime·sched.runqtail = nil;
@@ -2700,78 +2905,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
@@ -2780,57 +3005,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)
+ n = runqgrab(p2, batch);
+ if(n == 0)
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);
- 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;
}
@@ -2838,14 +3030,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 < nelem(gs); i++) {
if(runqget(&p) != nil)
@@ -2867,20 +3055,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 < nelem(gs); i++) {
for(j = 0; j < i; j++) {
@@ -2914,6 +3093,7 @@ runtime·testSchedLocalQueueSteal(void)
}
extern void runtime·morestack(void);
+uintptr runtime·externalthreadhandlerp;
// Does f mark the top of a goroutine stack?
bool
@@ -2924,18 +3104,21 @@ runtime·topofstack(Func *f)
f->entry == (uintptr)runtime·mcall ||
f->entry == (uintptr)runtime·morestack ||
f->entry == (uintptr)runtime·lessstack ||
- f->entry == (uintptr)_rt0_go;
+ f->entry == (uintptr)_rt0_go ||
+ (runtime·externalthreadhandlerp != 0 && f->entry == runtime·externalthreadhandlerp);
}
-void
-runtime∕debug·setMaxThreads(intgo in, intgo out)
+int32
+runtime·setmaxthreads(int32 in)
{
+ int32 out;
+
runtime·lock(&runtime·sched);
out = runtime·sched.maxmcount;
runtime·sched.maxmcount = in;
checkmcount();
runtime·unlock(&runtime·sched);
- FLUSH(&out);
+ return out;
}
static int8 experiment[] = GOEXPERIMENT; // defined in zaexperiment.h
diff --git a/src/pkg/runtime/proc.p b/src/pkg/runtime/proc.p
deleted file mode 100644
index f0b46de61..000000000
--- a/src/pkg/runtime/proc.p
+++ /dev/null
@@ -1,526 +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.
-
-/*
-model for proc.c as of 2011/07/22.
-
-takes 4900 seconds to explore 1189070 states
-with G=3, var_gomaxprocs=1
-on a Core i7 L640 2.13 GHz Lenovo X201s.
-
-rm -f proc.p.trail pan.* pan
-spin -a proc.p
-gcc -DSAFETY -DREACH -DMEMLIM'='4000 -o pan pan.c
-pan -w28 -n -i -m500000
-test -f proc.p.trail && pan -r proc.p.trail
-*/
-
-/*
- * scheduling parameters
- */
-
-/*
- * the number of goroutines G doubles as the maximum
- * number of OS threads; the max is reachable when all
- * the goroutines are blocked in system calls.
- */
-#define G 3
-
-/*
- * whether to allow gomaxprocs to vary during execution.
- * enabling this checks the scheduler even when code is
- * calling GOMAXPROCS, but it also slows down the verification
- * by about 10x.
- */
-#define var_gomaxprocs 1 /* allow gomaxprocs to vary */
-
-/* gomaxprocs */
-#if var_gomaxprocs
-byte gomaxprocs = 3;
-#else
-#define gomaxprocs 3
-#endif
-
-/* queue of waiting M's: sched_mhead[:mwait] */
-byte mwait;
-byte sched_mhead[G];
-
-/* garbage collector state */
-bit gc_lock, gcwaiting;
-
-/* goroutines sleeping, waiting to run */
-byte gsleep, gwait;
-
-/* scheduler state */
-bit sched_lock;
-bit sched_stopped;
-bit atomic_gwaiting, atomic_waitstop;
-byte atomic_mcpu, atomic_mcpumax;
-
-/* M struct fields - state for handing off g to m. */
-bit m_waitnextg[G];
-bit m_havenextg[G];
-bit m_nextg[G];
-
-/*
- * opt_atomic/opt_dstep mark atomic/deterministics
- * sequences that are marked only for reasons of
- * optimization, not for correctness of the algorithms.
- *
- * in general any code that runs while holding the
- * schedlock and does not refer to or modify the atomic_*
- * fields can be marked atomic/dstep without affecting
- * the usefulness of the model. since we trust the lock
- * implementation, what we really want to test is the
- * interleaving of the atomic fast paths with entersyscall
- * and exitsyscall.
- */
-#define opt_atomic atomic
-#define opt_dstep d_step
-
-/* locks */
-inline lock(x) {
- d_step { x == 0; x = 1 }
-}
-
-inline unlock(x) {
- d_step { assert x == 1; x = 0 }
-}
-
-/* notes */
-inline noteclear(x) {
- x = 0
-}
-
-inline notesleep(x) {
- x == 1
-}
-
-inline notewakeup(x) {
- opt_dstep { assert x == 0; x = 1 }
-}
-
-/*
- * scheduler
- */
-inline schedlock() {
- lock(sched_lock)
-}
-
-inline schedunlock() {
- unlock(sched_lock)
-}
-
-/*
- * canaddmcpu is like the C function but takes
- * an extra argument to include in the test, to model
- * "cannget() && canaddmcpu()" as "canaddmcpu(cangget())"
- */
-inline canaddmcpu(g) {
- d_step {
- g && atomic_mcpu < atomic_mcpumax;
- atomic_mcpu++;
- }
-}
-
-/*
- * gput is like the C function.
- * instead of tracking goroutines explicitly we
- * maintain only the count of the number of
- * waiting goroutines.
- */
-inline gput() {
- /* omitted: lockedm, idlem concerns */
- opt_dstep {
- gwait++;
- if
- :: gwait == 1 ->
- atomic_gwaiting = 1
- :: else
- fi
- }
-}
-
-/*
- * cangget is a macro so it can be passed to
- * canaddmcpu (see above).
- */
-#define cangget() (gwait>0)
-
-/*
- * gget is like the C function.
- */
-inline gget() {
- opt_dstep {
- assert gwait > 0;
- gwait--;
- if
- :: gwait == 0 ->
- atomic_gwaiting = 0
- :: else
- fi
- }
-}
-
-/*
- * mput is like the C function.
- * here we do keep an explicit list of waiting M's,
- * so that we know which ones can be awakened.
- * we use _pid-1 because the monitor is proc 0.
- */
-inline mput() {
- opt_dstep {
- sched_mhead[mwait] = _pid - 1;
- mwait++
- }
-}
-
-/*
- * mnextg is like the C function mnextg(m, g).
- * it passes an unspecified goroutine to m to start running.
- */
-inline mnextg(m) {
- opt_dstep {
- m_nextg[m] = 1;
- if
- :: m_waitnextg[m] ->
- m_waitnextg[m] = 0;
- notewakeup(m_havenextg[m])
- :: else
- fi
- }
-}
-
-/*
- * mgetnextg handles the main m handoff in matchmg.
- * it is like mget() || new M followed by mnextg(m, g),
- * but combined to avoid a local variable.
- * unlike the C code, a new M simply assumes it is
- * running a g instead of using the mnextg coordination
- * to obtain one.
- */
-inline mgetnextg() {
- opt_atomic {
- if
- :: mwait > 0 ->
- mwait--;
- mnextg(sched_mhead[mwait]);
- sched_mhead[mwait] = 0;
- :: else ->
- run mstart();
- fi
- }
-}
-
-/*
- * nextgandunlock is like the C function.
- * it pulls a g off the queue or else waits for one.
- */
-inline nextgandunlock() {
- assert atomic_mcpu <= G;
-
- if
- :: m_nextg[_pid-1] ->
- m_nextg[_pid-1] = 0;
- schedunlock();
- :: canaddmcpu(!m_nextg[_pid-1] && cangget()) ->
- gget();
- schedunlock();
- :: else ->
- opt_dstep {
- mput();
- m_nextg[_pid-1] = 0;
- m_waitnextg[_pid-1] = 1;
- noteclear(m_havenextg[_pid-1]);
- }
- if
- :: atomic_waitstop && atomic_mcpu <= atomic_mcpumax ->
- atomic_waitstop = 0;
- notewakeup(sched_stopped)
- :: else
- fi;
- schedunlock();
- opt_dstep {
- notesleep(m_havenextg[_pid-1]);
- assert m_nextg[_pid-1];
- m_nextg[_pid-1] = 0;
- }
- fi
-}
-
-/*
- * stoptheworld is like the C function.
- */
-inline stoptheworld() {
- schedlock();
- gcwaiting = 1;
- atomic_mcpumax = 1;
- do
- :: d_step { atomic_mcpu > 1 ->
- noteclear(sched_stopped);
- assert !atomic_waitstop;
- atomic_waitstop = 1 }
- schedunlock();
- notesleep(sched_stopped);
- schedlock();
- :: else ->
- break
- od;
- schedunlock();
-}
-
-/*
- * starttheworld is like the C function.
- */
-inline starttheworld() {
- schedlock();
- gcwaiting = 0;
- atomic_mcpumax = gomaxprocs;
- matchmg();
- schedunlock();
-}
-
-/*
- * matchmg is like the C function.
- */
-inline matchmg() {
- do
- :: canaddmcpu(cangget()) ->
- gget();
- mgetnextg();
- :: else -> break
- od
-}
-
-/*
- * ready is like the C function.
- * it puts a g on the run queue.
- */
-inline ready() {
- schedlock();
- gput()
- matchmg()
- schedunlock()
-}
-
-/*
- * schedule simulates the C scheduler.
- * it assumes that there is always a goroutine
- * running already, and the goroutine has entered
- * the scheduler for an unspecified reason,
- * either to yield or to block.
- */
-inline schedule() {
- schedlock();
-
- mustsched = 0;
- atomic_mcpu--;
- assert atomic_mcpu <= G;
- if
- :: skip ->
- // goroutine yields, still runnable
- gput();
- :: gsleep+1 < G ->
- // goroutine goes to sleep (but there is another that can wake it)
- gsleep++
- fi;
-
- // Find goroutine to run.
- nextgandunlock()
-}
-
-/*
- * schedpend is > 0 if a goroutine is about to committed to
- * entering the scheduler but has not yet done so.
- * Just as we don't test for the undesirable conditions when a
- * goroutine is in the scheduler, we don't test for them when
- * a goroutine will be in the scheduler shortly.
- * Modeling this state lets us replace mcpu cas loops with
- * simpler mcpu atomic adds.
- */
-byte schedpend;
-
-/*
- * entersyscall is like the C function.
- */
-inline entersyscall() {
- bit willsched;
-
- /*
- * Fast path. Check all the conditions tested during schedlock/schedunlock
- * below, and if we can get through the whole thing without stopping, run it
- * in one atomic cas-based step.
- */
- atomic {
- atomic_mcpu--;
- if
- :: atomic_gwaiting ->
- skip
- :: atomic_waitstop && atomic_mcpu <= atomic_mcpumax ->
- skip
- :: else ->
- goto Lreturn_entersyscall;
- fi;
- willsched = 1;
- schedpend++;
- }
-
- /*
- * Normal path.
- */
- schedlock()
- opt_dstep {
- if
- :: willsched ->
- schedpend--;
- willsched = 0
- :: else
- fi
- }
- if
- :: atomic_gwaiting ->
- matchmg()
- :: else
- fi;
- if
- :: atomic_waitstop && atomic_mcpu <= atomic_mcpumax ->
- atomic_waitstop = 0;
- notewakeup(sched_stopped)
- :: else
- fi;
- schedunlock();
-Lreturn_entersyscall:
- skip
-}
-
-/*
- * exitsyscall is like the C function.
- */
-inline exitsyscall() {
- /*
- * Fast path. If there's a cpu available, use it.
- */
- atomic {
- // omitted profilehz check
- atomic_mcpu++;
- if
- :: atomic_mcpu >= atomic_mcpumax ->
- skip
- :: else ->
- goto Lreturn_exitsyscall
- fi
- }
-
- /*
- * Normal path.
- */
- schedlock();
- d_step {
- if
- :: atomic_mcpu <= atomic_mcpumax ->
- skip
- :: else ->
- mustsched = 1
- fi
- }
- schedunlock()
-Lreturn_exitsyscall:
- skip
-}
-
-#if var_gomaxprocs
-inline gomaxprocsfunc() {
- schedlock();
- opt_atomic {
- if
- :: gomaxprocs != 1 -> gomaxprocs = 1
- :: gomaxprocs != 2 -> gomaxprocs = 2
- :: gomaxprocs != 3 -> gomaxprocs = 3
- fi;
- }
- if
- :: gcwaiting != 0 ->
- assert atomic_mcpumax == 1
- :: else ->
- atomic_mcpumax = gomaxprocs;
- if
- :: atomic_mcpu > gomaxprocs ->
- mustsched = 1
- :: else ->
- matchmg()
- fi
- fi;
- schedunlock();
-}
-#endif
-
-/*
- * mstart is the entry point for a new M.
- * our model of an M is always running some
- * unspecified goroutine.
- */
-proctype mstart() {
- /*
- * mustsched is true if the goroutine must enter the
- * scheduler instead of continuing to execute.
- */
- bit mustsched;
-
- do
- :: skip ->
- // goroutine reschedules.
- schedule()
- :: !mustsched ->
- // goroutine does something.
- if
- :: skip ->
- // goroutine executes system call
- entersyscall();
- exitsyscall()
- :: atomic { gsleep > 0; gsleep-- } ->
- // goroutine wakes another goroutine
- ready()
- :: lock(gc_lock) ->
- // goroutine runs a garbage collection
- stoptheworld();
- starttheworld();
- unlock(gc_lock)
-#if var_gomaxprocs
- :: skip ->
- // goroutine picks a new gomaxprocs
- gomaxprocsfunc()
-#endif
- fi
- od;
-
- assert 0;
-}
-
-/*
- * monitor initializes the scheduler state
- * and then watches for impossible conditions.
- */
-active proctype monitor() {
- opt_dstep {
- byte i = 1;
- do
- :: i < G ->
- gput();
- i++
- :: else -> break
- od;
- atomic_mcpu = 1;
- atomic_mcpumax = 1;
- }
- run mstart();
-
- do
- // Should never have goroutines waiting with procs available.
- :: !sched_lock && schedpend==0 && gwait > 0 && atomic_mcpu < atomic_mcpumax ->
- assert 0
- // Should never have gc waiting for stop if things have already stopped.
- :: !sched_lock && schedpend==0 && atomic_waitstop && atomic_mcpu <= atomic_mcpumax ->
- assert 0
- od
-}
diff --git a/src/pkg/runtime/proc_test.go b/src/pkg/runtime/proc_test.go
index dd70ed97d..5be355195 100644
--- a/src/pkg/runtime/proc_test.go
+++ b/src/pkg/runtime/proc_test.go
@@ -244,6 +244,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 {
@@ -327,24 +370,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/src/pkg/runtime/race.c b/src/pkg/runtime/race.c
index 6ee55beff..eb0be7fa6 100644
--- a/src/pkg/runtime/race.c
+++ b/src/pkg/runtime/race.c
@@ -9,178 +9,96 @@
#include "arch_GOARCH.h"
#include "malloc.h"
#include "race.h"
-#include "../../cmd/ld/textflag.h"
-
-void runtime∕race·Initialize(uintptr *racectx);
-void runtime∕race·MapShadow(void *addr, uintptr size);
-void runtime∕race·Finalize(void);
-void runtime∕race·FinalizerGoroutine(uintptr racectx);
-void runtime∕race·Read(uintptr racectx, void *addr, void *pc);
-void runtime∕race·Write(uintptr racectx, void *addr, void *pc);
-void runtime∕race·ReadRange(uintptr racectx, void *addr, uintptr sz, void *pc);
-void runtime∕race·WriteRange(uintptr racectx, void *addr, uintptr sz, void *pc);
-void runtime∕race·FuncEnter(uintptr racectx, void *pc);
-void runtime∕race·FuncExit(uintptr racectx);
-void runtime∕race·Malloc(uintptr racectx, void *p, uintptr sz, void *pc);
-void runtime∕race·Free(void *p);
-void runtime∕race·GoStart(uintptr racectx, uintptr *chracectx, void *pc);
-void runtime∕race·GoEnd(uintptr racectx);
-void runtime∕race·Acquire(uintptr racectx, void *addr);
-void runtime∕race·Release(uintptr racectx, void *addr);
-void runtime∕race·ReleaseMerge(uintptr racectx, void *addr);
+#include "type.h"
+#include "typekind.h"
+
+// Race runtime functions called via runtime·racecall.
+void __tsan_init(void);
+void __tsan_fini(void);
+void __tsan_map_shadow(void);
+void __tsan_finalizer_goroutine(void);
+void __tsan_go_start(void);
+void __tsan_go_end(void);
+void __tsan_malloc(void);
+void __tsan_acquire(void);
+void __tsan_release(void);
+void __tsan_release_merge(void);
+
+// Mimic what cmd/cgo would do.
+#pragma cgo_import_static __tsan_init
+#pragma cgo_import_static __tsan_fini
+#pragma cgo_import_static __tsan_map_shadow
+#pragma cgo_import_static __tsan_finalizer_goroutine
+#pragma cgo_import_static __tsan_go_start
+#pragma cgo_import_static __tsan_go_end
+#pragma cgo_import_static __tsan_malloc
+#pragma cgo_import_static __tsan_acquire
+#pragma cgo_import_static __tsan_release
+#pragma cgo_import_static __tsan_release_merge
+
+// These are called from race_amd64.s.
+#pragma cgo_import_static __tsan_read
+#pragma cgo_import_static __tsan_read_pc
+#pragma cgo_import_static __tsan_read_range
+#pragma cgo_import_static __tsan_write
+#pragma cgo_import_static __tsan_write_pc
+#pragma cgo_import_static __tsan_write_range
+#pragma cgo_import_static __tsan_func_enter
+#pragma cgo_import_static __tsan_func_exit
extern byte noptrdata[];
extern byte enoptrbss[];
+
+// start/end of heap for race_amd64.s
+uintptr runtime·racearenastart;
+uintptr runtime·racearenaend;
-static bool onstack(uintptr argp);
+void runtime·racefuncenter(void *callpc);
+void runtime·racefuncexit(void);
+void runtime·racereadrangepc1(void *addr, uintptr sz, void *pc);
+void runtime·racewriterangepc1(void *addr, uintptr sz, void *pc);
+void runtime·racesymbolizethunk(void*);
-// We set m->racecall around all calls into race library to trigger fast path in cgocall.
-// Also we increment m->locks to disable preemption and potential rescheduling
-// to ensure that we reset m->racecall on the correct m.
+// racecall allows calling an arbitrary function f from C race runtime
+// with up to 4 uintptr arguments.
+void runtime·racecall(void(*f)(void), ...);
uintptr
runtime·raceinit(void)
{
uintptr racectx, start, size;
- m->racecall = true;
- m->locks++;
- runtime∕race·Initialize(&racectx);
+ // cgo is required to initialize libc, which is used by race runtime
+ if(!runtime·iscgo)
+ runtime·throw("raceinit: race build must use cgo");
+ runtime·racecall(__tsan_init, &racectx, runtime·racesymbolizethunk);
// Round data segment to page boundaries, because it's used in mmap().
start = (uintptr)noptrdata & ~(PageSize-1);
size = ROUND((uintptr)enoptrbss - start, PageSize);
- runtime∕race·MapShadow((void*)start, size);
- m->locks--;
- m->racecall = false;
+ runtime·racecall(__tsan_map_shadow, start, size);
return racectx;
}
void
runtime·racefini(void)
{
- m->racecall = true;
- m->locks++;
- runtime∕race·Finalize();
- m->locks--;
- m->racecall = false;
+ runtime·racecall(__tsan_fini);
}
void
runtime·racemapshadow(void *addr, uintptr size)
{
- m->racecall = true;
- m->locks++;
- runtime∕race·MapShadow(addr, size);
- m->locks--;
- m->racecall = false;
-}
-
-// Called from instrumented code.
-// If we split stack, getcallerpc() can return runtime·lessstack().
-#pragma textflag NOSPLIT
-void
-runtime·racewrite(uintptr addr)
-{
- if(!onstack(addr)) {
- m->racecall = true;
- m->locks++;
- runtime∕race·Write(g->racectx, (void*)addr, runtime·getcallerpc(&addr));
- m->locks--;
- m->racecall = false;
- }
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racewriterange(uintptr addr, uintptr sz)
-{
- if(!onstack(addr)) {
- m->racecall = true;
- m->locks++;
- runtime∕race·WriteRange(g->racectx, (void*)addr, sz, runtime·getcallerpc(&addr));
- m->locks--;
- m->racecall = false;
- }
-}
-
-// Called from instrumented code.
-// If we split stack, getcallerpc() can return runtime·lessstack().
-#pragma textflag NOSPLIT
-void
-runtime·raceread(uintptr addr)
-{
- if(!onstack(addr)) {
- m->racecall = true;
- m->locks++;
- runtime∕race·Read(g->racectx, (void*)addr, runtime·getcallerpc(&addr));
- m->locks--;
- m->racecall = false;
- }
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racereadrange(uintptr addr, uintptr sz)
-{
- if(!onstack(addr)) {
- m->racecall = true;
- m->locks++;
- runtime∕race·ReadRange(g->racectx, (void*)addr, sz, runtime·getcallerpc(&addr));
- m->locks--;
- m->racecall = false;
- }
-}
-
-// Called from runtime·racefuncenter (assembly).
-#pragma textflag NOSPLIT
-void
-runtime·racefuncenter1(uintptr pc)
-{
- // If the caller PC is lessstack, use slower runtime·callers
- // to walk across the stack split to find the real caller.
- if(pc == (uintptr)runtime·lessstack)
- runtime·callers(2, &pc, 1);
-
- m->racecall = true;
- m->locks++;
- runtime∕race·FuncEnter(g->racectx, (void*)pc);
- m->locks--;
- m->racecall = false;
-}
-
-// Called from instrumented code.
-#pragma textflag NOSPLIT
-void
-runtime·racefuncexit(void)
-{
- m->racecall = true;
- m->locks++;
- runtime∕race·FuncExit(g->racectx);
- m->locks--;
- m->racecall = false;
+ if(runtime·racearenastart == 0)
+ runtime·racearenastart = (uintptr)addr;
+ if(runtime·racearenaend < (uintptr)addr+size)
+ runtime·racearenaend = (uintptr)addr+size;
+ runtime·racecall(__tsan_map_shadow, addr, size);
}
void
runtime·racemalloc(void *p, uintptr sz)
{
- // use m->curg because runtime·stackalloc() is called from g0
- if(m->curg == nil)
- return;
- m->racecall = true;
- m->locks++;
- runtime∕race·Malloc(m->curg->racectx, p, sz, /* unused pc */ 0);
- m->locks--;
- m->racecall = false;
-}
-
-void
-runtime·racefree(void *p)
-{
- m->racecall = true;
- m->locks++;
- runtime∕race·Free(p);
- m->locks--;
- m->racecall = false;
+ runtime·racecall(__tsan_malloc, p, sz);
}
uintptr
@@ -188,96 +106,58 @@ runtime·racegostart(void *pc)
{
uintptr racectx;
- m->racecall = true;
- m->locks++;
- runtime∕race·GoStart(g->racectx, &racectx, pc);
- m->locks--;
- m->racecall = false;
+ runtime·racecall(__tsan_go_start, g->racectx, &racectx, pc);
return racectx;
}
void
runtime·racegoend(void)
{
- m->racecall = true;
- m->locks++;
- runtime∕race·GoEnd(g->racectx);
- m->locks--;
- m->racecall = false;
-}
-
-static void
-memoryaccess(void *addr, uintptr callpc, uintptr pc, bool write)
-{
- uintptr racectx;
-
- if(!onstack((uintptr)addr)) {
- m->racecall = true;
- m->locks++;
- racectx = g->racectx;
- if(callpc) {
- if(callpc == (uintptr)runtime·lessstack)
- runtime·callers(3, &callpc, 1);
- runtime∕race·FuncEnter(racectx, (void*)callpc);
- }
- if(write)
- runtime∕race·Write(racectx, addr, (void*)pc);
- else
- runtime∕race·Read(racectx, addr, (void*)pc);
- if(callpc)
- runtime∕race·FuncExit(racectx);
- m->locks--;
- m->racecall = false;
- }
+ runtime·racecall(__tsan_go_end, g->racectx);
}
void
-runtime·racewritepc(void *addr, void *callpc, void *pc)
+runtime·racewriterangepc(void *addr, uintptr sz, void *callpc, void *pc)
{
- memoryaccess(addr, (uintptr)callpc, (uintptr)pc, true);
+ if(callpc != nil)
+ runtime·racefuncenter(callpc);
+ runtime·racewriterangepc1(addr, sz, pc);
+ if(callpc != nil)
+ runtime·racefuncexit();
}
void
-runtime·racereadpc(void *addr, void *callpc, void *pc)
+runtime·racereadrangepc(void *addr, uintptr sz, void *callpc, void *pc)
{
- memoryaccess(addr, (uintptr)callpc, (uintptr)pc, false);
+ if(callpc != nil)
+ runtime·racefuncenter(callpc);
+ runtime·racereadrangepc1(addr, sz, pc);
+ if(callpc != nil)
+ runtime·racefuncexit();
}
-static void
-rangeaccess(void *addr, uintptr size, uintptr callpc, uintptr pc, bool write)
+void
+runtime·racewriteobjectpc(void *addr, Type *t, void *callpc, void *pc)
{
- uintptr racectx;
+ uint8 kind;
- if(!onstack((uintptr)addr)) {
- m->racecall = true;
- m->locks++;
- racectx = g->racectx;
- if(callpc) {
- if(callpc == (uintptr)runtime·lessstack)
- runtime·callers(3, &callpc, 1);
- runtime∕race·FuncEnter(racectx, (void*)callpc);
- }
- if(write)
- runtime∕race·WriteRange(racectx, addr, size, (void*)pc);
- else
- runtime∕race·ReadRange(racectx, addr, size, (void*)pc);
- if(callpc)
- runtime∕race·FuncExit(racectx);
- m->locks--;
- m->racecall = false;
- }
+ kind = t->kind & ~KindNoPointers;
+ if(kind == KindArray || kind == KindStruct)
+ runtime·racewriterangepc(addr, t->size, callpc, pc);
+ else
+ runtime·racewritepc(addr, callpc, pc);
}
void
-runtime·racewriterangepc(void *addr, uintptr sz, void *callpc, void *pc)
+runtime·racereadobjectpc(void *addr, Type *t, void *callpc, void *pc)
{
- rangeaccess(addr, sz, (uintptr)callpc, (uintptr)pc, true);
-}
+ uint8 kind;
-void
-runtime·racereadrangepc(void *addr, uintptr sz, void *callpc, void *pc)
-{
- rangeaccess(addr, sz, (uintptr)callpc, (uintptr)pc, false);
+ kind = t->kind & ~KindNoPointers;
+ if(kind == KindArray || kind == KindStruct)
+ runtime·racereadrangepc(addr, t->size, callpc, pc);
+ else
+ runtime·racereadpc(addr, callpc, pc);
}
void
@@ -291,11 +171,7 @@ runtime·raceacquireg(G *gp, void *addr)
{
if(g->raceignore)
return;
- m->racecall = true;
- m->locks++;
- runtime∕race·Acquire(gp->racectx, addr);
- m->locks--;
- m->racecall = false;
+ runtime·racecall(__tsan_acquire, gp->racectx, addr);
}
void
@@ -309,11 +185,7 @@ runtime·racereleaseg(G *gp, void *addr)
{
if(g->raceignore)
return;
- m->racecall = true;
- m->locks++;
- runtime∕race·Release(gp->racectx, addr);
- m->locks--;
- m->racecall = false;
+ runtime·racecall(__tsan_release, gp->racectx, addr);
}
void
@@ -327,21 +199,13 @@ runtime·racereleasemergeg(G *gp, void *addr)
{
if(g->raceignore)
return;
- m->racecall = true;
- m->locks++;
- runtime∕race·ReleaseMerge(gp->racectx, addr);
- m->locks--;
- m->racecall = false;
+ runtime·racecall(__tsan_release_merge, gp->racectx, addr);
}
void
runtime·racefingo(void)
{
- m->racecall = true;
- m->locks++;
- runtime∕race·FinalizerGoroutine(g->racectx);
- m->locks--;
- m->racecall = false;
+ runtime·racecall(__tsan_finalizer_goroutine, g->racectx);
}
// func RaceAcquire(addr unsafe.Pointer)
@@ -379,38 +243,6 @@ runtime·RaceSemrelease(uint32 *s)
runtime·semrelease(s);
}
-// func RaceRead(addr unsafe.Pointer)
-#pragma textflag NOSPLIT
-void
-runtime·RaceRead(void *addr)
-{
- memoryaccess(addr, 0, (uintptr)runtime·getcallerpc(&addr), false);
-}
-
-// func RaceWrite(addr unsafe.Pointer)
-#pragma textflag NOSPLIT
-void
-runtime·RaceWrite(void *addr)
-{
- memoryaccess(addr, 0, (uintptr)runtime·getcallerpc(&addr), true);
-}
-
-// func RaceReadRange(addr unsafe.Pointer, len int)
-#pragma textflag NOSPLIT
-void
-runtime·RaceReadRange(void *addr, intgo len)
-{
- rangeaccess(addr, len, 0, (uintptr)runtime·getcallerpc(&addr), false);
-}
-
-// func RaceWriteRange(addr unsafe.Pointer, len int)
-#pragma textflag NOSPLIT
-void
-runtime·RaceWriteRange(void *addr, intgo len)
-{
- rangeaccess(addr, len, 0, (uintptr)runtime·getcallerpc(&addr), true);
-}
-
// func RaceDisable()
void
runtime·RaceDisable(void)
@@ -425,14 +257,36 @@ runtime·RaceEnable(void)
g->raceignore--;
}
-static bool
-onstack(uintptr argp)
+typedef struct SymbolizeContext SymbolizeContext;
+struct SymbolizeContext
+{
+ uintptr pc;
+ int8* func;
+ int8* file;
+ uintptr line;
+ uintptr off;
+ uintptr res;
+};
+
+// Callback from C into Go, runs on g0.
+void
+runtime·racesymbolize(SymbolizeContext *ctx)
{
- // noptrdata, data, bss, noptrbss
- // the layout is in ../../cmd/ld/data.c
- if((byte*)argp >= noptrdata && (byte*)argp < enoptrbss)
- return false;
- if((byte*)argp >= runtime·mheap.arena_start && (byte*)argp < runtime·mheap.arena_used)
- return false;
- return true;
+ Func *f;
+ String file;
+
+ f = runtime·findfunc(ctx->pc);
+ if(f == nil) {
+ ctx->func = "??";
+ ctx->file = "-";
+ ctx->line = 0;
+ ctx->off = ctx->pc;
+ ctx->res = 1;
+ return;
+ }
+ ctx->func = runtime·funcname(f);
+ ctx->line = runtime·funcline(f, ctx->pc, &file);
+ ctx->file = (int8*)file.str; // assume zero-terminated
+ ctx->off = ctx->pc - f->entry;
+ ctx->res = 1;
}
diff --git a/src/pkg/runtime/race.h b/src/pkg/runtime/race.h
index f7aa99dc2..fee31e09f 100644
--- a/src/pkg/runtime/race.h
+++ b/src/pkg/runtime/race.h
@@ -17,13 +17,14 @@ 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·racereadobjectpc(void *addr, Type *t, void *callpc, void *pc);
+void runtime·racewriteobjectpc(void *addr, Type *t, void *callpc, void *pc);
void runtime·racefingo(void);
void runtime·raceacquire(void *addr);
void runtime·raceacquireg(G *gp, void *addr);
diff --git a/src/pkg/runtime/race/README b/src/pkg/runtime/race/README
index 0b73bd857..785640607 100644
--- a/src/pkg/runtime/race/README
+++ b/src/pkg/runtime/race/README
@@ -9,4 +9,4 @@ $ ./buildgo.sh
Tested with gcc 4.6.1 and 4.7.0. On Windows it's built with 64-bit MinGW.
-Current runtime is built on rev 191161.
+Current runtime is built on rev 203116.
diff --git a/src/pkg/runtime/race/race.go b/src/pkg/runtime/race/race.go
index 5b44bde83..e53cacf4a 100644
--- a/src/pkg/runtime/race/race.go
+++ b/src/pkg/runtime/race/race.go
@@ -6,116 +6,10 @@
package race
-/*
-void __tsan_init(void **racectx);
-void __tsan_fini(void);
-void __tsan_map_shadow(void *addr, void *size);
-void __tsan_go_start(void *racectx, void **chracectx, void *pc);
-void __tsan_go_end(void *racectx);
-void __tsan_read(void *racectx, void *addr, void *pc);
-void __tsan_write(void *racectx, void *addr, void *pc);
-void __tsan_read_range(void *racectx, void *addr, long sz, long step, void *pc);
-void __tsan_write_range(void *racectx, void *addr, long sz, long step, void *pc);
-void __tsan_func_enter(void *racectx, void *pc);
-void __tsan_func_exit(void *racectx);
-void __tsan_malloc(void *racectx, void *p, long sz, void *pc);
-void __tsan_free(void *p);
-void __tsan_acquire(void *racectx, void *addr);
-void __tsan_release(void *racectx, void *addr);
-void __tsan_release_merge(void *racectx, void *addr);
-void __tsan_finalizer_goroutine(void *racectx);
-*/
-import "C"
-
-import (
- "runtime"
- "unsafe"
-)
-
-func Initialize(racectx *uintptr) {
- C.__tsan_init((*unsafe.Pointer)(unsafe.Pointer(racectx)))
-}
-
-func Finalize() {
- C.__tsan_fini()
-}
-
-func MapShadow(addr, size uintptr) {
- C.__tsan_map_shadow(unsafe.Pointer(addr), unsafe.Pointer(size))
-}
-
-func FinalizerGoroutine(racectx uintptr) {
- C.__tsan_finalizer_goroutine(unsafe.Pointer(racectx))
-}
-
-func Read(racectx uintptr, addr, pc uintptr) {
- C.__tsan_read(unsafe.Pointer(racectx), unsafe.Pointer(addr), unsafe.Pointer(pc))
-}
-
-func Write(racectx uintptr, addr, pc uintptr) {
- C.__tsan_write(unsafe.Pointer(racectx), unsafe.Pointer(addr), unsafe.Pointer(pc))
-}
-
-func ReadRange(racectx uintptr, addr, sz, pc uintptr) {
- C.__tsan_read_range(unsafe.Pointer(racectx), unsafe.Pointer(addr),
- C.long(sz), 0 /*step is unused*/, unsafe.Pointer(pc))
-}
-
-func WriteRange(racectx uintptr, addr, sz, pc uintptr) {
- C.__tsan_write_range(unsafe.Pointer(racectx), unsafe.Pointer(addr),
- C.long(sz), 0 /*step is unused*/, unsafe.Pointer(pc))
-}
+// This file merely ensures that we link in runtime/cgo in race build,
+// this is turn ensures that runtime uses pthread_create to create threads.
+// The prebuilt race runtime lives in race_GOOS_GOARCH.syso.
+// Calls to the runtime are done directly from src/pkg/runtime/race.c.
-func FuncEnter(racectx uintptr, pc uintptr) {
- C.__tsan_func_enter(unsafe.Pointer(racectx), unsafe.Pointer(pc))
-}
-
-func FuncExit(racectx uintptr) {
- C.__tsan_func_exit(unsafe.Pointer(racectx))
-}
-
-func Malloc(racectx uintptr, p, sz, pc uintptr) {
- C.__tsan_malloc(unsafe.Pointer(racectx), unsafe.Pointer(p), C.long(sz), unsafe.Pointer(pc))
-}
-
-func Free(p uintptr) {
- C.__tsan_free(unsafe.Pointer(p))
-}
-
-func GoStart(racectx uintptr, chracectx *uintptr, pc uintptr) {
- C.__tsan_go_start(unsafe.Pointer(racectx), (*unsafe.Pointer)(unsafe.Pointer(chracectx)), unsafe.Pointer(pc))
-}
-
-func GoEnd(racectx uintptr) {
- C.__tsan_go_end(unsafe.Pointer(racectx))
-}
-
-func Acquire(racectx uintptr, addr uintptr) {
- C.__tsan_acquire(unsafe.Pointer(racectx), unsafe.Pointer(addr))
-}
-
-func Release(racectx uintptr, addr uintptr) {
- C.__tsan_release(unsafe.Pointer(racectx), unsafe.Pointer(addr))
-}
-
-func ReleaseMerge(racectx uintptr, addr uintptr) {
- C.__tsan_release_merge(unsafe.Pointer(racectx), unsafe.Pointer(addr))
-}
-
-//export __tsan_symbolize
-func __tsan_symbolize(pc uintptr, fun, file **C.char, line, off *C.int) C.int {
- f := runtime.FuncForPC(pc)
- if f == nil {
- *fun = C.CString("??")
- *file = C.CString("-")
- *line = 0
- *off = C.int(pc)
- return 1
- }
- fi, l := f.FileLine(pc)
- *fun = C.CString(f.Name())
- *file = C.CString(fi)
- *line = C.int(l)
- *off = C.int(pc - f.Entry())
- return 1
-}
+// void __race_unused_func(void);
+import "C"
diff --git a/src/pkg/runtime/race/race_darwin_amd64.syso b/src/pkg/runtime/race/race_darwin_amd64.syso
index 96a43c9a9..249a878ef 100644
--- a/src/pkg/runtime/race/race_darwin_amd64.syso
+++ b/src/pkg/runtime/race/race_darwin_amd64.syso
Binary files differ
diff --git a/src/pkg/runtime/race/race_linux_amd64.syso b/src/pkg/runtime/race/race_linux_amd64.syso
index 50bde9648..8120484d4 100644
--- a/src/pkg/runtime/race/race_linux_amd64.syso
+++ b/src/pkg/runtime/race/race_linux_amd64.syso
Binary files differ
diff --git a/src/pkg/runtime/race/race_test.go b/src/pkg/runtime/race/race_test.go
index 4776ae22d..7e0ee866a 100644
--- a/src/pkg/runtime/race/race_test.go
+++ b/src/pkg/runtime/race/race_test.go
@@ -44,7 +44,7 @@ func TestRace(t *testing.T) {
if err != nil {
t.Fatalf("Failed to run tests: %v\n%v", err, string(testOutput))
}
- reader := bufio.NewReader(bytes.NewBuffer(testOutput))
+ reader := bufio.NewReader(bytes.NewReader(testOutput))
funcName := ""
var tsanLog []string
@@ -155,3 +155,18 @@ func runTests() ([]byte, error) {
cmd.Env = append(cmd.Env, `GORACE="suppress_equal_stacks=0 suppress_equal_addresses=0 exitcode=0"`)
return cmd.CombinedOutput()
}
+
+func TestIssue8102(t *testing.T) {
+ // If this compiles with -race, the test passes.
+ type S struct {
+ x interface{}
+ i int
+ }
+ c := make(chan int)
+ a := [2]*int{}
+ for ; ; c <- *a[S{}.i] {
+ if t != nil {
+ break
+ }
+ }
+}
diff --git a/src/pkg/runtime/race/race_windows_amd64.syso b/src/pkg/runtime/race/race_windows_amd64.syso
index 46eb1274f..67db40f21 100644
--- a/src/pkg/runtime/race/race_windows_amd64.syso
+++ b/src/pkg/runtime/race/race_windows_amd64.syso
Binary files differ
diff --git a/src/pkg/runtime/race/testdata/chan_test.go b/src/pkg/runtime/race/testdata/chan_test.go
index 614ba4a4e..4a3d5290f 100644
--- a/src/pkg/runtime/race/testdata/chan_test.go
+++ b/src/pkg/runtime/race/testdata/chan_test.go
@@ -347,6 +347,119 @@ func TestRaceChanSendSelectClose(t *testing.T) {
<-compl
}
+func TestRaceSelectReadWriteAsync(t *testing.T) {
+ done := make(chan bool)
+ x := 0
+ c1 := make(chan int, 10)
+ c2 := make(chan int, 10)
+ c3 := make(chan int)
+ c2 <- 1
+ go func() {
+ select {
+ case c1 <- x: // read of x races with...
+ case c3 <- 1:
+ }
+ done <- true
+ }()
+ select {
+ case x = <-c2: // ... write to x here
+ case c3 <- 1:
+ }
+ <-done
+}
+
+func TestRaceSelectReadWriteSync(t *testing.T) {
+ done := make(chan bool)
+ x := 0
+ c1 := make(chan int)
+ c2 := make(chan int)
+ c3 := make(chan int)
+ // make c1 and c2 ready for communication
+ go func() {
+ <-c1
+ }()
+ go func() {
+ c2 <- 1
+ }()
+ go func() {
+ select {
+ case c1 <- x: // read of x races with...
+ case c3 <- 1:
+ }
+ done <- true
+ }()
+ select {
+ case x = <-c2: // ... write to x here
+ case c3 <- 1:
+ }
+ <-done
+}
+
+func TestNoRaceSelectReadWriteAsync(t *testing.T) {
+ done := make(chan bool)
+ x := 0
+ c1 := make(chan int)
+ c2 := make(chan int)
+ go func() {
+ select {
+ case c1 <- x: // read of x does not race with...
+ case c2 <- 1:
+ }
+ done <- true
+ }()
+ select {
+ case x = <-c1: // ... write to x here
+ case c2 <- 1:
+ }
+ <-done
+}
+
+func TestRaceChanReadWriteAsync(t *testing.T) {
+ done := make(chan bool)
+ c1 := make(chan int, 10)
+ c2 := make(chan int, 10)
+ c2 <- 10
+ x := 0
+ go func() {
+ c1 <- x // read of x races with...
+ done <- true
+ }()
+ x = <-c2 // ... write to x here
+ <-done
+}
+
+func TestRaceChanReadWriteSync(t *testing.T) {
+ done := make(chan bool)
+ c1 := make(chan int)
+ c2 := make(chan int)
+ // make c1 and c2 ready for communication
+ go func() {
+ <-c1
+ }()
+ go func() {
+ c2 <- 10
+ }()
+ x := 0
+ go func() {
+ c1 <- x // read of x races with...
+ done <- true
+ }()
+ x = <-c2 // ... write to x here
+ <-done
+}
+
+func TestNoRaceChanReadWriteAsync(t *testing.T) {
+ done := make(chan bool)
+ c1 := make(chan int, 10)
+ x := 0
+ go func() {
+ c1 <- x // read of x does not race with...
+ done <- true
+ }()
+ x = <-c1 // ... write to x here
+ <-done
+}
+
func TestNoRaceProducerConsumerUnbuffered(t *testing.T) {
type Task struct {
f func()
@@ -454,20 +567,6 @@ func TestRaceChanCloseLen(t *testing.T) {
v = 2
}
-func TestRaceChanSameCell(t *testing.T) {
- c := make(chan int, 1)
- v := 0
- go func() {
- v = 1
- c <- 42
- <-c
- }()
- time.Sleep(1e7)
- c <- 43
- <-c
- _ = v
-}
-
func TestRaceChanCloseSend(t *testing.T) {
compl := make(chan bool, 1)
c := make(chan int, 10)
@@ -478,3 +577,83 @@ func TestRaceChanCloseSend(t *testing.T) {
c <- 0
<-compl
}
+
+func TestNoRaceChanMutex(t *testing.T) {
+ done := make(chan struct{})
+ mtx := make(chan struct{}, 1)
+ data := 0
+ go func() {
+ mtx <- struct{}{}
+ data = 42
+ <-mtx
+ done <- struct{}{}
+ }()
+ mtx <- struct{}{}
+ data = 43
+ <-mtx
+ <-done
+}
+
+func TestNoRaceSelectMutex(t *testing.T) {
+ done := make(chan struct{})
+ mtx := make(chan struct{}, 1)
+ aux := make(chan bool)
+ data := 0
+ go func() {
+ select {
+ case mtx <- struct{}{}:
+ case <-aux:
+ }
+ data = 42
+ select {
+ case <-mtx:
+ case <-aux:
+ }
+ done <- struct{}{}
+ }()
+ select {
+ case mtx <- struct{}{}:
+ case <-aux:
+ }
+ data = 43
+ select {
+ case <-mtx:
+ case <-aux:
+ }
+ <-done
+}
+
+func TestRaceChanSem(t *testing.T) {
+ done := make(chan struct{})
+ mtx := make(chan bool, 2)
+ data := 0
+ go func() {
+ mtx <- true
+ data = 42
+ <-mtx
+ done <- struct{}{}
+ }()
+ mtx <- true
+ data = 43
+ <-mtx
+ <-done
+}
+
+func TestNoRaceChanWaitGroup(t *testing.T) {
+ const N = 10
+ chanWg := make(chan bool, N/2)
+ data := make([]int, N)
+ for i := 0; i < N; i++ {
+ chanWg <- true
+ go func(i int) {
+ data[i] = 42
+ <-chanWg
+ }(i)
+ }
+ for i := 0; i < cap(chanWg); i++ {
+ chanWg <- true
+ }
+ for i := 0; i < N; i++ {
+ _ = data[i]
+ }
+}
diff --git a/src/pkg/runtime/race/testdata/finalizer_test.go b/src/pkg/runtime/race/testdata/finalizer_test.go
index 2b2607689..222cbf67a 100644
--- a/src/pkg/runtime/race/testdata/finalizer_test.go
+++ b/src/pkg/runtime/race/testdata/finalizer_test.go
@@ -14,16 +14,16 @@ import (
func TestNoRaceFin(t *testing.T) {
c := make(chan bool)
go func() {
- x := new(int)
- runtime.SetFinalizer(x, func(x *int) {
- *x = 42
+ x := new(string)
+ runtime.SetFinalizer(x, func(x *string) {
+ *x = "foo"
})
- *x = 66
+ *x = "bar"
c <- true
}()
<-c
runtime.GC()
- time.Sleep(1e8)
+ time.Sleep(100 * time.Millisecond)
}
var finVar struct {
@@ -34,8 +34,8 @@ var finVar struct {
func TestNoRaceFinGlobal(t *testing.T) {
c := make(chan bool)
go func() {
- x := new(int)
- runtime.SetFinalizer(x, func(x *int) {
+ x := new(string)
+ runtime.SetFinalizer(x, func(x *string) {
finVar.Lock()
finVar.cnt++
finVar.Unlock()
@@ -44,7 +44,7 @@ func TestNoRaceFinGlobal(t *testing.T) {
}()
<-c
runtime.GC()
- time.Sleep(1e8)
+ time.Sleep(100 * time.Millisecond)
finVar.Lock()
finVar.cnt++
finVar.Unlock()
@@ -54,14 +54,14 @@ func TestRaceFin(t *testing.T) {
c := make(chan bool)
y := 0
go func() {
- x := new(int)
- runtime.SetFinalizer(x, func(x *int) {
+ x := new(string)
+ runtime.SetFinalizer(x, func(x *string) {
y = 42
})
c <- true
}()
<-c
runtime.GC()
- time.Sleep(1e8)
+ time.Sleep(100 * time.Millisecond)
y = 66
}
diff --git a/src/pkg/runtime/race/testdata/map_test.go b/src/pkg/runtime/race/testdata/map_test.go
index 35db8db69..98e2a5f10 100644
--- a/src/pkg/runtime/race/testdata/map_test.go
+++ b/src/pkg/runtime/race/testdata/map_test.go
@@ -159,3 +159,82 @@ func TestRaceMapVariable3(t *testing.T) {
m = make(map[int]int)
<-ch
}
+
+type Big struct {
+ x [17]int32
+}
+
+func TestRaceMapLookupPartKey(t *testing.T) {
+ k := &Big{}
+ m := make(map[Big]bool)
+ ch := make(chan bool, 1)
+ go func() {
+ k.x[8] = 1
+ ch <- true
+ }()
+ _ = m[*k]
+ <-ch
+}
+
+func TestRaceMapLookupPartKey2(t *testing.T) {
+ k := &Big{}
+ m := make(map[Big]bool)
+ ch := make(chan bool, 1)
+ go func() {
+ k.x[8] = 1
+ ch <- true
+ }()
+ _, _ = m[*k]
+ <-ch
+}
+func TestRaceMapDeletePartKey(t *testing.T) {
+ k := &Big{}
+ m := make(map[Big]bool)
+ ch := make(chan bool, 1)
+ go func() {
+ k.x[8] = 1
+ ch <- true
+ }()
+ delete(m, *k)
+ <-ch
+}
+
+func TestRaceMapInsertPartKey(t *testing.T) {
+ k := &Big{}
+ m := make(map[Big]bool)
+ ch := make(chan bool, 1)
+ go func() {
+ k.x[8] = 1
+ ch <- true
+ }()
+ m[*k] = true
+ <-ch
+}
+
+func TestRaceMapInsertPartVal(t *testing.T) {
+ v := &Big{}
+ m := make(map[int]Big)
+ ch := make(chan bool, 1)
+ go func() {
+ v.x[8] = 1
+ ch <- true
+ }()
+ m[1] = *v
+ <-ch
+}
+
+// Test for issue 7561.
+func TestRaceMapAssignMultipleReturn(t *testing.T) {
+ connect := func() (int, error) { return 42, nil }
+ conns := make(map[int][]int)
+ conns[1] = []int{0}
+ ch := make(chan bool, 1)
+ var err error
+ go func() {
+ conns[1][0], err = connect()
+ ch <- true
+ }()
+ x := conns[1][0]
+ _ = x
+ <-ch
+}
diff --git a/src/pkg/runtime/race/testdata/mop_test.go b/src/pkg/runtime/race/testdata/mop_test.go
index b0b66562c..14591b184 100644
--- a/src/pkg/runtime/race/testdata/mop_test.go
+++ b/src/pkg/runtime/race/testdata/mop_test.go
@@ -1933,3 +1933,25 @@ func TestRaceMethodThunk4(t *testing.T) {
*(*int)(d.Base) = 42
<-done
}
+
+func TestNoRaceTinyAlloc(t *testing.T) {
+ const P = 4
+ const N = 1e6
+ var tinySink *byte
+ done := make(chan bool)
+ for p := 0; p < P; p++ {
+ go func() {
+ for i := 0; i < N; i++ {
+ var b byte
+ if b != 0 {
+ tinySink = &b // make it heap allocated
+ }
+ b = 42
+ }
+ done <- true
+ }()
+ }
+ for p := 0; p < P; p++ {
+ <-done
+ }
+}
diff --git a/src/pkg/runtime/race0.c b/src/pkg/runtime/race0.c
index b74b03583..eddb0be79 100644
--- a/src/pkg/runtime/race0.c
+++ b/src/pkg/runtime/race0.c
@@ -111,12 +111,6 @@ runtime·racemalloc(void *p, uintptr sz)
USED(sz);
}
-void
-runtime·racefree(void *p)
-{
- USED(p);
-}
-
uintptr
runtime·racegostart(void *pc)
{
diff --git a/src/pkg/runtime/race_amd64.s b/src/pkg/runtime/race_amd64.s
index a33b77a50..d60cf899b 100644
--- a/src/pkg/runtime/race_amd64.s
+++ b/src/pkg/runtime/race_amd64.s
@@ -4,13 +4,241 @@
// +build race
+#include "zasm_GOOS_GOARCH.h"
+#include "funcdata.h"
#include "../../cmd/ld/textflag.h"
+// The following thunks allow calling the gcc-compiled race runtime directly
+// from Go code without going all the way through cgo.
+// First, it's much faster (up to 50% speedup for real Go programs).
+// Second, it eliminates race-related special cases from cgocall and scheduler.
+// Third, in long-term it will allow to remove cyclic runtime/race dependency on cmd/go.
+
+// A brief recap of the amd64 calling convention.
+// Arguments are passed in DI, SI, DX, CX, R8, R9, the rest is on stack.
+// Callee-saved registers are: BX, BP, R12-R15.
+// SP must be 16-byte aligned.
+// On Windows:
+// Arguments are passed in CX, DX, R8, R9, the rest is on stack.
+// Callee-saved registers are: BX, BP, DI, SI, R12-R15.
+// SP must be 16-byte aligned. Windows also requires "stack-backing" for the 4 register arguments:
+// http://msdn.microsoft.com/en-us/library/ms235286.aspx
+// We do not do this, because it seems to be intended for vararg/unprototyped functions.
+// Gcc-compiled race runtime does not try to use that space.
+
+#ifdef GOOS_windows
+#define RARG0 CX
+#define RARG1 DX
+#define RARG2 R8
+#define RARG3 R9
+#else
+#define RARG0 DI
+#define RARG1 SI
+#define RARG2 DX
+#define RARG3 CX
+#endif
+
+// func runtime·raceread(addr uintptr)
+// Called from instrumented code.
+TEXT runtime·raceread(SB), NOSPLIT, $0-8
+ MOVQ addr+0(FP), RARG1
+ MOVQ (SP), RARG2
+ // void __tsan_read(ThreadState *thr, void *addr, void *pc);
+ MOVQ $__tsan_read(SB), AX
+ JMP racecalladdr<>(SB)
+
+// func runtime·RaceRead(addr uintptr)
+TEXT runtime·RaceRead(SB), NOSPLIT, $0-8
+ // This needs to be a tail call, because raceread reads caller pc.
+ JMP runtime·raceread(SB)
+
+// void runtime·racereadpc(void *addr, void *callpc, void *pc)
+TEXT runtime·racereadpc(SB), NOSPLIT, $0-24
+ MOVQ addr+0(FP), RARG1
+ MOVQ callpc+8(FP), RARG2
+ MOVQ pc+16(FP), RARG3
+ // void __tsan_read_pc(ThreadState *thr, void *addr, void *callpc, void *pc);
+ MOVQ $__tsan_read_pc(SB), AX
+ JMP racecalladdr<>(SB)
+
+// func runtime·racewrite(addr uintptr)
+// Called from instrumented code.
+TEXT runtime·racewrite(SB), NOSPLIT, $0-8
+ MOVQ addr+0(FP), RARG1
+ MOVQ (SP), RARG2
+ // void __tsan_write(ThreadState *thr, void *addr, void *pc);
+ MOVQ $__tsan_write(SB), AX
+ JMP racecalladdr<>(SB)
+
+// func runtime·RaceWrite(addr uintptr)
+TEXT runtime·RaceWrite(SB), NOSPLIT, $0-8
+ // This needs to be a tail call, because racewrite reads caller pc.
+ JMP runtime·racewrite(SB)
+
+// void runtime·racewritepc(void *addr, void *callpc, void *pc)
+TEXT runtime·racewritepc(SB), NOSPLIT, $0-24
+ MOVQ addr+0(FP), RARG1
+ MOVQ callpc+8(FP), RARG2
+ MOVQ cp+16(FP), RARG3
+ // void __tsan_write_pc(ThreadState *thr, void *addr, void *callpc, void *pc);
+ MOVQ $__tsan_write_pc(SB), AX
+ JMP racecalladdr<>(SB)
+
+// func runtime·racereadrange(addr, size uintptr)
+// Called from instrumented code.
+TEXT runtime·racereadrange(SB), NOSPLIT, $0-16
+ MOVQ addr+0(FP), RARG1
+ MOVQ size+8(FP), RARG2
+ MOVQ (SP), RARG3
+ // void __tsan_read_range(ThreadState *thr, void *addr, uintptr size, void *pc);
+ MOVQ $__tsan_read_range(SB), AX
+ JMP racecalladdr<>(SB)
+
+// func runtime·RaceReadRange(addr, size uintptr)
+TEXT runtime·RaceReadRange(SB), NOSPLIT, $0-16
+ // This needs to be a tail call, because racereadrange reads caller pc.
+ JMP runtime·racereadrange(SB)
+
+// void runtime·racereadrangepc1(void *addr, uintptr sz, void *pc)
+TEXT runtime·racereadrangepc1(SB), NOSPLIT, $0-24
+ MOVQ addr+0(FP), RARG1
+ MOVQ size+8(FP), RARG2
+ MOVQ pc+16(FP), RARG3
+ // void __tsan_read_range(ThreadState *thr, void *addr, uintptr size, void *pc);
+ MOVQ $__tsan_read_range(SB), AX
+ JMP racecalladdr<>(SB)
+
+// func runtime·racewriterange(addr, size uintptr)
+// Called from instrumented code.
+TEXT runtime·racewriterange(SB), NOSPLIT, $0-16
+ MOVQ addr+0(FP), RARG1
+ MOVQ size+8(FP), RARG2
+ MOVQ (SP), RARG3
+ // void __tsan_write_range(ThreadState *thr, void *addr, uintptr size, void *pc);
+ MOVQ $__tsan_write_range(SB), AX
+ JMP racecalladdr<>(SB)
+
+// func runtime·RaceWriteRange(addr, size uintptr)
+TEXT runtime·RaceWriteRange(SB), NOSPLIT, $0-16
+ // This needs to be a tail call, because racewriterange reads caller pc.
+ JMP runtime·racewriterange(SB)
+
+// void runtime·racewriterangepc1(void *addr, uintptr sz, void *pc)
+TEXT runtime·racewriterangepc1(SB), NOSPLIT, $0-24
+ MOVQ addr+0(FP), RARG1
+ MOVQ size+8(FP), RARG2
+ MOVQ pc+16(FP), RARG3
+ // void __tsan_write_range(ThreadState *thr, void *addr, uintptr size, void *pc);
+ MOVQ $__tsan_write_range(SB), AX
+ JMP racecalladdr<>(SB)
+
+// If addr (RARG1) is out of range, do nothing.
+// Otherwise, setup goroutine context and invoke racecall. Other arguments already set.
+TEXT racecalladdr<>(SB), NOSPLIT, $0-0
+ get_tls(R12)
+ MOVQ g(R12), R14
+ MOVQ g_racectx(R14), RARG0 // goroutine context
+ // Check that addr is within [arenastart, arenaend) or within [noptrdata, enoptrbss).
+ CMPQ RARG1, runtime·racearenastart(SB)
+ JB racecalladdr_data
+ CMPQ RARG1, runtime·racearenaend(SB)
+ JB racecalladdr_call
+racecalladdr_data:
+ CMPQ RARG1, $noptrdata(SB)
+ JB racecalladdr_ret
+ CMPQ RARG1, $enoptrbss(SB)
+ JAE racecalladdr_ret
+racecalladdr_call:
+ MOVQ AX, AX // w/o this 6a miscompiles this function
+ JMP racecall<>(SB)
+racecalladdr_ret:
+ RET
+
// func runtime·racefuncenter(pc uintptr)
-TEXT runtime·racefuncenter(SB), NOSPLIT, $16-8
- MOVQ DX, saved-8(SP) // save function entry context (for closures)
- MOVQ pc+0(FP), DX
- MOVQ DX, arg-16(SP)
- CALL runtime·racefuncenter1(SB)
- MOVQ saved-8(SP), DX
+// Called from instrumented code.
+TEXT runtime·racefuncenter(SB), NOSPLIT, $0-8
+ MOVQ DX, R15 // save function entry context (for closures)
+ get_tls(R12)
+ MOVQ g(R12), R14
+ MOVQ g_racectx(R14), RARG0 // goroutine context
+ MOVQ callpc+0(FP), RARG1
+ // void __tsan_func_enter(ThreadState *thr, void *pc);
+ MOVQ $__tsan_func_enter(SB), AX
+ CALL racecall<>(SB)
+ MOVQ R15, DX // restore function entry context
+ RET
+
+// func runtime·racefuncexit()
+// Called from instrumented code.
+TEXT runtime·racefuncexit(SB), NOSPLIT, $0-0
+ get_tls(R12)
+ MOVQ g(R12), R14
+ MOVQ g_racectx(R14), RARG0 // goroutine context
+ // void __tsan_func_exit(ThreadState *thr);
+ MOVQ $__tsan_func_exit(SB), AX
+ JMP racecall<>(SB)
+
+// void runtime·racecall(void(*f)(...), ...)
+// Calls C function f from race runtime and passes up to 4 arguments to it.
+// The arguments are never heap-object-preserving pointers, so we pretend there are no arguments.
+TEXT runtime·racecall(SB), NOSPLIT, $0-0
+ MOVQ fn+0(FP), AX
+ MOVQ arg0+8(FP), RARG0
+ MOVQ arg1+16(FP), RARG1
+ MOVQ arg2+24(FP), RARG2
+ MOVQ arg3+32(FP), RARG3
+ JMP racecall<>(SB)
+
+// Switches SP to g0 stack and calls (AX). Arguments already set.
+TEXT racecall<>(SB), NOSPLIT, $0-0
+ get_tls(R12)
+ MOVQ m(R12), R13
+ MOVQ g(R12), R14
+ // Switch to g0 stack.
+ MOVQ SP, R12 // callee-saved, preserved across the CALL
+ MOVQ m_g0(R13), R10
+ CMPQ R10, R14
+ JE racecall_cont // already on g0
+ MOVQ (g_sched+gobuf_sp)(R10), SP
+racecall_cont:
+ ANDQ $~15, SP // alignment for gcc ABI
+ CALL AX
+ MOVQ R12, SP
+ RET
+
+// C->Go callback thunk that allows to call runtime·racesymbolize from C code.
+// Direct Go->C race call has only switched SP, finish g->g0 switch by setting correct g.
+// The overall effect of Go->C->Go call chain is similar to that of mcall.
+TEXT runtime·racesymbolizethunk(SB), NOSPLIT, $56-8
+ // Save callee-saved registers (Go code won't respect that).
+ // This is superset of darwin/linux/windows registers.
+ PUSHQ BX
+ PUSHQ BP
+ PUSHQ DI
+ PUSHQ SI
+ PUSHQ R12
+ PUSHQ R13
+ PUSHQ R14
+ PUSHQ R15
+ // Set g = g0.
+ get_tls(R12)
+ MOVQ m(R12), R13
+ MOVQ m_g0(R13), R14
+ MOVQ R14, g(R12) // g = m->g0
+ MOVQ RARG0, 0(SP) // func arg
+ CALL runtime·racesymbolize(SB)
+ // All registers are smashed after Go code, reload.
+ get_tls(R12)
+ MOVQ m(R12), R13
+ MOVQ m_curg(R13), R14
+ MOVQ R14, g(R12) // g = m->curg
+ // Restore callee-saved registers.
+ POPQ R15
+ POPQ R14
+ POPQ R13
+ POPQ R12
+ POPQ SI
+ POPQ DI
+ POPQ BP
+ POPQ BX
RET
diff --git a/src/pkg/runtime/rdebug.goc b/src/pkg/runtime/rdebug.goc
new file mode 100644
index 000000000..042b30ace
--- /dev/null
+++ b/src/pkg/runtime/rdebug.goc
@@ -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.
+
+package runtime∕debug
+#include "runtime.h"
+#include "arch_GOARCH.h"
+#include "malloc.h"
+#include "stack.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 = g->paniconfault;
+ g->paniconfault = enabled;
+}
diff --git a/src/pkg/runtime/rt0_freebsd_arm.s b/src/pkg/runtime/rt0_freebsd_arm.s
index d11087639..56219f899 100644
--- a/src/pkg/runtime/rt0_freebsd_arm.s
+++ b/src/pkg/runtime/rt0_freebsd_arm.s
@@ -11,3 +11,8 @@ TEXT _rt0_arm_freebsd(SB),NOSPLIT,$-4
MOVW $4(R13), R1 // argv
MOVM.DB.W [R0-R1], (R13)
B _rt0_go(SB)
+
+TEXT main(SB),NOSPLIT,$-4
+ MOVM.DB.W [R0-R1], (R13)
+ MOVW $_rt0_go(SB), R4
+ B (R4)
diff --git a/src/pkg/runtime/rt0_nacl_386.s b/src/pkg/runtime/rt0_nacl_386.s
new file mode 100644
index 000000000..8b713548f
--- /dev/null
+++ b/src/pkg/runtime/rt0_nacl_386.s
@@ -0,0 +1,22 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "../../cmd/ld/textflag.h"
+
+// NaCl entry has:
+// 0(FP) - arg block == SP+8
+// 4(FP) - cleanup function pointer, always 0
+// 8(FP) - envc
+// 12(FP) - argc
+// 16(FP) - argv, then 0, then envv, then 0, then auxv
+TEXT _rt0_386_nacl(SB),NOSPLIT,$8
+ MOVL argc+12(FP), AX
+ LEAL argv+16(FP), BX
+ MOVL AX, 0(SP)
+ MOVL BX, 4(SP)
+ CALL main(SB)
+ INT $3
+
+TEXT main(SB),NOSPLIT,$0
+ JMP _rt0_go(SB)
diff --git a/src/pkg/runtime/rt0_nacl_amd64p32.s b/src/pkg/runtime/rt0_nacl_amd64p32.s
new file mode 100644
index 000000000..502d2e2bf
--- /dev/null
+++ b/src/pkg/runtime/rt0_nacl_amd64p32.s
@@ -0,0 +1,30 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "../../cmd/ld/textflag.h"
+
+// NaCl entry on 32-bit x86 has DI pointing at the arg block, which contains:
+//
+// 0(DI) - cleanup function pointer, always 0
+// 4(DI) - envc
+// 8(DI) - argc
+// 12(DI) - argv, then 0, then envv, then 0, then auxv
+// NaCl entry here is almost the same, except that there
+// is no saved caller PC, so 0(FP) is -8(FP) and so on.
+TEXT _rt0_amd64p32_nacl(SB),NOSPLIT,$16
+ MOVL DI, 0(SP)
+ CALL runtime·nacl_sysinfo(SB)
+ MOVL 0(SP), DI
+ MOVL 8(DI), AX
+ LEAL 12(DI), BX
+ MOVL AX, 0(SP)
+ MOVL BX, 4(SP)
+ CALL main(SB)
+ INT $3
+
+TEXT main(SB),NOSPLIT,$0
+ // Uncomment for fake time like on Go Playground.
+ //MOVQ $1257894000000000000, AX
+ //MOVQ AX, runtime·timens(SB)
+ JMP _rt0_go(SB)
diff --git a/src/pkg/runtime/rt0_solaris_amd64.s b/src/pkg/runtime/rt0_solaris_amd64.s
new file mode 100644
index 000000000..4aca991f0
--- /dev/null
+++ b/src/pkg/runtime/rt0_solaris_amd64.s
@@ -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.
+
+#include "../../cmd/ld/textflag.h"
+
+TEXT _rt0_amd64_solaris(SB),NOSPLIT,$-8
+ LEAQ 8(SP), SI // argv
+ MOVQ 0(SP), DI // argc
+ MOVQ $main(SB), AX
+ JMP AX
+
+TEXT main(SB),NOSPLIT,$-8
+ MOVQ $_rt0_go(SB), AX
+ JMP AX
+
+DATA runtime·issolaris(SB)/4, $1
+GLOBL runtime·issolaris(SB), $4
diff --git a/src/pkg/runtime/runtime-gdb.py b/src/pkg/runtime/runtime-gdb.py
index e704f4c4b..eedac7cf4 100644
--- a/src/pkg/runtime/runtime-gdb.py
+++ b/src/pkg/runtime/runtime-gdb.py
@@ -15,10 +15,14 @@ path to this file based on the path to the runtime package.
# circumventing the pretty print triggering.
-import sys, re
-
-print >>sys.stderr, "Loading Go Runtime support."
-
+from __future__ import print_function
+import re
+import sys
+
+print("Loading Go Runtime support.", file=sys.stderr)
+#http://python3porting.com/differences.html
+if sys.version > '3':
+ xrange = range
# allow to manually reload while developing
goobjfile = gdb.current_objfile() or gdb.objfiles()[0]
goobjfile.pretty_printers = []
@@ -27,6 +31,7 @@ goobjfile.pretty_printers = []
# Pretty Printers
#
+
class StringTypePrinter:
"Pretty print Go strings."
@@ -61,8 +66,8 @@ class SliceTypePrinter:
if self.val["len"] > self.val["cap"]:
return
ptr = self.val["array"]
- for idx in range(self.val["len"]):
- yield ('[%d]' % idx, (ptr + idx).dereference())
+ for idx in range(int(self.val["len"])):
+ yield ('[{0}]'.format(idx), (ptr + idx).dereference())
class MapTypePrinter:
@@ -72,7 +77,7 @@ class MapTypePrinter:
to inspect their contents with this pretty printer.
"""
- pattern = re.compile(r'^struct hash<.*>$')
+ pattern = re.compile(r'^map\[.*\].*$')
def __init__(self, val):
self.val = val
@@ -90,14 +95,15 @@ class MapTypePrinter:
flags = self.val['flags']
inttype = self.val['hash0'].type
cnt = 0
- for bucket in xrange(2 ** B):
+ for bucket in xrange(2 ** int(B)):
bp = buckets + bucket
if oldbuckets:
oldbucket = bucket & (2 ** (B - 1) - 1)
oldbp = oldbuckets + oldbucket
oldb = oldbp.dereference()
- if (oldb['overflow'].cast(inttype) & 1) == 0: # old bucket not evacuated yet
- if bucket >= 2 ** (B - 1): continue # already did old bucket
+ if (oldb['overflow'].cast(inttype) & 1) == 0: # old bucket not evacuated yet
+ if bucket >= 2 ** (B - 1):
+ continue # already did old bucket
bp = oldbp
while bp:
b = bp.dereference()
@@ -109,11 +115,12 @@ class MapTypePrinter:
k = k.dereference()
if flags & 2:
v = v.dereference()
- yield '%d' % cnt, k
- yield '%d' % (cnt + 1), v
+ yield str(cnt), k
+ yield str(cnt + 1), v
cnt += 2
bp = b['overflow']
+
class ChanTypePrinter:
"""Pretty print chan[T] types.
@@ -138,7 +145,7 @@ class ChanTypePrinter:
ptr = (self.val.address + 1).cast(et.pointer())
for i in range(self.val["qcount"]):
j = (self.val["recvx"] + i) % self.val["dataqsiz"]
- yield ('[%d]' % i, (ptr + j).dereference())
+ yield ('[{0}]'.format(i), (ptr + j).dereference())
#
@@ -150,11 +157,11 @@ def makematcher(klass):
try:
if klass.pattern.match(str(val.type)):
return klass(val)
- except:
+ except Exception:
pass
return matcher
-goobjfile.pretty_printers.extend([makematcher(k) for k in vars().values() if hasattr(k, 'pattern')])
+goobjfile.pretty_printers.extend([makematcher(var) for var in vars().values() if hasattr(var, 'pattern')])
#
# For reference, this is what we're trying to do:
@@ -169,34 +176,35 @@ goobjfile.pretty_printers.extend([makematcher(k) for k in vars().values() if has
def is_iface(val):
try:
- return str(val['tab'].type) == "struct runtime.itab *" \
- and str(val['data'].type) == "void *"
- except:
+ return str(val['tab'].type) == "struct runtime.itab *" and str(val['data'].type) == "void *"
+ except gdb.error:
pass
+
def is_eface(val):
try:
- return str(val['_type'].type) == "struct runtime._type *" \
- and str(val['data'].type) == "void *"
- except:
+ return str(val['_type'].type) == "struct runtime._type *" and str(val['data'].type) == "void *"
+ except gdb.error:
pass
+
def lookup_type(name):
try:
return gdb.lookup_type(name)
- except:
+ except gdb.error:
pass
try:
return gdb.lookup_type('struct ' + name)
- except:
+ except gdb.error:
pass
try:
return gdb.lookup_type('struct ' + name[1:]).pointer()
- except:
+ except gdb.error:
pass
_rctp_type = gdb.lookup_type("struct runtime.rtype").pointer()
+
def iface_commontype(obj):
if is_iface(obj):
go_type_ptr = obj['tab']['_type']
@@ -204,9 +212,9 @@ def iface_commontype(obj):
go_type_ptr = obj['_type']
else:
return
-
+
return go_type_ptr.cast(_rctp_type).dereference()
-
+
def iface_dtype(obj):
"Decode type of the data field of an eface or iface struct."
@@ -221,7 +229,7 @@ def iface_dtype(obj):
dynamic_gdb_type = lookup_type(dtype_name)
if dynamic_gdb_type is None:
return
-
+
type_size = int(dynamic_go_type['size'])
uintptr_size = int(dynamic_go_type['size'].type.sizeof) # size is itself an uintptr
if type_size > uintptr_size:
@@ -229,6 +237,7 @@ def iface_dtype(obj):
return dynamic_gdb_type
+
def iface_dtype_name(obj):
"Decode type name of the data field of an eface or iface struct."
@@ -254,15 +263,15 @@ class IfacePrinter:
return 0x0
try:
dtype = iface_dtype(self.val)
- except:
+ except Exception:
return "<bad dynamic type>"
if dtype is None: # trouble looking up, print something reasonable
- return "(%s)%s" % (iface_dtype_name(self.val), self.val['data'])
+ return "({0}){0}".format(iface_dtype_name(self.val), self.val['data'])
try:
return self.val['data'].cast(dtype).dereference()
- except:
+ except Exception:
pass
return self.val['data'].cast(dtype)
@@ -277,16 +286,14 @@ goobjfile.pretty_printers.append(ifacematcher)
# Convenience Functions
#
+
class GoLenFunc(gdb.Function):
"Length of strings, slices, maps or channels"
- how = ((StringTypePrinter, 'len'),
- (SliceTypePrinter, 'len'),
- (MapTypePrinter, 'count'),
- (ChanTypePrinter, 'qcount'))
+ how = ((StringTypePrinter, 'len'), (SliceTypePrinter, 'len'), (MapTypePrinter, 'count'), (ChanTypePrinter, 'qcount'))
def __init__(self):
- super(GoLenFunc, self).__init__("len")
+ gdb.Function.__init__(self, "len")
def invoke(self, obj):
typename = str(obj.type)
@@ -294,14 +301,14 @@ class GoLenFunc(gdb.Function):
if klass.pattern.match(typename):
return obj[fld]
+
class GoCapFunc(gdb.Function):
"Capacity of slices or channels"
- how = ((SliceTypePrinter, 'cap'),
- (ChanTypePrinter, 'dataqsiz'))
+ how = ((SliceTypePrinter, 'cap'), (ChanTypePrinter, 'dataqsiz'))
def __init__(self):
- super(GoCapFunc, self).__init__("cap")
+ gdb.Function.__init__(self, "cap")
def invoke(self, obj):
typename = str(obj.type)
@@ -309,6 +316,7 @@ class GoCapFunc(gdb.Function):
if klass.pattern.match(typename):
return obj[fld]
+
class DTypeFunc(gdb.Function):
"""Cast Interface values to their dynamic type.
@@ -316,12 +324,12 @@ class DTypeFunc(gdb.Function):
"""
def __init__(self):
- super(DTypeFunc, self).__init__("dtype")
+ gdb.Function.__init__(self, "dtype")
def invoke(self, obj):
try:
return obj['data'].cast(iface_dtype(obj))
- except:
+ except gdb.error:
pass
return obj
@@ -331,6 +339,7 @@ class DTypeFunc(gdb.Function):
sts = ('idle', 'runnable', 'running', 'syscall', 'waiting', 'moribund', 'dead', 'recovery')
+
def linked_list(ptr, linkfield):
while ptr:
yield ptr
@@ -341,29 +350,47 @@ class GoroutinesCmd(gdb.Command):
"List all goroutines."
def __init__(self):
- super(GoroutinesCmd, self).__init__("info goroutines", gdb.COMMAND_STACK, gdb.COMPLETE_NONE)
+ gdb.Command.__init__(self, "info goroutines", gdb.COMMAND_STACK, gdb.COMPLETE_NONE)
- def invoke(self, arg, from_tty):
+ def invoke(self, _arg, _from_tty):
# args = gdb.string_to_argv(arg)
vp = gdb.lookup_type('void').pointer()
for ptr in linked_list(gdb.parse_and_eval("'runtime.allg'"), 'alllink'):
- if ptr['status'] == 6: # 'gdead'
+ if ptr['status'] == 6: # 'gdead'
continue
s = ' '
if ptr['m']:
s = '*'
pc = ptr['sched']['pc'].cast(vp)
- sp = ptr['sched']['sp'].cast(vp)
- blk = gdb.block_for_pc(long((pc)))
- print s, ptr['goid'], "%8s" % sts[long((ptr['status']))], blk.function
+ # python2 will not cast pc (type void*) to an int cleanly
+ # instead python2 and python3 work with the hex string representation
+ # of the void pointer which we can parse back into an int.
+ # int(pc) will not work.
+ try:
+ #python3 / newer versions of gdb
+ pc = int(pc)
+ except gdb.error:
+ pc = int(str(pc), 16)
+ blk = gdb.block_for_pc(pc)
+ print(s, ptr['goid'], "{0:8s}".format(sts[int(ptr['status'])]), blk.function)
+
def find_goroutine(goid):
+ """
+ find_goroutine attempts to find the goroutine identified by goid.
+ It returns a touple of gdv.Value's representing the stack pointer
+ and program counter pointer for the goroutine.
+
+ @param int goid
+
+ @return tuple (gdb.Value, gdb.Value)
+ """
vp = gdb.lookup_type('void').pointer()
for ptr in linked_list(gdb.parse_and_eval("'runtime.allg'"), 'alllink'):
- if ptr['status'] == 6: # 'gdead'
+ if ptr['status'] == 6: # 'gdead'
continue
if ptr['goid'] == goid:
- return [ptr['sched'][x].cast(vp) for x in 'pc', 'sp']
+ return (ptr['sched'][x].cast(vp) for x in ('pc', 'sp'))
return None, None
@@ -380,20 +407,25 @@ class GoroutineCmd(gdb.Command):
"""
def __init__(self):
- super(GoroutineCmd, self).__init__("goroutine", gdb.COMMAND_STACK, gdb.COMPLETE_NONE)
+ gdb.Command.__init__(self, "goroutine", gdb.COMMAND_STACK, gdb.COMPLETE_NONE)
- def invoke(self, arg, from_tty):
+ def invoke(self, arg, _from_tty):
goid, cmd = arg.split(None, 1)
goid = gdb.parse_and_eval(goid)
pc, sp = find_goroutine(int(goid))
if not pc:
- print "No such goroutine: ", goid
+ print("No such goroutine: ", goid)
return
+ try:
+ #python3 / newer versions of gdb
+ pc = int(pc)
+ except gdb.error:
+ pc = int(str(pc), 16)
save_frame = gdb.selected_frame()
gdb.parse_and_eval('$save_pc = $pc')
gdb.parse_and_eval('$save_sp = $sp')
- gdb.parse_and_eval('$pc = 0x%x' % long(pc))
- gdb.parse_and_eval('$sp = 0x%x' % long(sp))
+ gdb.parse_and_eval('$pc = {0}'.format(str(pc)))
+ gdb.parse_and_eval('$sp = {0}'.format(str(sp)))
try:
gdb.execute(cmd)
finally:
@@ -406,31 +438,33 @@ class GoIfaceCmd(gdb.Command):
"Print Static and dynamic interface types"
def __init__(self):
- super(GoIfaceCmd, self).__init__("iface", gdb.COMMAND_DATA, gdb.COMPLETE_SYMBOL)
+ gdb.Command.__init__(self, "iface", gdb.COMMAND_DATA, gdb.COMPLETE_SYMBOL)
- def invoke(self, arg, from_tty):
+ def invoke(self, arg, _from_tty):
for obj in gdb.string_to_argv(arg):
try:
#TODO fix quoting for qualified variable names
- obj = gdb.parse_and_eval("%s" % obj)
- except Exception, e:
- print "Can't parse ", obj, ": ", e
+ obj = gdb.parse_and_eval(str(obj))
+ except Exception as e:
+ print("Can't parse ", obj, ": ", e)
continue
if obj['data'] == 0:
dtype = "nil"
else:
dtype = iface_dtype(obj)
-
+
if dtype is None:
- print "Not an interface: ", obj.type
+ print("Not an interface: ", obj.type)
continue
- print "%s: %s" % (obj.type, dtype)
+ print("{0}: {1}".format(obj.type, dtype))
# TODO: print interface's methods and dynamic type's func pointers thereof.
-#rsc: "to find the number of entries in the itab's Fn field look at itab.inter->numMethods
-#i am sure i have the names wrong but look at the interface type and its method count"
+#rsc: "to find the number of entries in the itab's Fn field look at
+# itab.inter->numMethods
+# i am sure i have the names wrong but look at the interface type
+# and its method count"
# so Itype will start with a commontype which has kind = interface
#
diff --git a/src/pkg/runtime/runtime.c b/src/pkg/runtime/runtime.c
index ab9fed805..3a4f7199e 100644
--- a/src/pkg/runtime/runtime.c
+++ b/src/pkg/runtime/runtime.c
@@ -3,6 +3,7 @@
// license that can be found in the LICENSE file.
#include "runtime.h"
+#include "stack.h"
#include "arch_GOARCH.h"
#include "../../cmd/ld/textflag.h"
@@ -10,13 +11,12 @@ enum {
maxround = sizeof(uintptr),
};
-/*
- * We assume that all architectures turn faults and the like
- * into apparent calls to runtime.sigpanic. If we see a "call"
- * to runtime.sigpanic, we do not back up the PC to find the
- * line number of the CALL instruction, because there is no CALL.
- */
-void runtime·sigpanic(void);
+// 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;
// The GOTRACEBACK environment variable controls the
// behavior of a Go program that is crashing and exiting.
@@ -28,18 +28,28 @@ int32
runtime·gotraceback(bool *crash)
{
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(p, (byte*)"crash") == 0) {
- if(crash != nil)
- *crash = true;
- return 2; // extra information
+ if(m->traceback != 0)
+ return m->traceback;
+ x = runtime·atomicload(&traceback_cache);
+ if(x == ~(uint32)0) {
+ p = runtime·getenv("GOTRACEBACK");
+ if(p == nil)
+ p = (byte*)"";
+ if(p[0] == '\0')
+ x = 1<<1;
+ else if(runtime·strcmp(p, (byte*)"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;
}
int32
@@ -87,6 +97,7 @@ runtime·args(int32 c, uint8 **v)
}
int32 runtime·isplan9;
+int32 runtime·issolaris;
int32 runtime·iswindows;
// Information about what cpu features are available.
@@ -127,16 +138,8 @@ runtime·goenvs_unix(void)
syscall·envs.array = (byte*)s;
syscall·envs.len = n;
syscall·envs.cap = n;
-}
-void
-runtime·getgoroot(String out)
-{
- byte *p;
-
- p = runtime·getenv("GOROOT");
- out = runtime·gostringnocopy(p);
- FLUSH(&out);
+ traceback_cache = ~(uint32)0;
}
int32
@@ -273,62 +276,9 @@ runtime·check(void)
runtime·throw("float32nan3");
TestAtomic64();
-}
-
-void
-runtime·Caller(intgo skip, uintptr retpc, String retfile, intgo retline, bool retbool)
-{
- Func *f, *g;
- uintptr pc;
- uintptr rpc[2];
-
- /*
- * Ask for two PCs: the one we were asked for
- * and what it called, so that we can see if it
- * "called" sigpanic.
- */
- retpc = 0;
- if(runtime·callers(1+skip-1, rpc, 2) < 2) {
- retfile = runtime·emptystring;
- retline = 0;
- retbool = false;
- } else if((f = runtime·findfunc(rpc[1])) == nil) {
- retfile = runtime·emptystring;
- retline = 0;
- retbool = true; // have retpc at least
- } else {
- retpc = rpc[1];
- pc = retpc;
- g = runtime·findfunc(rpc[0]);
- if(pc > f->entry && (g == nil || g->entry != (uintptr)runtime·sigpanic))
- pc--;
- retline = runtime·funcline(f, pc, &retfile);
- retbool = true;
- }
- FLUSH(&retpc);
- FLUSH(&retfile);
- FLUSH(&retline);
- FLUSH(&retbool);
-}
-void
-runtime·Callers(intgo skip, Slice pc, intgo retn)
-{
- // runtime.callers uses pc.array==nil as a signal
- // to print a stack trace. Pick off 0-length pc here
- // so that we don't let a nil pc slice get to it.
- if(pc.len == 0)
- retn = 0;
- else
- retn = runtime·callers(skip, (uintptr*)pc.array, pc.len);
- FLUSH(&retn);
-}
-
-void
-runtime·FuncForPC(uintptr pc, void *retf)
-{
- retf = runtime·findfunc(pc);
- FLUSH(&retf);
+ if(FixedStack != runtime·round2(FixedStack))
+ runtime·throw("FixedStack is not power-of-2");
}
uint32
@@ -374,22 +324,18 @@ runtime·tickspersecond(void)
return res;
}
-void
-runtime∕pprof·runtime_cyclesPerSecond(int64 res)
-{
- res = runtime·tickspersecond();
- FLUSH(&res);
-}
-
DebugVars runtime·debug;
static struct {
int8* 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
diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h
index f7c2adb12..511550378 100644
--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -28,6 +28,12 @@ typedef int32 intgo; // Go's int
typedef uint32 uintgo; // Go's uint
#endif
+#ifdef _64BITREG
+typedef uint64 uintreg;
+#else
+typedef uint32 uintreg;
+#endif
+
/*
* get rid of C types
* the / / / forces a syntax error immediately,
@@ -66,17 +72,17 @@ typedef struct Itab Itab;
typedef struct InterfaceType InterfaceType;
typedef struct Eface Eface;
typedef struct Type Type;
+typedef struct PtrType PtrType;
typedef struct ChanType ChanType;
typedef struct MapType MapType;
typedef struct Defer Defer;
-typedef struct DeferChunk DeferChunk;
typedef struct Panic Panic;
typedef struct Hmap Hmap;
+typedef struct Hiter Hiter;
typedef struct Hchan Hchan;
typedef struct Complex64 Complex64;
typedef struct Complex128 Complex128;
-typedef struct WinCall WinCall;
-typedef struct SEH SEH;
+typedef struct LibCall LibCall;
typedef struct WinCallbackContext WinCallbackContext;
typedef struct Timers Timers;
typedef struct Timer Timer;
@@ -93,10 +99,10 @@ typedef struct DebugVars DebugVars;
*
* "extern register" is a special storage class implemented by 6c, 8c, etc.
* On the ARM, it is an actual register; elsewhere it is a slot in thread-
- * local storage indexed by a segment register. See zasmhdr in
+ * local storage indexed by a pseudo-register TLS. See zasmhdr in
* src/cmd/dist/buildruntime.c for details, and be aware that the linker may
* make further OS-specific changes to the compiler's output. For example,
- * 6l/linux rewrites 0(GS) as -16(FS).
+ * 6l/linux rewrites 0(TLS) as -16(FS).
*
* Every C file linked into a Go program must include runtime.h so that the
* C compiler (6c, 8c, etc.) knows to avoid other uses of these dedicated
@@ -208,8 +214,8 @@ struct Gobuf
uintptr sp;
uintptr pc;
G* g;
- uintptr ret;
void* ctxt;
+ uintreg ret;
uintptr lr;
};
struct GCStats
@@ -223,7 +229,7 @@ struct GCStats
uint64 nsleep;
};
-struct WinCall
+struct LibCall
{
void (*fn)(void*);
uintptr n; // number of parameters
@@ -232,17 +238,14 @@ struct WinCall
uintptr r2;
uintptr err; // error number
};
-struct SEH
-{
- void* prev;
- void* handler;
-};
+
// describes how to handle callback
struct WinCallbackContext
{
void* gobody; // Go function to call
uintptr argsize; // callback arguments size (in bytes)
uintptr restorestack; // adjust stack on return by (in bytes) (386 only)
+ bool cleanstack;
};
struct G
@@ -251,7 +254,6 @@ struct G
uintptr stackguard0; // cannot move - also known to linker, libmach, runtime/cgo
uintptr stackbase; // cannot move - also known to libmach, runtime/cgo
uint32 panicwrap; // cannot move - also known to linker
- uint32 selgen; // valid sudog pointer
Defer* defer;
Panic* panic;
Gobuf sched;
@@ -262,24 +264,23 @@ struct G
uintptr stackguard; // same as stackguard0, but not set to StackPreempt
uintptr stack0;
uintptr stacksize;
- G* alllink; // on allg
void* param; // passed parameter on wakeup
int16 status;
int64 goid;
+ int64 waitsince; // approx time when the G become blocked
int8* waitreason; // if status==Gwaiting
G* schedlink;
bool ispanic;
bool issystem; // do not output in stack dump
bool isbackground; // ignore in deadlock detector
bool preempt; // preemption signal, duplicates stackguard0 = StackPreempt
+ bool paniconfault; // panic (instead of crash) on unexpected fault address
int8 raceignore; // ignore race detection events
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;
@@ -287,6 +288,7 @@ struct G
uintptr racectx;
uintptr end[];
};
+
struct M
{
G* g0; // goroutine with scheduling stack
@@ -295,8 +297,8 @@ struct M
// Fields not known to debuggers.
uint32 moreframesize; // size arguments to morestack
- uint32 moreargsize;
- uintptr cret; // return value from C
+ uint32 moreargsize; // known by amd64 asm to follow moreframesize
+ uintreg cret; // return value from C
uint64 procid; // for debuggers, but offset not hard-coded
G* gsignal; // signal-handling G
uintptr tls[4]; // thread-local storage (for x86 extern register)
@@ -310,10 +312,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
@@ -338,23 +342,37 @@ struct M
uint32 waitsemacount;
uint32 waitsemalock;
GCStats gcstats;
- bool racecall;
bool needextram;
- void (*waitunlockf)(Lock*);
+ uint8 traceback;
+ bool (*waitunlockf)(G*, void*);
void* waitlock;
-
- uintptr settype_buf[1024];
- uintptr settype_bufsize;
-
+ uintptr forkstackguard;
#ifdef GOOS_windows
void* thread; // thread handle
- WinCall wincall;
+ // these are here because they are too large to be on the stack
+ // of low-level NOSPLIT functions.
+ LibCall libcall;
+ uintptr libcallpc; // for cpu profiler
+ uintptr libcallsp;
+ G* libcallg;
+#endif
+#ifdef GOOS_solaris
+ int32* perrno; // pointer to TLS errno
+ // these are here because they are too large to be on the stack
+ // of low-level NOSPLIT functions.
+ LibCall libcall;
+ struct {
+ int64 tv_sec;
+ int64 tv_nsec;
+ } ts;
+ struct {
+ uintptr v[6];
+ } scratch;
#endif
#ifdef GOOS_plan9
int8* notesig;
byte* errstr;
#endif
- SEH* seh;
uintptr end[];
};
@@ -369,12 +387,16 @@ struct P
uint32 syscalltick; // incremented on every system call
M* m; // back-link to associated M (nil if idle)
MCache* mcache;
+ Defer* deferpool[5]; // pool of available Defer structs of different sizes (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;
@@ -406,8 +428,8 @@ struct Stktop
uint32 panicwrap;
uint8* argp; // pointer to arguments in old frame
- uintptr free; // if free>0, call stackfree using free as size
bool panic; // is this frame the top of a panic?
+ bool malloced;
};
struct SigTab
{
@@ -423,6 +445,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
@@ -456,6 +479,16 @@ struct Itab
void (*fun[])(void);
};
+#ifdef GOOS_nacl
+enum {
+ NaCl = 1,
+};
+#else
+enum {
+ NaCl = 0,
+};
+#endif
+
#ifdef GOOS_windows
enum {
Windows = 1
@@ -465,6 +498,15 @@ enum {
Windows = 0
};
#endif
+#ifdef GOOS_solaris
+enum {
+ Solaris = 1
+};
+#else
+enum {
+ Solaris = 0
+};
+#endif
struct Timers
{
@@ -480,6 +522,8 @@ 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
@@ -533,12 +577,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
@@ -548,13 +596,13 @@ extern bool runtime·precisestack;
#define nelem(x) (sizeof(x)/sizeof((x)[0]))
#define nil ((void*)0)
#define offsetof(s,m) (uint32)(&(((s*)0)->m))
-#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 */
/*
* known to compiler
*/
enum {
- Structrnd = sizeof(uintptr)
+ Structrnd = sizeof(uintreg),
};
/*
@@ -648,7 +696,6 @@ struct Defer
{
int32 siz;
bool special; // not part of defer frame
- bool free; // if special, free when done
byte* argp; // where args were copied from
byte* pc;
FuncVal* fn;
@@ -656,11 +703,10 @@ struct Defer
void* args[1]; // padded to actual size
};
-struct DeferChunk
-{
- DeferChunk *prev;
- uintptr off;
-};
+// argp used in Defer structs when there is no argp.
+// TODO(rsc): Maybe we could use nil instead, but we've always used -1
+// and I don't want to change this days before the Go 1.3 release.
+#define NoArgs ((byte*)-1)
/*
* panics
@@ -670,7 +716,9 @@ struct Panic
Eface arg; // argument to panic
uintptr stackbase; // g->stackbase in panic
Panic* link; // link to earlier panic
+ Defer* defer; // current executing defer
bool recovered; // whether this panic is over
+ bool aborted; // the panic was aborted
};
/*
@@ -681,6 +729,7 @@ struct Stkframe
{
Func* fn; // function being run
uintptr pc; // program counter within fn
+ uintptr continpc; // program counter where execution can continue, or 0 if not
uintptr lr; // program counter at caller aka link register
uintptr sp; // stack pointer at pc
uintptr fp; // stack pointer at caller aka frame pointer
@@ -689,18 +738,24 @@ struct Stkframe
uintptr arglen; // number of bytes at argp
};
-int32 runtime·gentraceback(uintptr, uintptr, uintptr, G*, int32, uintptr*, int32, void(*)(Stkframe*, void*), void*, bool);
+int32 runtime·gentraceback(uintptr, uintptr, uintptr, G*, int32, uintptr*, int32, bool(*)(Stkframe*, void*), void*, bool);
void runtime·traceback(uintptr pc, uintptr sp, uintptr lr, G* gp);
void runtime·tracebackothers(G*);
bool runtime·haszeroargs(uintptr pc);
bool runtime·topofstack(Func*);
+enum
+{
+ // The maximum number of frames we print for a traceback
+ TracebackMaxFrames = 100,
+};
/*
* external data
*/
extern String runtime·emptystring;
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;
@@ -722,6 +777,7 @@ extern uintptr runtime·maxstacksize;
* common functions and data
*/
int32 runtime·strcmp(byte*, byte*);
+int32 runtime·strncmp(byte*, byte*, uintptr);
byte* runtime·strstr(byte*, byte*);
intgo runtime·findnull(byte*);
intgo runtime·findnullw(uint16*);
@@ -729,11 +785,33 @@ void runtime·dump(byte*, int32);
int32 runtime·runetochar(byte*, int32);
int32 runtime·charntorune(int32*, uint8*, int32);
+
/*
- * very low level c-called
- */
+ * This macro is used when writing C functions
+ * called as if they were Go functions.
+ * Passed the address of a result before a return statement,
+ * it makes sure the result has been flushed to memory
+ * before the return.
+ *
+ * It is difficult to write such functions portably, because
+ * of the varying requirements on the alignment of the
+ * first output value. Almost all code should write such
+ * functions in .goc files, where goc2c (part of cmd/dist)
+ * can arrange the correct alignment for the target system.
+ * Goc2c also takes care of conveying to the garbage collector
+ * which parts of the argument list are inputs vs outputs.
+ *
+ * Therefore, do NOT use this macro if at all possible.
+ */
#define FLUSH(x) USED(x)
+/*
+ * GoOutput is a type with the same alignment requirements as the
+ * initial output argument from a Go function. Only for use in cases
+ * where using goc2c is not possible. See comment on FLUSH above.
+ */
+typedef uint64 GoOutput;
+
void runtime·gogo(Gobuf*);
void runtime·gostartcall(Gobuf*, void(*)(void), void*);
void runtime·gostartcallfn(Gobuf*, FuncVal*);
@@ -745,8 +823,10 @@ void runtime·goenvs_unix(void);
void* runtime·getu(void);
void runtime·throw(int8*);
void runtime·panicstring(int8*);
+bool runtime·canpanic(G*);
void runtime·prints(int8*);
void runtime·printf(int8*, ...);
+int32 runtime·snprintf(byte*, int32, int8*, ...);
byte* runtime·mchr(byte*, byte, byte*);
int32 runtime·mcmp(byte*, byte*, uintptr);
void runtime·memmove(void*, void*, uintptr);
@@ -764,24 +844,9 @@ int32 runtime·gotraceback(bool *crash);
void runtime·goroutineheader(G*);
int32 runtime·open(int8*, int32, int32);
int32 runtime·read(int32, void*, int32);
-int32 runtime·write(int32, void*, int32);
+int32 runtime·write(uintptr, void*, int32); // use uintptr to accommodate windows.
int32 runtime·close(int32);
int32 runtime·mincore(void*, uintptr, byte*);
-bool runtime·cas(uint32*, uint32, uint32);
-bool runtime·cas64(uint64*, uint64, uint64);
-bool runtime·casp(void**, void*, void*);
-// Don't confuse with XADD x86 instruction,
-// this one is actually 'addx', that is, add-and-fetch.
-uint32 runtime·xadd(uint32 volatile*, int32);
-uint64 runtime·xadd64(uint64 volatile*, int64);
-uint32 runtime·xchg(uint32 volatile*, uint32);
-uint64 runtime·xchg64(uint64 volatile*, uint64);
-uint32 runtime·atomicload(uint32 volatile*);
-void runtime·atomicstore(uint32 volatile*, uint32);
-void runtime·atomicstore64(uint64 volatile*, uint64);
-uint64 runtime·atomicload64(uint64 volatile*);
-void* runtime·atomicloadp(void* volatile*);
-void runtime·atomicstorep(void* volatile*, void*);
void runtime·jmpdefer(FuncVal*, void*);
void runtime·exit1(int32);
void runtime·ready(G*);
@@ -802,12 +867,12 @@ int32 runtime·funcarglen(Func*, uintptr);
int32 runtime·funcspdelta(Func*, uintptr);
int8* runtime·funcname(Func*);
int32 runtime·pcdatavalue(Func*, int32, uintptr);
-void* runtime·stackalloc(uint32);
-void runtime·stackfree(void*, uintptr);
+void* runtime·stackalloc(G*, uint32);
+void runtime·stackfree(G*, void*, Stktop*);
+void runtime·shrinkstack(G*);
MCache* runtime·allocmcache(void);
void runtime·freemcache(MCache*);
void runtime·mallocinit(void);
-void runtime·mprofinit(void);
bool runtime·ifaceeq_c(Iface, Iface);
bool runtime·efaceeq_c(Eface, Eface);
uintptr runtime·ifacehash(Iface, uintptr);
@@ -822,15 +887,35 @@ void runtime·mcall(void(*)(G*));
uint32 runtime·fastrand1(void);
void runtime·rewindmorestack(Gobuf*);
int32 runtime·timediv(int64, int32, int32*);
+int32 runtime·round2(int32 x); // round x up to a power of 2.
+
+// atomic operations
+bool runtime·cas(uint32*, uint32, uint32);
+bool runtime·cas64(uint64*, uint64, uint64);
+bool runtime·casp(void**, void*, void*);
+// Don't confuse with XADD x86 instruction,
+// this one is actually 'addx', that is, add-and-fetch.
+uint32 runtime·xadd(uint32 volatile*, int32);
+uint64 runtime·xadd64(uint64 volatile*, int64);
+uint32 runtime·xchg(uint32 volatile*, uint32);
+uint64 runtime·xchg64(uint64 volatile*, uint64);
+void* runtime·xchgp(void* volatile*, void*);
+uint32 runtime·atomicload(uint32 volatile*);
+void runtime·atomicstore(uint32 volatile*, uint32);
+void runtime·atomicstore64(uint64 volatile*, uint64);
+uint64 runtime·atomicload64(uint64 volatile*);
+void* runtime·atomicloadp(void* volatile*);
+void runtime·atomicstorep(void* volatile*, void*);
-void runtime·setmg(M*, G*);
-void runtime·newextram(void);
+void runtime·setmg(M*, G*);
+void runtime·newextram(void);
void runtime·exit(int32);
void runtime·breakpoint(void);
void runtime·gosched(void);
void runtime·gosched0(G*);
void runtime·schedtrace(bool);
-void runtime·park(void(*)(Lock*), Lock*, int8*);
+void runtime·park(bool(*)(G*, void*), void*, int8*);
+void runtime·parkunlock(Lock*, int8*);
void runtime·tsleep(int64, int8*);
M* runtime·newm(void);
void runtime·goexit(void);
@@ -841,12 +926,13 @@ void runtime·exitsyscall(void);
G* runtime·newproc1(FuncVal*, byte*, int32, int32, void*);
bool runtime·sigsend(int32 sig);
int32 runtime·callers(int32, uintptr*, int32);
-int64 runtime·nanotime(void);
+int64 runtime·nanotime(void); // monotonic time
+int64 runtime·unixnanotime(void); // real time, can skip
void runtime·dopanic(int32);
void runtime·startpanic(void);
void runtime·freezetheworld(void);
void runtime·unwindstack(G*, byte*);
-void runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp);
+void runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp, M *mp);
void runtime·resetcpuprofiler(int32);
void runtime·setcpuprofilerate(void(*)(uintptr*, int32), int32);
void runtime·usleep(uint32);
@@ -862,10 +948,19 @@ 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_itabs(void (*callback)(Itab*));
+void runtime·iterate_finq(void (*callback)(FuncVal*, byte*, uintptr, Type*, PtrType*));
#pragma varargck argpos runtime·printf 1
#pragma varargck type "c" int32
@@ -954,13 +1049,7 @@ 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);
-
-/*
- * This is consistent across Linux and BSD.
- * If a new OS is added that is different, move this to
- * $GOOS/$GOARCH/defs.h.
- */
-#define EACCES 13
+void runtime·parforiters(ParFor*, uintptr, uintptr*, uintptr*);
/*
* low level C-called
@@ -992,10 +1081,11 @@ void runtime·printhex(uint64);
void runtime·printslice(Slice);
void runtime·printcomplex(Complex128);
void runtime·newstackcall(FuncVal*, byte*, uint32);
-void reflect·call(FuncVal*, byte*, uint32);
+void reflect·call(FuncVal*, byte*, uint32, uint32);
void runtime·panic(Eface);
void runtime·panicindex(void);
void runtime·panicslice(void);
+void runtime·panicdivide(void);
/*
* runtime c-called (but written in Go)
@@ -1036,16 +1126,8 @@ void runtime·procyield(uint32);
void runtime·osyield(void);
void runtime·lockOSThread(void);
void runtime·unlockOSThread(void);
+bool runtime·lockedOSThread(void);
-void runtime·mapassign(MapType*, Hmap*, byte*, byte*);
-void runtime·mapaccess(MapType*, Hmap*, byte*, byte*, bool*);
-void runtime·mapiternext(struct hash_iter*);
-bool runtime·mapiterkey(struct hash_iter*, void*);
-Hmap* runtime·makemap_c(MapType*, int64);
-
-Hchan* runtime·makechan_c(ChanType*, int64);
-void runtime·chansend(ChanType*, Hchan*, byte*, bool*, void*);
-void runtime·chanrecv(ChanType*, Hchan*, byte*, bool*, bool*);
bool runtime·showframe(Func*, G*);
void runtime·printcreatedby(G*);
diff --git a/src/pkg/runtime/runtime1.goc b/src/pkg/runtime/runtime1.goc
index d2c38dfef..c6f6b626a 100644
--- a/src/pkg/runtime/runtime1.goc
+++ b/src/pkg/runtime/runtime1.goc
@@ -4,6 +4,8 @@
package runtime
#include "runtime.h"
+#include "arch_GOARCH.h"
+#include "type.h"
func GOMAXPROCS(n int) (ret int) {
ret = runtime·gomaxprocsfunc(n);
@@ -12,3 +14,115 @@ 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 gogoBytes() (x int32) {
+ x = RuntimeGogoBytes;
+}
+
+func typestring(e Eface) (s String) {
+ s = *e.type->string;
+}
+
+func golockedOSThread() (ret bool) {
+ ret = runtime·lockedOSThread();
+}
+
+func NumGoroutine() (ret int) {
+ ret = runtime·gcount();
+}
+
+func getgoroot() (out String) {
+ byte *p;
+
+ p = runtime·getenv("GOROOT");
+ out = runtime·gostringnocopy(p);
+}
+
+/*
+ * We assume that all architectures turn faults and the like
+ * into apparent calls to runtime.sigpanic. If we see a "call"
+ * to runtime.sigpanic, we do not back up the PC to find the
+ * line number of the CALL instruction, because there is no CALL.
+ */
+void runtime·sigpanic(void);
+
+func Caller(skip int) (retpc uintptr, retfile String, retline int, retbool bool) {
+ Func *f, *g;
+ uintptr pc;
+ uintptr rpc[2];
+
+ /*
+ * Ask for two PCs: the one we were asked for
+ * and what it called, so that we can see if it
+ * "called" sigpanic.
+ */
+ retpc = 0;
+ if(runtime·callers(1+skip-1, rpc, 2) < 2) {
+ retfile = runtime·emptystring;
+ retline = 0;
+ retbool = false;
+ } else if((f = runtime·findfunc(rpc[1])) == nil) {
+ retfile = runtime·emptystring;
+ retline = 0;
+ retbool = true; // have retpc at least
+ } else {
+ retpc = rpc[1];
+ pc = retpc;
+ g = runtime·findfunc(rpc[0]);
+ if(pc > f->entry && (g == nil || g->entry != (uintptr)runtime·sigpanic))
+ pc--;
+ retline = runtime·funcline(f, pc, &retfile);
+ retbool = true;
+ }
+}
+
+func Callers(skip int, pc Slice) (retn int) {
+ // runtime.callers uses pc.array==nil as a signal
+ // to print a stack trace. Pick off 0-length pc here
+ // so that we don't let a nil pc slice get to it.
+ if(pc.len == 0)
+ retn = 0;
+ else
+ retn = runtime·callers(skip, (uintptr*)pc.array, pc.len);
+}
+
+func runtime∕pprof·runtime_cyclesPerSecond() (res int64) {
+ res = runtime·tickspersecond();
+}
+
+func sync·runtime_procPin() (p int) {
+ M *mp;
+
+ mp = m;
+ // Disable preemption.
+ mp->locks++;
+ p = mp->p->id;
+}
+
+func sync·runtime_procUnpin() {
+ m->locks--;
+}
diff --git a/src/pkg/runtime/runtime_test.go b/src/pkg/runtime/runtime_test.go
index de6e5498e..5a9f52fe0 100644
--- a/src/pkg/runtime/runtime_test.go
+++ b/src/pkg/runtime/runtime_test.go
@@ -10,9 +10,11 @@ import (
"os"
"os/exec"
. "runtime"
+ "runtime/debug"
"strconv"
"strings"
"testing"
+ "unsafe"
)
var errf error
@@ -93,6 +95,10 @@ 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) {
+ if GOOS == "nacl" {
+ t.Skip("skipping on nacl")
+ }
+
dir, err := ioutil.TempDir("", "go-build")
if err != nil {
t.Fatalf("failed to create temp directory: %v", err)
@@ -104,7 +110,7 @@ func TestRuntimeGogoBytes(t *testing.T) {
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)
}
@@ -122,3 +128,77 @@ 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,
+ // no 0xffffffffffff0001; 0xffff0001 is mapped for 32-bit user space on OS X
+ // no 0xfffffffffff00001; 0xfff00001 is mapped for 32-bit user space sometimes on Linux
+ 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)
+
+ for _, addr := range faultAddrs {
+ testSetPanicOnFault(t, uintptr(addr))
+ }
+}
+
+func testSetPanicOnFault(t *testing.T, addr uintptr) {
+ if GOOS == "nacl" {
+ t.Skip("nacl doesn't seem to fault on high addresses")
+ }
+
+ defer func() {
+ if err := recover(); err == nil {
+ t.Fatalf("did not find error in recover")
+ }
+ }()
+
+ var p *int
+ p = (*int)(unsafe.Pointer(addr))
+ println(*p)
+ t.Fatalf("still here - should have faulted on address %#x", addr)
+}
diff --git a/src/pkg/runtime/runtime_unix_test.go b/src/pkg/runtime/runtime_unix_test.go
new file mode 100644
index 000000000..963de8cdb
--- /dev/null
+++ b/src/pkg/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/src/pkg/runtime/sema.goc b/src/pkg/runtime/sema.goc
index 57f32a0dd..c1e8e4e18 100644
--- a/src/pkg/runtime/sema.goc
+++ b/src/pkg/runtime/sema.goc
@@ -137,7 +137,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);
@@ -254,7 +254,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);
}
@@ -288,7 +288,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/src/pkg/runtime/signal_386.c b/src/pkg/runtime/signal_386.c
index 5a913c646..70fcc6a63 100644
--- a/src/pkg/runtime/signal_386.c
+++ b/src/pkg/runtime/signal_386.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 netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd
#include "runtime.h"
#include "defs_GOOS_GOARCH.h"
@@ -39,15 +39,12 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
bool crash;
if(sig == SIGPROF) {
- runtime·sigprof((byte*)SIG_EIP(info, ctxt), (byte*)SIG_ESP(info, ctxt), nil, gp);
+ runtime·sigprof((byte*)SIG_EIP(info, ctxt), (byte*)SIG_ESP(info, ctxt), nil, gp, m);
return;
}
t = &runtime·sigtab[sig];
if(SIG_CODE0(info, ctxt) != SI_USER && (t->flags & SigPanic)) {
- if(gp == nil || gp == m->g0)
- goto Throw;
-
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
@@ -94,7 +91,6 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
if(!(t->flags & SigThrow))
return;
-Throw:
m->throwing = 1;
m->caughtsig = gp;
runtime·startpanic();
@@ -112,6 +108,7 @@ Throw:
runtime·printf("\n");
if(runtime·gotraceback(&crash)){
+ runtime·goroutineheader(gp);
runtime·traceback(SIG_EIP(info, ctxt), SIG_ESP(info, ctxt), 0, gp);
runtime·tracebackothers(gp);
runtime·printf("\n");
diff --git a/src/pkg/runtime/signal_amd64.c b/src/pkg/runtime/signal_amd64x.c
index f0cbb1f8c..04026f32f 100644
--- a/src/pkg/runtime/signal_amd64.c
+++ b/src/pkg/runtime/signal_amd64x.c
@@ -2,7 +2,8 @@
// 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 amd64 amd64p32
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
#include "runtime.h"
#include "defs_GOOS_GOARCH.h"
@@ -47,15 +48,33 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
bool crash;
if(sig == SIGPROF) {
- runtime·sigprof((byte*)SIG_RIP(info, ctxt), (byte*)SIG_RSP(info, ctxt), nil, gp);
+ runtime·sigprof((byte*)SIG_RIP(info, ctxt), (byte*)SIG_RSP(info, ctxt), nil, gp, m);
return;
}
+#ifdef GOOS_darwin
+ // x86-64 has 48-bit virtual addresses. The top 16 bits must echo bit 47.
+ // The hardware delivers a different kind of fault for a malformed address
+ // than it does for an attempt to access a valid but unmapped address.
+ // OS X 10.9.2 mishandles the malformed address case, making it look like
+ // a user-generated signal (like someone ran kill -SEGV ourpid).
+ // We pass user-generated signals to os/signal, or else ignore them.
+ // Doing that here - and returning to the faulting code - results in an
+ // infinite loop. It appears the best we can do is rewrite what the kernel
+ // delivers into something more like the truth. The address used below
+ // has very little chance of being the one that caused the fault, but it is
+ // malformed, it is clearly not a real pointer, and if it does get printed
+ // in real life, people will probably search for it and find this code.
+ // There are no Google hits for b01dfacedebac1e or 0xb01dfacedebac1e
+ // as I type this comment.
+ if(sig == SIGSEGV && SIG_CODE0(info, ctxt) == SI_USER) {
+ SIG_CODE0(info, ctxt) = SI_USER+1;
+ info->si_addr = (void*)(uintptr)0xb01dfacedebac1eULL;
+ }
+#endif
+
t = &runtime·sigtab[sig];
if(SIG_CODE0(info, ctxt) != SI_USER && (t->flags & SigPanic)) {
- if(gp == nil || gp == m->g0)
- goto Throw;
-
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
@@ -89,6 +108,8 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
// won't get to see who faulted.)
if(SIG_RIP(info, ctxt) != 0) {
sp = (uintptr*)SIG_RSP(info, ctxt);
+ if(sizeof(uintreg) > sizeof(uintptr))
+ *--sp = 0;
*--sp = SIG_RIP(info, ctxt);
SIG_RSP(info, ctxt) = (uintptr)sp;
}
@@ -104,7 +125,6 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
if(!(t->flags & SigThrow))
return;
-Throw:
m->throwing = 1;
m->caughtsig = gp;
runtime·startpanic();
@@ -122,6 +142,7 @@ Throw:
runtime·printf("\n");
if(runtime·gotraceback(&crash)){
+ runtime·goroutineheader(gp);
runtime·traceback(SIG_RIP(info, ctxt), SIG_RSP(info, ctxt), 0, gp);
runtime·tracebackothers(gp);
runtime·printf("\n");
diff --git a/src/pkg/runtime/signal_arm.c b/src/pkg/runtime/signal_arm.c
index a6e239601..9b2a43d9b 100644
--- a/src/pkg/runtime/signal_arm.c
+++ b/src/pkg/runtime/signal_arm.c
@@ -46,15 +46,12 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
bool crash;
if(sig == SIGPROF) {
- runtime·sigprof((uint8*)SIG_PC(info, ctxt), (uint8*)SIG_SP(info, ctxt), (uint8*)SIG_LR(info, ctxt), gp);
+ runtime·sigprof((uint8*)SIG_PC(info, ctxt), (uint8*)SIG_SP(info, ctxt), (uint8*)SIG_LR(info, ctxt), gp, m);
return;
}
t = &runtime·sigtab[sig];
if(SIG_CODE0(info, ctxt) != SI_USER && (t->flags & SigPanic)) {
- if(gp == nil || gp == m->g0)
- goto Throw;
-
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
@@ -92,7 +89,6 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
if(!(t->flags & SigThrow))
return;
-Throw:
m->throwing = 1;
m->caughtsig = gp;
if(runtime·panicking) // traceback already printed
@@ -112,6 +108,7 @@ Throw:
runtime·printf("\n");
if(runtime·gotraceback(&crash)){
+ runtime·goroutineheader(gp);
runtime·traceback(SIG_PC(info, ctxt), SIG_SP(info, ctxt), SIG_LR(info, ctxt), gp);
runtime·tracebackothers(gp);
runtime·printf("\n");
diff --git a/src/pkg/runtime/signal_nacl_386.h b/src/pkg/runtime/signal_nacl_386.h
new file mode 100644
index 000000000..c9481b5f4
--- /dev/null
+++ b/src/pkg/runtime/signal_nacl_386.h
@@ -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.
+
+#define SIG_REGS(ctxt) (((ExcContext*)(ctxt))->regs)
+
+#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).eax)
+#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).ebx)
+#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).ecx)
+#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).edx)
+#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).edi)
+#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).esi)
+#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).ebp)
+#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).esp)
+#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).eip)
+#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).eflags)
+
+#define SIG_CS(info, ctxt) (~0)
+#define SIG_FS(info, ctxt) (~0)
+#define SIG_GS(info, ctxt) (~0)
+
+#define SIG_CODE0(info, ctxt) (~0)
+#define SIG_CODE1(info, ctxt) (0)
diff --git a/src/pkg/runtime/signal_nacl_amd64p32.h b/src/pkg/runtime/signal_nacl_amd64p32.h
new file mode 100644
index 000000000..c58593a29
--- /dev/null
+++ b/src/pkg/runtime/signal_nacl_amd64p32.h
@@ -0,0 +1,31 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define SIG_REGS(ctxt) (((ExcContext*)(ctxt))->regs64)
+
+#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).rax)
+#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).rbx)
+#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).rcx)
+#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).rdx)
+#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).rdi)
+#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).rsi)
+#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).rbp)
+#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).rsp)
+#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).r8)
+#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).r9)
+#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).r10)
+#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).r11)
+#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).r12)
+#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).r13)
+#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).r14)
+#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).r15)
+#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).rip)
+#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).rflags)
+
+#define SIG_CS(info, ctxt) (~0)
+#define SIG_FS(info, ctxt) (~0)
+#define SIG_GS(info, ctxt) (~0)
+
+#define SIG_CODE0(info, ctxt) (~0)
+#define SIG_CODE1(info, ctxt) (0)
diff --git a/src/pkg/runtime/signal_solaris_amd64.h b/src/pkg/runtime/signal_solaris_amd64.h
new file mode 100644
index 000000000..c2e0a1549
--- /dev/null
+++ b/src/pkg/runtime/signal_solaris_amd64.h
@@ -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.
+
+#define SIG_REGS(ctxt) (((Ucontext*)(ctxt))->uc_mcontext)
+
+#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RAX])
+#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RBX])
+#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RCX])
+#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RDX])
+#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RDI])
+#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RSI])
+#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RBP])
+#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RSP])
+#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R8])
+#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R9])
+#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R10])
+#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R11])
+#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R12])
+#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R13])
+#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R14])
+#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R15])
+#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RIP])
+#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RFLAGS])
+
+#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).gregs[REG_CS])
+#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).gregs[REG_FS])
+#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).gregs[REG_GS])
+
+#define SIG_CODE0(info, ctxt) ((info)->si_code)
+#define SIG_CODE1(info, ctxt) (*(uintptr*)&(info)->__data[0])
diff --git a/src/pkg/runtime/signal_unix.c b/src/pkg/runtime/signal_unix.c
index 4d14b2208..246a1eb25 100644
--- a/src/pkg/runtime/signal_unix.c
+++ b/src/pkg/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 "runtime.h"
#include "defs_GOOS_GOARCH.h"
@@ -113,6 +113,7 @@ runtime·crash(void)
return;
#endif
+ runtime·unblocksignals();
runtime·setsig(SIGABRT, SIG_DFL, false);
runtime·raise(SIGABRT);
}
diff --git a/src/pkg/runtime/signals_freebsd.h b/src/pkg/runtime/signals_freebsd.h
index 4d27e050d..8d45c50c3 100644
--- a/src/pkg/runtime/signals_freebsd.h
+++ b/src/pkg/runtime/signals_freebsd.h
@@ -21,7 +21,7 @@ SigTab runtime·sigtab[] = {
/* 9 */ 0, "SIGKILL: kill",
/* 10 */ P, "SIGBUS: bus error",
/* 11 */ P, "SIGSEGV: segmentation violation",
- /* 12 */ T, "SIGSYS: bad system call",
+ /* 12 */ N, "SIGSYS: bad system call",
/* 13 */ N, "SIGPIPE: write to broken pipe",
/* 14 */ N, "SIGALRM: alarm clock",
/* 15 */ N+K, "SIGTERM: termination",
diff --git a/src/pkg/runtime/signals_linux.h b/src/pkg/runtime/signals_linux.h
index 9c3567007..368afc1c8 100644
--- a/src/pkg/runtime/signals_linux.h
+++ b/src/pkg/runtime/signals_linux.h
@@ -41,7 +41,7 @@ SigTab runtime·sigtab[] = {
/* 29 */ N, "SIGIO: i/o now possible",
/* 30 */ N, "SIGPWR: power failure restart",
/* 31 */ N, "SIGSYS: bad system call",
- /* 32 */ N, "signal 32",
+ /* 32 */ 0, "signal 32", /* SIGCANCEL; see issue 6997 */
/* 33 */ 0, "signal 33", /* SIGSETXID; see issue 3871 */
/* 34 */ N, "signal 34",
/* 35 */ N, "signal 35",
diff --git a/src/pkg/runtime/signals_nacl.h b/src/pkg/runtime/signals_nacl.h
new file mode 100644
index 000000000..229b58590
--- /dev/null
+++ b/src/pkg/runtime/signals_nacl.h
@@ -0,0 +1,50 @@
+// 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.
+
+#define N SigNotify
+#define K SigKill
+#define T SigThrow
+#define P SigPanic
+#define D SigDefault
+
+SigTab runtime·sigtab[] = {
+ /* 0 */ 0, "SIGNONE: no trap",
+ /* 1 */ N+K, "SIGHUP: terminal line hangup",
+ /* 2 */ N+K, "SIGINT: interrupt",
+ /* 3 */ N+T, "SIGQUIT: quit",
+ /* 4 */ T, "SIGILL: illegal instruction",
+ /* 5 */ T, "SIGTRAP: trace trap",
+ /* 6 */ N+T, "SIGABRT: abort",
+ /* 7 */ T, "SIGEMT: emulate instruction executed",
+ /* 8 */ P, "SIGFPE: floating-point exception",
+ /* 9 */ 0, "SIGKILL: kill",
+ /* 10 */ P, "SIGBUS: bus error",
+ /* 11 */ P, "SIGSEGV: segmentation violation",
+ /* 12 */ T, "SIGSYS: bad system call",
+ /* 13 */ N, "SIGPIPE: write to broken pipe",
+ /* 14 */ N, "SIGALRM: alarm clock",
+ /* 15 */ N+K, "SIGTERM: termination",
+ /* 16 */ N, "SIGURG: urgent condition on socket",
+ /* 17 */ 0, "SIGSTOP: stop",
+ /* 18 */ N+D, "SIGTSTP: keyboard stop",
+ /* 19 */ 0, "SIGCONT: continue after stop",
+ /* 20 */ N, "SIGCHLD: child status has changed",
+ /* 21 */ N+D, "SIGTTIN: background read from tty",
+ /* 22 */ N+D, "SIGTTOU: background write to tty",
+ /* 23 */ N, "SIGIO: i/o now possible",
+ /* 24 */ N, "SIGXCPU: cpu limit exceeded",
+ /* 25 */ N, "SIGXFSZ: file size limit exceeded",
+ /* 26 */ N, "SIGVTALRM: virtual alarm clock",
+ /* 27 */ N, "SIGPROF: profiling alarm clock",
+ /* 28 */ N, "SIGWINCH: window size change",
+ /* 29 */ N, "SIGINFO: status request from keyboard",
+ /* 30 */ N, "SIGUSR1: user-defined signal 1",
+ /* 31 */ N, "SIGUSR2: user-defined signal 2",
+};
+
+#undef N
+#undef K
+#undef T
+#undef P
+#undef D
diff --git a/src/pkg/runtime/signals_plan9.h b/src/pkg/runtime/signals_plan9.h
index f9bec65fc..818f508cf 100644
--- a/src/pkg/runtime/signals_plan9.h
+++ b/src/pkg/runtime/signals_plan9.h
@@ -3,26 +3,58 @@
// license that can be found in the LICENSE file.
#define N SigNotify
+#define K SigKill
#define T SigThrow
#define P SigPanic
+#define E SigGoExit
+
+// Incoming notes are compared against this table using strncmp, so the
+// order matters: longer patterns must appear before their prefixes.
+// There are #defined SIG constants in os_plan9.h for the table index of
+// some of these.
+//
+// If you add entries to this table, you must respect the prefix ordering
+// and also update the constant values is os_plan9.h.
SigTab runtime·sigtab[] = {
- P, "sys: fp:",
-
- // Go libraries expect to be able
- // to recover from memory
- // read/write errors, so we flag
- // those as panics. All other traps
- // are generally more serious and
- // should immediately throw an
- // exception.
- P, "sys: trap: fault read addr",
- P, "sys: trap: fault write addr",
- T, "sys: trap:",
-
- N, "sys: bad sys call",
+ // Traps that we cannot be recovered.
+ T, "sys: trap: debug exception",
+ T, "sys: trap: invalid opcode",
+
+ // We can recover from some memory errors in runtime·sigpanic.
+ P, "sys: trap: fault read addr", // SIGRFAULT
+ P, "sys: trap: fault write addr", // SIGWFAULT
+
+ // We can also recover from math errors.
+ P, "sys: trap: divide error", // SIGINTDIV
+ P, "sys: fp:", // SIGFLOAT
+
+ // All other traps are normally handled as if they were marked SigThrow.
+ // We mark them SigPanic here so that debug.SetPanicOnFault will work.
+ P, "sys: trap:", // SIGTRAP
+
+ // Writes to a closed pipe can be handled if desired, otherwise they're ignored.
+ N, "sys: write on closed pipe",
+
+ // Other system notes are more serious and cannot be recovered.
+ T, "sys:",
+
+ // Issued to all other procs when calling runtime·exit.
+ E, "go: exit ",
+
+ // Kill is sent by external programs to cause an exit.
+ K, "kill",
+
+ // Interrupts can be handled if desired, otherwise they cause an exit.
+ N+K, "interrupt",
+ N+K, "hangup",
+
+ // Alarms can be handled if desired, otherwise they're ignored.
+ N, "alarm",
};
#undef N
+#undef K
#undef T
#undef P
+#undef E
diff --git a/src/pkg/runtime/signals_solaris.h b/src/pkg/runtime/signals_solaris.h
new file mode 100644
index 000000000..c272cad29
--- /dev/null
+++ b/src/pkg/runtime/signals_solaris.h
@@ -0,0 +1,94 @@
+// 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.
+
+#define N SigNotify
+#define K SigKill
+#define T SigThrow
+#define P SigPanic
+#define D SigDefault
+
+SigTab runtime·sigtab[] = {
+ /* 0 */ 0, "SIGNONE: no trap",
+ /* 1 */ N+K, "SIGHUP: hangup",
+ /* 2 */ N+K, "SIGINT: interrupt (rubout)",
+ /* 3 */ N+T, "SIGQUIT: quit (ASCII FS)",
+ /* 4 */ T, "SIGILL: illegal instruction (not reset when caught)",
+ /* 5 */ T, "SIGTRAP: trace trap (not reset when caught)",
+ /* 6 */ N+T, "SIGABRT: used by abort, replace SIGIOT in the future",
+ /* 7 */ T, "SIGEMT: EMT instruction",
+ /* 8 */ P, "SIGFPE: floating point exception",
+ /* 9 */ 0, "SIGKILL: kill (cannot be caught or ignored)",
+ /* 10 */ P, "SIGBUS: bus error",
+ /* 11 */ P, "SIGSEGV: segmentation violation",
+ /* 12 */ T, "SIGSYS: bad argument to system call",
+ /* 13 */ N, "SIGPIPE: write on a pipe with no one to read it",
+ /* 14 */ N, "SIGALRM: alarm clock",
+ /* 15 */ N+K, "SIGTERM: software termination signal from kill",
+ /* 16 */ N, "SIGUSR1: user defined signal 1",
+ /* 17 */ N, "SIGUSR2: user defined signal 2",
+ /* 18 */ N, "SIGCLD: child status change",
+ /* 18 */ N, "SIGCHLD: child status change alias (POSIX)",
+ /* 19 */ N, "SIGPWR: power-fail restart",
+ /* 20 */ N, "SIGWINCH: window size change",
+ /* 21 */ N, "SIGURG: urgent socket condition",
+ /* 22 */ N, "SIGPOLL: pollable event occured",
+ /* 23 */ N+D, "SIGSTOP: stop (cannot be caught or ignored)",
+ /* 24 */ 0, "SIGTSTP: user stop requested from tty",
+ /* 25 */ 0, "SIGCONT: stopped process has been continued",
+ /* 26 */ N+D, "SIGTTIN: background tty read attempted",
+ /* 27 */ N+D, "SIGTTOU: background tty write attempted",
+ /* 28 */ N, "SIGVTALRM: virtual timer expired",
+ /* 29 */ N, "SIGPROF: profiling timer expired",
+ /* 30 */ N, "SIGXCPU: exceeded cpu limit",
+ /* 31 */ N, "SIGXFSZ: exceeded file size limit",
+ /* 32 */ N, "SIGWAITING: reserved signal no longer used by",
+ /* 33 */ N, "SIGLWP: reserved signal no longer used by",
+ /* 34 */ N, "SIGFREEZE: special signal used by CPR",
+ /* 35 */ N, "SIGTHAW: special signal used by CPR",
+ /* 36 */ 0, "SIGCANCEL: reserved signal for thread cancellation",
+ /* 37 */ N, "SIGLOST: resource lost (eg, record-lock lost)",
+ /* 38 */ N, "SIGXRES: resource control exceeded",
+ /* 39 */ N, "SIGJVM1: reserved signal for Java Virtual Machine",
+ /* 40 */ N, "SIGJVM2: reserved signal for Java Virtual Machine",
+
+ /* TODO(aram): what should be do about these signals? D or N? is this set static? */
+ /* 41 */ N, "real time signal",
+ /* 42 */ N, "real time signal",
+ /* 43 */ N, "real time signal",
+ /* 44 */ N, "real time signal",
+ /* 45 */ N, "real time signal",
+ /* 46 */ N, "real time signal",
+ /* 47 */ N, "real time signal",
+ /* 48 */ N, "real time signal",
+ /* 49 */ N, "real time signal",
+ /* 50 */ N, "real time signal",
+ /* 51 */ N, "real time signal",
+ /* 52 */ N, "real time signal",
+ /* 53 */ N, "real time signal",
+ /* 54 */ N, "real time signal",
+ /* 55 */ N, "real time signal",
+ /* 56 */ N, "real time signal",
+ /* 57 */ N, "real time signal",
+ /* 58 */ N, "real time signal",
+ /* 59 */ N, "real time signal",
+ /* 60 */ N, "real time signal",
+ /* 61 */ N, "real time signal",
+ /* 62 */ N, "real time signal",
+ /* 63 */ N, "real time signal",
+ /* 64 */ N, "real time signal",
+ /* 65 */ N, "real time signal",
+ /* 66 */ N, "real time signal",
+ /* 67 */ N, "real time signal",
+ /* 68 */ N, "real time signal",
+ /* 69 */ N, "real time signal",
+ /* 70 */ N, "real time signal",
+ /* 71 */ N, "real time signal",
+ /* 72 */ N, "real time signal",
+};
+
+#undef N
+#undef K
+#undef T
+#undef P
+#undef D
diff --git a/src/pkg/runtime/slice.c b/src/pkg/runtime/slice.goc
index ef8ab7fe0..2a14dafab 100644
--- a/src/pkg/runtime/slice.c
+++ b/src/pkg/runtime/slice.goc
@@ -2,12 +2,14 @@
// 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_GOARCH.h"
#include "type.h"
#include "typekind.h"
#include "malloc.h"
#include "race.h"
+#include "stack.h"
#include "../../cmd/ld/textflag.h"
enum
@@ -17,13 +19,9 @@ enum
static void makeslice1(SliceType*, intgo, intgo, Slice*);
static void growslice1(SliceType*, Slice, intgo, Slice *);
- void runtime·copy(Slice to, Slice fm, uintptr width, intgo ret);
// see also unsafe·NewArray
-// makeslice(typ *Type, len, cap int64) (ary []any);
-void
-runtime·makeslice(SliceType *t, int64 len, int64 cap, Slice ret)
-{
+func makeslice(t *SliceType, len int64, cap int64) (ret Slice) {
// 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,
@@ -58,9 +56,7 @@ makeslice1(SliceType *t, intgo len, intgo cap, Slice *ret)
}
// growslice(type *Type, x, []T, n int64) []T
-void
-runtime·growslice(SliceType *t, Slice old, int64 n, Slice ret)
-{
+func growslice(t *SliceType, old Slice, n int64) (ret Slice) {
int64 cap;
void *pc;
@@ -69,7 +65,7 @@ runtime·growslice(SliceType *t, Slice old, int64 n, Slice ret)
cap = old.cap + n;
- if((intgo)cap != cap || cap < old.cap || (t->elem->size > 0 && cap > MaxMem/t->elem->size))
+ if((intgo)cap != cap || cap < (int64)old.cap || (t->elem->size > 0 && cap > MaxMem/t->elem->size))
runtime·panicstring("growslice: cap out of range");
if(raceenabled) {
@@ -79,8 +75,6 @@ runtime·growslice(SliceType *t, Slice old, int64 n, Slice ret)
growslice1(t, old, cap, &ret);
- FLUSH(&ret);
-
if(debug) {
runtime·printf("growslice(%S,", *t->string);
runtime·printslice(old);
@@ -92,33 +86,53 @@ runtime·growslice(SliceType *t, Slice old, int64 n, Slice ret)
static void
growslice1(SliceType *t, Slice x, intgo newcap, Slice *ret)
{
- intgo m;
+ intgo newcap1;
+ uintptr capmem, lenmem;
+ int32 flag;
+ Type *typ;
+
+ typ = t->elem;
+ if(typ->size == 0) {
+ *ret = x;
+ ret->cap = newcap;
+ return;
+ }
- m = x.cap;
+ newcap1 = x.cap;
// Using newcap directly for m+m < newcap handles
// both the case where m == 0 and also the case where
// m+m/4 wraps around, in which case the loop
// below might never terminate.
- if(m+m < newcap)
- m = newcap;
+ if(newcap1+newcap1 < newcap)
+ newcap1 = newcap;
else {
do {
if(x.len < 1024)
- m += m;
+ newcap1 += newcap1;
else
- m += m/4;
- } while(m < newcap);
+ newcap1 += newcap1/4;
+ } while(newcap1 < newcap);
}
- makeslice1(t, x.len, m, ret);
- runtime·memmove(ret->array, x.array, ret->len * t->elem->size);
+
+ if(newcap1 > MaxMem/typ->size)
+ runtime·panicstring("growslice: cap out of range");
+ capmem = runtime·roundupsize(newcap1*typ->size);
+ flag = 0;
+ // Can't use FlagNoZero w/o FlagNoScan, because otherwise GC can scan unitialized memory.
+ if(typ->kind&KindNoPointers)
+ flag = FlagNoScan|FlagNoZero;
+ ret->array = runtime·mallocgc(capmem, (uintptr)typ|TypeInfo_Array, flag);
+ ret->len = x.len;
+ ret->cap = capmem/typ->size;
+ lenmem = x.len*typ->size;
+ runtime·memmove(ret->array, x.array, lenmem);
+ if(typ->kind&KindNoPointers)
+ runtime·memclr(ret->array+lenmem, capmem-lenmem);
}
-// copy(to any, fr any, wid uintptr) int
#pragma textflag NOSPLIT
-void
-runtime·copy(Slice to, Slice fm, uintptr width, intgo ret)
-{
+func copy(to Slice, fm Slice, width uintptr) (ret int) {
void *pc;
if(fm.len == 0 || to.len == 0 || width == 0) {
@@ -143,7 +157,6 @@ runtime·copy(Slice to, Slice fm, uintptr width, intgo ret)
}
out:
- FLUSH(&ret);
if(debug) {
runtime·prints("main·copy: to=");
@@ -159,9 +172,7 @@ out:
}
#pragma textflag NOSPLIT
-void
-runtime·slicestringcopy(Slice to, String fm, intgo ret)
-{
+func slicestringcopy(to Slice, fm String) (ret int) {
void *pc;
if(fm.len == 0 || to.len == 0) {
@@ -180,13 +191,10 @@ runtime·slicestringcopy(Slice to, String fm, intgo ret)
runtime·memmove(to.array, fm.str, ret);
-out:
- FLUSH(&ret);
+out:;
}
-void
-runtime·printslice(Slice a)
-{
+func printslice(a Slice) {
runtime·prints("[");
runtime·printint(a.len);
runtime·prints("/");
diff --git a/src/pkg/runtime/softfloat_arm.c b/src/pkg/runtime/softfloat_arm.c
index f5801dde4..29a52bd0e 100644
--- a/src/pkg/runtime/softfloat_arm.c
+++ b/src/pkg/runtime/softfloat_arm.c
@@ -16,7 +16,7 @@
#define FLAGS_V (1U << 28)
void runtime·abort(void);
-void math·sqrtC(uint64, uint64*);
+void runtime·sqrtC(uint64, uint64*);
static uint32 trace = 0;
@@ -413,7 +413,7 @@ stage3: // regd, regm are 4bit variables
break;
case 0xeeb10bc0: // D[regd] = sqrt D[regm]
- math·sqrtC(getd(regm), &uval);
+ runtime·sqrtC(getd(regm), &uval);
putd(regd, uval);
if(trace)
diff --git a/src/pkg/runtime/sqrt.go b/src/pkg/runtime/sqrt.go
new file mode 100644
index 000000000..34a8c3806
--- /dev/null
+++ b/src/pkg/runtime/sqrt.go
@@ -0,0 +1,150 @@
+// 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.
+
+// Copy of math/sqrt.go, here for use by ARM softfloat.
+
+package runtime
+
+import "unsafe"
+
+// The original C code and the long comment below are
+// from FreeBSD's /usr/src/lib/msun/src/e_sqrt.c and
+// came with this notice. The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// __ieee754_sqrt(x)
+// Return correctly rounded sqrt.
+// -----------------------------------------
+// | Use the hardware sqrt if you have one |
+// -----------------------------------------
+// Method:
+// Bit by bit method using integer arithmetic. (Slow, but portable)
+// 1. Normalization
+// Scale x to y in [1,4) with even powers of 2:
+// find an integer k such that 1 <= (y=x*2**(2k)) < 4, then
+// sqrt(x) = 2**k * sqrt(y)
+// 2. Bit by bit computation
+// Let q = sqrt(y) truncated to i bit after binary point (q = 1),
+// i 0
+// i+1 2
+// s = 2*q , and y = 2 * ( y - q ). (1)
+// i i i i
+//
+// To compute q from q , one checks whether
+// i+1 i
+//
+// -(i+1) 2
+// (q + 2 ) <= y. (2)
+// i
+// -(i+1)
+// If (2) is false, then q = q ; otherwise q = q + 2 .
+// i+1 i i+1 i
+//
+// With some algebraic manipulation, it is not difficult to see
+// that (2) is equivalent to
+// -(i+1)
+// s + 2 <= y (3)
+// i i
+//
+// The advantage of (3) is that s and y can be computed by
+// i i
+// the following recurrence formula:
+// if (3) is false
+//
+// s = s , y = y ; (4)
+// i+1 i i+1 i
+//
+// otherwise,
+// -i -(i+1)
+// s = s + 2 , y = y - s - 2 (5)
+// i+1 i i+1 i i
+//
+// One may easily use induction to prove (4) and (5).
+// Note. Since the left hand side of (3) contain only i+2 bits,
+// it does not necessary to do a full (53-bit) comparison
+// in (3).
+// 3. Final rounding
+// After generating the 53 bits result, we compute one more bit.
+// Together with the remainder, we can decide whether the
+// result is exact, bigger than 1/2ulp, or less than 1/2ulp
+// (it will never equal to 1/2ulp).
+// The rounding mode can be detected by checking whether
+// huge + tiny is equal to huge, and whether huge - tiny is
+// equal to huge for some floating point number "huge" and "tiny".
+//
+//
+// Notes: Rounding mode detection omitted.
+
+const (
+ uvnan = 0x7FF8000000000001
+ uvinf = 0x7FF0000000000000
+ uvneginf = 0xFFF0000000000000
+ mask = 0x7FF
+ shift = 64 - 11 - 1
+ bias = 1023
+ maxFloat64 = 1.797693134862315708145274237317043567981e+308 // 2**1023 * (2**53 - 1) / 2**52
+)
+
+func float64bits(f float64) uint64 { return *(*uint64)(unsafe.Pointer(&f)) }
+func float64frombits(b uint64) float64 { return *(*float64)(unsafe.Pointer(&b)) }
+
+func sqrt(x float64) float64 {
+ // special cases
+ switch {
+ case x == 0 || x != x || x > maxFloat64:
+ return x
+ case x < 0:
+ return nan
+ }
+ ix := float64bits(x)
+ // normalize x
+ exp := int((ix >> shift) & mask)
+ if exp == 0 { // subnormal x
+ for ix&1<<shift == 0 {
+ ix <<= 1
+ exp--
+ }
+ exp++
+ }
+ exp -= bias // unbias exponent
+ ix &^= mask << shift
+ ix |= 1 << shift
+ if exp&1 == 1 { // odd exp, double x to make it even
+ ix <<= 1
+ }
+ exp >>= 1 // exp = exp/2, exponent of square root
+ // generate sqrt(x) bit by bit
+ ix <<= 1
+ var q, s uint64 // q = sqrt(x)
+ r := uint64(1 << (shift + 1)) // r = moving bit from MSB to LSB
+ for r != 0 {
+ t := s + r
+ if t <= ix {
+ s = t + r
+ ix -= t
+ q += r
+ }
+ ix <<= 1
+ r >>= 1
+ }
+ // final rounding
+ if ix != 0 { // remainder, result not exact
+ q += q & 1 // round according to extra bit
+ }
+ ix = q>>1 + uint64(exp-1+bias)<<shift // significand + biased exponent
+ return float64frombits(ix)
+}
+
+func sqrtC(f float64, r *float64) {
+ *r = sqrt(f)
+}
diff --git a/src/pkg/runtime/stack.c b/src/pkg/runtime/stack.c
index 634706051..1680f004e 100644
--- a/src/pkg/runtime/stack.c
+++ b/src/pkg/runtime/stack.c
@@ -6,10 +6,21 @@
#include "arch_GOARCH.h"
#include "malloc.h"
#include "stack.h"
+#include "funcdata.h"
+#include "typekind.h"
+#include "type.h"
+#include "../../cmd/ld/textflag.h"
enum
{
+ // StackDebug == 0: no logging
+ // == 1: logging of per-stack operations
+ // == 2: logging of per-frame operations
+ // == 3: logging of per-word updates
+ // == 4: logging of per-word reads
StackDebug = 0,
+ StackFromSystem = 0, // allocate stacks from system memory instead of the heap
+ StackFaultOnFree = 0, // old stacks are mapped noaccess to detect use after free
};
typedef struct StackCacheNode StackCacheNode;
@@ -74,22 +85,37 @@ stackcacherelease(void)
}
void*
-runtime·stackalloc(uint32 n)
+runtime·stackalloc(G *gp, uint32 n)
{
uint32 pos;
void *v;
+ bool malloced;
+ Stktop *top;
// Stackalloc must be called on scheduler stack, so that we
// never try to grow the stack during the code that stackalloc runs.
// Doing so would cause a deadlock (issue 1547).
if(g != m->g0)
runtime·throw("stackalloc not on scheduler stack");
+ if((n & (n-1)) != 0)
+ runtime·throw("stack size not a power of 2");
+ if(StackDebug >= 1)
+ runtime·printf("stackalloc %d\n", n);
+
+ gp->stacksize += n;
+ if(runtime·debug.efence || StackFromSystem) {
+ v = runtime·SysAlloc(ROUND(n, PageSize), &mstats.stacks_sys);
+ if(v == nil)
+ runtime·throw("out of memory (stackalloc)");
+ return v;
+ }
- // Stacks are usually allocated with a fixed-size free-list allocator,
- // but if we need a stack of non-standard size, we fall back on malloc
- // (assuming that inside malloc and GC all the stack frames are small,
+ // Minimum-sized stacks are allocated with a fixed-size free-list allocator,
+ // but if we need a stack of a bigger size, we fall back on malloc
+ // (assuming that inside malloc all the stack frames are small,
// so that we do not deadlock).
- if(n == FixedStack || m->mallocing || m->gcing) {
+ malloced = true;
+ if(n == FixedStack || m->mallocing) {
if(n != FixedStack) {
runtime·printf("stackalloc: in malloc, size=%d want %d\n", FixedStack, n);
runtime·throw("stackalloc");
@@ -102,27 +128,46 @@ runtime·stackalloc(uint32 n)
m->stackcachepos = pos;
m->stackcachecnt--;
m->stackinuse++;
- return v;
- }
- return runtime·mallocgc(n, 0, FlagNoProfiling|FlagNoGC|FlagNoZero|FlagNoInvokeGC);
+ malloced = false;
+ } else
+ v = runtime·mallocgc(n, 0, FlagNoProfiling|FlagNoGC|FlagNoZero|FlagNoInvokeGC);
+
+ top = (Stktop*)((byte*)v+n-sizeof(Stktop));
+ runtime·memclr((byte*)top, sizeof(*top));
+ top->malloced = malloced;
+ return v;
}
void
-runtime·stackfree(void *v, uintptr n)
+runtime·stackfree(G *gp, void *v, Stktop *top)
{
uint32 pos;
-
- if(n == FixedStack || m->mallocing || m->gcing) {
- if(m->stackcachecnt == StackCacheSize)
- stackcacherelease();
- pos = m->stackcachepos;
- m->stackcache[pos] = v;
- m->stackcachepos = (pos + 1) % StackCacheSize;
- m->stackcachecnt++;
- m->stackinuse--;
+ uintptr n;
+
+ n = (uintptr)(top+1) - (uintptr)v;
+ if(StackDebug >= 1)
+ runtime·printf("stackfree %p %d\n", v, (int32)n);
+ gp->stacksize -= n;
+ if(runtime·debug.efence || StackFromSystem) {
+ if(runtime·debug.efence || StackFaultOnFree)
+ runtime·SysFault(v, n);
+ else
+ runtime·SysFree(v, n, &mstats.stacks_sys);
+ return;
+ }
+ if(top->malloced) {
+ runtime·free(v);
return;
}
- runtime·free(v);
+ if(n != FixedStack)
+ runtime·throw("stackfree: bad fixed size");
+ if(m->stackcachecnt == StackCacheSize)
+ stackcacherelease();
+ pos = m->stackcachepos;
+ m->stackcache[pos] = v;
+ m->stackcachepos = (pos + 1) % StackCacheSize;
+ m->stackcachecnt++;
+ m->stackinuse--;
}
// Called from runtime·lessstack when returning from a function which
@@ -145,12 +190,12 @@ runtime·oldstack(void)
sp = (byte*)top;
argsize = top->argsize;
- if(StackDebug) {
+ if(StackDebug >= 1) {
runtime·printf("runtime: oldstack gobuf={pc:%p sp:%p lr:%p} cret=%p argsize=%p\n",
- top->gobuf.pc, top->gobuf.sp, top->gobuf.lr, m->cret, (uintptr)argsize);
+ top->gobuf.pc, top->gobuf.sp, top->gobuf.lr, (uintptr)m->cret, (uintptr)argsize);
}
- // gp->status is usually Grunning, but it could be Gsyscall if a stack split
+ // gp->status is usually Grunning, but it could be Gsyscall if a stack overflow
// happens during a function call inside entersyscall.
oldstatus = gp->status;
@@ -175,11 +220,7 @@ runtime·oldstack(void)
gp->stackguard = top->stackguard;
gp->stackguard0 = gp->stackguard;
gp->panicwrap = top->panicwrap;
-
- if(top->free != 0) {
- gp->stacksize -= top->free;
- runtime·stackfree(old, top->free);
- }
+ runtime·stackfree(gp, old, top);
gp->status = oldstatus;
runtime·gogo(&gp->sched);
@@ -187,6 +228,435 @@ runtime·oldstack(void)
uintptr runtime·maxstacksize = 1<<20; // enough until runtime.main sets it for real
+static uint8*
+mapnames[] = {
+ (uint8*)"---",
+ (uint8*)"scalar",
+ (uint8*)"ptr",
+ (uint8*)"multi",
+};
+
+// Stack frame layout
+//
+// (x86)
+// +------------------+
+// | args from caller |
+// +------------------+ <- frame->argp
+// | return address |
+// +------------------+ <- frame->varp
+// | locals |
+// +------------------+
+// | args to callee |
+// +------------------+ <- frame->sp
+//
+// (arm: TODO)
+
+typedef struct CopyableInfo CopyableInfo;
+struct CopyableInfo {
+ byte *stk; // bottom address of segment
+ byte *base; // top address of segment (including Stktop)
+ int32 frames; // count of copyable frames (-1 = not copyable)
+};
+
+void runtime·main(void);
+
+static bool
+checkframecopy(Stkframe *frame, void *arg)
+{
+ CopyableInfo *cinfo;
+ Func *f;
+ StackMap *stackmap;
+
+ cinfo = arg;
+ f = frame->fn;
+ if(StackDebug >= 2)
+ runtime·printf(" checking %s frame=[%p,%p] stk=[%p,%p]\n", runtime·funcname(f), frame->sp, frame->fp, cinfo->stk, cinfo->base);
+ // if we're not in the segment any more, return immediately.
+ if(frame->varp < cinfo->stk || frame->varp >= cinfo->base) {
+ if(StackDebug >= 2)
+ runtime·printf(" <next segment>\n");
+ return false; // stop traceback
+ }
+ if(f->entry == (uintptr)runtime·main) {
+ // A special routine at the TOS of the main routine.
+ // We will allow it to be copied even though we don't
+ // have full GC info for it (because it is written in C).
+ cinfo->frames++;
+ return false; // stop traceback
+ }
+ if(frame->varp != (byte*)frame->sp) { // not in prologue (and has at least one local or outarg)
+ stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps);
+ if(stackmap == nil) {
+ cinfo->frames = -1;
+ if(StackDebug >= 1)
+ runtime·printf("copystack: no locals info for %s\n", runtime·funcname(f));
+ return false;
+ }
+ if(stackmap->n <= 0) {
+ cinfo->frames = -1;
+ if(StackDebug >= 1)
+ runtime·printf("copystack: locals size info only for %s\n", runtime·funcname(f));
+ return false;
+ }
+ }
+ if(frame->arglen != 0) {
+ stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps);
+ if(stackmap == nil) {
+ cinfo->frames = -1;
+ if(StackDebug >= 1)
+ runtime·printf("copystack: no arg info for %s\n", runtime·funcname(f));
+ return false;
+ }
+ }
+ cinfo->frames++;
+ return true; // this frame is ok; keep going
+}
+
+// If the top segment of the stack contains an uncopyable
+// frame, return -1. Otherwise return the number of frames
+// in the top segment, all of which are copyable.
+static int32
+copyabletopsegment(G *gp)
+{
+ CopyableInfo cinfo;
+ Defer *d;
+ Func *f;
+ FuncVal *fn;
+ StackMap *stackmap;
+
+ cinfo.stk = (byte*)gp->stackguard - StackGuard;
+ cinfo.base = (byte*)gp->stackbase + sizeof(Stktop);
+ cinfo.frames = 0;
+
+ // Check that each frame is copyable. As a side effect,
+ // count the frames.
+ runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff, checkframecopy, &cinfo, false);
+ if(StackDebug >= 1 && cinfo.frames != -1)
+ runtime·printf("copystack: %d copyable frames\n", cinfo.frames);
+
+ // Check to make sure all Defers are copyable
+ for(d = gp->defer; d != nil; d = d->link) {
+ if(cinfo.stk <= (byte*)d && (byte*)d < cinfo.base) {
+ // Defer is on the stack. Its copyableness has
+ // been established during stack walking.
+ // For now, this only happens with the Defer in runtime.main.
+ continue;
+ }
+ if(d->argp < cinfo.stk || cinfo.base <= d->argp)
+ break; // a defer for the next segment
+ fn = d->fn;
+ if(fn == nil) // See issue 8047
+ continue;
+ f = runtime·findfunc((uintptr)fn->fn);
+ if(f == nil)
+ return -1;
+
+ // Check to make sure we have an args pointer map for the defer's args.
+ // We only need the args map, but we check
+ // for the locals map also, because when the locals map
+ // isn't provided it means the ptr map came from C and
+ // C (particularly, cgo) lies to us. See issue 7695.
+ stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps);
+ if(stackmap == nil || stackmap->n <= 0)
+ return -1;
+ stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps);
+ if(stackmap == nil || stackmap->n <= 0)
+ return -1;
+
+ if(cinfo.stk <= (byte*)fn && (byte*)fn < cinfo.base) {
+ // FuncVal is on the stack. Again, its copyableness
+ // was established during stack walking.
+ continue;
+ }
+ // The FuncVal may have pointers in it, but fortunately for us
+ // the compiler won't put pointers into the stack in a
+ // heap-allocated FuncVal.
+ // One day if we do need to check this, we'll need maps of the
+ // pointerness of the closure args. The only place we have that map
+ // right now is in the gc program for the FuncVal. Ugh.
+ }
+
+ return cinfo.frames;
+}
+
+typedef struct AdjustInfo AdjustInfo;
+struct AdjustInfo {
+ byte *oldstk; // bottom address of segment
+ byte *oldbase; // top address of segment (after Stktop)
+ uintptr delta; // ptr distance from old to new stack (newbase - oldbase)
+};
+
+// bv describes the memory starting at address scanp.
+// Adjust any pointers contained therein.
+static void
+adjustpointers(byte **scanp, BitVector *bv, AdjustInfo *adjinfo, Func *f)
+{
+ uintptr delta;
+ int32 num, i;
+ byte *p, *minp, *maxp;
+ Type *t;
+ Itab *tab;
+
+ minp = adjinfo->oldstk;
+ maxp = adjinfo->oldbase;
+ delta = adjinfo->delta;
+ num = bv->n / BitsPerPointer;
+ for(i = 0; i < num; i++) {
+ if(StackDebug >= 4)
+ runtime·printf(" %p:%s:%p\n", &scanp[i], mapnames[bv->data[i / (32 / BitsPerPointer)] >> (i * BitsPerPointer & 31) & 3], scanp[i]);
+ switch(bv->data[i / (32 / BitsPerPointer)] >> (i * BitsPerPointer & 31) & 3) {
+ case BitsDead:
+ if(runtime·debug.gcdead)
+ scanp[i] = (byte*)PoisonStack;
+ break;
+ case BitsScalar:
+ break;
+ case BitsPointer:
+ p = scanp[i];
+ if(f != nil && (byte*)0 < p && (p < (byte*)PageSize || (uintptr)p == PoisonGC || (uintptr)p == PoisonStack)) {
+ // Looks like a junk value in a pointer slot.
+ // Live analysis wrong?
+ m->traceback = 2;
+ runtime·printf("runtime: bad pointer in frame %s at %p: %p\n", runtime·funcname(f), &scanp[i], p);
+ runtime·throw("bad pointer!");
+ }
+ if(minp <= p && p < maxp) {
+ if(StackDebug >= 3)
+ runtime·printf("adjust ptr %p %s\n", p, runtime·funcname(f));
+ scanp[i] = p + delta;
+ }
+ break;
+ case BitsMultiWord:
+ switch(bv->data[(i+1) / (32 / BitsPerPointer)] >> ((i+1) * BitsPerPointer & 31) & 3) {
+ case BitsString:
+ // string referents are never on the stack, never need to be adjusted
+ i++; // skip len
+ break;
+ case BitsSlice:
+ p = scanp[i];
+ if(minp <= p && p < maxp) {
+ if(StackDebug >= 3)
+ runtime·printf("adjust slice %p\n", p);
+ scanp[i] = p + delta;
+ }
+ i += 2; // skip len, cap
+ break;
+ case BitsEface:
+ t = (Type*)scanp[i];
+ if(t != nil && (t->size > PtrSize || (t->kind & KindNoPointers) == 0)) {
+ p = scanp[i+1];
+ if(minp <= p && p < maxp) {
+ if(StackDebug >= 3)
+ runtime·printf("adjust eface %p\n", p);
+ if(t->size > PtrSize) // currently we always allocate such objects on the heap
+ runtime·throw("large interface value found on stack");
+ scanp[i+1] = p + delta;
+ }
+ }
+ i++;
+ break;
+ case BitsIface:
+ tab = (Itab*)scanp[i];
+ if(tab != nil) {
+ t = tab->type;
+ //runtime·printf(" type=%p\n", t);
+ if(t->size > PtrSize || (t->kind & KindNoPointers) == 0) {
+ p = scanp[i+1];
+ if(minp <= p && p < maxp) {
+ if(StackDebug >= 3)
+ runtime·printf("adjust iface %p\n", p);
+ if(t->size > PtrSize) // currently we always allocate such objects on the heap
+ runtime·throw("large interface value found on stack");
+ scanp[i+1] = p + delta;
+ }
+ }
+ }
+ i++;
+ break;
+ }
+ break;
+ }
+ }
+}
+
+// Note: the argument/return area is adjusted by the callee.
+static bool
+adjustframe(Stkframe *frame, void *arg)
+{
+ AdjustInfo *adjinfo;
+ Func *f;
+ StackMap *stackmap;
+ int32 pcdata;
+ BitVector bv;
+ uintptr targetpc;
+
+ adjinfo = arg;
+ f = frame->fn;
+ if(StackDebug >= 2)
+ runtime·printf(" adjusting %s frame=[%p,%p] pc=%p continpc=%p\n", runtime·funcname(f), frame->sp, frame->fp, frame->pc, frame->continpc);
+ if(f->entry == (uintptr)runtime·main)
+ return true;
+ targetpc = frame->continpc;
+ if(targetpc == 0) {
+ // Frame is dead.
+ return true;
+ }
+ if(targetpc != f->entry)
+ targetpc--;
+ pcdata = runtime·pcdatavalue(f, PCDATA_StackMapIndex, targetpc);
+ if(pcdata == -1)
+ pcdata = 0; // in prologue
+
+ // adjust local pointers
+ if(frame->varp != (byte*)frame->sp) {
+ stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps);
+ if(stackmap == nil)
+ runtime·throw("no locals info");
+ if(stackmap->n <= 0)
+ runtime·throw("locals size info only");
+ bv = runtime·stackmapdata(stackmap, pcdata);
+ if(StackDebug >= 3)
+ runtime·printf(" locals\n");
+ adjustpointers((byte**)frame->varp - bv.n / BitsPerPointer, &bv, adjinfo, f);
+ }
+ // adjust inargs and outargs
+ if(frame->arglen != 0) {
+ stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps);
+ if(stackmap == nil)
+ runtime·throw("no arg info");
+ bv = runtime·stackmapdata(stackmap, pcdata);
+ if(StackDebug >= 3)
+ runtime·printf(" args\n");
+ adjustpointers((byte**)frame->argp, &bv, adjinfo, nil);
+ }
+ return true;
+}
+
+static void
+adjustctxt(G *gp, AdjustInfo *adjinfo)
+{
+ if(adjinfo->oldstk <= (byte*)gp->sched.ctxt && (byte*)gp->sched.ctxt < adjinfo->oldbase)
+ gp->sched.ctxt = (byte*)gp->sched.ctxt + adjinfo->delta;
+}
+
+static void
+adjustdefers(G *gp, AdjustInfo *adjinfo)
+{
+ Defer *d, **dp;
+ Func *f;
+ FuncVal *fn;
+ StackMap *stackmap;
+ BitVector bv;
+
+ for(dp = &gp->defer, d = *dp; d != nil; dp = &d->link, d = *dp) {
+ if(adjinfo->oldstk <= (byte*)d && (byte*)d < adjinfo->oldbase) {
+ // The Defer record is on the stack. Its fields will
+ // get adjusted appropriately.
+ // This only happens for runtime.main now, but a compiler
+ // optimization could do more of this.
+ *dp = (Defer*)((byte*)d + adjinfo->delta);
+ continue;
+ }
+ if(d->argp < adjinfo->oldstk || adjinfo->oldbase <= d->argp)
+ break; // a defer for the next segment
+ fn = d->fn;
+ if(fn == nil) {
+ // Defer of nil function. It will panic when run, and there
+ // aren't any args to adjust. See issue 8047.
+ d->argp += adjinfo->delta;
+ continue;
+ }
+ f = runtime·findfunc((uintptr)fn->fn);
+ if(f == nil)
+ runtime·throw("can't adjust unknown defer");
+ if(StackDebug >= 4)
+ runtime·printf(" checking defer %s\n", runtime·funcname(f));
+ // Defer's FuncVal might be on the stack
+ if(adjinfo->oldstk <= (byte*)fn && (byte*)fn < adjinfo->oldbase) {
+ if(StackDebug >= 3)
+ runtime·printf(" adjust defer fn %s\n", runtime·funcname(f));
+ d->fn = (FuncVal*)((byte*)fn + adjinfo->delta);
+ } else {
+ // deferred function's args might point into the stack.
+ if(StackDebug >= 3)
+ runtime·printf(" adjust deferred args for %s\n", runtime·funcname(f));
+ stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps);
+ if(stackmap == nil)
+ runtime·throw("runtime: deferred function has no arg ptr map");
+ bv = runtime·stackmapdata(stackmap, 0);
+ adjustpointers(d->args, &bv, adjinfo, f);
+ }
+ d->argp += adjinfo->delta;
+ }
+}
+
+// Copies the top stack segment of gp to a new stack segment of a
+// different size. The top segment must contain nframes frames.
+static void
+copystack(G *gp, uintptr nframes, uintptr newsize)
+{
+ byte *oldstk, *oldbase, *newstk, *newbase;
+ uintptr oldsize, used;
+ AdjustInfo adjinfo;
+ Stktop *oldtop, *newtop;
+ bool malloced;
+
+ if(gp->syscallstack != 0)
+ runtime·throw("can't handle stack copy in syscall yet");
+ oldstk = (byte*)gp->stackguard - StackGuard;
+ oldbase = (byte*)gp->stackbase + sizeof(Stktop);
+ oldsize = oldbase - oldstk;
+ used = oldbase - (byte*)gp->sched.sp;
+ oldtop = (Stktop*)gp->stackbase;
+
+ // allocate new stack
+ newstk = runtime·stackalloc(gp, newsize);
+ newbase = newstk + newsize;
+ newtop = (Stktop*)(newbase - sizeof(Stktop));
+ malloced = newtop->malloced;
+
+ if(StackDebug >= 1)
+ runtime·printf("copystack [%p %p]/%d -> [%p %p]/%d\n", oldstk, oldbase, (int32)oldsize, newstk, newbase, (int32)newsize);
+ USED(oldsize);
+
+ // adjust pointers in the to-be-copied frames
+ adjinfo.oldstk = oldstk;
+ adjinfo.oldbase = oldbase;
+ adjinfo.delta = newbase - oldbase;
+ runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, nframes, adjustframe, &adjinfo, false);
+
+ // adjust other miscellaneous things that have pointers into stacks.
+ adjustctxt(gp, &adjinfo);
+ adjustdefers(gp, &adjinfo);
+
+ // copy the stack (including Stktop) to the new location
+ runtime·memmove(newbase - used, oldbase - used, used);
+ newtop->malloced = malloced;
+
+ // Swap out old stack for new one
+ gp->stackbase = (uintptr)newtop;
+ gp->stackguard = (uintptr)newstk + StackGuard;
+ gp->stackguard0 = (uintptr)newstk + StackGuard; // NOTE: might clobber a preempt request
+ if(gp->stack0 == (uintptr)oldstk)
+ gp->stack0 = (uintptr)newstk;
+ gp->sched.sp = (uintptr)(newbase - used);
+
+ // free old stack
+ runtime·stackfree(gp, oldstk, oldtop);
+}
+
+// round x up to a power of 2.
+int32
+runtime·round2(int32 x)
+{
+ int32 s;
+
+ s = 0;
+ while((1 << s) < x)
+ s++;
+ return 1 << s;
+}
+
// Called from runtime·newstackcall or from runtime·morestack when a new
// stack segment is needed. Allocate a new stack big enough for
// m->moreframesize bytes, copy m->moreargsize bytes to the new frame,
@@ -195,16 +665,18 @@ uintptr runtime·maxstacksize = 1<<20; // enough until runtime.main sets it for
void
runtime·newstack(void)
{
- int32 framesize, argsize, oldstatus;
+ int32 framesize, argsize, oldstatus, oldsize, newsize, nframes;
Stktop *top, *oldtop;
- byte *stk;
+ byte *stk, *oldstk, *oldbase;
uintptr sp;
uintptr *src, *dst, *dstend;
G *gp;
- Gobuf label;
+ Gobuf label, morebuf;
+ void *moreargp;
bool newstackcall;
- uintptr free;
+ if(m->forkstackguard)
+ runtime·throw("split stack after fork");
if(m->morebuf.g != m->curg) {
runtime·printf("runtime: newstack called from g=%p\n"
"\tm=%p m->curg=%p m->g0=%p m->gsignal=%p\n",
@@ -212,15 +684,21 @@ runtime·newstack(void)
runtime·throw("runtime: wrong goroutine in newstack");
}
- // gp->status is usually Grunning, but it could be Gsyscall if a stack split
+ // gp->status is usually Grunning, but it could be Gsyscall if a stack overflow
// happens during a function call inside entersyscall.
gp = m->curg;
oldstatus = gp->status;
framesize = m->moreframesize;
argsize = m->moreargsize;
+ moreargp = m->moreargp;
+ m->moreargp = nil;
+ morebuf = m->morebuf;
+ m->morebuf.pc = (uintptr)nil;
+ m->morebuf.lr = (uintptr)nil;
+ m->morebuf.sp = (uintptr)nil;
gp->status = Gwaiting;
- gp->waitreason = "stack split";
+ gp->waitreason = "stack growth";
newstackcall = framesize==1;
if(newstackcall)
framesize = 0;
@@ -234,7 +712,7 @@ runtime·newstack(void)
// The call to morestack cost a word.
sp -= sizeof(uintptr);
}
- if(StackDebug || sp < gp->stackguard - StackGuard) {
+ if(StackDebug >= 1 || sp < gp->stackguard - StackGuard) {
runtime·printf("runtime: newstack framesize=%p argsize=%p sp=%p stack=[%p, %p]\n"
"\tmorebuf={pc:%p sp:%p lr:%p}\n"
"\tsched={pc:%p sp:%p lr:%p ctxt:%p}\n",
@@ -248,8 +726,8 @@ runtime·newstack(void)
}
if(argsize % sizeof(uintptr) != 0) {
- runtime·printf("runtime: stack split with misaligned argsize %d\n", argsize);
- runtime·throw("runtime: stack split argsize");
+ runtime·printf("runtime: stack growth with misaligned argsize %d\n", argsize);
+ runtime·throw("runtime: stack growth argsize");
}
if(gp->stackguard0 == (uintptr)StackPreempt) {
@@ -258,7 +736,7 @@ runtime·newstack(void)
if(oldstatus == Grunning && m->p == nil && m->locks == 0)
runtime·throw("runtime: g is running but p is not");
if(oldstatus == Gsyscall && m->locks == 0)
- runtime·throw("runtime: stack split during syscall");
+ runtime·throw("runtime: stack growth during syscall");
// Be conservative about where we preempt.
// We are interested in preempting user Go code, not runtime code.
if(oldstatus != Grunning || m->locks || m->mallocing || m->gcing || m->p->status != Prunning) {
@@ -273,46 +751,55 @@ runtime·newstack(void)
runtime·gosched0(gp); // never return
}
- if(newstackcall && m->morebuf.sp - sizeof(Stktop) - argsize - 32 > gp->stackguard) {
- // special case: called from runtime.newstackcall (framesize==1)
- // to call code with an arbitrary argument size,
- // and we have enough space on the current stack.
- // the new Stktop* is necessary to unwind, but
- // we don't need to create a new segment.
- top = (Stktop*)(m->morebuf.sp - sizeof(*top));
- stk = (byte*)gp->stackguard - StackGuard;
- free = 0;
- } else {
- // allocate new segment.
- framesize += argsize;
- framesize += StackExtra; // room for more functions, Stktop.
- if(framesize < StackMin)
- framesize = StackMin;
- framesize += StackSystem;
- gp->stacksize += framesize;
- if(gp->stacksize > runtime·maxstacksize) {
- runtime·printf("runtime: goroutine stack exceeds %D-byte limit\n", (uint64)runtime·maxstacksize);
- runtime·throw("stack overflow");
+ // If every frame on the top segment is copyable, allocate a bigger segment
+ // and move the segment instead of allocating a new segment.
+ if(runtime·copystack) {
+ if(!runtime·precisestack)
+ runtime·throw("can't copy stacks without precise stacks");
+ nframes = copyabletopsegment(gp);
+ if(nframes != -1) {
+ oldstk = (byte*)gp->stackguard - StackGuard;
+ oldbase = (byte*)gp->stackbase + sizeof(Stktop);
+ oldsize = oldbase - oldstk;
+ newsize = oldsize * 2;
+ copystack(gp, nframes, newsize);
+ if(StackDebug >= 1)
+ runtime·printf("stack grow done\n");
+ if(gp->stacksize > runtime·maxstacksize) {
+ runtime·printf("runtime: goroutine stack exceeds %D-byte limit\n", (uint64)runtime·maxstacksize);
+ runtime·throw("stack overflow");
+ }
+ gp->status = oldstatus;
+ runtime·gogo(&gp->sched);
}
- stk = runtime·stackalloc(framesize);
- top = (Stktop*)(stk+framesize-sizeof(*top));
- free = framesize;
+ // TODO: if stack is uncopyable because we're in C code, patch return value at
+ // end of C code to trigger a copy as soon as C code exits. That way, we'll
+ // have stack available if we get this deep again.
}
- if(StackDebug) {
+ // allocate new segment.
+ framesize += argsize;
+ framesize += StackExtra; // room for more functions, Stktop.
+ if(framesize < StackMin)
+ framesize = StackMin;
+ framesize += StackSystem;
+ framesize = runtime·round2(framesize);
+ stk = runtime·stackalloc(gp, framesize);
+ if(gp->stacksize > runtime·maxstacksize) {
+ runtime·printf("runtime: goroutine stack exceeds %D-byte limit\n", (uint64)runtime·maxstacksize);
+ runtime·throw("stack overflow");
+ }
+ top = (Stktop*)(stk+framesize-sizeof(*top));
+
+ if(StackDebug >= 1) {
runtime·printf("\t-> new stack [%p, %p]\n", stk, top);
}
top->stackbase = gp->stackbase;
top->stackguard = gp->stackguard;
- top->gobuf = m->morebuf;
- top->argp = m->moreargp;
+ top->gobuf = morebuf;
+ top->argp = moreargp;
top->argsize = argsize;
- top->free = free;
- m->moreargp = nil;
- m->morebuf.pc = (uintptr)nil;
- m->morebuf.lr = (uintptr)nil;
- m->morebuf.sp = (uintptr)nil;
// copy flag from panic
top->panic = gp->ispanic;
@@ -365,18 +852,96 @@ runtime·newstack(void)
*(int32*)345 = 123; // never return
}
+#pragma textflag NOSPLIT
+void
+runtime·nilfunc(void)
+{
+ *(byte*)0 = 0;
+}
+
// adjust Gobuf as if it executed a call to fn
// and then did an immediate gosave.
void
runtime·gostartcallfn(Gobuf *gobuf, FuncVal *fv)
{
- runtime·gostartcall(gobuf, fv->fn, fv);
+ void *fn;
+
+ if(fv != nil)
+ fn = fv->fn;
+ else
+ fn = runtime·nilfunc;
+ runtime·gostartcall(gobuf, fn, fv);
}
+// Maybe shrink the stack being used by gp.
+// Called at garbage collection time.
void
-runtime∕debug·setMaxStack(intgo in, intgo out)
+runtime·shrinkstack(G *gp)
{
- out = runtime·maxstacksize;
- runtime·maxstacksize = in;
- FLUSH(&out);
+ int32 nframes;
+ byte *oldstk, *oldbase;
+ uintptr used, oldsize, newsize;
+ MSpan *span;
+
+ if(!runtime·copystack)
+ return;
+ oldstk = (byte*)gp->stackguard - StackGuard;
+ oldbase = (byte*)gp->stackbase + sizeof(Stktop);
+ oldsize = oldbase - oldstk;
+ newsize = oldsize / 2;
+ if(newsize < FixedStack)
+ return; // don't shrink below the minimum-sized stack
+ used = oldbase - (byte*)gp->sched.sp;
+ if(used >= oldsize / 4)
+ return; // still using at least 1/4 of the segment.
+
+ // To shrink to less than 1/2 a page, we need to copy.
+ if(newsize < PageSize/2) {
+ if(gp->syscallstack != (uintptr)nil) // TODO: can we handle this case?
+ return;
+#ifdef GOOS_windows
+ if(gp->m != nil && gp->m->libcallsp != 0)
+ return;
+#endif
+ nframes = copyabletopsegment(gp);
+ if(nframes == -1)
+ return;
+ copystack(gp, nframes, newsize);
+ return;
+ }
+
+ // To shrink a stack of one page size or more, we can shrink it
+ // without copying. Just deallocate the lower half.
+ span = runtime·MHeap_LookupMaybe(&runtime·mheap, oldstk);
+ if(span == nil)
+ return; // stack allocated outside heap. Can't shrink it. Can happen if stack is allocated while inside malloc. TODO: shrink by copying?
+ if(span->elemsize != oldsize)
+ runtime·throw("span element size doesn't match stack size");
+ if((uintptr)oldstk != span->start << PageShift)
+ runtime·throw("stack not at start of span");
+
+ if(StackDebug)
+ runtime·printf("shrinking stack in place %p %X->%X\n", oldstk, oldsize, newsize);
+
+ // new stack guard for smaller stack
+ gp->stackguard = (uintptr)oldstk + newsize + StackGuard;
+ gp->stackguard0 = (uintptr)oldstk + newsize + StackGuard;
+ if(gp->stack0 == (uintptr)oldstk)
+ gp->stack0 = (uintptr)oldstk + newsize;
+ gp->stacksize -= oldsize - newsize;
+
+ // Free bottom half of the stack.
+ if(runtime·debug.efence || StackFromSystem) {
+ if(runtime·debug.efence || StackFaultOnFree)
+ runtime·SysFault(oldstk, newsize);
+ else
+ runtime·SysFree(oldstk, newsize, &mstats.stacks_sys);
+ return;
+ }
+ // First, we trick malloc into thinking
+ // we allocated the stack as two separate half-size allocs. Then the
+ // free() call does the rest of the work for us.
+ runtime·MSpan_EnsureSwept(span);
+ runtime·MHeap_SplitSpan(&runtime·mheap, span);
+ runtime·free(oldstk);
}
diff --git a/src/pkg/runtime/stack.h b/src/pkg/runtime/stack.h
index 296eb688d..18ab30b69 100644
--- a/src/pkg/runtime/stack.h
+++ b/src/pkg/runtime/stack.h
@@ -77,7 +77,8 @@ enum {
// If the amount needed for the splitting frame + StackExtra
// is less than this number, the stack will have this size instead.
StackMin = 8192,
- FixedStack = StackMin + StackSystem,
+ StackSystemRounded = StackSystem + (-StackSystem & (StackMin-1)),
+ FixedStack = StackMin + StackSystemRounded,
// Functions that need frames bigger than this use an extra
// instruction to do the stack split check, to avoid overflow
@@ -102,7 +103,7 @@ enum {
// The assumed size of the top-of-stack data block.
// The actual size can be smaller than this but cannot be larger.
// Checked in proc.c's runtime.malg.
- StackTop = 96,
+ StackTop = 88,
};
// Goroutine preemption request.
diff --git a/src/pkg/runtime/stack_gen_test.go b/src/pkg/runtime/stack_gen_test.go
new file mode 100644
index 000000000..28101062c
--- /dev/null
+++ b/src/pkg/runtime/stack_gen_test.go
@@ -0,0 +1,1473 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime_test
+
+import (
+ . "runtime"
+)
+
+var splitTests = []func() (uintptr, uintptr){
+ // Edit .+1,/^}/-1|seq 4 4 5000 | sed 's/.*/ stack&,/' | fmt
+ stack4, stack8, stack12, stack16, stack20, stack24, stack28,
+ stack32, stack36, stack40, stack44, stack48, stack52, stack56,
+ stack60, stack64, stack68, stack72, stack76, stack80, stack84,
+ stack88, stack92, stack96, stack100, stack104, stack108, stack112,
+ stack116, stack120, stack124, stack128, stack132, stack136,
+ stack140, stack144, stack148, stack152, stack156, stack160,
+ stack164, stack168, stack172, stack176, stack180, stack184,
+ stack188, stack192, stack196, stack200, stack204, stack208,
+ stack212, stack216, stack220, stack224, stack228, stack232,
+ stack236, stack240, stack244, stack248, stack252, stack256,
+ stack260, stack264, stack268, stack272, stack276, stack280,
+ stack284, stack288, stack292, stack296, stack300, stack304,
+ stack308, stack312, stack316, stack320, stack324, stack328,
+ stack332, stack336, stack340, stack344, stack348, stack352,
+ stack356, stack360, stack364, stack368, stack372, stack376,
+ stack380, stack384, stack388, stack392, stack396, stack400,
+ stack404, stack408, stack412, stack416, stack420, stack424,
+ stack428, stack432, stack436, stack440, stack444, stack448,
+ stack452, stack456, stack460, stack464, stack468, stack472,
+ stack476, stack480, stack484, stack488, stack492, stack496,
+ stack500, stack504, stack508, stack512, stack516, stack520,
+ stack524, stack528, stack532, stack536, stack540, stack544,
+ stack548, stack552, stack556, stack560, stack564, stack568,
+ stack572, stack576, stack580, stack584, stack588, stack592,
+ stack596, stack600, stack604, stack608, stack612, stack616,
+ stack620, stack624, stack628, stack632, stack636, stack640,
+ stack644, stack648, stack652, stack656, stack660, stack664,
+ stack668, stack672, stack676, stack680, stack684, stack688,
+ stack692, stack696, stack700, stack704, stack708, stack712,
+ stack716, stack720, stack724, stack728, stack732, stack736,
+ stack740, stack744, stack748, stack752, stack756, stack760,
+ stack764, stack768, stack772, stack776, stack780, stack784,
+ stack788, stack792, stack796, stack800, stack804, stack808,
+ stack812, stack816, stack820, stack824, stack828, stack832,
+ stack836, stack840, stack844, stack848, stack852, stack856,
+ stack860, stack864, stack868, stack872, stack876, stack880,
+ stack884, stack888, stack892, stack896, stack900, stack904,
+ stack908, stack912, stack916, stack920, stack924, stack928,
+ stack932, stack936, stack940, stack944, stack948, stack952,
+ stack956, stack960, stack964, stack968, stack972, stack976,
+ stack980, stack984, stack988, stack992, stack996, stack1000,
+ stack1004, stack1008, stack1012, stack1016, stack1020, stack1024,
+ stack1028, stack1032, stack1036, stack1040, stack1044, stack1048,
+ stack1052, stack1056, stack1060, stack1064, stack1068, stack1072,
+ stack1076, stack1080, stack1084, stack1088, stack1092, stack1096,
+ stack1100, stack1104, stack1108, stack1112, stack1116, stack1120,
+ stack1124, stack1128, stack1132, stack1136, stack1140, stack1144,
+ stack1148, stack1152, stack1156, stack1160, stack1164, stack1168,
+ stack1172, stack1176, stack1180, stack1184, stack1188, stack1192,
+ stack1196, stack1200, stack1204, stack1208, stack1212, stack1216,
+ stack1220, stack1224, stack1228, stack1232, stack1236, stack1240,
+ stack1244, stack1248, stack1252, stack1256, stack1260, stack1264,
+ stack1268, stack1272, stack1276, stack1280, stack1284, stack1288,
+ stack1292, stack1296, stack1300, stack1304, stack1308, stack1312,
+ stack1316, stack1320, stack1324, stack1328, stack1332, stack1336,
+ stack1340, stack1344, stack1348, stack1352, stack1356, stack1360,
+ stack1364, stack1368, stack1372, stack1376, stack1380, stack1384,
+ stack1388, stack1392, stack1396, stack1400, stack1404, stack1408,
+ stack1412, stack1416, stack1420, stack1424, stack1428, stack1432,
+ stack1436, stack1440, stack1444, stack1448, stack1452, stack1456,
+ stack1460, stack1464, stack1468, stack1472, stack1476, stack1480,
+ stack1484, stack1488, stack1492, stack1496, stack1500, stack1504,
+ stack1508, stack1512, stack1516, stack1520, stack1524, stack1528,
+ stack1532, stack1536, stack1540, stack1544, stack1548, stack1552,
+ stack1556, stack1560, stack1564, stack1568, stack1572, stack1576,
+ stack1580, stack1584, stack1588, stack1592, stack1596, stack1600,
+ stack1604, stack1608, stack1612, stack1616, stack1620, stack1624,
+ stack1628, stack1632, stack1636, stack1640, stack1644, stack1648,
+ stack1652, stack1656, stack1660, stack1664, stack1668, stack1672,
+ stack1676, stack1680, stack1684, stack1688, stack1692, stack1696,
+ stack1700, stack1704, stack1708, stack1712, stack1716, stack1720,
+ stack1724, stack1728, stack1732, stack1736, stack1740, stack1744,
+ stack1748, stack1752, stack1756, stack1760, stack1764, stack1768,
+ stack1772, stack1776, stack1780, stack1784, stack1788, stack1792,
+ stack1796, stack1800, stack1804, stack1808, stack1812, stack1816,
+ stack1820, stack1824, stack1828, stack1832, stack1836, stack1840,
+ stack1844, stack1848, stack1852, stack1856, stack1860, stack1864,
+ stack1868, stack1872, stack1876, stack1880, stack1884, stack1888,
+ stack1892, stack1896, stack1900, stack1904, stack1908, stack1912,
+ stack1916, stack1920, stack1924, stack1928, stack1932, stack1936,
+ stack1940, stack1944, stack1948, stack1952, stack1956, stack1960,
+ stack1964, stack1968, stack1972, stack1976, stack1980, stack1984,
+ stack1988, stack1992, stack1996, stack2000, stack2004, stack2008,
+ stack2012, stack2016, stack2020, stack2024, stack2028, stack2032,
+ stack2036, stack2040, stack2044, stack2048, stack2052, stack2056,
+ stack2060, stack2064, stack2068, stack2072, stack2076, stack2080,
+ stack2084, stack2088, stack2092, stack2096, stack2100, stack2104,
+ stack2108, stack2112, stack2116, stack2120, stack2124, stack2128,
+ stack2132, stack2136, stack2140, stack2144, stack2148, stack2152,
+ stack2156, stack2160, stack2164, stack2168, stack2172, stack2176,
+ stack2180, stack2184, stack2188, stack2192, stack2196, stack2200,
+ stack2204, stack2208, stack2212, stack2216, stack2220, stack2224,
+ stack2228, stack2232, stack2236, stack2240, stack2244, stack2248,
+ stack2252, stack2256, stack2260, stack2264, stack2268, stack2272,
+ stack2276, stack2280, stack2284, stack2288, stack2292, stack2296,
+ stack2300, stack2304, stack2308, stack2312, stack2316, stack2320,
+ stack2324, stack2328, stack2332, stack2336, stack2340, stack2344,
+ stack2348, stack2352, stack2356, stack2360, stack2364, stack2368,
+ stack2372, stack2376, stack2380, stack2384, stack2388, stack2392,
+ stack2396, stack2400, stack2404, stack2408, stack2412, stack2416,
+ stack2420, stack2424, stack2428, stack2432, stack2436, stack2440,
+ stack2444, stack2448, stack2452, stack2456, stack2460, stack2464,
+ stack2468, stack2472, stack2476, stack2480, stack2484, stack2488,
+ stack2492, stack2496, stack2500, stack2504, stack2508, stack2512,
+ stack2516, stack2520, stack2524, stack2528, stack2532, stack2536,
+ stack2540, stack2544, stack2548, stack2552, stack2556, stack2560,
+ stack2564, stack2568, stack2572, stack2576, stack2580, stack2584,
+ stack2588, stack2592, stack2596, stack2600, stack2604, stack2608,
+ stack2612, stack2616, stack2620, stack2624, stack2628, stack2632,
+ stack2636, stack2640, stack2644, stack2648, stack2652, stack2656,
+ stack2660, stack2664, stack2668, stack2672, stack2676, stack2680,
+ stack2684, stack2688, stack2692, stack2696, stack2700, stack2704,
+ stack2708, stack2712, stack2716, stack2720, stack2724, stack2728,
+ stack2732, stack2736, stack2740, stack2744, stack2748, stack2752,
+ stack2756, stack2760, stack2764, stack2768, stack2772, stack2776,
+ stack2780, stack2784, stack2788, stack2792, stack2796, stack2800,
+ stack2804, stack2808, stack2812, stack2816, stack2820, stack2824,
+ stack2828, stack2832, stack2836, stack2840, stack2844, stack2848,
+ stack2852, stack2856, stack2860, stack2864, stack2868, stack2872,
+ stack2876, stack2880, stack2884, stack2888, stack2892, stack2896,
+ stack2900, stack2904, stack2908, stack2912, stack2916, stack2920,
+ stack2924, stack2928, stack2932, stack2936, stack2940, stack2944,
+ stack2948, stack2952, stack2956, stack2960, stack2964, stack2968,
+ stack2972, stack2976, stack2980, stack2984, stack2988, stack2992,
+ stack2996, stack3000, stack3004, stack3008, stack3012, stack3016,
+ stack3020, stack3024, stack3028, stack3032, stack3036, stack3040,
+ stack3044, stack3048, stack3052, stack3056, stack3060, stack3064,
+ stack3068, stack3072, stack3076, stack3080, stack3084, stack3088,
+ stack3092, stack3096, stack3100, stack3104, stack3108, stack3112,
+ stack3116, stack3120, stack3124, stack3128, stack3132, stack3136,
+ stack3140, stack3144, stack3148, stack3152, stack3156, stack3160,
+ stack3164, stack3168, stack3172, stack3176, stack3180, stack3184,
+ stack3188, stack3192, stack3196, stack3200, stack3204, stack3208,
+ stack3212, stack3216, stack3220, stack3224, stack3228, stack3232,
+ stack3236, stack3240, stack3244, stack3248, stack3252, stack3256,
+ stack3260, stack3264, stack3268, stack3272, stack3276, stack3280,
+ stack3284, stack3288, stack3292, stack3296, stack3300, stack3304,
+ stack3308, stack3312, stack3316, stack3320, stack3324, stack3328,
+ stack3332, stack3336, stack3340, stack3344, stack3348, stack3352,
+ stack3356, stack3360, stack3364, stack3368, stack3372, stack3376,
+ stack3380, stack3384, stack3388, stack3392, stack3396, stack3400,
+ stack3404, stack3408, stack3412, stack3416, stack3420, stack3424,
+ stack3428, stack3432, stack3436, stack3440, stack3444, stack3448,
+ stack3452, stack3456, stack3460, stack3464, stack3468, stack3472,
+ stack3476, stack3480, stack3484, stack3488, stack3492, stack3496,
+ stack3500, stack3504, stack3508, stack3512, stack3516, stack3520,
+ stack3524, stack3528, stack3532, stack3536, stack3540, stack3544,
+ stack3548, stack3552, stack3556, stack3560, stack3564, stack3568,
+ stack3572, stack3576, stack3580, stack3584, stack3588, stack3592,
+ stack3596, stack3600, stack3604, stack3608, stack3612, stack3616,
+ stack3620, stack3624, stack3628, stack3632, stack3636, stack3640,
+ stack3644, stack3648, stack3652, stack3656, stack3660, stack3664,
+ stack3668, stack3672, stack3676, stack3680, stack3684, stack3688,
+ stack3692, stack3696, stack3700, stack3704, stack3708, stack3712,
+ stack3716, stack3720, stack3724, stack3728, stack3732, stack3736,
+ stack3740, stack3744, stack3748, stack3752, stack3756, stack3760,
+ stack3764, stack3768, stack3772, stack3776, stack3780, stack3784,
+ stack3788, stack3792, stack3796, stack3800, stack3804, stack3808,
+ stack3812, stack3816, stack3820, stack3824, stack3828, stack3832,
+ stack3836, stack3840, stack3844, stack3848, stack3852, stack3856,
+ stack3860, stack3864, stack3868, stack3872, stack3876, stack3880,
+ stack3884, stack3888, stack3892, stack3896, stack3900, stack3904,
+ stack3908, stack3912, stack3916, stack3920, stack3924, stack3928,
+ stack3932, stack3936, stack3940, stack3944, stack3948, stack3952,
+ stack3956, stack3960, stack3964, stack3968, stack3972, stack3976,
+ stack3980, stack3984, stack3988, stack3992, stack3996, stack4000,
+ stack4004, stack4008, stack4012, stack4016, stack4020, stack4024,
+ stack4028, stack4032, stack4036, stack4040, stack4044, stack4048,
+ stack4052, stack4056, stack4060, stack4064, stack4068, stack4072,
+ stack4076, stack4080, stack4084, stack4088, stack4092, stack4096,
+ stack4100, stack4104, stack4108, stack4112, stack4116, stack4120,
+ stack4124, stack4128, stack4132, stack4136, stack4140, stack4144,
+ stack4148, stack4152, stack4156, stack4160, stack4164, stack4168,
+ stack4172, stack4176, stack4180, stack4184, stack4188, stack4192,
+ stack4196, stack4200, stack4204, stack4208, stack4212, stack4216,
+ stack4220, stack4224, stack4228, stack4232, stack4236, stack4240,
+ stack4244, stack4248, stack4252, stack4256, stack4260, stack4264,
+ stack4268, stack4272, stack4276, stack4280, stack4284, stack4288,
+ stack4292, stack4296, stack4300, stack4304, stack4308, stack4312,
+ stack4316, stack4320, stack4324, stack4328, stack4332, stack4336,
+ stack4340, stack4344, stack4348, stack4352, stack4356, stack4360,
+ stack4364, stack4368, stack4372, stack4376, stack4380, stack4384,
+ stack4388, stack4392, stack4396, stack4400, stack4404, stack4408,
+ stack4412, stack4416, stack4420, stack4424, stack4428, stack4432,
+ stack4436, stack4440, stack4444, stack4448, stack4452, stack4456,
+ stack4460, stack4464, stack4468, stack4472, stack4476, stack4480,
+ stack4484, stack4488, stack4492, stack4496, stack4500, stack4504,
+ stack4508, stack4512, stack4516, stack4520, stack4524, stack4528,
+ stack4532, stack4536, stack4540, stack4544, stack4548, stack4552,
+ stack4556, stack4560, stack4564, stack4568, stack4572, stack4576,
+ stack4580, stack4584, stack4588, stack4592, stack4596, stack4600,
+ stack4604, stack4608, stack4612, stack4616, stack4620, stack4624,
+ stack4628, stack4632, stack4636, stack4640, stack4644, stack4648,
+ stack4652, stack4656, stack4660, stack4664, stack4668, stack4672,
+ stack4676, stack4680, stack4684, stack4688, stack4692, stack4696,
+ stack4700, stack4704, stack4708, stack4712, stack4716, stack4720,
+ stack4724, stack4728, stack4732, stack4736, stack4740, stack4744,
+ stack4748, stack4752, stack4756, stack4760, stack4764, stack4768,
+ stack4772, stack4776, stack4780, stack4784, stack4788, stack4792,
+ stack4796, stack4800, stack4804, stack4808, stack4812, stack4816,
+ stack4820, stack4824, stack4828, stack4832, stack4836, stack4840,
+ stack4844, stack4848, stack4852, stack4856, stack4860, stack4864,
+ stack4868, stack4872, stack4876, stack4880, stack4884, stack4888,
+ stack4892, stack4896, stack4900, stack4904, stack4908, stack4912,
+ stack4916, stack4920, stack4924, stack4928, stack4932, stack4936,
+ stack4940, stack4944, stack4948, stack4952, stack4956, stack4960,
+ stack4964, stack4968, stack4972, stack4976, stack4980, stack4984,
+ stack4988, stack4992, stack4996, stack5000,
+}
+
+// Edit .+1,$ | seq 4 4 5000 | sed 's/.*/func stack&()(uintptr, uintptr) { var buf [&]byte; use(buf[:]); return Stackguard() }/'
+func stack4() (uintptr, uintptr) { var buf [4]byte; use(buf[:]); return Stackguard() }
+func stack8() (uintptr, uintptr) { var buf [8]byte; use(buf[:]); return Stackguard() }
+func stack12() (uintptr, uintptr) { var buf [12]byte; use(buf[:]); return Stackguard() }
+func stack16() (uintptr, uintptr) { var buf [16]byte; use(buf[:]); return Stackguard() }
+func stack20() (uintptr, uintptr) { var buf [20]byte; use(buf[:]); return Stackguard() }
+func stack24() (uintptr, uintptr) { var buf [24]byte; use(buf[:]); return Stackguard() }
+func stack28() (uintptr, uintptr) { var buf [28]byte; use(buf[:]); return Stackguard() }
+func stack32() (uintptr, uintptr) { var buf [32]byte; use(buf[:]); return Stackguard() }
+func stack36() (uintptr, uintptr) { var buf [36]byte; use(buf[:]); return Stackguard() }
+func stack40() (uintptr, uintptr) { var buf [40]byte; use(buf[:]); return Stackguard() }
+func stack44() (uintptr, uintptr) { var buf [44]byte; use(buf[:]); return Stackguard() }
+func stack48() (uintptr, uintptr) { var buf [48]byte; use(buf[:]); return Stackguard() }
+func stack52() (uintptr, uintptr) { var buf [52]byte; use(buf[:]); return Stackguard() }
+func stack56() (uintptr, uintptr) { var buf [56]byte; use(buf[:]); return Stackguard() }
+func stack60() (uintptr, uintptr) { var buf [60]byte; use(buf[:]); return Stackguard() }
+func stack64() (uintptr, uintptr) { var buf [64]byte; use(buf[:]); return Stackguard() }
+func stack68() (uintptr, uintptr) { var buf [68]byte; use(buf[:]); return Stackguard() }
+func stack72() (uintptr, uintptr) { var buf [72]byte; use(buf[:]); return Stackguard() }
+func stack76() (uintptr, uintptr) { var buf [76]byte; use(buf[:]); return Stackguard() }
+func stack80() (uintptr, uintptr) { var buf [80]byte; use(buf[:]); return Stackguard() }
+func stack84() (uintptr, uintptr) { var buf [84]byte; use(buf[:]); return Stackguard() }
+func stack88() (uintptr, uintptr) { var buf [88]byte; use(buf[:]); return Stackguard() }
+func stack92() (uintptr, uintptr) { var buf [92]byte; use(buf[:]); return Stackguard() }
+func stack96() (uintptr, uintptr) { var buf [96]byte; use(buf[:]); return Stackguard() }
+func stack100() (uintptr, uintptr) { var buf [100]byte; use(buf[:]); return Stackguard() }
+func stack104() (uintptr, uintptr) { var buf [104]byte; use(buf[:]); return Stackguard() }
+func stack108() (uintptr, uintptr) { var buf [108]byte; use(buf[:]); return Stackguard() }
+func stack112() (uintptr, uintptr) { var buf [112]byte; use(buf[:]); return Stackguard() }
+func stack116() (uintptr, uintptr) { var buf [116]byte; use(buf[:]); return Stackguard() }
+func stack120() (uintptr, uintptr) { var buf [120]byte; use(buf[:]); return Stackguard() }
+func stack124() (uintptr, uintptr) { var buf [124]byte; use(buf[:]); return Stackguard() }
+func stack128() (uintptr, uintptr) { var buf [128]byte; use(buf[:]); return Stackguard() }
+func stack132() (uintptr, uintptr) { var buf [132]byte; use(buf[:]); return Stackguard() }
+func stack136() (uintptr, uintptr) { var buf [136]byte; use(buf[:]); return Stackguard() }
+func stack140() (uintptr, uintptr) { var buf [140]byte; use(buf[:]); return Stackguard() }
+func stack144() (uintptr, uintptr) { var buf [144]byte; use(buf[:]); return Stackguard() }
+func stack148() (uintptr, uintptr) { var buf [148]byte; use(buf[:]); return Stackguard() }
+func stack152() (uintptr, uintptr) { var buf [152]byte; use(buf[:]); return Stackguard() }
+func stack156() (uintptr, uintptr) { var buf [156]byte; use(buf[:]); return Stackguard() }
+func stack160() (uintptr, uintptr) { var buf [160]byte; use(buf[:]); return Stackguard() }
+func stack164() (uintptr, uintptr) { var buf [164]byte; use(buf[:]); return Stackguard() }
+func stack168() (uintptr, uintptr) { var buf [168]byte; use(buf[:]); return Stackguard() }
+func stack172() (uintptr, uintptr) { var buf [172]byte; use(buf[:]); return Stackguard() }
+func stack176() (uintptr, uintptr) { var buf [176]byte; use(buf[:]); return Stackguard() }
+func stack180() (uintptr, uintptr) { var buf [180]byte; use(buf[:]); return Stackguard() }
+func stack184() (uintptr, uintptr) { var buf [184]byte; use(buf[:]); return Stackguard() }
+func stack188() (uintptr, uintptr) { var buf [188]byte; use(buf[:]); return Stackguard() }
+func stack192() (uintptr, uintptr) { var buf [192]byte; use(buf[:]); return Stackguard() }
+func stack196() (uintptr, uintptr) { var buf [196]byte; use(buf[:]); return Stackguard() }
+func stack200() (uintptr, uintptr) { var buf [200]byte; use(buf[:]); return Stackguard() }
+func stack204() (uintptr, uintptr) { var buf [204]byte; use(buf[:]); return Stackguard() }
+func stack208() (uintptr, uintptr) { var buf [208]byte; use(buf[:]); return Stackguard() }
+func stack212() (uintptr, uintptr) { var buf [212]byte; use(buf[:]); return Stackguard() }
+func stack216() (uintptr, uintptr) { var buf [216]byte; use(buf[:]); return Stackguard() }
+func stack220() (uintptr, uintptr) { var buf [220]byte; use(buf[:]); return Stackguard() }
+func stack224() (uintptr, uintptr) { var buf [224]byte; use(buf[:]); return Stackguard() }
+func stack228() (uintptr, uintptr) { var buf [228]byte; use(buf[:]); return Stackguard() }
+func stack232() (uintptr, uintptr) { var buf [232]byte; use(buf[:]); return Stackguard() }
+func stack236() (uintptr, uintptr) { var buf [236]byte; use(buf[:]); return Stackguard() }
+func stack240() (uintptr, uintptr) { var buf [240]byte; use(buf[:]); return Stackguard() }
+func stack244() (uintptr, uintptr) { var buf [244]byte; use(buf[:]); return Stackguard() }
+func stack248() (uintptr, uintptr) { var buf [248]byte; use(buf[:]); return Stackguard() }
+func stack252() (uintptr, uintptr) { var buf [252]byte; use(buf[:]); return Stackguard() }
+func stack256() (uintptr, uintptr) { var buf [256]byte; use(buf[:]); return Stackguard() }
+func stack260() (uintptr, uintptr) { var buf [260]byte; use(buf[:]); return Stackguard() }
+func stack264() (uintptr, uintptr) { var buf [264]byte; use(buf[:]); return Stackguard() }
+func stack268() (uintptr, uintptr) { var buf [268]byte; use(buf[:]); return Stackguard() }
+func stack272() (uintptr, uintptr) { var buf [272]byte; use(buf[:]); return Stackguard() }
+func stack276() (uintptr, uintptr) { var buf [276]byte; use(buf[:]); return Stackguard() }
+func stack280() (uintptr, uintptr) { var buf [280]byte; use(buf[:]); return Stackguard() }
+func stack284() (uintptr, uintptr) { var buf [284]byte; use(buf[:]); return Stackguard() }
+func stack288() (uintptr, uintptr) { var buf [288]byte; use(buf[:]); return Stackguard() }
+func stack292() (uintptr, uintptr) { var buf [292]byte; use(buf[:]); return Stackguard() }
+func stack296() (uintptr, uintptr) { var buf [296]byte; use(buf[:]); return Stackguard() }
+func stack300() (uintptr, uintptr) { var buf [300]byte; use(buf[:]); return Stackguard() }
+func stack304() (uintptr, uintptr) { var buf [304]byte; use(buf[:]); return Stackguard() }
+func stack308() (uintptr, uintptr) { var buf [308]byte; use(buf[:]); return Stackguard() }
+func stack312() (uintptr, uintptr) { var buf [312]byte; use(buf[:]); return Stackguard() }
+func stack316() (uintptr, uintptr) { var buf [316]byte; use(buf[:]); return Stackguard() }
+func stack320() (uintptr, uintptr) { var buf [320]byte; use(buf[:]); return Stackguard() }
+func stack324() (uintptr, uintptr) { var buf [324]byte; use(buf[:]); return Stackguard() }
+func stack328() (uintptr, uintptr) { var buf [328]byte; use(buf[:]); return Stackguard() }
+func stack332() (uintptr, uintptr) { var buf [332]byte; use(buf[:]); return Stackguard() }
+func stack336() (uintptr, uintptr) { var buf [336]byte; use(buf[:]); return Stackguard() }
+func stack340() (uintptr, uintptr) { var buf [340]byte; use(buf[:]); return Stackguard() }
+func stack344() (uintptr, uintptr) { var buf [344]byte; use(buf[:]); return Stackguard() }
+func stack348() (uintptr, uintptr) { var buf [348]byte; use(buf[:]); return Stackguard() }
+func stack352() (uintptr, uintptr) { var buf [352]byte; use(buf[:]); return Stackguard() }
+func stack356() (uintptr, uintptr) { var buf [356]byte; use(buf[:]); return Stackguard() }
+func stack360() (uintptr, uintptr) { var buf [360]byte; use(buf[:]); return Stackguard() }
+func stack364() (uintptr, uintptr) { var buf [364]byte; use(buf[:]); return Stackguard() }
+func stack368() (uintptr, uintptr) { var buf [368]byte; use(buf[:]); return Stackguard() }
+func stack372() (uintptr, uintptr) { var buf [372]byte; use(buf[:]); return Stackguard() }
+func stack376() (uintptr, uintptr) { var buf [376]byte; use(buf[:]); return Stackguard() }
+func stack380() (uintptr, uintptr) { var buf [380]byte; use(buf[:]); return Stackguard() }
+func stack384() (uintptr, uintptr) { var buf [384]byte; use(buf[:]); return Stackguard() }
+func stack388() (uintptr, uintptr) { var buf [388]byte; use(buf[:]); return Stackguard() }
+func stack392() (uintptr, uintptr) { var buf [392]byte; use(buf[:]); return Stackguard() }
+func stack396() (uintptr, uintptr) { var buf [396]byte; use(buf[:]); return Stackguard() }
+func stack400() (uintptr, uintptr) { var buf [400]byte; use(buf[:]); return Stackguard() }
+func stack404() (uintptr, uintptr) { var buf [404]byte; use(buf[:]); return Stackguard() }
+func stack408() (uintptr, uintptr) { var buf [408]byte; use(buf[:]); return Stackguard() }
+func stack412() (uintptr, uintptr) { var buf [412]byte; use(buf[:]); return Stackguard() }
+func stack416() (uintptr, uintptr) { var buf [416]byte; use(buf[:]); return Stackguard() }
+func stack420() (uintptr, uintptr) { var buf [420]byte; use(buf[:]); return Stackguard() }
+func stack424() (uintptr, uintptr) { var buf [424]byte; use(buf[:]); return Stackguard() }
+func stack428() (uintptr, uintptr) { var buf [428]byte; use(buf[:]); return Stackguard() }
+func stack432() (uintptr, uintptr) { var buf [432]byte; use(buf[:]); return Stackguard() }
+func stack436() (uintptr, uintptr) { var buf [436]byte; use(buf[:]); return Stackguard() }
+func stack440() (uintptr, uintptr) { var buf [440]byte; use(buf[:]); return Stackguard() }
+func stack444() (uintptr, uintptr) { var buf [444]byte; use(buf[:]); return Stackguard() }
+func stack448() (uintptr, uintptr) { var buf [448]byte; use(buf[:]); return Stackguard() }
+func stack452() (uintptr, uintptr) { var buf [452]byte; use(buf[:]); return Stackguard() }
+func stack456() (uintptr, uintptr) { var buf [456]byte; use(buf[:]); return Stackguard() }
+func stack460() (uintptr, uintptr) { var buf [460]byte; use(buf[:]); return Stackguard() }
+func stack464() (uintptr, uintptr) { var buf [464]byte; use(buf[:]); return Stackguard() }
+func stack468() (uintptr, uintptr) { var buf [468]byte; use(buf[:]); return Stackguard() }
+func stack472() (uintptr, uintptr) { var buf [472]byte; use(buf[:]); return Stackguard() }
+func stack476() (uintptr, uintptr) { var buf [476]byte; use(buf[:]); return Stackguard() }
+func stack480() (uintptr, uintptr) { var buf [480]byte; use(buf[:]); return Stackguard() }
+func stack484() (uintptr, uintptr) { var buf [484]byte; use(buf[:]); return Stackguard() }
+func stack488() (uintptr, uintptr) { var buf [488]byte; use(buf[:]); return Stackguard() }
+func stack492() (uintptr, uintptr) { var buf [492]byte; use(buf[:]); return Stackguard() }
+func stack496() (uintptr, uintptr) { var buf [496]byte; use(buf[:]); return Stackguard() }
+func stack500() (uintptr, uintptr) { var buf [500]byte; use(buf[:]); return Stackguard() }
+func stack504() (uintptr, uintptr) { var buf [504]byte; use(buf[:]); return Stackguard() }
+func stack508() (uintptr, uintptr) { var buf [508]byte; use(buf[:]); return Stackguard() }
+func stack512() (uintptr, uintptr) { var buf [512]byte; use(buf[:]); return Stackguard() }
+func stack516() (uintptr, uintptr) { var buf [516]byte; use(buf[:]); return Stackguard() }
+func stack520() (uintptr, uintptr) { var buf [520]byte; use(buf[:]); return Stackguard() }
+func stack524() (uintptr, uintptr) { var buf [524]byte; use(buf[:]); return Stackguard() }
+func stack528() (uintptr, uintptr) { var buf [528]byte; use(buf[:]); return Stackguard() }
+func stack532() (uintptr, uintptr) { var buf [532]byte; use(buf[:]); return Stackguard() }
+func stack536() (uintptr, uintptr) { var buf [536]byte; use(buf[:]); return Stackguard() }
+func stack540() (uintptr, uintptr) { var buf [540]byte; use(buf[:]); return Stackguard() }
+func stack544() (uintptr, uintptr) { var buf [544]byte; use(buf[:]); return Stackguard() }
+func stack548() (uintptr, uintptr) { var buf [548]byte; use(buf[:]); return Stackguard() }
+func stack552() (uintptr, uintptr) { var buf [552]byte; use(buf[:]); return Stackguard() }
+func stack556() (uintptr, uintptr) { var buf [556]byte; use(buf[:]); return Stackguard() }
+func stack560() (uintptr, uintptr) { var buf [560]byte; use(buf[:]); return Stackguard() }
+func stack564() (uintptr, uintptr) { var buf [564]byte; use(buf[:]); return Stackguard() }
+func stack568() (uintptr, uintptr) { var buf [568]byte; use(buf[:]); return Stackguard() }
+func stack572() (uintptr, uintptr) { var buf [572]byte; use(buf[:]); return Stackguard() }
+func stack576() (uintptr, uintptr) { var buf [576]byte; use(buf[:]); return Stackguard() }
+func stack580() (uintptr, uintptr) { var buf [580]byte; use(buf[:]); return Stackguard() }
+func stack584() (uintptr, uintptr) { var buf [584]byte; use(buf[:]); return Stackguard() }
+func stack588() (uintptr, uintptr) { var buf [588]byte; use(buf[:]); return Stackguard() }
+func stack592() (uintptr, uintptr) { var buf [592]byte; use(buf[:]); return Stackguard() }
+func stack596() (uintptr, uintptr) { var buf [596]byte; use(buf[:]); return Stackguard() }
+func stack600() (uintptr, uintptr) { var buf [600]byte; use(buf[:]); return Stackguard() }
+func stack604() (uintptr, uintptr) { var buf [604]byte; use(buf[:]); return Stackguard() }
+func stack608() (uintptr, uintptr) { var buf [608]byte; use(buf[:]); return Stackguard() }
+func stack612() (uintptr, uintptr) { var buf [612]byte; use(buf[:]); return Stackguard() }
+func stack616() (uintptr, uintptr) { var buf [616]byte; use(buf[:]); return Stackguard() }
+func stack620() (uintptr, uintptr) { var buf [620]byte; use(buf[:]); return Stackguard() }
+func stack624() (uintptr, uintptr) { var buf [624]byte; use(buf[:]); return Stackguard() }
+func stack628() (uintptr, uintptr) { var buf [628]byte; use(buf[:]); return Stackguard() }
+func stack632() (uintptr, uintptr) { var buf [632]byte; use(buf[:]); return Stackguard() }
+func stack636() (uintptr, uintptr) { var buf [636]byte; use(buf[:]); return Stackguard() }
+func stack640() (uintptr, uintptr) { var buf [640]byte; use(buf[:]); return Stackguard() }
+func stack644() (uintptr, uintptr) { var buf [644]byte; use(buf[:]); return Stackguard() }
+func stack648() (uintptr, uintptr) { var buf [648]byte; use(buf[:]); return Stackguard() }
+func stack652() (uintptr, uintptr) { var buf [652]byte; use(buf[:]); return Stackguard() }
+func stack656() (uintptr, uintptr) { var buf [656]byte; use(buf[:]); return Stackguard() }
+func stack660() (uintptr, uintptr) { var buf [660]byte; use(buf[:]); return Stackguard() }
+func stack664() (uintptr, uintptr) { var buf [664]byte; use(buf[:]); return Stackguard() }
+func stack668() (uintptr, uintptr) { var buf [668]byte; use(buf[:]); return Stackguard() }
+func stack672() (uintptr, uintptr) { var buf [672]byte; use(buf[:]); return Stackguard() }
+func stack676() (uintptr, uintptr) { var buf [676]byte; use(buf[:]); return Stackguard() }
+func stack680() (uintptr, uintptr) { var buf [680]byte; use(buf[:]); return Stackguard() }
+func stack684() (uintptr, uintptr) { var buf [684]byte; use(buf[:]); return Stackguard() }
+func stack688() (uintptr, uintptr) { var buf [688]byte; use(buf[:]); return Stackguard() }
+func stack692() (uintptr, uintptr) { var buf [692]byte; use(buf[:]); return Stackguard() }
+func stack696() (uintptr, uintptr) { var buf [696]byte; use(buf[:]); return Stackguard() }
+func stack700() (uintptr, uintptr) { var buf [700]byte; use(buf[:]); return Stackguard() }
+func stack704() (uintptr, uintptr) { var buf [704]byte; use(buf[:]); return Stackguard() }
+func stack708() (uintptr, uintptr) { var buf [708]byte; use(buf[:]); return Stackguard() }
+func stack712() (uintptr, uintptr) { var buf [712]byte; use(buf[:]); return Stackguard() }
+func stack716() (uintptr, uintptr) { var buf [716]byte; use(buf[:]); return Stackguard() }
+func stack720() (uintptr, uintptr) { var buf [720]byte; use(buf[:]); return Stackguard() }
+func stack724() (uintptr, uintptr) { var buf [724]byte; use(buf[:]); return Stackguard() }
+func stack728() (uintptr, uintptr) { var buf [728]byte; use(buf[:]); return Stackguard() }
+func stack732() (uintptr, uintptr) { var buf [732]byte; use(buf[:]); return Stackguard() }
+func stack736() (uintptr, uintptr) { var buf [736]byte; use(buf[:]); return Stackguard() }
+func stack740() (uintptr, uintptr) { var buf [740]byte; use(buf[:]); return Stackguard() }
+func stack744() (uintptr, uintptr) { var buf [744]byte; use(buf[:]); return Stackguard() }
+func stack748() (uintptr, uintptr) { var buf [748]byte; use(buf[:]); return Stackguard() }
+func stack752() (uintptr, uintptr) { var buf [752]byte; use(buf[:]); return Stackguard() }
+func stack756() (uintptr, uintptr) { var buf [756]byte; use(buf[:]); return Stackguard() }
+func stack760() (uintptr, uintptr) { var buf [760]byte; use(buf[:]); return Stackguard() }
+func stack764() (uintptr, uintptr) { var buf [764]byte; use(buf[:]); return Stackguard() }
+func stack768() (uintptr, uintptr) { var buf [768]byte; use(buf[:]); return Stackguard() }
+func stack772() (uintptr, uintptr) { var buf [772]byte; use(buf[:]); return Stackguard() }
+func stack776() (uintptr, uintptr) { var buf [776]byte; use(buf[:]); return Stackguard() }
+func stack780() (uintptr, uintptr) { var buf [780]byte; use(buf[:]); return Stackguard() }
+func stack784() (uintptr, uintptr) { var buf [784]byte; use(buf[:]); return Stackguard() }
+func stack788() (uintptr, uintptr) { var buf [788]byte; use(buf[:]); return Stackguard() }
+func stack792() (uintptr, uintptr) { var buf [792]byte; use(buf[:]); return Stackguard() }
+func stack796() (uintptr, uintptr) { var buf [796]byte; use(buf[:]); return Stackguard() }
+func stack800() (uintptr, uintptr) { var buf [800]byte; use(buf[:]); return Stackguard() }
+func stack804() (uintptr, uintptr) { var buf [804]byte; use(buf[:]); return Stackguard() }
+func stack808() (uintptr, uintptr) { var buf [808]byte; use(buf[:]); return Stackguard() }
+func stack812() (uintptr, uintptr) { var buf [812]byte; use(buf[:]); return Stackguard() }
+func stack816() (uintptr, uintptr) { var buf [816]byte; use(buf[:]); return Stackguard() }
+func stack820() (uintptr, uintptr) { var buf [820]byte; use(buf[:]); return Stackguard() }
+func stack824() (uintptr, uintptr) { var buf [824]byte; use(buf[:]); return Stackguard() }
+func stack828() (uintptr, uintptr) { var buf [828]byte; use(buf[:]); return Stackguard() }
+func stack832() (uintptr, uintptr) { var buf [832]byte; use(buf[:]); return Stackguard() }
+func stack836() (uintptr, uintptr) { var buf [836]byte; use(buf[:]); return Stackguard() }
+func stack840() (uintptr, uintptr) { var buf [840]byte; use(buf[:]); return Stackguard() }
+func stack844() (uintptr, uintptr) { var buf [844]byte; use(buf[:]); return Stackguard() }
+func stack848() (uintptr, uintptr) { var buf [848]byte; use(buf[:]); return Stackguard() }
+func stack852() (uintptr, uintptr) { var buf [852]byte; use(buf[:]); return Stackguard() }
+func stack856() (uintptr, uintptr) { var buf [856]byte; use(buf[:]); return Stackguard() }
+func stack860() (uintptr, uintptr) { var buf [860]byte; use(buf[:]); return Stackguard() }
+func stack864() (uintptr, uintptr) { var buf [864]byte; use(buf[:]); return Stackguard() }
+func stack868() (uintptr, uintptr) { var buf [868]byte; use(buf[:]); return Stackguard() }
+func stack872() (uintptr, uintptr) { var buf [872]byte; use(buf[:]); return Stackguard() }
+func stack876() (uintptr, uintptr) { var buf [876]byte; use(buf[:]); return Stackguard() }
+func stack880() (uintptr, uintptr) { var buf [880]byte; use(buf[:]); return Stackguard() }
+func stack884() (uintptr, uintptr) { var buf [884]byte; use(buf[:]); return Stackguard() }
+func stack888() (uintptr, uintptr) { var buf [888]byte; use(buf[:]); return Stackguard() }
+func stack892() (uintptr, uintptr) { var buf [892]byte; use(buf[:]); return Stackguard() }
+func stack896() (uintptr, uintptr) { var buf [896]byte; use(buf[:]); return Stackguard() }
+func stack900() (uintptr, uintptr) { var buf [900]byte; use(buf[:]); return Stackguard() }
+func stack904() (uintptr, uintptr) { var buf [904]byte; use(buf[:]); return Stackguard() }
+func stack908() (uintptr, uintptr) { var buf [908]byte; use(buf[:]); return Stackguard() }
+func stack912() (uintptr, uintptr) { var buf [912]byte; use(buf[:]); return Stackguard() }
+func stack916() (uintptr, uintptr) { var buf [916]byte; use(buf[:]); return Stackguard() }
+func stack920() (uintptr, uintptr) { var buf [920]byte; use(buf[:]); return Stackguard() }
+func stack924() (uintptr, uintptr) { var buf [924]byte; use(buf[:]); return Stackguard() }
+func stack928() (uintptr, uintptr) { var buf [928]byte; use(buf[:]); return Stackguard() }
+func stack932() (uintptr, uintptr) { var buf [932]byte; use(buf[:]); return Stackguard() }
+func stack936() (uintptr, uintptr) { var buf [936]byte; use(buf[:]); return Stackguard() }
+func stack940() (uintptr, uintptr) { var buf [940]byte; use(buf[:]); return Stackguard() }
+func stack944() (uintptr, uintptr) { var buf [944]byte; use(buf[:]); return Stackguard() }
+func stack948() (uintptr, uintptr) { var buf [948]byte; use(buf[:]); return Stackguard() }
+func stack952() (uintptr, uintptr) { var buf [952]byte; use(buf[:]); return Stackguard() }
+func stack956() (uintptr, uintptr) { var buf [956]byte; use(buf[:]); return Stackguard() }
+func stack960() (uintptr, uintptr) { var buf [960]byte; use(buf[:]); return Stackguard() }
+func stack964() (uintptr, uintptr) { var buf [964]byte; use(buf[:]); return Stackguard() }
+func stack968() (uintptr, uintptr) { var buf [968]byte; use(buf[:]); return Stackguard() }
+func stack972() (uintptr, uintptr) { var buf [972]byte; use(buf[:]); return Stackguard() }
+func stack976() (uintptr, uintptr) { var buf [976]byte; use(buf[:]); return Stackguard() }
+func stack980() (uintptr, uintptr) { var buf [980]byte; use(buf[:]); return Stackguard() }
+func stack984() (uintptr, uintptr) { var buf [984]byte; use(buf[:]); return Stackguard() }
+func stack988() (uintptr, uintptr) { var buf [988]byte; use(buf[:]); return Stackguard() }
+func stack992() (uintptr, uintptr) { var buf [992]byte; use(buf[:]); return Stackguard() }
+func stack996() (uintptr, uintptr) { var buf [996]byte; use(buf[:]); return Stackguard() }
+func stack1000() (uintptr, uintptr) { var buf [1000]byte; use(buf[:]); return Stackguard() }
+func stack1004() (uintptr, uintptr) { var buf [1004]byte; use(buf[:]); return Stackguard() }
+func stack1008() (uintptr, uintptr) { var buf [1008]byte; use(buf[:]); return Stackguard() }
+func stack1012() (uintptr, uintptr) { var buf [1012]byte; use(buf[:]); return Stackguard() }
+func stack1016() (uintptr, uintptr) { var buf [1016]byte; use(buf[:]); return Stackguard() }
+func stack1020() (uintptr, uintptr) { var buf [1020]byte; use(buf[:]); return Stackguard() }
+func stack1024() (uintptr, uintptr) { var buf [1024]byte; use(buf[:]); return Stackguard() }
+func stack1028() (uintptr, uintptr) { var buf [1028]byte; use(buf[:]); return Stackguard() }
+func stack1032() (uintptr, uintptr) { var buf [1032]byte; use(buf[:]); return Stackguard() }
+func stack1036() (uintptr, uintptr) { var buf [1036]byte; use(buf[:]); return Stackguard() }
+func stack1040() (uintptr, uintptr) { var buf [1040]byte; use(buf[:]); return Stackguard() }
+func stack1044() (uintptr, uintptr) { var buf [1044]byte; use(buf[:]); return Stackguard() }
+func stack1048() (uintptr, uintptr) { var buf [1048]byte; use(buf[:]); return Stackguard() }
+func stack1052() (uintptr, uintptr) { var buf [1052]byte; use(buf[:]); return Stackguard() }
+func stack1056() (uintptr, uintptr) { var buf [1056]byte; use(buf[:]); return Stackguard() }
+func stack1060() (uintptr, uintptr) { var buf [1060]byte; use(buf[:]); return Stackguard() }
+func stack1064() (uintptr, uintptr) { var buf [1064]byte; use(buf[:]); return Stackguard() }
+func stack1068() (uintptr, uintptr) { var buf [1068]byte; use(buf[:]); return Stackguard() }
+func stack1072() (uintptr, uintptr) { var buf [1072]byte; use(buf[:]); return Stackguard() }
+func stack1076() (uintptr, uintptr) { var buf [1076]byte; use(buf[:]); return Stackguard() }
+func stack1080() (uintptr, uintptr) { var buf [1080]byte; use(buf[:]); return Stackguard() }
+func stack1084() (uintptr, uintptr) { var buf [1084]byte; use(buf[:]); return Stackguard() }
+func stack1088() (uintptr, uintptr) { var buf [1088]byte; use(buf[:]); return Stackguard() }
+func stack1092() (uintptr, uintptr) { var buf [1092]byte; use(buf[:]); return Stackguard() }
+func stack1096() (uintptr, uintptr) { var buf [1096]byte; use(buf[:]); return Stackguard() }
+func stack1100() (uintptr, uintptr) { var buf [1100]byte; use(buf[:]); return Stackguard() }
+func stack1104() (uintptr, uintptr) { var buf [1104]byte; use(buf[:]); return Stackguard() }
+func stack1108() (uintptr, uintptr) { var buf [1108]byte; use(buf[:]); return Stackguard() }
+func stack1112() (uintptr, uintptr) { var buf [1112]byte; use(buf[:]); return Stackguard() }
+func stack1116() (uintptr, uintptr) { var buf [1116]byte; use(buf[:]); return Stackguard() }
+func stack1120() (uintptr, uintptr) { var buf [1120]byte; use(buf[:]); return Stackguard() }
+func stack1124() (uintptr, uintptr) { var buf [1124]byte; use(buf[:]); return Stackguard() }
+func stack1128() (uintptr, uintptr) { var buf [1128]byte; use(buf[:]); return Stackguard() }
+func stack1132() (uintptr, uintptr) { var buf [1132]byte; use(buf[:]); return Stackguard() }
+func stack1136() (uintptr, uintptr) { var buf [1136]byte; use(buf[:]); return Stackguard() }
+func stack1140() (uintptr, uintptr) { var buf [1140]byte; use(buf[:]); return Stackguard() }
+func stack1144() (uintptr, uintptr) { var buf [1144]byte; use(buf[:]); return Stackguard() }
+func stack1148() (uintptr, uintptr) { var buf [1148]byte; use(buf[:]); return Stackguard() }
+func stack1152() (uintptr, uintptr) { var buf [1152]byte; use(buf[:]); return Stackguard() }
+func stack1156() (uintptr, uintptr) { var buf [1156]byte; use(buf[:]); return Stackguard() }
+func stack1160() (uintptr, uintptr) { var buf [1160]byte; use(buf[:]); return Stackguard() }
+func stack1164() (uintptr, uintptr) { var buf [1164]byte; use(buf[:]); return Stackguard() }
+func stack1168() (uintptr, uintptr) { var buf [1168]byte; use(buf[:]); return Stackguard() }
+func stack1172() (uintptr, uintptr) { var buf [1172]byte; use(buf[:]); return Stackguard() }
+func stack1176() (uintptr, uintptr) { var buf [1176]byte; use(buf[:]); return Stackguard() }
+func stack1180() (uintptr, uintptr) { var buf [1180]byte; use(buf[:]); return Stackguard() }
+func stack1184() (uintptr, uintptr) { var buf [1184]byte; use(buf[:]); return Stackguard() }
+func stack1188() (uintptr, uintptr) { var buf [1188]byte; use(buf[:]); return Stackguard() }
+func stack1192() (uintptr, uintptr) { var buf [1192]byte; use(buf[:]); return Stackguard() }
+func stack1196() (uintptr, uintptr) { var buf [1196]byte; use(buf[:]); return Stackguard() }
+func stack1200() (uintptr, uintptr) { var buf [1200]byte; use(buf[:]); return Stackguard() }
+func stack1204() (uintptr, uintptr) { var buf [1204]byte; use(buf[:]); return Stackguard() }
+func stack1208() (uintptr, uintptr) { var buf [1208]byte; use(buf[:]); return Stackguard() }
+func stack1212() (uintptr, uintptr) { var buf [1212]byte; use(buf[:]); return Stackguard() }
+func stack1216() (uintptr, uintptr) { var buf [1216]byte; use(buf[:]); return Stackguard() }
+func stack1220() (uintptr, uintptr) { var buf [1220]byte; use(buf[:]); return Stackguard() }
+func stack1224() (uintptr, uintptr) { var buf [1224]byte; use(buf[:]); return Stackguard() }
+func stack1228() (uintptr, uintptr) { var buf [1228]byte; use(buf[:]); return Stackguard() }
+func stack1232() (uintptr, uintptr) { var buf [1232]byte; use(buf[:]); return Stackguard() }
+func stack1236() (uintptr, uintptr) { var buf [1236]byte; use(buf[:]); return Stackguard() }
+func stack1240() (uintptr, uintptr) { var buf [1240]byte; use(buf[:]); return Stackguard() }
+func stack1244() (uintptr, uintptr) { var buf [1244]byte; use(buf[:]); return Stackguard() }
+func stack1248() (uintptr, uintptr) { var buf [1248]byte; use(buf[:]); return Stackguard() }
+func stack1252() (uintptr, uintptr) { var buf [1252]byte; use(buf[:]); return Stackguard() }
+func stack1256() (uintptr, uintptr) { var buf [1256]byte; use(buf[:]); return Stackguard() }
+func stack1260() (uintptr, uintptr) { var buf [1260]byte; use(buf[:]); return Stackguard() }
+func stack1264() (uintptr, uintptr) { var buf [1264]byte; use(buf[:]); return Stackguard() }
+func stack1268() (uintptr, uintptr) { var buf [1268]byte; use(buf[:]); return Stackguard() }
+func stack1272() (uintptr, uintptr) { var buf [1272]byte; use(buf[:]); return Stackguard() }
+func stack1276() (uintptr, uintptr) { var buf [1276]byte; use(buf[:]); return Stackguard() }
+func stack1280() (uintptr, uintptr) { var buf [1280]byte; use(buf[:]); return Stackguard() }
+func stack1284() (uintptr, uintptr) { var buf [1284]byte; use(buf[:]); return Stackguard() }
+func stack1288() (uintptr, uintptr) { var buf [1288]byte; use(buf[:]); return Stackguard() }
+func stack1292() (uintptr, uintptr) { var buf [1292]byte; use(buf[:]); return Stackguard() }
+func stack1296() (uintptr, uintptr) { var buf [1296]byte; use(buf[:]); return Stackguard() }
+func stack1300() (uintptr, uintptr) { var buf [1300]byte; use(buf[:]); return Stackguard() }
+func stack1304() (uintptr, uintptr) { var buf [1304]byte; use(buf[:]); return Stackguard() }
+func stack1308() (uintptr, uintptr) { var buf [1308]byte; use(buf[:]); return Stackguard() }
+func stack1312() (uintptr, uintptr) { var buf [1312]byte; use(buf[:]); return Stackguard() }
+func stack1316() (uintptr, uintptr) { var buf [1316]byte; use(buf[:]); return Stackguard() }
+func stack1320() (uintptr, uintptr) { var buf [1320]byte; use(buf[:]); return Stackguard() }
+func stack1324() (uintptr, uintptr) { var buf [1324]byte; use(buf[:]); return Stackguard() }
+func stack1328() (uintptr, uintptr) { var buf [1328]byte; use(buf[:]); return Stackguard() }
+func stack1332() (uintptr, uintptr) { var buf [1332]byte; use(buf[:]); return Stackguard() }
+func stack1336() (uintptr, uintptr) { var buf [1336]byte; use(buf[:]); return Stackguard() }
+func stack1340() (uintptr, uintptr) { var buf [1340]byte; use(buf[:]); return Stackguard() }
+func stack1344() (uintptr, uintptr) { var buf [1344]byte; use(buf[:]); return Stackguard() }
+func stack1348() (uintptr, uintptr) { var buf [1348]byte; use(buf[:]); return Stackguard() }
+func stack1352() (uintptr, uintptr) { var buf [1352]byte; use(buf[:]); return Stackguard() }
+func stack1356() (uintptr, uintptr) { var buf [1356]byte; use(buf[:]); return Stackguard() }
+func stack1360() (uintptr, uintptr) { var buf [1360]byte; use(buf[:]); return Stackguard() }
+func stack1364() (uintptr, uintptr) { var buf [1364]byte; use(buf[:]); return Stackguard() }
+func stack1368() (uintptr, uintptr) { var buf [1368]byte; use(buf[:]); return Stackguard() }
+func stack1372() (uintptr, uintptr) { var buf [1372]byte; use(buf[:]); return Stackguard() }
+func stack1376() (uintptr, uintptr) { var buf [1376]byte; use(buf[:]); return Stackguard() }
+func stack1380() (uintptr, uintptr) { var buf [1380]byte; use(buf[:]); return Stackguard() }
+func stack1384() (uintptr, uintptr) { var buf [1384]byte; use(buf[:]); return Stackguard() }
+func stack1388() (uintptr, uintptr) { var buf [1388]byte; use(buf[:]); return Stackguard() }
+func stack1392() (uintptr, uintptr) { var buf [1392]byte; use(buf[:]); return Stackguard() }
+func stack1396() (uintptr, uintptr) { var buf [1396]byte; use(buf[:]); return Stackguard() }
+func stack1400() (uintptr, uintptr) { var buf [1400]byte; use(buf[:]); return Stackguard() }
+func stack1404() (uintptr, uintptr) { var buf [1404]byte; use(buf[:]); return Stackguard() }
+func stack1408() (uintptr, uintptr) { var buf [1408]byte; use(buf[:]); return Stackguard() }
+func stack1412() (uintptr, uintptr) { var buf [1412]byte; use(buf[:]); return Stackguard() }
+func stack1416() (uintptr, uintptr) { var buf [1416]byte; use(buf[:]); return Stackguard() }
+func stack1420() (uintptr, uintptr) { var buf [1420]byte; use(buf[:]); return Stackguard() }
+func stack1424() (uintptr, uintptr) { var buf [1424]byte; use(buf[:]); return Stackguard() }
+func stack1428() (uintptr, uintptr) { var buf [1428]byte; use(buf[:]); return Stackguard() }
+func stack1432() (uintptr, uintptr) { var buf [1432]byte; use(buf[:]); return Stackguard() }
+func stack1436() (uintptr, uintptr) { var buf [1436]byte; use(buf[:]); return Stackguard() }
+func stack1440() (uintptr, uintptr) { var buf [1440]byte; use(buf[:]); return Stackguard() }
+func stack1444() (uintptr, uintptr) { var buf [1444]byte; use(buf[:]); return Stackguard() }
+func stack1448() (uintptr, uintptr) { var buf [1448]byte; use(buf[:]); return Stackguard() }
+func stack1452() (uintptr, uintptr) { var buf [1452]byte; use(buf[:]); return Stackguard() }
+func stack1456() (uintptr, uintptr) { var buf [1456]byte; use(buf[:]); return Stackguard() }
+func stack1460() (uintptr, uintptr) { var buf [1460]byte; use(buf[:]); return Stackguard() }
+func stack1464() (uintptr, uintptr) { var buf [1464]byte; use(buf[:]); return Stackguard() }
+func stack1468() (uintptr, uintptr) { var buf [1468]byte; use(buf[:]); return Stackguard() }
+func stack1472() (uintptr, uintptr) { var buf [1472]byte; use(buf[:]); return Stackguard() }
+func stack1476() (uintptr, uintptr) { var buf [1476]byte; use(buf[:]); return Stackguard() }
+func stack1480() (uintptr, uintptr) { var buf [1480]byte; use(buf[:]); return Stackguard() }
+func stack1484() (uintptr, uintptr) { var buf [1484]byte; use(buf[:]); return Stackguard() }
+func stack1488() (uintptr, uintptr) { var buf [1488]byte; use(buf[:]); return Stackguard() }
+func stack1492() (uintptr, uintptr) { var buf [1492]byte; use(buf[:]); return Stackguard() }
+func stack1496() (uintptr, uintptr) { var buf [1496]byte; use(buf[:]); return Stackguard() }
+func stack1500() (uintptr, uintptr) { var buf [1500]byte; use(buf[:]); return Stackguard() }
+func stack1504() (uintptr, uintptr) { var buf [1504]byte; use(buf[:]); return Stackguard() }
+func stack1508() (uintptr, uintptr) { var buf [1508]byte; use(buf[:]); return Stackguard() }
+func stack1512() (uintptr, uintptr) { var buf [1512]byte; use(buf[:]); return Stackguard() }
+func stack1516() (uintptr, uintptr) { var buf [1516]byte; use(buf[:]); return Stackguard() }
+func stack1520() (uintptr, uintptr) { var buf [1520]byte; use(buf[:]); return Stackguard() }
+func stack1524() (uintptr, uintptr) { var buf [1524]byte; use(buf[:]); return Stackguard() }
+func stack1528() (uintptr, uintptr) { var buf [1528]byte; use(buf[:]); return Stackguard() }
+func stack1532() (uintptr, uintptr) { var buf [1532]byte; use(buf[:]); return Stackguard() }
+func stack1536() (uintptr, uintptr) { var buf [1536]byte; use(buf[:]); return Stackguard() }
+func stack1540() (uintptr, uintptr) { var buf [1540]byte; use(buf[:]); return Stackguard() }
+func stack1544() (uintptr, uintptr) { var buf [1544]byte; use(buf[:]); return Stackguard() }
+func stack1548() (uintptr, uintptr) { var buf [1548]byte; use(buf[:]); return Stackguard() }
+func stack1552() (uintptr, uintptr) { var buf [1552]byte; use(buf[:]); return Stackguard() }
+func stack1556() (uintptr, uintptr) { var buf [1556]byte; use(buf[:]); return Stackguard() }
+func stack1560() (uintptr, uintptr) { var buf [1560]byte; use(buf[:]); return Stackguard() }
+func stack1564() (uintptr, uintptr) { var buf [1564]byte; use(buf[:]); return Stackguard() }
+func stack1568() (uintptr, uintptr) { var buf [1568]byte; use(buf[:]); return Stackguard() }
+func stack1572() (uintptr, uintptr) { var buf [1572]byte; use(buf[:]); return Stackguard() }
+func stack1576() (uintptr, uintptr) { var buf [1576]byte; use(buf[:]); return Stackguard() }
+func stack1580() (uintptr, uintptr) { var buf [1580]byte; use(buf[:]); return Stackguard() }
+func stack1584() (uintptr, uintptr) { var buf [1584]byte; use(buf[:]); return Stackguard() }
+func stack1588() (uintptr, uintptr) { var buf [1588]byte; use(buf[:]); return Stackguard() }
+func stack1592() (uintptr, uintptr) { var buf [1592]byte; use(buf[:]); return Stackguard() }
+func stack1596() (uintptr, uintptr) { var buf [1596]byte; use(buf[:]); return Stackguard() }
+func stack1600() (uintptr, uintptr) { var buf [1600]byte; use(buf[:]); return Stackguard() }
+func stack1604() (uintptr, uintptr) { var buf [1604]byte; use(buf[:]); return Stackguard() }
+func stack1608() (uintptr, uintptr) { var buf [1608]byte; use(buf[:]); return Stackguard() }
+func stack1612() (uintptr, uintptr) { var buf [1612]byte; use(buf[:]); return Stackguard() }
+func stack1616() (uintptr, uintptr) { var buf [1616]byte; use(buf[:]); return Stackguard() }
+func stack1620() (uintptr, uintptr) { var buf [1620]byte; use(buf[:]); return Stackguard() }
+func stack1624() (uintptr, uintptr) { var buf [1624]byte; use(buf[:]); return Stackguard() }
+func stack1628() (uintptr, uintptr) { var buf [1628]byte; use(buf[:]); return Stackguard() }
+func stack1632() (uintptr, uintptr) { var buf [1632]byte; use(buf[:]); return Stackguard() }
+func stack1636() (uintptr, uintptr) { var buf [1636]byte; use(buf[:]); return Stackguard() }
+func stack1640() (uintptr, uintptr) { var buf [1640]byte; use(buf[:]); return Stackguard() }
+func stack1644() (uintptr, uintptr) { var buf [1644]byte; use(buf[:]); return Stackguard() }
+func stack1648() (uintptr, uintptr) { var buf [1648]byte; use(buf[:]); return Stackguard() }
+func stack1652() (uintptr, uintptr) { var buf [1652]byte; use(buf[:]); return Stackguard() }
+func stack1656() (uintptr, uintptr) { var buf [1656]byte; use(buf[:]); return Stackguard() }
+func stack1660() (uintptr, uintptr) { var buf [1660]byte; use(buf[:]); return Stackguard() }
+func stack1664() (uintptr, uintptr) { var buf [1664]byte; use(buf[:]); return Stackguard() }
+func stack1668() (uintptr, uintptr) { var buf [1668]byte; use(buf[:]); return Stackguard() }
+func stack1672() (uintptr, uintptr) { var buf [1672]byte; use(buf[:]); return Stackguard() }
+func stack1676() (uintptr, uintptr) { var buf [1676]byte; use(buf[:]); return Stackguard() }
+func stack1680() (uintptr, uintptr) { var buf [1680]byte; use(buf[:]); return Stackguard() }
+func stack1684() (uintptr, uintptr) { var buf [1684]byte; use(buf[:]); return Stackguard() }
+func stack1688() (uintptr, uintptr) { var buf [1688]byte; use(buf[:]); return Stackguard() }
+func stack1692() (uintptr, uintptr) { var buf [1692]byte; use(buf[:]); return Stackguard() }
+func stack1696() (uintptr, uintptr) { var buf [1696]byte; use(buf[:]); return Stackguard() }
+func stack1700() (uintptr, uintptr) { var buf [1700]byte; use(buf[:]); return Stackguard() }
+func stack1704() (uintptr, uintptr) { var buf [1704]byte; use(buf[:]); return Stackguard() }
+func stack1708() (uintptr, uintptr) { var buf [1708]byte; use(buf[:]); return Stackguard() }
+func stack1712() (uintptr, uintptr) { var buf [1712]byte; use(buf[:]); return Stackguard() }
+func stack1716() (uintptr, uintptr) { var buf [1716]byte; use(buf[:]); return Stackguard() }
+func stack1720() (uintptr, uintptr) { var buf [1720]byte; use(buf[:]); return Stackguard() }
+func stack1724() (uintptr, uintptr) { var buf [1724]byte; use(buf[:]); return Stackguard() }
+func stack1728() (uintptr, uintptr) { var buf [1728]byte; use(buf[:]); return Stackguard() }
+func stack1732() (uintptr, uintptr) { var buf [1732]byte; use(buf[:]); return Stackguard() }
+func stack1736() (uintptr, uintptr) { var buf [1736]byte; use(buf[:]); return Stackguard() }
+func stack1740() (uintptr, uintptr) { var buf [1740]byte; use(buf[:]); return Stackguard() }
+func stack1744() (uintptr, uintptr) { var buf [1744]byte; use(buf[:]); return Stackguard() }
+func stack1748() (uintptr, uintptr) { var buf [1748]byte; use(buf[:]); return Stackguard() }
+func stack1752() (uintptr, uintptr) { var buf [1752]byte; use(buf[:]); return Stackguard() }
+func stack1756() (uintptr, uintptr) { var buf [1756]byte; use(buf[:]); return Stackguard() }
+func stack1760() (uintptr, uintptr) { var buf [1760]byte; use(buf[:]); return Stackguard() }
+func stack1764() (uintptr, uintptr) { var buf [1764]byte; use(buf[:]); return Stackguard() }
+func stack1768() (uintptr, uintptr) { var buf [1768]byte; use(buf[:]); return Stackguard() }
+func stack1772() (uintptr, uintptr) { var buf [1772]byte; use(buf[:]); return Stackguard() }
+func stack1776() (uintptr, uintptr) { var buf [1776]byte; use(buf[:]); return Stackguard() }
+func stack1780() (uintptr, uintptr) { var buf [1780]byte; use(buf[:]); return Stackguard() }
+func stack1784() (uintptr, uintptr) { var buf [1784]byte; use(buf[:]); return Stackguard() }
+func stack1788() (uintptr, uintptr) { var buf [1788]byte; use(buf[:]); return Stackguard() }
+func stack1792() (uintptr, uintptr) { var buf [1792]byte; use(buf[:]); return Stackguard() }
+func stack1796() (uintptr, uintptr) { var buf [1796]byte; use(buf[:]); return Stackguard() }
+func stack1800() (uintptr, uintptr) { var buf [1800]byte; use(buf[:]); return Stackguard() }
+func stack1804() (uintptr, uintptr) { var buf [1804]byte; use(buf[:]); return Stackguard() }
+func stack1808() (uintptr, uintptr) { var buf [1808]byte; use(buf[:]); return Stackguard() }
+func stack1812() (uintptr, uintptr) { var buf [1812]byte; use(buf[:]); return Stackguard() }
+func stack1816() (uintptr, uintptr) { var buf [1816]byte; use(buf[:]); return Stackguard() }
+func stack1820() (uintptr, uintptr) { var buf [1820]byte; use(buf[:]); return Stackguard() }
+func stack1824() (uintptr, uintptr) { var buf [1824]byte; use(buf[:]); return Stackguard() }
+func stack1828() (uintptr, uintptr) { var buf [1828]byte; use(buf[:]); return Stackguard() }
+func stack1832() (uintptr, uintptr) { var buf [1832]byte; use(buf[:]); return Stackguard() }
+func stack1836() (uintptr, uintptr) { var buf [1836]byte; use(buf[:]); return Stackguard() }
+func stack1840() (uintptr, uintptr) { var buf [1840]byte; use(buf[:]); return Stackguard() }
+func stack1844() (uintptr, uintptr) { var buf [1844]byte; use(buf[:]); return Stackguard() }
+func stack1848() (uintptr, uintptr) { var buf [1848]byte; use(buf[:]); return Stackguard() }
+func stack1852() (uintptr, uintptr) { var buf [1852]byte; use(buf[:]); return Stackguard() }
+func stack1856() (uintptr, uintptr) { var buf [1856]byte; use(buf[:]); return Stackguard() }
+func stack1860() (uintptr, uintptr) { var buf [1860]byte; use(buf[:]); return Stackguard() }
+func stack1864() (uintptr, uintptr) { var buf [1864]byte; use(buf[:]); return Stackguard() }
+func stack1868() (uintptr, uintptr) { var buf [1868]byte; use(buf[:]); return Stackguard() }
+func stack1872() (uintptr, uintptr) { var buf [1872]byte; use(buf[:]); return Stackguard() }
+func stack1876() (uintptr, uintptr) { var buf [1876]byte; use(buf[:]); return Stackguard() }
+func stack1880() (uintptr, uintptr) { var buf [1880]byte; use(buf[:]); return Stackguard() }
+func stack1884() (uintptr, uintptr) { var buf [1884]byte; use(buf[:]); return Stackguard() }
+func stack1888() (uintptr, uintptr) { var buf [1888]byte; use(buf[:]); return Stackguard() }
+func stack1892() (uintptr, uintptr) { var buf [1892]byte; use(buf[:]); return Stackguard() }
+func stack1896() (uintptr, uintptr) { var buf [1896]byte; use(buf[:]); return Stackguard() }
+func stack1900() (uintptr, uintptr) { var buf [1900]byte; use(buf[:]); return Stackguard() }
+func stack1904() (uintptr, uintptr) { var buf [1904]byte; use(buf[:]); return Stackguard() }
+func stack1908() (uintptr, uintptr) { var buf [1908]byte; use(buf[:]); return Stackguard() }
+func stack1912() (uintptr, uintptr) { var buf [1912]byte; use(buf[:]); return Stackguard() }
+func stack1916() (uintptr, uintptr) { var buf [1916]byte; use(buf[:]); return Stackguard() }
+func stack1920() (uintptr, uintptr) { var buf [1920]byte; use(buf[:]); return Stackguard() }
+func stack1924() (uintptr, uintptr) { var buf [1924]byte; use(buf[:]); return Stackguard() }
+func stack1928() (uintptr, uintptr) { var buf [1928]byte; use(buf[:]); return Stackguard() }
+func stack1932() (uintptr, uintptr) { var buf [1932]byte; use(buf[:]); return Stackguard() }
+func stack1936() (uintptr, uintptr) { var buf [1936]byte; use(buf[:]); return Stackguard() }
+func stack1940() (uintptr, uintptr) { var buf [1940]byte; use(buf[:]); return Stackguard() }
+func stack1944() (uintptr, uintptr) { var buf [1944]byte; use(buf[:]); return Stackguard() }
+func stack1948() (uintptr, uintptr) { var buf [1948]byte; use(buf[:]); return Stackguard() }
+func stack1952() (uintptr, uintptr) { var buf [1952]byte; use(buf[:]); return Stackguard() }
+func stack1956() (uintptr, uintptr) { var buf [1956]byte; use(buf[:]); return Stackguard() }
+func stack1960() (uintptr, uintptr) { var buf [1960]byte; use(buf[:]); return Stackguard() }
+func stack1964() (uintptr, uintptr) { var buf [1964]byte; use(buf[:]); return Stackguard() }
+func stack1968() (uintptr, uintptr) { var buf [1968]byte; use(buf[:]); return Stackguard() }
+func stack1972() (uintptr, uintptr) { var buf [1972]byte; use(buf[:]); return Stackguard() }
+func stack1976() (uintptr, uintptr) { var buf [1976]byte; use(buf[:]); return Stackguard() }
+func stack1980() (uintptr, uintptr) { var buf [1980]byte; use(buf[:]); return Stackguard() }
+func stack1984() (uintptr, uintptr) { var buf [1984]byte; use(buf[:]); return Stackguard() }
+func stack1988() (uintptr, uintptr) { var buf [1988]byte; use(buf[:]); return Stackguard() }
+func stack1992() (uintptr, uintptr) { var buf [1992]byte; use(buf[:]); return Stackguard() }
+func stack1996() (uintptr, uintptr) { var buf [1996]byte; use(buf[:]); return Stackguard() }
+func stack2000() (uintptr, uintptr) { var buf [2000]byte; use(buf[:]); return Stackguard() }
+func stack2004() (uintptr, uintptr) { var buf [2004]byte; use(buf[:]); return Stackguard() }
+func stack2008() (uintptr, uintptr) { var buf [2008]byte; use(buf[:]); return Stackguard() }
+func stack2012() (uintptr, uintptr) { var buf [2012]byte; use(buf[:]); return Stackguard() }
+func stack2016() (uintptr, uintptr) { var buf [2016]byte; use(buf[:]); return Stackguard() }
+func stack2020() (uintptr, uintptr) { var buf [2020]byte; use(buf[:]); return Stackguard() }
+func stack2024() (uintptr, uintptr) { var buf [2024]byte; use(buf[:]); return Stackguard() }
+func stack2028() (uintptr, uintptr) { var buf [2028]byte; use(buf[:]); return Stackguard() }
+func stack2032() (uintptr, uintptr) { var buf [2032]byte; use(buf[:]); return Stackguard() }
+func stack2036() (uintptr, uintptr) { var buf [2036]byte; use(buf[:]); return Stackguard() }
+func stack2040() (uintptr, uintptr) { var buf [2040]byte; use(buf[:]); return Stackguard() }
+func stack2044() (uintptr, uintptr) { var buf [2044]byte; use(buf[:]); return Stackguard() }
+func stack2048() (uintptr, uintptr) { var buf [2048]byte; use(buf[:]); return Stackguard() }
+func stack2052() (uintptr, uintptr) { var buf [2052]byte; use(buf[:]); return Stackguard() }
+func stack2056() (uintptr, uintptr) { var buf [2056]byte; use(buf[:]); return Stackguard() }
+func stack2060() (uintptr, uintptr) { var buf [2060]byte; use(buf[:]); return Stackguard() }
+func stack2064() (uintptr, uintptr) { var buf [2064]byte; use(buf[:]); return Stackguard() }
+func stack2068() (uintptr, uintptr) { var buf [2068]byte; use(buf[:]); return Stackguard() }
+func stack2072() (uintptr, uintptr) { var buf [2072]byte; use(buf[:]); return Stackguard() }
+func stack2076() (uintptr, uintptr) { var buf [2076]byte; use(buf[:]); return Stackguard() }
+func stack2080() (uintptr, uintptr) { var buf [2080]byte; use(buf[:]); return Stackguard() }
+func stack2084() (uintptr, uintptr) { var buf [2084]byte; use(buf[:]); return Stackguard() }
+func stack2088() (uintptr, uintptr) { var buf [2088]byte; use(buf[:]); return Stackguard() }
+func stack2092() (uintptr, uintptr) { var buf [2092]byte; use(buf[:]); return Stackguard() }
+func stack2096() (uintptr, uintptr) { var buf [2096]byte; use(buf[:]); return Stackguard() }
+func stack2100() (uintptr, uintptr) { var buf [2100]byte; use(buf[:]); return Stackguard() }
+func stack2104() (uintptr, uintptr) { var buf [2104]byte; use(buf[:]); return Stackguard() }
+func stack2108() (uintptr, uintptr) { var buf [2108]byte; use(buf[:]); return Stackguard() }
+func stack2112() (uintptr, uintptr) { var buf [2112]byte; use(buf[:]); return Stackguard() }
+func stack2116() (uintptr, uintptr) { var buf [2116]byte; use(buf[:]); return Stackguard() }
+func stack2120() (uintptr, uintptr) { var buf [2120]byte; use(buf[:]); return Stackguard() }
+func stack2124() (uintptr, uintptr) { var buf [2124]byte; use(buf[:]); return Stackguard() }
+func stack2128() (uintptr, uintptr) { var buf [2128]byte; use(buf[:]); return Stackguard() }
+func stack2132() (uintptr, uintptr) { var buf [2132]byte; use(buf[:]); return Stackguard() }
+func stack2136() (uintptr, uintptr) { var buf [2136]byte; use(buf[:]); return Stackguard() }
+func stack2140() (uintptr, uintptr) { var buf [2140]byte; use(buf[:]); return Stackguard() }
+func stack2144() (uintptr, uintptr) { var buf [2144]byte; use(buf[:]); return Stackguard() }
+func stack2148() (uintptr, uintptr) { var buf [2148]byte; use(buf[:]); return Stackguard() }
+func stack2152() (uintptr, uintptr) { var buf [2152]byte; use(buf[:]); return Stackguard() }
+func stack2156() (uintptr, uintptr) { var buf [2156]byte; use(buf[:]); return Stackguard() }
+func stack2160() (uintptr, uintptr) { var buf [2160]byte; use(buf[:]); return Stackguard() }
+func stack2164() (uintptr, uintptr) { var buf [2164]byte; use(buf[:]); return Stackguard() }
+func stack2168() (uintptr, uintptr) { var buf [2168]byte; use(buf[:]); return Stackguard() }
+func stack2172() (uintptr, uintptr) { var buf [2172]byte; use(buf[:]); return Stackguard() }
+func stack2176() (uintptr, uintptr) { var buf [2176]byte; use(buf[:]); return Stackguard() }
+func stack2180() (uintptr, uintptr) { var buf [2180]byte; use(buf[:]); return Stackguard() }
+func stack2184() (uintptr, uintptr) { var buf [2184]byte; use(buf[:]); return Stackguard() }
+func stack2188() (uintptr, uintptr) { var buf [2188]byte; use(buf[:]); return Stackguard() }
+func stack2192() (uintptr, uintptr) { var buf [2192]byte; use(buf[:]); return Stackguard() }
+func stack2196() (uintptr, uintptr) { var buf [2196]byte; use(buf[:]); return Stackguard() }
+func stack2200() (uintptr, uintptr) { var buf [2200]byte; use(buf[:]); return Stackguard() }
+func stack2204() (uintptr, uintptr) { var buf [2204]byte; use(buf[:]); return Stackguard() }
+func stack2208() (uintptr, uintptr) { var buf [2208]byte; use(buf[:]); return Stackguard() }
+func stack2212() (uintptr, uintptr) { var buf [2212]byte; use(buf[:]); return Stackguard() }
+func stack2216() (uintptr, uintptr) { var buf [2216]byte; use(buf[:]); return Stackguard() }
+func stack2220() (uintptr, uintptr) { var buf [2220]byte; use(buf[:]); return Stackguard() }
+func stack2224() (uintptr, uintptr) { var buf [2224]byte; use(buf[:]); return Stackguard() }
+func stack2228() (uintptr, uintptr) { var buf [2228]byte; use(buf[:]); return Stackguard() }
+func stack2232() (uintptr, uintptr) { var buf [2232]byte; use(buf[:]); return Stackguard() }
+func stack2236() (uintptr, uintptr) { var buf [2236]byte; use(buf[:]); return Stackguard() }
+func stack2240() (uintptr, uintptr) { var buf [2240]byte; use(buf[:]); return Stackguard() }
+func stack2244() (uintptr, uintptr) { var buf [2244]byte; use(buf[:]); return Stackguard() }
+func stack2248() (uintptr, uintptr) { var buf [2248]byte; use(buf[:]); return Stackguard() }
+func stack2252() (uintptr, uintptr) { var buf [2252]byte; use(buf[:]); return Stackguard() }
+func stack2256() (uintptr, uintptr) { var buf [2256]byte; use(buf[:]); return Stackguard() }
+func stack2260() (uintptr, uintptr) { var buf [2260]byte; use(buf[:]); return Stackguard() }
+func stack2264() (uintptr, uintptr) { var buf [2264]byte; use(buf[:]); return Stackguard() }
+func stack2268() (uintptr, uintptr) { var buf [2268]byte; use(buf[:]); return Stackguard() }
+func stack2272() (uintptr, uintptr) { var buf [2272]byte; use(buf[:]); return Stackguard() }
+func stack2276() (uintptr, uintptr) { var buf [2276]byte; use(buf[:]); return Stackguard() }
+func stack2280() (uintptr, uintptr) { var buf [2280]byte; use(buf[:]); return Stackguard() }
+func stack2284() (uintptr, uintptr) { var buf [2284]byte; use(buf[:]); return Stackguard() }
+func stack2288() (uintptr, uintptr) { var buf [2288]byte; use(buf[:]); return Stackguard() }
+func stack2292() (uintptr, uintptr) { var buf [2292]byte; use(buf[:]); return Stackguard() }
+func stack2296() (uintptr, uintptr) { var buf [2296]byte; use(buf[:]); return Stackguard() }
+func stack2300() (uintptr, uintptr) { var buf [2300]byte; use(buf[:]); return Stackguard() }
+func stack2304() (uintptr, uintptr) { var buf [2304]byte; use(buf[:]); return Stackguard() }
+func stack2308() (uintptr, uintptr) { var buf [2308]byte; use(buf[:]); return Stackguard() }
+func stack2312() (uintptr, uintptr) { var buf [2312]byte; use(buf[:]); return Stackguard() }
+func stack2316() (uintptr, uintptr) { var buf [2316]byte; use(buf[:]); return Stackguard() }
+func stack2320() (uintptr, uintptr) { var buf [2320]byte; use(buf[:]); return Stackguard() }
+func stack2324() (uintptr, uintptr) { var buf [2324]byte; use(buf[:]); return Stackguard() }
+func stack2328() (uintptr, uintptr) { var buf [2328]byte; use(buf[:]); return Stackguard() }
+func stack2332() (uintptr, uintptr) { var buf [2332]byte; use(buf[:]); return Stackguard() }
+func stack2336() (uintptr, uintptr) { var buf [2336]byte; use(buf[:]); return Stackguard() }
+func stack2340() (uintptr, uintptr) { var buf [2340]byte; use(buf[:]); return Stackguard() }
+func stack2344() (uintptr, uintptr) { var buf [2344]byte; use(buf[:]); return Stackguard() }
+func stack2348() (uintptr, uintptr) { var buf [2348]byte; use(buf[:]); return Stackguard() }
+func stack2352() (uintptr, uintptr) { var buf [2352]byte; use(buf[:]); return Stackguard() }
+func stack2356() (uintptr, uintptr) { var buf [2356]byte; use(buf[:]); return Stackguard() }
+func stack2360() (uintptr, uintptr) { var buf [2360]byte; use(buf[:]); return Stackguard() }
+func stack2364() (uintptr, uintptr) { var buf [2364]byte; use(buf[:]); return Stackguard() }
+func stack2368() (uintptr, uintptr) { var buf [2368]byte; use(buf[:]); return Stackguard() }
+func stack2372() (uintptr, uintptr) { var buf [2372]byte; use(buf[:]); return Stackguard() }
+func stack2376() (uintptr, uintptr) { var buf [2376]byte; use(buf[:]); return Stackguard() }
+func stack2380() (uintptr, uintptr) { var buf [2380]byte; use(buf[:]); return Stackguard() }
+func stack2384() (uintptr, uintptr) { var buf [2384]byte; use(buf[:]); return Stackguard() }
+func stack2388() (uintptr, uintptr) { var buf [2388]byte; use(buf[:]); return Stackguard() }
+func stack2392() (uintptr, uintptr) { var buf [2392]byte; use(buf[:]); return Stackguard() }
+func stack2396() (uintptr, uintptr) { var buf [2396]byte; use(buf[:]); return Stackguard() }
+func stack2400() (uintptr, uintptr) { var buf [2400]byte; use(buf[:]); return Stackguard() }
+func stack2404() (uintptr, uintptr) { var buf [2404]byte; use(buf[:]); return Stackguard() }
+func stack2408() (uintptr, uintptr) { var buf [2408]byte; use(buf[:]); return Stackguard() }
+func stack2412() (uintptr, uintptr) { var buf [2412]byte; use(buf[:]); return Stackguard() }
+func stack2416() (uintptr, uintptr) { var buf [2416]byte; use(buf[:]); return Stackguard() }
+func stack2420() (uintptr, uintptr) { var buf [2420]byte; use(buf[:]); return Stackguard() }
+func stack2424() (uintptr, uintptr) { var buf [2424]byte; use(buf[:]); return Stackguard() }
+func stack2428() (uintptr, uintptr) { var buf [2428]byte; use(buf[:]); return Stackguard() }
+func stack2432() (uintptr, uintptr) { var buf [2432]byte; use(buf[:]); return Stackguard() }
+func stack2436() (uintptr, uintptr) { var buf [2436]byte; use(buf[:]); return Stackguard() }
+func stack2440() (uintptr, uintptr) { var buf [2440]byte; use(buf[:]); return Stackguard() }
+func stack2444() (uintptr, uintptr) { var buf [2444]byte; use(buf[:]); return Stackguard() }
+func stack2448() (uintptr, uintptr) { var buf [2448]byte; use(buf[:]); return Stackguard() }
+func stack2452() (uintptr, uintptr) { var buf [2452]byte; use(buf[:]); return Stackguard() }
+func stack2456() (uintptr, uintptr) { var buf [2456]byte; use(buf[:]); return Stackguard() }
+func stack2460() (uintptr, uintptr) { var buf [2460]byte; use(buf[:]); return Stackguard() }
+func stack2464() (uintptr, uintptr) { var buf [2464]byte; use(buf[:]); return Stackguard() }
+func stack2468() (uintptr, uintptr) { var buf [2468]byte; use(buf[:]); return Stackguard() }
+func stack2472() (uintptr, uintptr) { var buf [2472]byte; use(buf[:]); return Stackguard() }
+func stack2476() (uintptr, uintptr) { var buf [2476]byte; use(buf[:]); return Stackguard() }
+func stack2480() (uintptr, uintptr) { var buf [2480]byte; use(buf[:]); return Stackguard() }
+func stack2484() (uintptr, uintptr) { var buf [2484]byte; use(buf[:]); return Stackguard() }
+func stack2488() (uintptr, uintptr) { var buf [2488]byte; use(buf[:]); return Stackguard() }
+func stack2492() (uintptr, uintptr) { var buf [2492]byte; use(buf[:]); return Stackguard() }
+func stack2496() (uintptr, uintptr) { var buf [2496]byte; use(buf[:]); return Stackguard() }
+func stack2500() (uintptr, uintptr) { var buf [2500]byte; use(buf[:]); return Stackguard() }
+func stack2504() (uintptr, uintptr) { var buf [2504]byte; use(buf[:]); return Stackguard() }
+func stack2508() (uintptr, uintptr) { var buf [2508]byte; use(buf[:]); return Stackguard() }
+func stack2512() (uintptr, uintptr) { var buf [2512]byte; use(buf[:]); return Stackguard() }
+func stack2516() (uintptr, uintptr) { var buf [2516]byte; use(buf[:]); return Stackguard() }
+func stack2520() (uintptr, uintptr) { var buf [2520]byte; use(buf[:]); return Stackguard() }
+func stack2524() (uintptr, uintptr) { var buf [2524]byte; use(buf[:]); return Stackguard() }
+func stack2528() (uintptr, uintptr) { var buf [2528]byte; use(buf[:]); return Stackguard() }
+func stack2532() (uintptr, uintptr) { var buf [2532]byte; use(buf[:]); return Stackguard() }
+func stack2536() (uintptr, uintptr) { var buf [2536]byte; use(buf[:]); return Stackguard() }
+func stack2540() (uintptr, uintptr) { var buf [2540]byte; use(buf[:]); return Stackguard() }
+func stack2544() (uintptr, uintptr) { var buf [2544]byte; use(buf[:]); return Stackguard() }
+func stack2548() (uintptr, uintptr) { var buf [2548]byte; use(buf[:]); return Stackguard() }
+func stack2552() (uintptr, uintptr) { var buf [2552]byte; use(buf[:]); return Stackguard() }
+func stack2556() (uintptr, uintptr) { var buf [2556]byte; use(buf[:]); return Stackguard() }
+func stack2560() (uintptr, uintptr) { var buf [2560]byte; use(buf[:]); return Stackguard() }
+func stack2564() (uintptr, uintptr) { var buf [2564]byte; use(buf[:]); return Stackguard() }
+func stack2568() (uintptr, uintptr) { var buf [2568]byte; use(buf[:]); return Stackguard() }
+func stack2572() (uintptr, uintptr) { var buf [2572]byte; use(buf[:]); return Stackguard() }
+func stack2576() (uintptr, uintptr) { var buf [2576]byte; use(buf[:]); return Stackguard() }
+func stack2580() (uintptr, uintptr) { var buf [2580]byte; use(buf[:]); return Stackguard() }
+func stack2584() (uintptr, uintptr) { var buf [2584]byte; use(buf[:]); return Stackguard() }
+func stack2588() (uintptr, uintptr) { var buf [2588]byte; use(buf[:]); return Stackguard() }
+func stack2592() (uintptr, uintptr) { var buf [2592]byte; use(buf[:]); return Stackguard() }
+func stack2596() (uintptr, uintptr) { var buf [2596]byte; use(buf[:]); return Stackguard() }
+func stack2600() (uintptr, uintptr) { var buf [2600]byte; use(buf[:]); return Stackguard() }
+func stack2604() (uintptr, uintptr) { var buf [2604]byte; use(buf[:]); return Stackguard() }
+func stack2608() (uintptr, uintptr) { var buf [2608]byte; use(buf[:]); return Stackguard() }
+func stack2612() (uintptr, uintptr) { var buf [2612]byte; use(buf[:]); return Stackguard() }
+func stack2616() (uintptr, uintptr) { var buf [2616]byte; use(buf[:]); return Stackguard() }
+func stack2620() (uintptr, uintptr) { var buf [2620]byte; use(buf[:]); return Stackguard() }
+func stack2624() (uintptr, uintptr) { var buf [2624]byte; use(buf[:]); return Stackguard() }
+func stack2628() (uintptr, uintptr) { var buf [2628]byte; use(buf[:]); return Stackguard() }
+func stack2632() (uintptr, uintptr) { var buf [2632]byte; use(buf[:]); return Stackguard() }
+func stack2636() (uintptr, uintptr) { var buf [2636]byte; use(buf[:]); return Stackguard() }
+func stack2640() (uintptr, uintptr) { var buf [2640]byte; use(buf[:]); return Stackguard() }
+func stack2644() (uintptr, uintptr) { var buf [2644]byte; use(buf[:]); return Stackguard() }
+func stack2648() (uintptr, uintptr) { var buf [2648]byte; use(buf[:]); return Stackguard() }
+func stack2652() (uintptr, uintptr) { var buf [2652]byte; use(buf[:]); return Stackguard() }
+func stack2656() (uintptr, uintptr) { var buf [2656]byte; use(buf[:]); return Stackguard() }
+func stack2660() (uintptr, uintptr) { var buf [2660]byte; use(buf[:]); return Stackguard() }
+func stack2664() (uintptr, uintptr) { var buf [2664]byte; use(buf[:]); return Stackguard() }
+func stack2668() (uintptr, uintptr) { var buf [2668]byte; use(buf[:]); return Stackguard() }
+func stack2672() (uintptr, uintptr) { var buf [2672]byte; use(buf[:]); return Stackguard() }
+func stack2676() (uintptr, uintptr) { var buf [2676]byte; use(buf[:]); return Stackguard() }
+func stack2680() (uintptr, uintptr) { var buf [2680]byte; use(buf[:]); return Stackguard() }
+func stack2684() (uintptr, uintptr) { var buf [2684]byte; use(buf[:]); return Stackguard() }
+func stack2688() (uintptr, uintptr) { var buf [2688]byte; use(buf[:]); return Stackguard() }
+func stack2692() (uintptr, uintptr) { var buf [2692]byte; use(buf[:]); return Stackguard() }
+func stack2696() (uintptr, uintptr) { var buf [2696]byte; use(buf[:]); return Stackguard() }
+func stack2700() (uintptr, uintptr) { var buf [2700]byte; use(buf[:]); return Stackguard() }
+func stack2704() (uintptr, uintptr) { var buf [2704]byte; use(buf[:]); return Stackguard() }
+func stack2708() (uintptr, uintptr) { var buf [2708]byte; use(buf[:]); return Stackguard() }
+func stack2712() (uintptr, uintptr) { var buf [2712]byte; use(buf[:]); return Stackguard() }
+func stack2716() (uintptr, uintptr) { var buf [2716]byte; use(buf[:]); return Stackguard() }
+func stack2720() (uintptr, uintptr) { var buf [2720]byte; use(buf[:]); return Stackguard() }
+func stack2724() (uintptr, uintptr) { var buf [2724]byte; use(buf[:]); return Stackguard() }
+func stack2728() (uintptr, uintptr) { var buf [2728]byte; use(buf[:]); return Stackguard() }
+func stack2732() (uintptr, uintptr) { var buf [2732]byte; use(buf[:]); return Stackguard() }
+func stack2736() (uintptr, uintptr) { var buf [2736]byte; use(buf[:]); return Stackguard() }
+func stack2740() (uintptr, uintptr) { var buf [2740]byte; use(buf[:]); return Stackguard() }
+func stack2744() (uintptr, uintptr) { var buf [2744]byte; use(buf[:]); return Stackguard() }
+func stack2748() (uintptr, uintptr) { var buf [2748]byte; use(buf[:]); return Stackguard() }
+func stack2752() (uintptr, uintptr) { var buf [2752]byte; use(buf[:]); return Stackguard() }
+func stack2756() (uintptr, uintptr) { var buf [2756]byte; use(buf[:]); return Stackguard() }
+func stack2760() (uintptr, uintptr) { var buf [2760]byte; use(buf[:]); return Stackguard() }
+func stack2764() (uintptr, uintptr) { var buf [2764]byte; use(buf[:]); return Stackguard() }
+func stack2768() (uintptr, uintptr) { var buf [2768]byte; use(buf[:]); return Stackguard() }
+func stack2772() (uintptr, uintptr) { var buf [2772]byte; use(buf[:]); return Stackguard() }
+func stack2776() (uintptr, uintptr) { var buf [2776]byte; use(buf[:]); return Stackguard() }
+func stack2780() (uintptr, uintptr) { var buf [2780]byte; use(buf[:]); return Stackguard() }
+func stack2784() (uintptr, uintptr) { var buf [2784]byte; use(buf[:]); return Stackguard() }
+func stack2788() (uintptr, uintptr) { var buf [2788]byte; use(buf[:]); return Stackguard() }
+func stack2792() (uintptr, uintptr) { var buf [2792]byte; use(buf[:]); return Stackguard() }
+func stack2796() (uintptr, uintptr) { var buf [2796]byte; use(buf[:]); return Stackguard() }
+func stack2800() (uintptr, uintptr) { var buf [2800]byte; use(buf[:]); return Stackguard() }
+func stack2804() (uintptr, uintptr) { var buf [2804]byte; use(buf[:]); return Stackguard() }
+func stack2808() (uintptr, uintptr) { var buf [2808]byte; use(buf[:]); return Stackguard() }
+func stack2812() (uintptr, uintptr) { var buf [2812]byte; use(buf[:]); return Stackguard() }
+func stack2816() (uintptr, uintptr) { var buf [2816]byte; use(buf[:]); return Stackguard() }
+func stack2820() (uintptr, uintptr) { var buf [2820]byte; use(buf[:]); return Stackguard() }
+func stack2824() (uintptr, uintptr) { var buf [2824]byte; use(buf[:]); return Stackguard() }
+func stack2828() (uintptr, uintptr) { var buf [2828]byte; use(buf[:]); return Stackguard() }
+func stack2832() (uintptr, uintptr) { var buf [2832]byte; use(buf[:]); return Stackguard() }
+func stack2836() (uintptr, uintptr) { var buf [2836]byte; use(buf[:]); return Stackguard() }
+func stack2840() (uintptr, uintptr) { var buf [2840]byte; use(buf[:]); return Stackguard() }
+func stack2844() (uintptr, uintptr) { var buf [2844]byte; use(buf[:]); return Stackguard() }
+func stack2848() (uintptr, uintptr) { var buf [2848]byte; use(buf[:]); return Stackguard() }
+func stack2852() (uintptr, uintptr) { var buf [2852]byte; use(buf[:]); return Stackguard() }
+func stack2856() (uintptr, uintptr) { var buf [2856]byte; use(buf[:]); return Stackguard() }
+func stack2860() (uintptr, uintptr) { var buf [2860]byte; use(buf[:]); return Stackguard() }
+func stack2864() (uintptr, uintptr) { var buf [2864]byte; use(buf[:]); return Stackguard() }
+func stack2868() (uintptr, uintptr) { var buf [2868]byte; use(buf[:]); return Stackguard() }
+func stack2872() (uintptr, uintptr) { var buf [2872]byte; use(buf[:]); return Stackguard() }
+func stack2876() (uintptr, uintptr) { var buf [2876]byte; use(buf[:]); return Stackguard() }
+func stack2880() (uintptr, uintptr) { var buf [2880]byte; use(buf[:]); return Stackguard() }
+func stack2884() (uintptr, uintptr) { var buf [2884]byte; use(buf[:]); return Stackguard() }
+func stack2888() (uintptr, uintptr) { var buf [2888]byte; use(buf[:]); return Stackguard() }
+func stack2892() (uintptr, uintptr) { var buf [2892]byte; use(buf[:]); return Stackguard() }
+func stack2896() (uintptr, uintptr) { var buf [2896]byte; use(buf[:]); return Stackguard() }
+func stack2900() (uintptr, uintptr) { var buf [2900]byte; use(buf[:]); return Stackguard() }
+func stack2904() (uintptr, uintptr) { var buf [2904]byte; use(buf[:]); return Stackguard() }
+func stack2908() (uintptr, uintptr) { var buf [2908]byte; use(buf[:]); return Stackguard() }
+func stack2912() (uintptr, uintptr) { var buf [2912]byte; use(buf[:]); return Stackguard() }
+func stack2916() (uintptr, uintptr) { var buf [2916]byte; use(buf[:]); return Stackguard() }
+func stack2920() (uintptr, uintptr) { var buf [2920]byte; use(buf[:]); return Stackguard() }
+func stack2924() (uintptr, uintptr) { var buf [2924]byte; use(buf[:]); return Stackguard() }
+func stack2928() (uintptr, uintptr) { var buf [2928]byte; use(buf[:]); return Stackguard() }
+func stack2932() (uintptr, uintptr) { var buf [2932]byte; use(buf[:]); return Stackguard() }
+func stack2936() (uintptr, uintptr) { var buf [2936]byte; use(buf[:]); return Stackguard() }
+func stack2940() (uintptr, uintptr) { var buf [2940]byte; use(buf[:]); return Stackguard() }
+func stack2944() (uintptr, uintptr) { var buf [2944]byte; use(buf[:]); return Stackguard() }
+func stack2948() (uintptr, uintptr) { var buf [2948]byte; use(buf[:]); return Stackguard() }
+func stack2952() (uintptr, uintptr) { var buf [2952]byte; use(buf[:]); return Stackguard() }
+func stack2956() (uintptr, uintptr) { var buf [2956]byte; use(buf[:]); return Stackguard() }
+func stack2960() (uintptr, uintptr) { var buf [2960]byte; use(buf[:]); return Stackguard() }
+func stack2964() (uintptr, uintptr) { var buf [2964]byte; use(buf[:]); return Stackguard() }
+func stack2968() (uintptr, uintptr) { var buf [2968]byte; use(buf[:]); return Stackguard() }
+func stack2972() (uintptr, uintptr) { var buf [2972]byte; use(buf[:]); return Stackguard() }
+func stack2976() (uintptr, uintptr) { var buf [2976]byte; use(buf[:]); return Stackguard() }
+func stack2980() (uintptr, uintptr) { var buf [2980]byte; use(buf[:]); return Stackguard() }
+func stack2984() (uintptr, uintptr) { var buf [2984]byte; use(buf[:]); return Stackguard() }
+func stack2988() (uintptr, uintptr) { var buf [2988]byte; use(buf[:]); return Stackguard() }
+func stack2992() (uintptr, uintptr) { var buf [2992]byte; use(buf[:]); return Stackguard() }
+func stack2996() (uintptr, uintptr) { var buf [2996]byte; use(buf[:]); return Stackguard() }
+func stack3000() (uintptr, uintptr) { var buf [3000]byte; use(buf[:]); return Stackguard() }
+func stack3004() (uintptr, uintptr) { var buf [3004]byte; use(buf[:]); return Stackguard() }
+func stack3008() (uintptr, uintptr) { var buf [3008]byte; use(buf[:]); return Stackguard() }
+func stack3012() (uintptr, uintptr) { var buf [3012]byte; use(buf[:]); return Stackguard() }
+func stack3016() (uintptr, uintptr) { var buf [3016]byte; use(buf[:]); return Stackguard() }
+func stack3020() (uintptr, uintptr) { var buf [3020]byte; use(buf[:]); return Stackguard() }
+func stack3024() (uintptr, uintptr) { var buf [3024]byte; use(buf[:]); return Stackguard() }
+func stack3028() (uintptr, uintptr) { var buf [3028]byte; use(buf[:]); return Stackguard() }
+func stack3032() (uintptr, uintptr) { var buf [3032]byte; use(buf[:]); return Stackguard() }
+func stack3036() (uintptr, uintptr) { var buf [3036]byte; use(buf[:]); return Stackguard() }
+func stack3040() (uintptr, uintptr) { var buf [3040]byte; use(buf[:]); return Stackguard() }
+func stack3044() (uintptr, uintptr) { var buf [3044]byte; use(buf[:]); return Stackguard() }
+func stack3048() (uintptr, uintptr) { var buf [3048]byte; use(buf[:]); return Stackguard() }
+func stack3052() (uintptr, uintptr) { var buf [3052]byte; use(buf[:]); return Stackguard() }
+func stack3056() (uintptr, uintptr) { var buf [3056]byte; use(buf[:]); return Stackguard() }
+func stack3060() (uintptr, uintptr) { var buf [3060]byte; use(buf[:]); return Stackguard() }
+func stack3064() (uintptr, uintptr) { var buf [3064]byte; use(buf[:]); return Stackguard() }
+func stack3068() (uintptr, uintptr) { var buf [3068]byte; use(buf[:]); return Stackguard() }
+func stack3072() (uintptr, uintptr) { var buf [3072]byte; use(buf[:]); return Stackguard() }
+func stack3076() (uintptr, uintptr) { var buf [3076]byte; use(buf[:]); return Stackguard() }
+func stack3080() (uintptr, uintptr) { var buf [3080]byte; use(buf[:]); return Stackguard() }
+func stack3084() (uintptr, uintptr) { var buf [3084]byte; use(buf[:]); return Stackguard() }
+func stack3088() (uintptr, uintptr) { var buf [3088]byte; use(buf[:]); return Stackguard() }
+func stack3092() (uintptr, uintptr) { var buf [3092]byte; use(buf[:]); return Stackguard() }
+func stack3096() (uintptr, uintptr) { var buf [3096]byte; use(buf[:]); return Stackguard() }
+func stack3100() (uintptr, uintptr) { var buf [3100]byte; use(buf[:]); return Stackguard() }
+func stack3104() (uintptr, uintptr) { var buf [3104]byte; use(buf[:]); return Stackguard() }
+func stack3108() (uintptr, uintptr) { var buf [3108]byte; use(buf[:]); return Stackguard() }
+func stack3112() (uintptr, uintptr) { var buf [3112]byte; use(buf[:]); return Stackguard() }
+func stack3116() (uintptr, uintptr) { var buf [3116]byte; use(buf[:]); return Stackguard() }
+func stack3120() (uintptr, uintptr) { var buf [3120]byte; use(buf[:]); return Stackguard() }
+func stack3124() (uintptr, uintptr) { var buf [3124]byte; use(buf[:]); return Stackguard() }
+func stack3128() (uintptr, uintptr) { var buf [3128]byte; use(buf[:]); return Stackguard() }
+func stack3132() (uintptr, uintptr) { var buf [3132]byte; use(buf[:]); return Stackguard() }
+func stack3136() (uintptr, uintptr) { var buf [3136]byte; use(buf[:]); return Stackguard() }
+func stack3140() (uintptr, uintptr) { var buf [3140]byte; use(buf[:]); return Stackguard() }
+func stack3144() (uintptr, uintptr) { var buf [3144]byte; use(buf[:]); return Stackguard() }
+func stack3148() (uintptr, uintptr) { var buf [3148]byte; use(buf[:]); return Stackguard() }
+func stack3152() (uintptr, uintptr) { var buf [3152]byte; use(buf[:]); return Stackguard() }
+func stack3156() (uintptr, uintptr) { var buf [3156]byte; use(buf[:]); return Stackguard() }
+func stack3160() (uintptr, uintptr) { var buf [3160]byte; use(buf[:]); return Stackguard() }
+func stack3164() (uintptr, uintptr) { var buf [3164]byte; use(buf[:]); return Stackguard() }
+func stack3168() (uintptr, uintptr) { var buf [3168]byte; use(buf[:]); return Stackguard() }
+func stack3172() (uintptr, uintptr) { var buf [3172]byte; use(buf[:]); return Stackguard() }
+func stack3176() (uintptr, uintptr) { var buf [3176]byte; use(buf[:]); return Stackguard() }
+func stack3180() (uintptr, uintptr) { var buf [3180]byte; use(buf[:]); return Stackguard() }
+func stack3184() (uintptr, uintptr) { var buf [3184]byte; use(buf[:]); return Stackguard() }
+func stack3188() (uintptr, uintptr) { var buf [3188]byte; use(buf[:]); return Stackguard() }
+func stack3192() (uintptr, uintptr) { var buf [3192]byte; use(buf[:]); return Stackguard() }
+func stack3196() (uintptr, uintptr) { var buf [3196]byte; use(buf[:]); return Stackguard() }
+func stack3200() (uintptr, uintptr) { var buf [3200]byte; use(buf[:]); return Stackguard() }
+func stack3204() (uintptr, uintptr) { var buf [3204]byte; use(buf[:]); return Stackguard() }
+func stack3208() (uintptr, uintptr) { var buf [3208]byte; use(buf[:]); return Stackguard() }
+func stack3212() (uintptr, uintptr) { var buf [3212]byte; use(buf[:]); return Stackguard() }
+func stack3216() (uintptr, uintptr) { var buf [3216]byte; use(buf[:]); return Stackguard() }
+func stack3220() (uintptr, uintptr) { var buf [3220]byte; use(buf[:]); return Stackguard() }
+func stack3224() (uintptr, uintptr) { var buf [3224]byte; use(buf[:]); return Stackguard() }
+func stack3228() (uintptr, uintptr) { var buf [3228]byte; use(buf[:]); return Stackguard() }
+func stack3232() (uintptr, uintptr) { var buf [3232]byte; use(buf[:]); return Stackguard() }
+func stack3236() (uintptr, uintptr) { var buf [3236]byte; use(buf[:]); return Stackguard() }
+func stack3240() (uintptr, uintptr) { var buf [3240]byte; use(buf[:]); return Stackguard() }
+func stack3244() (uintptr, uintptr) { var buf [3244]byte; use(buf[:]); return Stackguard() }
+func stack3248() (uintptr, uintptr) { var buf [3248]byte; use(buf[:]); return Stackguard() }
+func stack3252() (uintptr, uintptr) { var buf [3252]byte; use(buf[:]); return Stackguard() }
+func stack3256() (uintptr, uintptr) { var buf [3256]byte; use(buf[:]); return Stackguard() }
+func stack3260() (uintptr, uintptr) { var buf [3260]byte; use(buf[:]); return Stackguard() }
+func stack3264() (uintptr, uintptr) { var buf [3264]byte; use(buf[:]); return Stackguard() }
+func stack3268() (uintptr, uintptr) { var buf [3268]byte; use(buf[:]); return Stackguard() }
+func stack3272() (uintptr, uintptr) { var buf [3272]byte; use(buf[:]); return Stackguard() }
+func stack3276() (uintptr, uintptr) { var buf [3276]byte; use(buf[:]); return Stackguard() }
+func stack3280() (uintptr, uintptr) { var buf [3280]byte; use(buf[:]); return Stackguard() }
+func stack3284() (uintptr, uintptr) { var buf [3284]byte; use(buf[:]); return Stackguard() }
+func stack3288() (uintptr, uintptr) { var buf [3288]byte; use(buf[:]); return Stackguard() }
+func stack3292() (uintptr, uintptr) { var buf [3292]byte; use(buf[:]); return Stackguard() }
+func stack3296() (uintptr, uintptr) { var buf [3296]byte; use(buf[:]); return Stackguard() }
+func stack3300() (uintptr, uintptr) { var buf [3300]byte; use(buf[:]); return Stackguard() }
+func stack3304() (uintptr, uintptr) { var buf [3304]byte; use(buf[:]); return Stackguard() }
+func stack3308() (uintptr, uintptr) { var buf [3308]byte; use(buf[:]); return Stackguard() }
+func stack3312() (uintptr, uintptr) { var buf [3312]byte; use(buf[:]); return Stackguard() }
+func stack3316() (uintptr, uintptr) { var buf [3316]byte; use(buf[:]); return Stackguard() }
+func stack3320() (uintptr, uintptr) { var buf [3320]byte; use(buf[:]); return Stackguard() }
+func stack3324() (uintptr, uintptr) { var buf [3324]byte; use(buf[:]); return Stackguard() }
+func stack3328() (uintptr, uintptr) { var buf [3328]byte; use(buf[:]); return Stackguard() }
+func stack3332() (uintptr, uintptr) { var buf [3332]byte; use(buf[:]); return Stackguard() }
+func stack3336() (uintptr, uintptr) { var buf [3336]byte; use(buf[:]); return Stackguard() }
+func stack3340() (uintptr, uintptr) { var buf [3340]byte; use(buf[:]); return Stackguard() }
+func stack3344() (uintptr, uintptr) { var buf [3344]byte; use(buf[:]); return Stackguard() }
+func stack3348() (uintptr, uintptr) { var buf [3348]byte; use(buf[:]); return Stackguard() }
+func stack3352() (uintptr, uintptr) { var buf [3352]byte; use(buf[:]); return Stackguard() }
+func stack3356() (uintptr, uintptr) { var buf [3356]byte; use(buf[:]); return Stackguard() }
+func stack3360() (uintptr, uintptr) { var buf [3360]byte; use(buf[:]); return Stackguard() }
+func stack3364() (uintptr, uintptr) { var buf [3364]byte; use(buf[:]); return Stackguard() }
+func stack3368() (uintptr, uintptr) { var buf [3368]byte; use(buf[:]); return Stackguard() }
+func stack3372() (uintptr, uintptr) { var buf [3372]byte; use(buf[:]); return Stackguard() }
+func stack3376() (uintptr, uintptr) { var buf [3376]byte; use(buf[:]); return Stackguard() }
+func stack3380() (uintptr, uintptr) { var buf [3380]byte; use(buf[:]); return Stackguard() }
+func stack3384() (uintptr, uintptr) { var buf [3384]byte; use(buf[:]); return Stackguard() }
+func stack3388() (uintptr, uintptr) { var buf [3388]byte; use(buf[:]); return Stackguard() }
+func stack3392() (uintptr, uintptr) { var buf [3392]byte; use(buf[:]); return Stackguard() }
+func stack3396() (uintptr, uintptr) { var buf [3396]byte; use(buf[:]); return Stackguard() }
+func stack3400() (uintptr, uintptr) { var buf [3400]byte; use(buf[:]); return Stackguard() }
+func stack3404() (uintptr, uintptr) { var buf [3404]byte; use(buf[:]); return Stackguard() }
+func stack3408() (uintptr, uintptr) { var buf [3408]byte; use(buf[:]); return Stackguard() }
+func stack3412() (uintptr, uintptr) { var buf [3412]byte; use(buf[:]); return Stackguard() }
+func stack3416() (uintptr, uintptr) { var buf [3416]byte; use(buf[:]); return Stackguard() }
+func stack3420() (uintptr, uintptr) { var buf [3420]byte; use(buf[:]); return Stackguard() }
+func stack3424() (uintptr, uintptr) { var buf [3424]byte; use(buf[:]); return Stackguard() }
+func stack3428() (uintptr, uintptr) { var buf [3428]byte; use(buf[:]); return Stackguard() }
+func stack3432() (uintptr, uintptr) { var buf [3432]byte; use(buf[:]); return Stackguard() }
+func stack3436() (uintptr, uintptr) { var buf [3436]byte; use(buf[:]); return Stackguard() }
+func stack3440() (uintptr, uintptr) { var buf [3440]byte; use(buf[:]); return Stackguard() }
+func stack3444() (uintptr, uintptr) { var buf [3444]byte; use(buf[:]); return Stackguard() }
+func stack3448() (uintptr, uintptr) { var buf [3448]byte; use(buf[:]); return Stackguard() }
+func stack3452() (uintptr, uintptr) { var buf [3452]byte; use(buf[:]); return Stackguard() }
+func stack3456() (uintptr, uintptr) { var buf [3456]byte; use(buf[:]); return Stackguard() }
+func stack3460() (uintptr, uintptr) { var buf [3460]byte; use(buf[:]); return Stackguard() }
+func stack3464() (uintptr, uintptr) { var buf [3464]byte; use(buf[:]); return Stackguard() }
+func stack3468() (uintptr, uintptr) { var buf [3468]byte; use(buf[:]); return Stackguard() }
+func stack3472() (uintptr, uintptr) { var buf [3472]byte; use(buf[:]); return Stackguard() }
+func stack3476() (uintptr, uintptr) { var buf [3476]byte; use(buf[:]); return Stackguard() }
+func stack3480() (uintptr, uintptr) { var buf [3480]byte; use(buf[:]); return Stackguard() }
+func stack3484() (uintptr, uintptr) { var buf [3484]byte; use(buf[:]); return Stackguard() }
+func stack3488() (uintptr, uintptr) { var buf [3488]byte; use(buf[:]); return Stackguard() }
+func stack3492() (uintptr, uintptr) { var buf [3492]byte; use(buf[:]); return Stackguard() }
+func stack3496() (uintptr, uintptr) { var buf [3496]byte; use(buf[:]); return Stackguard() }
+func stack3500() (uintptr, uintptr) { var buf [3500]byte; use(buf[:]); return Stackguard() }
+func stack3504() (uintptr, uintptr) { var buf [3504]byte; use(buf[:]); return Stackguard() }
+func stack3508() (uintptr, uintptr) { var buf [3508]byte; use(buf[:]); return Stackguard() }
+func stack3512() (uintptr, uintptr) { var buf [3512]byte; use(buf[:]); return Stackguard() }
+func stack3516() (uintptr, uintptr) { var buf [3516]byte; use(buf[:]); return Stackguard() }
+func stack3520() (uintptr, uintptr) { var buf [3520]byte; use(buf[:]); return Stackguard() }
+func stack3524() (uintptr, uintptr) { var buf [3524]byte; use(buf[:]); return Stackguard() }
+func stack3528() (uintptr, uintptr) { var buf [3528]byte; use(buf[:]); return Stackguard() }
+func stack3532() (uintptr, uintptr) { var buf [3532]byte; use(buf[:]); return Stackguard() }
+func stack3536() (uintptr, uintptr) { var buf [3536]byte; use(buf[:]); return Stackguard() }
+func stack3540() (uintptr, uintptr) { var buf [3540]byte; use(buf[:]); return Stackguard() }
+func stack3544() (uintptr, uintptr) { var buf [3544]byte; use(buf[:]); return Stackguard() }
+func stack3548() (uintptr, uintptr) { var buf [3548]byte; use(buf[:]); return Stackguard() }
+func stack3552() (uintptr, uintptr) { var buf [3552]byte; use(buf[:]); return Stackguard() }
+func stack3556() (uintptr, uintptr) { var buf [3556]byte; use(buf[:]); return Stackguard() }
+func stack3560() (uintptr, uintptr) { var buf [3560]byte; use(buf[:]); return Stackguard() }
+func stack3564() (uintptr, uintptr) { var buf [3564]byte; use(buf[:]); return Stackguard() }
+func stack3568() (uintptr, uintptr) { var buf [3568]byte; use(buf[:]); return Stackguard() }
+func stack3572() (uintptr, uintptr) { var buf [3572]byte; use(buf[:]); return Stackguard() }
+func stack3576() (uintptr, uintptr) { var buf [3576]byte; use(buf[:]); return Stackguard() }
+func stack3580() (uintptr, uintptr) { var buf [3580]byte; use(buf[:]); return Stackguard() }
+func stack3584() (uintptr, uintptr) { var buf [3584]byte; use(buf[:]); return Stackguard() }
+func stack3588() (uintptr, uintptr) { var buf [3588]byte; use(buf[:]); return Stackguard() }
+func stack3592() (uintptr, uintptr) { var buf [3592]byte; use(buf[:]); return Stackguard() }
+func stack3596() (uintptr, uintptr) { var buf [3596]byte; use(buf[:]); return Stackguard() }
+func stack3600() (uintptr, uintptr) { var buf [3600]byte; use(buf[:]); return Stackguard() }
+func stack3604() (uintptr, uintptr) { var buf [3604]byte; use(buf[:]); return Stackguard() }
+func stack3608() (uintptr, uintptr) { var buf [3608]byte; use(buf[:]); return Stackguard() }
+func stack3612() (uintptr, uintptr) { var buf [3612]byte; use(buf[:]); return Stackguard() }
+func stack3616() (uintptr, uintptr) { var buf [3616]byte; use(buf[:]); return Stackguard() }
+func stack3620() (uintptr, uintptr) { var buf [3620]byte; use(buf[:]); return Stackguard() }
+func stack3624() (uintptr, uintptr) { var buf [3624]byte; use(buf[:]); return Stackguard() }
+func stack3628() (uintptr, uintptr) { var buf [3628]byte; use(buf[:]); return Stackguard() }
+func stack3632() (uintptr, uintptr) { var buf [3632]byte; use(buf[:]); return Stackguard() }
+func stack3636() (uintptr, uintptr) { var buf [3636]byte; use(buf[:]); return Stackguard() }
+func stack3640() (uintptr, uintptr) { var buf [3640]byte; use(buf[:]); return Stackguard() }
+func stack3644() (uintptr, uintptr) { var buf [3644]byte; use(buf[:]); return Stackguard() }
+func stack3648() (uintptr, uintptr) { var buf [3648]byte; use(buf[:]); return Stackguard() }
+func stack3652() (uintptr, uintptr) { var buf [3652]byte; use(buf[:]); return Stackguard() }
+func stack3656() (uintptr, uintptr) { var buf [3656]byte; use(buf[:]); return Stackguard() }
+func stack3660() (uintptr, uintptr) { var buf [3660]byte; use(buf[:]); return Stackguard() }
+func stack3664() (uintptr, uintptr) { var buf [3664]byte; use(buf[:]); return Stackguard() }
+func stack3668() (uintptr, uintptr) { var buf [3668]byte; use(buf[:]); return Stackguard() }
+func stack3672() (uintptr, uintptr) { var buf [3672]byte; use(buf[:]); return Stackguard() }
+func stack3676() (uintptr, uintptr) { var buf [3676]byte; use(buf[:]); return Stackguard() }
+func stack3680() (uintptr, uintptr) { var buf [3680]byte; use(buf[:]); return Stackguard() }
+func stack3684() (uintptr, uintptr) { var buf [3684]byte; use(buf[:]); return Stackguard() }
+func stack3688() (uintptr, uintptr) { var buf [3688]byte; use(buf[:]); return Stackguard() }
+func stack3692() (uintptr, uintptr) { var buf [3692]byte; use(buf[:]); return Stackguard() }
+func stack3696() (uintptr, uintptr) { var buf [3696]byte; use(buf[:]); return Stackguard() }
+func stack3700() (uintptr, uintptr) { var buf [3700]byte; use(buf[:]); return Stackguard() }
+func stack3704() (uintptr, uintptr) { var buf [3704]byte; use(buf[:]); return Stackguard() }
+func stack3708() (uintptr, uintptr) { var buf [3708]byte; use(buf[:]); return Stackguard() }
+func stack3712() (uintptr, uintptr) { var buf [3712]byte; use(buf[:]); return Stackguard() }
+func stack3716() (uintptr, uintptr) { var buf [3716]byte; use(buf[:]); return Stackguard() }
+func stack3720() (uintptr, uintptr) { var buf [3720]byte; use(buf[:]); return Stackguard() }
+func stack3724() (uintptr, uintptr) { var buf [3724]byte; use(buf[:]); return Stackguard() }
+func stack3728() (uintptr, uintptr) { var buf [3728]byte; use(buf[:]); return Stackguard() }
+func stack3732() (uintptr, uintptr) { var buf [3732]byte; use(buf[:]); return Stackguard() }
+func stack3736() (uintptr, uintptr) { var buf [3736]byte; use(buf[:]); return Stackguard() }
+func stack3740() (uintptr, uintptr) { var buf [3740]byte; use(buf[:]); return Stackguard() }
+func stack3744() (uintptr, uintptr) { var buf [3744]byte; use(buf[:]); return Stackguard() }
+func stack3748() (uintptr, uintptr) { var buf [3748]byte; use(buf[:]); return Stackguard() }
+func stack3752() (uintptr, uintptr) { var buf [3752]byte; use(buf[:]); return Stackguard() }
+func stack3756() (uintptr, uintptr) { var buf [3756]byte; use(buf[:]); return Stackguard() }
+func stack3760() (uintptr, uintptr) { var buf [3760]byte; use(buf[:]); return Stackguard() }
+func stack3764() (uintptr, uintptr) { var buf [3764]byte; use(buf[:]); return Stackguard() }
+func stack3768() (uintptr, uintptr) { var buf [3768]byte; use(buf[:]); return Stackguard() }
+func stack3772() (uintptr, uintptr) { var buf [3772]byte; use(buf[:]); return Stackguard() }
+func stack3776() (uintptr, uintptr) { var buf [3776]byte; use(buf[:]); return Stackguard() }
+func stack3780() (uintptr, uintptr) { var buf [3780]byte; use(buf[:]); return Stackguard() }
+func stack3784() (uintptr, uintptr) { var buf [3784]byte; use(buf[:]); return Stackguard() }
+func stack3788() (uintptr, uintptr) { var buf [3788]byte; use(buf[:]); return Stackguard() }
+func stack3792() (uintptr, uintptr) { var buf [3792]byte; use(buf[:]); return Stackguard() }
+func stack3796() (uintptr, uintptr) { var buf [3796]byte; use(buf[:]); return Stackguard() }
+func stack3800() (uintptr, uintptr) { var buf [3800]byte; use(buf[:]); return Stackguard() }
+func stack3804() (uintptr, uintptr) { var buf [3804]byte; use(buf[:]); return Stackguard() }
+func stack3808() (uintptr, uintptr) { var buf [3808]byte; use(buf[:]); return Stackguard() }
+func stack3812() (uintptr, uintptr) { var buf [3812]byte; use(buf[:]); return Stackguard() }
+func stack3816() (uintptr, uintptr) { var buf [3816]byte; use(buf[:]); return Stackguard() }
+func stack3820() (uintptr, uintptr) { var buf [3820]byte; use(buf[:]); return Stackguard() }
+func stack3824() (uintptr, uintptr) { var buf [3824]byte; use(buf[:]); return Stackguard() }
+func stack3828() (uintptr, uintptr) { var buf [3828]byte; use(buf[:]); return Stackguard() }
+func stack3832() (uintptr, uintptr) { var buf [3832]byte; use(buf[:]); return Stackguard() }
+func stack3836() (uintptr, uintptr) { var buf [3836]byte; use(buf[:]); return Stackguard() }
+func stack3840() (uintptr, uintptr) { var buf [3840]byte; use(buf[:]); return Stackguard() }
+func stack3844() (uintptr, uintptr) { var buf [3844]byte; use(buf[:]); return Stackguard() }
+func stack3848() (uintptr, uintptr) { var buf [3848]byte; use(buf[:]); return Stackguard() }
+func stack3852() (uintptr, uintptr) { var buf [3852]byte; use(buf[:]); return Stackguard() }
+func stack3856() (uintptr, uintptr) { var buf [3856]byte; use(buf[:]); return Stackguard() }
+func stack3860() (uintptr, uintptr) { var buf [3860]byte; use(buf[:]); return Stackguard() }
+func stack3864() (uintptr, uintptr) { var buf [3864]byte; use(buf[:]); return Stackguard() }
+func stack3868() (uintptr, uintptr) { var buf [3868]byte; use(buf[:]); return Stackguard() }
+func stack3872() (uintptr, uintptr) { var buf [3872]byte; use(buf[:]); return Stackguard() }
+func stack3876() (uintptr, uintptr) { var buf [3876]byte; use(buf[:]); return Stackguard() }
+func stack3880() (uintptr, uintptr) { var buf [3880]byte; use(buf[:]); return Stackguard() }
+func stack3884() (uintptr, uintptr) { var buf [3884]byte; use(buf[:]); return Stackguard() }
+func stack3888() (uintptr, uintptr) { var buf [3888]byte; use(buf[:]); return Stackguard() }
+func stack3892() (uintptr, uintptr) { var buf [3892]byte; use(buf[:]); return Stackguard() }
+func stack3896() (uintptr, uintptr) { var buf [3896]byte; use(buf[:]); return Stackguard() }
+func stack3900() (uintptr, uintptr) { var buf [3900]byte; use(buf[:]); return Stackguard() }
+func stack3904() (uintptr, uintptr) { var buf [3904]byte; use(buf[:]); return Stackguard() }
+func stack3908() (uintptr, uintptr) { var buf [3908]byte; use(buf[:]); return Stackguard() }
+func stack3912() (uintptr, uintptr) { var buf [3912]byte; use(buf[:]); return Stackguard() }
+func stack3916() (uintptr, uintptr) { var buf [3916]byte; use(buf[:]); return Stackguard() }
+func stack3920() (uintptr, uintptr) { var buf [3920]byte; use(buf[:]); return Stackguard() }
+func stack3924() (uintptr, uintptr) { var buf [3924]byte; use(buf[:]); return Stackguard() }
+func stack3928() (uintptr, uintptr) { var buf [3928]byte; use(buf[:]); return Stackguard() }
+func stack3932() (uintptr, uintptr) { var buf [3932]byte; use(buf[:]); return Stackguard() }
+func stack3936() (uintptr, uintptr) { var buf [3936]byte; use(buf[:]); return Stackguard() }
+func stack3940() (uintptr, uintptr) { var buf [3940]byte; use(buf[:]); return Stackguard() }
+func stack3944() (uintptr, uintptr) { var buf [3944]byte; use(buf[:]); return Stackguard() }
+func stack3948() (uintptr, uintptr) { var buf [3948]byte; use(buf[:]); return Stackguard() }
+func stack3952() (uintptr, uintptr) { var buf [3952]byte; use(buf[:]); return Stackguard() }
+func stack3956() (uintptr, uintptr) { var buf [3956]byte; use(buf[:]); return Stackguard() }
+func stack3960() (uintptr, uintptr) { var buf [3960]byte; use(buf[:]); return Stackguard() }
+func stack3964() (uintptr, uintptr) { var buf [3964]byte; use(buf[:]); return Stackguard() }
+func stack3968() (uintptr, uintptr) { var buf [3968]byte; use(buf[:]); return Stackguard() }
+func stack3972() (uintptr, uintptr) { var buf [3972]byte; use(buf[:]); return Stackguard() }
+func stack3976() (uintptr, uintptr) { var buf [3976]byte; use(buf[:]); return Stackguard() }
+func stack3980() (uintptr, uintptr) { var buf [3980]byte; use(buf[:]); return Stackguard() }
+func stack3984() (uintptr, uintptr) { var buf [3984]byte; use(buf[:]); return Stackguard() }
+func stack3988() (uintptr, uintptr) { var buf [3988]byte; use(buf[:]); return Stackguard() }
+func stack3992() (uintptr, uintptr) { var buf [3992]byte; use(buf[:]); return Stackguard() }
+func stack3996() (uintptr, uintptr) { var buf [3996]byte; use(buf[:]); return Stackguard() }
+func stack4000() (uintptr, uintptr) { var buf [4000]byte; use(buf[:]); return Stackguard() }
+func stack4004() (uintptr, uintptr) { var buf [4004]byte; use(buf[:]); return Stackguard() }
+func stack4008() (uintptr, uintptr) { var buf [4008]byte; use(buf[:]); return Stackguard() }
+func stack4012() (uintptr, uintptr) { var buf [4012]byte; use(buf[:]); return Stackguard() }
+func stack4016() (uintptr, uintptr) { var buf [4016]byte; use(buf[:]); return Stackguard() }
+func stack4020() (uintptr, uintptr) { var buf [4020]byte; use(buf[:]); return Stackguard() }
+func stack4024() (uintptr, uintptr) { var buf [4024]byte; use(buf[:]); return Stackguard() }
+func stack4028() (uintptr, uintptr) { var buf [4028]byte; use(buf[:]); return Stackguard() }
+func stack4032() (uintptr, uintptr) { var buf [4032]byte; use(buf[:]); return Stackguard() }
+func stack4036() (uintptr, uintptr) { var buf [4036]byte; use(buf[:]); return Stackguard() }
+func stack4040() (uintptr, uintptr) { var buf [4040]byte; use(buf[:]); return Stackguard() }
+func stack4044() (uintptr, uintptr) { var buf [4044]byte; use(buf[:]); return Stackguard() }
+func stack4048() (uintptr, uintptr) { var buf [4048]byte; use(buf[:]); return Stackguard() }
+func stack4052() (uintptr, uintptr) { var buf [4052]byte; use(buf[:]); return Stackguard() }
+func stack4056() (uintptr, uintptr) { var buf [4056]byte; use(buf[:]); return Stackguard() }
+func stack4060() (uintptr, uintptr) { var buf [4060]byte; use(buf[:]); return Stackguard() }
+func stack4064() (uintptr, uintptr) { var buf [4064]byte; use(buf[:]); return Stackguard() }
+func stack4068() (uintptr, uintptr) { var buf [4068]byte; use(buf[:]); return Stackguard() }
+func stack4072() (uintptr, uintptr) { var buf [4072]byte; use(buf[:]); return Stackguard() }
+func stack4076() (uintptr, uintptr) { var buf [4076]byte; use(buf[:]); return Stackguard() }
+func stack4080() (uintptr, uintptr) { var buf [4080]byte; use(buf[:]); return Stackguard() }
+func stack4084() (uintptr, uintptr) { var buf [4084]byte; use(buf[:]); return Stackguard() }
+func stack4088() (uintptr, uintptr) { var buf [4088]byte; use(buf[:]); return Stackguard() }
+func stack4092() (uintptr, uintptr) { var buf [4092]byte; use(buf[:]); return Stackguard() }
+func stack4096() (uintptr, uintptr) { var buf [4096]byte; use(buf[:]); return Stackguard() }
+func stack4100() (uintptr, uintptr) { var buf [4100]byte; use(buf[:]); return Stackguard() }
+func stack4104() (uintptr, uintptr) { var buf [4104]byte; use(buf[:]); return Stackguard() }
+func stack4108() (uintptr, uintptr) { var buf [4108]byte; use(buf[:]); return Stackguard() }
+func stack4112() (uintptr, uintptr) { var buf [4112]byte; use(buf[:]); return Stackguard() }
+func stack4116() (uintptr, uintptr) { var buf [4116]byte; use(buf[:]); return Stackguard() }
+func stack4120() (uintptr, uintptr) { var buf [4120]byte; use(buf[:]); return Stackguard() }
+func stack4124() (uintptr, uintptr) { var buf [4124]byte; use(buf[:]); return Stackguard() }
+func stack4128() (uintptr, uintptr) { var buf [4128]byte; use(buf[:]); return Stackguard() }
+func stack4132() (uintptr, uintptr) { var buf [4132]byte; use(buf[:]); return Stackguard() }
+func stack4136() (uintptr, uintptr) { var buf [4136]byte; use(buf[:]); return Stackguard() }
+func stack4140() (uintptr, uintptr) { var buf [4140]byte; use(buf[:]); return Stackguard() }
+func stack4144() (uintptr, uintptr) { var buf [4144]byte; use(buf[:]); return Stackguard() }
+func stack4148() (uintptr, uintptr) { var buf [4148]byte; use(buf[:]); return Stackguard() }
+func stack4152() (uintptr, uintptr) { var buf [4152]byte; use(buf[:]); return Stackguard() }
+func stack4156() (uintptr, uintptr) { var buf [4156]byte; use(buf[:]); return Stackguard() }
+func stack4160() (uintptr, uintptr) { var buf [4160]byte; use(buf[:]); return Stackguard() }
+func stack4164() (uintptr, uintptr) { var buf [4164]byte; use(buf[:]); return Stackguard() }
+func stack4168() (uintptr, uintptr) { var buf [4168]byte; use(buf[:]); return Stackguard() }
+func stack4172() (uintptr, uintptr) { var buf [4172]byte; use(buf[:]); return Stackguard() }
+func stack4176() (uintptr, uintptr) { var buf [4176]byte; use(buf[:]); return Stackguard() }
+func stack4180() (uintptr, uintptr) { var buf [4180]byte; use(buf[:]); return Stackguard() }
+func stack4184() (uintptr, uintptr) { var buf [4184]byte; use(buf[:]); return Stackguard() }
+func stack4188() (uintptr, uintptr) { var buf [4188]byte; use(buf[:]); return Stackguard() }
+func stack4192() (uintptr, uintptr) { var buf [4192]byte; use(buf[:]); return Stackguard() }
+func stack4196() (uintptr, uintptr) { var buf [4196]byte; use(buf[:]); return Stackguard() }
+func stack4200() (uintptr, uintptr) { var buf [4200]byte; use(buf[:]); return Stackguard() }
+func stack4204() (uintptr, uintptr) { var buf [4204]byte; use(buf[:]); return Stackguard() }
+func stack4208() (uintptr, uintptr) { var buf [4208]byte; use(buf[:]); return Stackguard() }
+func stack4212() (uintptr, uintptr) { var buf [4212]byte; use(buf[:]); return Stackguard() }
+func stack4216() (uintptr, uintptr) { var buf [4216]byte; use(buf[:]); return Stackguard() }
+func stack4220() (uintptr, uintptr) { var buf [4220]byte; use(buf[:]); return Stackguard() }
+func stack4224() (uintptr, uintptr) { var buf [4224]byte; use(buf[:]); return Stackguard() }
+func stack4228() (uintptr, uintptr) { var buf [4228]byte; use(buf[:]); return Stackguard() }
+func stack4232() (uintptr, uintptr) { var buf [4232]byte; use(buf[:]); return Stackguard() }
+func stack4236() (uintptr, uintptr) { var buf [4236]byte; use(buf[:]); return Stackguard() }
+func stack4240() (uintptr, uintptr) { var buf [4240]byte; use(buf[:]); return Stackguard() }
+func stack4244() (uintptr, uintptr) { var buf [4244]byte; use(buf[:]); return Stackguard() }
+func stack4248() (uintptr, uintptr) { var buf [4248]byte; use(buf[:]); return Stackguard() }
+func stack4252() (uintptr, uintptr) { var buf [4252]byte; use(buf[:]); return Stackguard() }
+func stack4256() (uintptr, uintptr) { var buf [4256]byte; use(buf[:]); return Stackguard() }
+func stack4260() (uintptr, uintptr) { var buf [4260]byte; use(buf[:]); return Stackguard() }
+func stack4264() (uintptr, uintptr) { var buf [4264]byte; use(buf[:]); return Stackguard() }
+func stack4268() (uintptr, uintptr) { var buf [4268]byte; use(buf[:]); return Stackguard() }
+func stack4272() (uintptr, uintptr) { var buf [4272]byte; use(buf[:]); return Stackguard() }
+func stack4276() (uintptr, uintptr) { var buf [4276]byte; use(buf[:]); return Stackguard() }
+func stack4280() (uintptr, uintptr) { var buf [4280]byte; use(buf[:]); return Stackguard() }
+func stack4284() (uintptr, uintptr) { var buf [4284]byte; use(buf[:]); return Stackguard() }
+func stack4288() (uintptr, uintptr) { var buf [4288]byte; use(buf[:]); return Stackguard() }
+func stack4292() (uintptr, uintptr) { var buf [4292]byte; use(buf[:]); return Stackguard() }
+func stack4296() (uintptr, uintptr) { var buf [4296]byte; use(buf[:]); return Stackguard() }
+func stack4300() (uintptr, uintptr) { var buf [4300]byte; use(buf[:]); return Stackguard() }
+func stack4304() (uintptr, uintptr) { var buf [4304]byte; use(buf[:]); return Stackguard() }
+func stack4308() (uintptr, uintptr) { var buf [4308]byte; use(buf[:]); return Stackguard() }
+func stack4312() (uintptr, uintptr) { var buf [4312]byte; use(buf[:]); return Stackguard() }
+func stack4316() (uintptr, uintptr) { var buf [4316]byte; use(buf[:]); return Stackguard() }
+func stack4320() (uintptr, uintptr) { var buf [4320]byte; use(buf[:]); return Stackguard() }
+func stack4324() (uintptr, uintptr) { var buf [4324]byte; use(buf[:]); return Stackguard() }
+func stack4328() (uintptr, uintptr) { var buf [4328]byte; use(buf[:]); return Stackguard() }
+func stack4332() (uintptr, uintptr) { var buf [4332]byte; use(buf[:]); return Stackguard() }
+func stack4336() (uintptr, uintptr) { var buf [4336]byte; use(buf[:]); return Stackguard() }
+func stack4340() (uintptr, uintptr) { var buf [4340]byte; use(buf[:]); return Stackguard() }
+func stack4344() (uintptr, uintptr) { var buf [4344]byte; use(buf[:]); return Stackguard() }
+func stack4348() (uintptr, uintptr) { var buf [4348]byte; use(buf[:]); return Stackguard() }
+func stack4352() (uintptr, uintptr) { var buf [4352]byte; use(buf[:]); return Stackguard() }
+func stack4356() (uintptr, uintptr) { var buf [4356]byte; use(buf[:]); return Stackguard() }
+func stack4360() (uintptr, uintptr) { var buf [4360]byte; use(buf[:]); return Stackguard() }
+func stack4364() (uintptr, uintptr) { var buf [4364]byte; use(buf[:]); return Stackguard() }
+func stack4368() (uintptr, uintptr) { var buf [4368]byte; use(buf[:]); return Stackguard() }
+func stack4372() (uintptr, uintptr) { var buf [4372]byte; use(buf[:]); return Stackguard() }
+func stack4376() (uintptr, uintptr) { var buf [4376]byte; use(buf[:]); return Stackguard() }
+func stack4380() (uintptr, uintptr) { var buf [4380]byte; use(buf[:]); return Stackguard() }
+func stack4384() (uintptr, uintptr) { var buf [4384]byte; use(buf[:]); return Stackguard() }
+func stack4388() (uintptr, uintptr) { var buf [4388]byte; use(buf[:]); return Stackguard() }
+func stack4392() (uintptr, uintptr) { var buf [4392]byte; use(buf[:]); return Stackguard() }
+func stack4396() (uintptr, uintptr) { var buf [4396]byte; use(buf[:]); return Stackguard() }
+func stack4400() (uintptr, uintptr) { var buf [4400]byte; use(buf[:]); return Stackguard() }
+func stack4404() (uintptr, uintptr) { var buf [4404]byte; use(buf[:]); return Stackguard() }
+func stack4408() (uintptr, uintptr) { var buf [4408]byte; use(buf[:]); return Stackguard() }
+func stack4412() (uintptr, uintptr) { var buf [4412]byte; use(buf[:]); return Stackguard() }
+func stack4416() (uintptr, uintptr) { var buf [4416]byte; use(buf[:]); return Stackguard() }
+func stack4420() (uintptr, uintptr) { var buf [4420]byte; use(buf[:]); return Stackguard() }
+func stack4424() (uintptr, uintptr) { var buf [4424]byte; use(buf[:]); return Stackguard() }
+func stack4428() (uintptr, uintptr) { var buf [4428]byte; use(buf[:]); return Stackguard() }
+func stack4432() (uintptr, uintptr) { var buf [4432]byte; use(buf[:]); return Stackguard() }
+func stack4436() (uintptr, uintptr) { var buf [4436]byte; use(buf[:]); return Stackguard() }
+func stack4440() (uintptr, uintptr) { var buf [4440]byte; use(buf[:]); return Stackguard() }
+func stack4444() (uintptr, uintptr) { var buf [4444]byte; use(buf[:]); return Stackguard() }
+func stack4448() (uintptr, uintptr) { var buf [4448]byte; use(buf[:]); return Stackguard() }
+func stack4452() (uintptr, uintptr) { var buf [4452]byte; use(buf[:]); return Stackguard() }
+func stack4456() (uintptr, uintptr) { var buf [4456]byte; use(buf[:]); return Stackguard() }
+func stack4460() (uintptr, uintptr) { var buf [4460]byte; use(buf[:]); return Stackguard() }
+func stack4464() (uintptr, uintptr) { var buf [4464]byte; use(buf[:]); return Stackguard() }
+func stack4468() (uintptr, uintptr) { var buf [4468]byte; use(buf[:]); return Stackguard() }
+func stack4472() (uintptr, uintptr) { var buf [4472]byte; use(buf[:]); return Stackguard() }
+func stack4476() (uintptr, uintptr) { var buf [4476]byte; use(buf[:]); return Stackguard() }
+func stack4480() (uintptr, uintptr) { var buf [4480]byte; use(buf[:]); return Stackguard() }
+func stack4484() (uintptr, uintptr) { var buf [4484]byte; use(buf[:]); return Stackguard() }
+func stack4488() (uintptr, uintptr) { var buf [4488]byte; use(buf[:]); return Stackguard() }
+func stack4492() (uintptr, uintptr) { var buf [4492]byte; use(buf[:]); return Stackguard() }
+func stack4496() (uintptr, uintptr) { var buf [4496]byte; use(buf[:]); return Stackguard() }
+func stack4500() (uintptr, uintptr) { var buf [4500]byte; use(buf[:]); return Stackguard() }
+func stack4504() (uintptr, uintptr) { var buf [4504]byte; use(buf[:]); return Stackguard() }
+func stack4508() (uintptr, uintptr) { var buf [4508]byte; use(buf[:]); return Stackguard() }
+func stack4512() (uintptr, uintptr) { var buf [4512]byte; use(buf[:]); return Stackguard() }
+func stack4516() (uintptr, uintptr) { var buf [4516]byte; use(buf[:]); return Stackguard() }
+func stack4520() (uintptr, uintptr) { var buf [4520]byte; use(buf[:]); return Stackguard() }
+func stack4524() (uintptr, uintptr) { var buf [4524]byte; use(buf[:]); return Stackguard() }
+func stack4528() (uintptr, uintptr) { var buf [4528]byte; use(buf[:]); return Stackguard() }
+func stack4532() (uintptr, uintptr) { var buf [4532]byte; use(buf[:]); return Stackguard() }
+func stack4536() (uintptr, uintptr) { var buf [4536]byte; use(buf[:]); return Stackguard() }
+func stack4540() (uintptr, uintptr) { var buf [4540]byte; use(buf[:]); return Stackguard() }
+func stack4544() (uintptr, uintptr) { var buf [4544]byte; use(buf[:]); return Stackguard() }
+func stack4548() (uintptr, uintptr) { var buf [4548]byte; use(buf[:]); return Stackguard() }
+func stack4552() (uintptr, uintptr) { var buf [4552]byte; use(buf[:]); return Stackguard() }
+func stack4556() (uintptr, uintptr) { var buf [4556]byte; use(buf[:]); return Stackguard() }
+func stack4560() (uintptr, uintptr) { var buf [4560]byte; use(buf[:]); return Stackguard() }
+func stack4564() (uintptr, uintptr) { var buf [4564]byte; use(buf[:]); return Stackguard() }
+func stack4568() (uintptr, uintptr) { var buf [4568]byte; use(buf[:]); return Stackguard() }
+func stack4572() (uintptr, uintptr) { var buf [4572]byte; use(buf[:]); return Stackguard() }
+func stack4576() (uintptr, uintptr) { var buf [4576]byte; use(buf[:]); return Stackguard() }
+func stack4580() (uintptr, uintptr) { var buf [4580]byte; use(buf[:]); return Stackguard() }
+func stack4584() (uintptr, uintptr) { var buf [4584]byte; use(buf[:]); return Stackguard() }
+func stack4588() (uintptr, uintptr) { var buf [4588]byte; use(buf[:]); return Stackguard() }
+func stack4592() (uintptr, uintptr) { var buf [4592]byte; use(buf[:]); return Stackguard() }
+func stack4596() (uintptr, uintptr) { var buf [4596]byte; use(buf[:]); return Stackguard() }
+func stack4600() (uintptr, uintptr) { var buf [4600]byte; use(buf[:]); return Stackguard() }
+func stack4604() (uintptr, uintptr) { var buf [4604]byte; use(buf[:]); return Stackguard() }
+func stack4608() (uintptr, uintptr) { var buf [4608]byte; use(buf[:]); return Stackguard() }
+func stack4612() (uintptr, uintptr) { var buf [4612]byte; use(buf[:]); return Stackguard() }
+func stack4616() (uintptr, uintptr) { var buf [4616]byte; use(buf[:]); return Stackguard() }
+func stack4620() (uintptr, uintptr) { var buf [4620]byte; use(buf[:]); return Stackguard() }
+func stack4624() (uintptr, uintptr) { var buf [4624]byte; use(buf[:]); return Stackguard() }
+func stack4628() (uintptr, uintptr) { var buf [4628]byte; use(buf[:]); return Stackguard() }
+func stack4632() (uintptr, uintptr) { var buf [4632]byte; use(buf[:]); return Stackguard() }
+func stack4636() (uintptr, uintptr) { var buf [4636]byte; use(buf[:]); return Stackguard() }
+func stack4640() (uintptr, uintptr) { var buf [4640]byte; use(buf[:]); return Stackguard() }
+func stack4644() (uintptr, uintptr) { var buf [4644]byte; use(buf[:]); return Stackguard() }
+func stack4648() (uintptr, uintptr) { var buf [4648]byte; use(buf[:]); return Stackguard() }
+func stack4652() (uintptr, uintptr) { var buf [4652]byte; use(buf[:]); return Stackguard() }
+func stack4656() (uintptr, uintptr) { var buf [4656]byte; use(buf[:]); return Stackguard() }
+func stack4660() (uintptr, uintptr) { var buf [4660]byte; use(buf[:]); return Stackguard() }
+func stack4664() (uintptr, uintptr) { var buf [4664]byte; use(buf[:]); return Stackguard() }
+func stack4668() (uintptr, uintptr) { var buf [4668]byte; use(buf[:]); return Stackguard() }
+func stack4672() (uintptr, uintptr) { var buf [4672]byte; use(buf[:]); return Stackguard() }
+func stack4676() (uintptr, uintptr) { var buf [4676]byte; use(buf[:]); return Stackguard() }
+func stack4680() (uintptr, uintptr) { var buf [4680]byte; use(buf[:]); return Stackguard() }
+func stack4684() (uintptr, uintptr) { var buf [4684]byte; use(buf[:]); return Stackguard() }
+func stack4688() (uintptr, uintptr) { var buf [4688]byte; use(buf[:]); return Stackguard() }
+func stack4692() (uintptr, uintptr) { var buf [4692]byte; use(buf[:]); return Stackguard() }
+func stack4696() (uintptr, uintptr) { var buf [4696]byte; use(buf[:]); return Stackguard() }
+func stack4700() (uintptr, uintptr) { var buf [4700]byte; use(buf[:]); return Stackguard() }
+func stack4704() (uintptr, uintptr) { var buf [4704]byte; use(buf[:]); return Stackguard() }
+func stack4708() (uintptr, uintptr) { var buf [4708]byte; use(buf[:]); return Stackguard() }
+func stack4712() (uintptr, uintptr) { var buf [4712]byte; use(buf[:]); return Stackguard() }
+func stack4716() (uintptr, uintptr) { var buf [4716]byte; use(buf[:]); return Stackguard() }
+func stack4720() (uintptr, uintptr) { var buf [4720]byte; use(buf[:]); return Stackguard() }
+func stack4724() (uintptr, uintptr) { var buf [4724]byte; use(buf[:]); return Stackguard() }
+func stack4728() (uintptr, uintptr) { var buf [4728]byte; use(buf[:]); return Stackguard() }
+func stack4732() (uintptr, uintptr) { var buf [4732]byte; use(buf[:]); return Stackguard() }
+func stack4736() (uintptr, uintptr) { var buf [4736]byte; use(buf[:]); return Stackguard() }
+func stack4740() (uintptr, uintptr) { var buf [4740]byte; use(buf[:]); return Stackguard() }
+func stack4744() (uintptr, uintptr) { var buf [4744]byte; use(buf[:]); return Stackguard() }
+func stack4748() (uintptr, uintptr) { var buf [4748]byte; use(buf[:]); return Stackguard() }
+func stack4752() (uintptr, uintptr) { var buf [4752]byte; use(buf[:]); return Stackguard() }
+func stack4756() (uintptr, uintptr) { var buf [4756]byte; use(buf[:]); return Stackguard() }
+func stack4760() (uintptr, uintptr) { var buf [4760]byte; use(buf[:]); return Stackguard() }
+func stack4764() (uintptr, uintptr) { var buf [4764]byte; use(buf[:]); return Stackguard() }
+func stack4768() (uintptr, uintptr) { var buf [4768]byte; use(buf[:]); return Stackguard() }
+func stack4772() (uintptr, uintptr) { var buf [4772]byte; use(buf[:]); return Stackguard() }
+func stack4776() (uintptr, uintptr) { var buf [4776]byte; use(buf[:]); return Stackguard() }
+func stack4780() (uintptr, uintptr) { var buf [4780]byte; use(buf[:]); return Stackguard() }
+func stack4784() (uintptr, uintptr) { var buf [4784]byte; use(buf[:]); return Stackguard() }
+func stack4788() (uintptr, uintptr) { var buf [4788]byte; use(buf[:]); return Stackguard() }
+func stack4792() (uintptr, uintptr) { var buf [4792]byte; use(buf[:]); return Stackguard() }
+func stack4796() (uintptr, uintptr) { var buf [4796]byte; use(buf[:]); return Stackguard() }
+func stack4800() (uintptr, uintptr) { var buf [4800]byte; use(buf[:]); return Stackguard() }
+func stack4804() (uintptr, uintptr) { var buf [4804]byte; use(buf[:]); return Stackguard() }
+func stack4808() (uintptr, uintptr) { var buf [4808]byte; use(buf[:]); return Stackguard() }
+func stack4812() (uintptr, uintptr) { var buf [4812]byte; use(buf[:]); return Stackguard() }
+func stack4816() (uintptr, uintptr) { var buf [4816]byte; use(buf[:]); return Stackguard() }
+func stack4820() (uintptr, uintptr) { var buf [4820]byte; use(buf[:]); return Stackguard() }
+func stack4824() (uintptr, uintptr) { var buf [4824]byte; use(buf[:]); return Stackguard() }
+func stack4828() (uintptr, uintptr) { var buf [4828]byte; use(buf[:]); return Stackguard() }
+func stack4832() (uintptr, uintptr) { var buf [4832]byte; use(buf[:]); return Stackguard() }
+func stack4836() (uintptr, uintptr) { var buf [4836]byte; use(buf[:]); return Stackguard() }
+func stack4840() (uintptr, uintptr) { var buf [4840]byte; use(buf[:]); return Stackguard() }
+func stack4844() (uintptr, uintptr) { var buf [4844]byte; use(buf[:]); return Stackguard() }
+func stack4848() (uintptr, uintptr) { var buf [4848]byte; use(buf[:]); return Stackguard() }
+func stack4852() (uintptr, uintptr) { var buf [4852]byte; use(buf[:]); return Stackguard() }
+func stack4856() (uintptr, uintptr) { var buf [4856]byte; use(buf[:]); return Stackguard() }
+func stack4860() (uintptr, uintptr) { var buf [4860]byte; use(buf[:]); return Stackguard() }
+func stack4864() (uintptr, uintptr) { var buf [4864]byte; use(buf[:]); return Stackguard() }
+func stack4868() (uintptr, uintptr) { var buf [4868]byte; use(buf[:]); return Stackguard() }
+func stack4872() (uintptr, uintptr) { var buf [4872]byte; use(buf[:]); return Stackguard() }
+func stack4876() (uintptr, uintptr) { var buf [4876]byte; use(buf[:]); return Stackguard() }
+func stack4880() (uintptr, uintptr) { var buf [4880]byte; use(buf[:]); return Stackguard() }
+func stack4884() (uintptr, uintptr) { var buf [4884]byte; use(buf[:]); return Stackguard() }
+func stack4888() (uintptr, uintptr) { var buf [4888]byte; use(buf[:]); return Stackguard() }
+func stack4892() (uintptr, uintptr) { var buf [4892]byte; use(buf[:]); return Stackguard() }
+func stack4896() (uintptr, uintptr) { var buf [4896]byte; use(buf[:]); return Stackguard() }
+func stack4900() (uintptr, uintptr) { var buf [4900]byte; use(buf[:]); return Stackguard() }
+func stack4904() (uintptr, uintptr) { var buf [4904]byte; use(buf[:]); return Stackguard() }
+func stack4908() (uintptr, uintptr) { var buf [4908]byte; use(buf[:]); return Stackguard() }
+func stack4912() (uintptr, uintptr) { var buf [4912]byte; use(buf[:]); return Stackguard() }
+func stack4916() (uintptr, uintptr) { var buf [4916]byte; use(buf[:]); return Stackguard() }
+func stack4920() (uintptr, uintptr) { var buf [4920]byte; use(buf[:]); return Stackguard() }
+func stack4924() (uintptr, uintptr) { var buf [4924]byte; use(buf[:]); return Stackguard() }
+func stack4928() (uintptr, uintptr) { var buf [4928]byte; use(buf[:]); return Stackguard() }
+func stack4932() (uintptr, uintptr) { var buf [4932]byte; use(buf[:]); return Stackguard() }
+func stack4936() (uintptr, uintptr) { var buf [4936]byte; use(buf[:]); return Stackguard() }
+func stack4940() (uintptr, uintptr) { var buf [4940]byte; use(buf[:]); return Stackguard() }
+func stack4944() (uintptr, uintptr) { var buf [4944]byte; use(buf[:]); return Stackguard() }
+func stack4948() (uintptr, uintptr) { var buf [4948]byte; use(buf[:]); return Stackguard() }
+func stack4952() (uintptr, uintptr) { var buf [4952]byte; use(buf[:]); return Stackguard() }
+func stack4956() (uintptr, uintptr) { var buf [4956]byte; use(buf[:]); return Stackguard() }
+func stack4960() (uintptr, uintptr) { var buf [4960]byte; use(buf[:]); return Stackguard() }
+func stack4964() (uintptr, uintptr) { var buf [4964]byte; use(buf[:]); return Stackguard() }
+func stack4968() (uintptr, uintptr) { var buf [4968]byte; use(buf[:]); return Stackguard() }
+func stack4972() (uintptr, uintptr) { var buf [4972]byte; use(buf[:]); return Stackguard() }
+func stack4976() (uintptr, uintptr) { var buf [4976]byte; use(buf[:]); return Stackguard() }
+func stack4980() (uintptr, uintptr) { var buf [4980]byte; use(buf[:]); return Stackguard() }
+func stack4984() (uintptr, uintptr) { var buf [4984]byte; use(buf[:]); return Stackguard() }
+func stack4988() (uintptr, uintptr) { var buf [4988]byte; use(buf[:]); return Stackguard() }
+func stack4992() (uintptr, uintptr) { var buf [4992]byte; use(buf[:]); return Stackguard() }
+func stack4996() (uintptr, uintptr) { var buf [4996]byte; use(buf[:]); return Stackguard() }
+func stack5000() (uintptr, uintptr) { var buf [5000]byte; use(buf[:]); return Stackguard() }
diff --git a/src/pkg/runtime/stack_test.go b/src/pkg/runtime/stack_test.go
index 00c2d0e06..f0c599ac5 100644
--- a/src/pkg/runtime/stack_test.go
+++ b/src/pkg/runtime/stack_test.go
@@ -2,6 +2,22 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+package runtime_test
+
+import (
+ . "runtime"
+ "sync"
+ "testing"
+ "time"
+ "unsafe"
+)
+
+// See stack.h.
+const (
+ StackGuard = 256
+ StackLimit = 128
+)
+
// Test stack split logic by calling functions of every frame size
// from near 0 up to and beyond the default segment size (4k).
// Each of those functions reports its SP + stack limit, and then
@@ -28,22 +44,6 @@
// stack_test.go:22: after runtime_test.stack3860: sp=0x7f7818d5d048 < limit=0x7f7818d5d080
// stack_test.go:22: after runtime_test.stack3864: sp=0x7f7818d5d048 < limit=0x7f7818d5d080
// FAIL
-
-package runtime_test
-
-import (
- . "runtime"
- "testing"
- "time"
- "unsafe"
-)
-
-// See stack.h.
-const (
- StackGuard = 256
- StackLimit = 128
-)
-
func TestStackSplit(t *testing.T) {
for _, f := range splitTests {
sp, guard := f()
@@ -56,218 +56,6 @@ func TestStackSplit(t *testing.T) {
}
}
-var splitTests = []func() (uintptr, uintptr){
- // Edit .+1,/^}/-1|seq 4 4 5000 | sed 's/.*/ stack&,/' | fmt
- stack4, stack8, stack12, stack16, stack20, stack24, stack28,
- stack32, stack36, stack40, stack44, stack48, stack52, stack56,
- stack60, stack64, stack68, stack72, stack76, stack80, stack84,
- stack88, stack92, stack96, stack100, stack104, stack108, stack112,
- stack116, stack120, stack124, stack128, stack132, stack136,
- stack140, stack144, stack148, stack152, stack156, stack160,
- stack164, stack168, stack172, stack176, stack180, stack184,
- stack188, stack192, stack196, stack200, stack204, stack208,
- stack212, stack216, stack220, stack224, stack228, stack232,
- stack236, stack240, stack244, stack248, stack252, stack256,
- stack260, stack264, stack268, stack272, stack276, stack280,
- stack284, stack288, stack292, stack296, stack300, stack304,
- stack308, stack312, stack316, stack320, stack324, stack328,
- stack332, stack336, stack340, stack344, stack348, stack352,
- stack356, stack360, stack364, stack368, stack372, stack376,
- stack380, stack384, stack388, stack392, stack396, stack400,
- stack404, stack408, stack412, stack416, stack420, stack424,
- stack428, stack432, stack436, stack440, stack444, stack448,
- stack452, stack456, stack460, stack464, stack468, stack472,
- stack476, stack480, stack484, stack488, stack492, stack496,
- stack500, stack504, stack508, stack512, stack516, stack520,
- stack524, stack528, stack532, stack536, stack540, stack544,
- stack548, stack552, stack556, stack560, stack564, stack568,
- stack572, stack576, stack580, stack584, stack588, stack592,
- stack596, stack600, stack604, stack608, stack612, stack616,
- stack620, stack624, stack628, stack632, stack636, stack640,
- stack644, stack648, stack652, stack656, stack660, stack664,
- stack668, stack672, stack676, stack680, stack684, stack688,
- stack692, stack696, stack700, stack704, stack708, stack712,
- stack716, stack720, stack724, stack728, stack732, stack736,
- stack740, stack744, stack748, stack752, stack756, stack760,
- stack764, stack768, stack772, stack776, stack780, stack784,
- stack788, stack792, stack796, stack800, stack804, stack808,
- stack812, stack816, stack820, stack824, stack828, stack832,
- stack836, stack840, stack844, stack848, stack852, stack856,
- stack860, stack864, stack868, stack872, stack876, stack880,
- stack884, stack888, stack892, stack896, stack900, stack904,
- stack908, stack912, stack916, stack920, stack924, stack928,
- stack932, stack936, stack940, stack944, stack948, stack952,
- stack956, stack960, stack964, stack968, stack972, stack976,
- stack980, stack984, stack988, stack992, stack996, stack1000,
- stack1004, stack1008, stack1012, stack1016, stack1020, stack1024,
- stack1028, stack1032, stack1036, stack1040, stack1044, stack1048,
- stack1052, stack1056, stack1060, stack1064, stack1068, stack1072,
- stack1076, stack1080, stack1084, stack1088, stack1092, stack1096,
- stack1100, stack1104, stack1108, stack1112, stack1116, stack1120,
- stack1124, stack1128, stack1132, stack1136, stack1140, stack1144,
- stack1148, stack1152, stack1156, stack1160, stack1164, stack1168,
- stack1172, stack1176, stack1180, stack1184, stack1188, stack1192,
- stack1196, stack1200, stack1204, stack1208, stack1212, stack1216,
- stack1220, stack1224, stack1228, stack1232, stack1236, stack1240,
- stack1244, stack1248, stack1252, stack1256, stack1260, stack1264,
- stack1268, stack1272, stack1276, stack1280, stack1284, stack1288,
- stack1292, stack1296, stack1300, stack1304, stack1308, stack1312,
- stack1316, stack1320, stack1324, stack1328, stack1332, stack1336,
- stack1340, stack1344, stack1348, stack1352, stack1356, stack1360,
- stack1364, stack1368, stack1372, stack1376, stack1380, stack1384,
- stack1388, stack1392, stack1396, stack1400, stack1404, stack1408,
- stack1412, stack1416, stack1420, stack1424, stack1428, stack1432,
- stack1436, stack1440, stack1444, stack1448, stack1452, stack1456,
- stack1460, stack1464, stack1468, stack1472, stack1476, stack1480,
- stack1484, stack1488, stack1492, stack1496, stack1500, stack1504,
- stack1508, stack1512, stack1516, stack1520, stack1524, stack1528,
- stack1532, stack1536, stack1540, stack1544, stack1548, stack1552,
- stack1556, stack1560, stack1564, stack1568, stack1572, stack1576,
- stack1580, stack1584, stack1588, stack1592, stack1596, stack1600,
- stack1604, stack1608, stack1612, stack1616, stack1620, stack1624,
- stack1628, stack1632, stack1636, stack1640, stack1644, stack1648,
- stack1652, stack1656, stack1660, stack1664, stack1668, stack1672,
- stack1676, stack1680, stack1684, stack1688, stack1692, stack1696,
- stack1700, stack1704, stack1708, stack1712, stack1716, stack1720,
- stack1724, stack1728, stack1732, stack1736, stack1740, stack1744,
- stack1748, stack1752, stack1756, stack1760, stack1764, stack1768,
- stack1772, stack1776, stack1780, stack1784, stack1788, stack1792,
- stack1796, stack1800, stack1804, stack1808, stack1812, stack1816,
- stack1820, stack1824, stack1828, stack1832, stack1836, stack1840,
- stack1844, stack1848, stack1852, stack1856, stack1860, stack1864,
- stack1868, stack1872, stack1876, stack1880, stack1884, stack1888,
- stack1892, stack1896, stack1900, stack1904, stack1908, stack1912,
- stack1916, stack1920, stack1924, stack1928, stack1932, stack1936,
- stack1940, stack1944, stack1948, stack1952, stack1956, stack1960,
- stack1964, stack1968, stack1972, stack1976, stack1980, stack1984,
- stack1988, stack1992, stack1996, stack2000, stack2004, stack2008,
- stack2012, stack2016, stack2020, stack2024, stack2028, stack2032,
- stack2036, stack2040, stack2044, stack2048, stack2052, stack2056,
- stack2060, stack2064, stack2068, stack2072, stack2076, stack2080,
- stack2084, stack2088, stack2092, stack2096, stack2100, stack2104,
- stack2108, stack2112, stack2116, stack2120, stack2124, stack2128,
- stack2132, stack2136, stack2140, stack2144, stack2148, stack2152,
- stack2156, stack2160, stack2164, stack2168, stack2172, stack2176,
- stack2180, stack2184, stack2188, stack2192, stack2196, stack2200,
- stack2204, stack2208, stack2212, stack2216, stack2220, stack2224,
- stack2228, stack2232, stack2236, stack2240, stack2244, stack2248,
- stack2252, stack2256, stack2260, stack2264, stack2268, stack2272,
- stack2276, stack2280, stack2284, stack2288, stack2292, stack2296,
- stack2300, stack2304, stack2308, stack2312, stack2316, stack2320,
- stack2324, stack2328, stack2332, stack2336, stack2340, stack2344,
- stack2348, stack2352, stack2356, stack2360, stack2364, stack2368,
- stack2372, stack2376, stack2380, stack2384, stack2388, stack2392,
- stack2396, stack2400, stack2404, stack2408, stack2412, stack2416,
- stack2420, stack2424, stack2428, stack2432, stack2436, stack2440,
- stack2444, stack2448, stack2452, stack2456, stack2460, stack2464,
- stack2468, stack2472, stack2476, stack2480, stack2484, stack2488,
- stack2492, stack2496, stack2500, stack2504, stack2508, stack2512,
- stack2516, stack2520, stack2524, stack2528, stack2532, stack2536,
- stack2540, stack2544, stack2548, stack2552, stack2556, stack2560,
- stack2564, stack2568, stack2572, stack2576, stack2580, stack2584,
- stack2588, stack2592, stack2596, stack2600, stack2604, stack2608,
- stack2612, stack2616, stack2620, stack2624, stack2628, stack2632,
- stack2636, stack2640, stack2644, stack2648, stack2652, stack2656,
- stack2660, stack2664, stack2668, stack2672, stack2676, stack2680,
- stack2684, stack2688, stack2692, stack2696, stack2700, stack2704,
- stack2708, stack2712, stack2716, stack2720, stack2724, stack2728,
- stack2732, stack2736, stack2740, stack2744, stack2748, stack2752,
- stack2756, stack2760, stack2764, stack2768, stack2772, stack2776,
- stack2780, stack2784, stack2788, stack2792, stack2796, stack2800,
- stack2804, stack2808, stack2812, stack2816, stack2820, stack2824,
- stack2828, stack2832, stack2836, stack2840, stack2844, stack2848,
- stack2852, stack2856, stack2860, stack2864, stack2868, stack2872,
- stack2876, stack2880, stack2884, stack2888, stack2892, stack2896,
- stack2900, stack2904, stack2908, stack2912, stack2916, stack2920,
- stack2924, stack2928, stack2932, stack2936, stack2940, stack2944,
- stack2948, stack2952, stack2956, stack2960, stack2964, stack2968,
- stack2972, stack2976, stack2980, stack2984, stack2988, stack2992,
- stack2996, stack3000, stack3004, stack3008, stack3012, stack3016,
- stack3020, stack3024, stack3028, stack3032, stack3036, stack3040,
- stack3044, stack3048, stack3052, stack3056, stack3060, stack3064,
- stack3068, stack3072, stack3076, stack3080, stack3084, stack3088,
- stack3092, stack3096, stack3100, stack3104, stack3108, stack3112,
- stack3116, stack3120, stack3124, stack3128, stack3132, stack3136,
- stack3140, stack3144, stack3148, stack3152, stack3156, stack3160,
- stack3164, stack3168, stack3172, stack3176, stack3180, stack3184,
- stack3188, stack3192, stack3196, stack3200, stack3204, stack3208,
- stack3212, stack3216, stack3220, stack3224, stack3228, stack3232,
- stack3236, stack3240, stack3244, stack3248, stack3252, stack3256,
- stack3260, stack3264, stack3268, stack3272, stack3276, stack3280,
- stack3284, stack3288, stack3292, stack3296, stack3300, stack3304,
- stack3308, stack3312, stack3316, stack3320, stack3324, stack3328,
- stack3332, stack3336, stack3340, stack3344, stack3348, stack3352,
- stack3356, stack3360, stack3364, stack3368, stack3372, stack3376,
- stack3380, stack3384, stack3388, stack3392, stack3396, stack3400,
- stack3404, stack3408, stack3412, stack3416, stack3420, stack3424,
- stack3428, stack3432, stack3436, stack3440, stack3444, stack3448,
- stack3452, stack3456, stack3460, stack3464, stack3468, stack3472,
- stack3476, stack3480, stack3484, stack3488, stack3492, stack3496,
- stack3500, stack3504, stack3508, stack3512, stack3516, stack3520,
- stack3524, stack3528, stack3532, stack3536, stack3540, stack3544,
- stack3548, stack3552, stack3556, stack3560, stack3564, stack3568,
- stack3572, stack3576, stack3580, stack3584, stack3588, stack3592,
- stack3596, stack3600, stack3604, stack3608, stack3612, stack3616,
- stack3620, stack3624, stack3628, stack3632, stack3636, stack3640,
- stack3644, stack3648, stack3652, stack3656, stack3660, stack3664,
- stack3668, stack3672, stack3676, stack3680, stack3684, stack3688,
- stack3692, stack3696, stack3700, stack3704, stack3708, stack3712,
- stack3716, stack3720, stack3724, stack3728, stack3732, stack3736,
- stack3740, stack3744, stack3748, stack3752, stack3756, stack3760,
- stack3764, stack3768, stack3772, stack3776, stack3780, stack3784,
- stack3788, stack3792, stack3796, stack3800, stack3804, stack3808,
- stack3812, stack3816, stack3820, stack3824, stack3828, stack3832,
- stack3836, stack3840, stack3844, stack3848, stack3852, stack3856,
- stack3860, stack3864, stack3868, stack3872, stack3876, stack3880,
- stack3884, stack3888, stack3892, stack3896, stack3900, stack3904,
- stack3908, stack3912, stack3916, stack3920, stack3924, stack3928,
- stack3932, stack3936, stack3940, stack3944, stack3948, stack3952,
- stack3956, stack3960, stack3964, stack3968, stack3972, stack3976,
- stack3980, stack3984, stack3988, stack3992, stack3996, stack4000,
- stack4004, stack4008, stack4012, stack4016, stack4020, stack4024,
- stack4028, stack4032, stack4036, stack4040, stack4044, stack4048,
- stack4052, stack4056, stack4060, stack4064, stack4068, stack4072,
- stack4076, stack4080, stack4084, stack4088, stack4092, stack4096,
- stack4100, stack4104, stack4108, stack4112, stack4116, stack4120,
- stack4124, stack4128, stack4132, stack4136, stack4140, stack4144,
- stack4148, stack4152, stack4156, stack4160, stack4164, stack4168,
- stack4172, stack4176, stack4180, stack4184, stack4188, stack4192,
- stack4196, stack4200, stack4204, stack4208, stack4212, stack4216,
- stack4220, stack4224, stack4228, stack4232, stack4236, stack4240,
- stack4244, stack4248, stack4252, stack4256, stack4260, stack4264,
- stack4268, stack4272, stack4276, stack4280, stack4284, stack4288,
- stack4292, stack4296, stack4300, stack4304, stack4308, stack4312,
- stack4316, stack4320, stack4324, stack4328, stack4332, stack4336,
- stack4340, stack4344, stack4348, stack4352, stack4356, stack4360,
- stack4364, stack4368, stack4372, stack4376, stack4380, stack4384,
- stack4388, stack4392, stack4396, stack4400, stack4404, stack4408,
- stack4412, stack4416, stack4420, stack4424, stack4428, stack4432,
- stack4436, stack4440, stack4444, stack4448, stack4452, stack4456,
- stack4460, stack4464, stack4468, stack4472, stack4476, stack4480,
- stack4484, stack4488, stack4492, stack4496, stack4500, stack4504,
- stack4508, stack4512, stack4516, stack4520, stack4524, stack4528,
- stack4532, stack4536, stack4540, stack4544, stack4548, stack4552,
- stack4556, stack4560, stack4564, stack4568, stack4572, stack4576,
- stack4580, stack4584, stack4588, stack4592, stack4596, stack4600,
- stack4604, stack4608, stack4612, stack4616, stack4620, stack4624,
- stack4628, stack4632, stack4636, stack4640, stack4644, stack4648,
- stack4652, stack4656, stack4660, stack4664, stack4668, stack4672,
- stack4676, stack4680, stack4684, stack4688, stack4692, stack4696,
- stack4700, stack4704, stack4708, stack4712, stack4716, stack4720,
- stack4724, stack4728, stack4732, stack4736, stack4740, stack4744,
- stack4748, stack4752, stack4756, stack4760, stack4764, stack4768,
- stack4772, stack4776, stack4780, stack4784, stack4788, stack4792,
- stack4796, stack4800, stack4804, stack4808, stack4812, stack4816,
- stack4820, stack4824, stack4828, stack4832, stack4836, stack4840,
- stack4844, stack4848, stack4852, stack4856, stack4860, stack4864,
- stack4868, stack4872, stack4876, stack4880, stack4884, stack4888,
- stack4892, stack4896, stack4900, stack4904, stack4908, stack4912,
- stack4916, stack4920, stack4924, stack4928, stack4932, stack4936,
- stack4940, stack4944, stack4948, stack4952, stack4956, stack4960,
- stack4964, stack4968, stack4972, stack4976, stack4980, stack4984,
- stack4988, stack4992, stack4996, stack5000,
-}
-
var Used byte
func use(buf []byte) {
@@ -276,1258 +64,6 @@ func use(buf []byte) {
}
}
-// Edit .+1,$ | seq 4 4 5000 | sed 's/.*/func stack&()(uintptr, uintptr) { var buf [&]byte; use(buf[:]); return Stackguard() }/'
-func stack4() (uintptr, uintptr) { var buf [4]byte; use(buf[:]); return Stackguard() }
-func stack8() (uintptr, uintptr) { var buf [8]byte; use(buf[:]); return Stackguard() }
-func stack12() (uintptr, uintptr) { var buf [12]byte; use(buf[:]); return Stackguard() }
-func stack16() (uintptr, uintptr) { var buf [16]byte; use(buf[:]); return Stackguard() }
-func stack20() (uintptr, uintptr) { var buf [20]byte; use(buf[:]); return Stackguard() }
-func stack24() (uintptr, uintptr) { var buf [24]byte; use(buf[:]); return Stackguard() }
-func stack28() (uintptr, uintptr) { var buf [28]byte; use(buf[:]); return Stackguard() }
-func stack32() (uintptr, uintptr) { var buf [32]byte; use(buf[:]); return Stackguard() }
-func stack36() (uintptr, uintptr) { var buf [36]byte; use(buf[:]); return Stackguard() }
-func stack40() (uintptr, uintptr) { var buf [40]byte; use(buf[:]); return Stackguard() }
-func stack44() (uintptr, uintptr) { var buf [44]byte; use(buf[:]); return Stackguard() }
-func stack48() (uintptr, uintptr) { var buf [48]byte; use(buf[:]); return Stackguard() }
-func stack52() (uintptr, uintptr) { var buf [52]byte; use(buf[:]); return Stackguard() }
-func stack56() (uintptr, uintptr) { var buf [56]byte; use(buf[:]); return Stackguard() }
-func stack60() (uintptr, uintptr) { var buf [60]byte; use(buf[:]); return Stackguard() }
-func stack64() (uintptr, uintptr) { var buf [64]byte; use(buf[:]); return Stackguard() }
-func stack68() (uintptr, uintptr) { var buf [68]byte; use(buf[:]); return Stackguard() }
-func stack72() (uintptr, uintptr) { var buf [72]byte; use(buf[:]); return Stackguard() }
-func stack76() (uintptr, uintptr) { var buf [76]byte; use(buf[:]); return Stackguard() }
-func stack80() (uintptr, uintptr) { var buf [80]byte; use(buf[:]); return Stackguard() }
-func stack84() (uintptr, uintptr) { var buf [84]byte; use(buf[:]); return Stackguard() }
-func stack88() (uintptr, uintptr) { var buf [88]byte; use(buf[:]); return Stackguard() }
-func stack92() (uintptr, uintptr) { var buf [92]byte; use(buf[:]); return Stackguard() }
-func stack96() (uintptr, uintptr) { var buf [96]byte; use(buf[:]); return Stackguard() }
-func stack100() (uintptr, uintptr) { var buf [100]byte; use(buf[:]); return Stackguard() }
-func stack104() (uintptr, uintptr) { var buf [104]byte; use(buf[:]); return Stackguard() }
-func stack108() (uintptr, uintptr) { var buf [108]byte; use(buf[:]); return Stackguard() }
-func stack112() (uintptr, uintptr) { var buf [112]byte; use(buf[:]); return Stackguard() }
-func stack116() (uintptr, uintptr) { var buf [116]byte; use(buf[:]); return Stackguard() }
-func stack120() (uintptr, uintptr) { var buf [120]byte; use(buf[:]); return Stackguard() }
-func stack124() (uintptr, uintptr) { var buf [124]byte; use(buf[:]); return Stackguard() }
-func stack128() (uintptr, uintptr) { var buf [128]byte; use(buf[:]); return Stackguard() }
-func stack132() (uintptr, uintptr) { var buf [132]byte; use(buf[:]); return Stackguard() }
-func stack136() (uintptr, uintptr) { var buf [136]byte; use(buf[:]); return Stackguard() }
-func stack140() (uintptr, uintptr) { var buf [140]byte; use(buf[:]); return Stackguard() }
-func stack144() (uintptr, uintptr) { var buf [144]byte; use(buf[:]); return Stackguard() }
-func stack148() (uintptr, uintptr) { var buf [148]byte; use(buf[:]); return Stackguard() }
-func stack152() (uintptr, uintptr) { var buf [152]byte; use(buf[:]); return Stackguard() }
-func stack156() (uintptr, uintptr) { var buf [156]byte; use(buf[:]); return Stackguard() }
-func stack160() (uintptr, uintptr) { var buf [160]byte; use(buf[:]); return Stackguard() }
-func stack164() (uintptr, uintptr) { var buf [164]byte; use(buf[:]); return Stackguard() }
-func stack168() (uintptr, uintptr) { var buf [168]byte; use(buf[:]); return Stackguard() }
-func stack172() (uintptr, uintptr) { var buf [172]byte; use(buf[:]); return Stackguard() }
-func stack176() (uintptr, uintptr) { var buf [176]byte; use(buf[:]); return Stackguard() }
-func stack180() (uintptr, uintptr) { var buf [180]byte; use(buf[:]); return Stackguard() }
-func stack184() (uintptr, uintptr) { var buf [184]byte; use(buf[:]); return Stackguard() }
-func stack188() (uintptr, uintptr) { var buf [188]byte; use(buf[:]); return Stackguard() }
-func stack192() (uintptr, uintptr) { var buf [192]byte; use(buf[:]); return Stackguard() }
-func stack196() (uintptr, uintptr) { var buf [196]byte; use(buf[:]); return Stackguard() }
-func stack200() (uintptr, uintptr) { var buf [200]byte; use(buf[:]); return Stackguard() }
-func stack204() (uintptr, uintptr) { var buf [204]byte; use(buf[:]); return Stackguard() }
-func stack208() (uintptr, uintptr) { var buf [208]byte; use(buf[:]); return Stackguard() }
-func stack212() (uintptr, uintptr) { var buf [212]byte; use(buf[:]); return Stackguard() }
-func stack216() (uintptr, uintptr) { var buf [216]byte; use(buf[:]); return Stackguard() }
-func stack220() (uintptr, uintptr) { var buf [220]byte; use(buf[:]); return Stackguard() }
-func stack224() (uintptr, uintptr) { var buf [224]byte; use(buf[:]); return Stackguard() }
-func stack228() (uintptr, uintptr) { var buf [228]byte; use(buf[:]); return Stackguard() }
-func stack232() (uintptr, uintptr) { var buf [232]byte; use(buf[:]); return Stackguard() }
-func stack236() (uintptr, uintptr) { var buf [236]byte; use(buf[:]); return Stackguard() }
-func stack240() (uintptr, uintptr) { var buf [240]byte; use(buf[:]); return Stackguard() }
-func stack244() (uintptr, uintptr) { var buf [244]byte; use(buf[:]); return Stackguard() }
-func stack248() (uintptr, uintptr) { var buf [248]byte; use(buf[:]); return Stackguard() }
-func stack252() (uintptr, uintptr) { var buf [252]byte; use(buf[:]); return Stackguard() }
-func stack256() (uintptr, uintptr) { var buf [256]byte; use(buf[:]); return Stackguard() }
-func stack260() (uintptr, uintptr) { var buf [260]byte; use(buf[:]); return Stackguard() }
-func stack264() (uintptr, uintptr) { var buf [264]byte; use(buf[:]); return Stackguard() }
-func stack268() (uintptr, uintptr) { var buf [268]byte; use(buf[:]); return Stackguard() }
-func stack272() (uintptr, uintptr) { var buf [272]byte; use(buf[:]); return Stackguard() }
-func stack276() (uintptr, uintptr) { var buf [276]byte; use(buf[:]); return Stackguard() }
-func stack280() (uintptr, uintptr) { var buf [280]byte; use(buf[:]); return Stackguard() }
-func stack284() (uintptr, uintptr) { var buf [284]byte; use(buf[:]); return Stackguard() }
-func stack288() (uintptr, uintptr) { var buf [288]byte; use(buf[:]); return Stackguard() }
-func stack292() (uintptr, uintptr) { var buf [292]byte; use(buf[:]); return Stackguard() }
-func stack296() (uintptr, uintptr) { var buf [296]byte; use(buf[:]); return Stackguard() }
-func stack300() (uintptr, uintptr) { var buf [300]byte; use(buf[:]); return Stackguard() }
-func stack304() (uintptr, uintptr) { var buf [304]byte; use(buf[:]); return Stackguard() }
-func stack308() (uintptr, uintptr) { var buf [308]byte; use(buf[:]); return Stackguard() }
-func stack312() (uintptr, uintptr) { var buf [312]byte; use(buf[:]); return Stackguard() }
-func stack316() (uintptr, uintptr) { var buf [316]byte; use(buf[:]); return Stackguard() }
-func stack320() (uintptr, uintptr) { var buf [320]byte; use(buf[:]); return Stackguard() }
-func stack324() (uintptr, uintptr) { var buf [324]byte; use(buf[:]); return Stackguard() }
-func stack328() (uintptr, uintptr) { var buf [328]byte; use(buf[:]); return Stackguard() }
-func stack332() (uintptr, uintptr) { var buf [332]byte; use(buf[:]); return Stackguard() }
-func stack336() (uintptr, uintptr) { var buf [336]byte; use(buf[:]); return Stackguard() }
-func stack340() (uintptr, uintptr) { var buf [340]byte; use(buf[:]); return Stackguard() }
-func stack344() (uintptr, uintptr) { var buf [344]byte; use(buf[:]); return Stackguard() }
-func stack348() (uintptr, uintptr) { var buf [348]byte; use(buf[:]); return Stackguard() }
-func stack352() (uintptr, uintptr) { var buf [352]byte; use(buf[:]); return Stackguard() }
-func stack356() (uintptr, uintptr) { var buf [356]byte; use(buf[:]); return Stackguard() }
-func stack360() (uintptr, uintptr) { var buf [360]byte; use(buf[:]); return Stackguard() }
-func stack364() (uintptr, uintptr) { var buf [364]byte; use(buf[:]); return Stackguard() }
-func stack368() (uintptr, uintptr) { var buf [368]byte; use(buf[:]); return Stackguard() }
-func stack372() (uintptr, uintptr) { var buf [372]byte; use(buf[:]); return Stackguard() }
-func stack376() (uintptr, uintptr) { var buf [376]byte; use(buf[:]); return Stackguard() }
-func stack380() (uintptr, uintptr) { var buf [380]byte; use(buf[:]); return Stackguard() }
-func stack384() (uintptr, uintptr) { var buf [384]byte; use(buf[:]); return Stackguard() }
-func stack388() (uintptr, uintptr) { var buf [388]byte; use(buf[:]); return Stackguard() }
-func stack392() (uintptr, uintptr) { var buf [392]byte; use(buf[:]); return Stackguard() }
-func stack396() (uintptr, uintptr) { var buf [396]byte; use(buf[:]); return Stackguard() }
-func stack400() (uintptr, uintptr) { var buf [400]byte; use(buf[:]); return Stackguard() }
-func stack404() (uintptr, uintptr) { var buf [404]byte; use(buf[:]); return Stackguard() }
-func stack408() (uintptr, uintptr) { var buf [408]byte; use(buf[:]); return Stackguard() }
-func stack412() (uintptr, uintptr) { var buf [412]byte; use(buf[:]); return Stackguard() }
-func stack416() (uintptr, uintptr) { var buf [416]byte; use(buf[:]); return Stackguard() }
-func stack420() (uintptr, uintptr) { var buf [420]byte; use(buf[:]); return Stackguard() }
-func stack424() (uintptr, uintptr) { var buf [424]byte; use(buf[:]); return Stackguard() }
-func stack428() (uintptr, uintptr) { var buf [428]byte; use(buf[:]); return Stackguard() }
-func stack432() (uintptr, uintptr) { var buf [432]byte; use(buf[:]); return Stackguard() }
-func stack436() (uintptr, uintptr) { var buf [436]byte; use(buf[:]); return Stackguard() }
-func stack440() (uintptr, uintptr) { var buf [440]byte; use(buf[:]); return Stackguard() }
-func stack444() (uintptr, uintptr) { var buf [444]byte; use(buf[:]); return Stackguard() }
-func stack448() (uintptr, uintptr) { var buf [448]byte; use(buf[:]); return Stackguard() }
-func stack452() (uintptr, uintptr) { var buf [452]byte; use(buf[:]); return Stackguard() }
-func stack456() (uintptr, uintptr) { var buf [456]byte; use(buf[:]); return Stackguard() }
-func stack460() (uintptr, uintptr) { var buf [460]byte; use(buf[:]); return Stackguard() }
-func stack464() (uintptr, uintptr) { var buf [464]byte; use(buf[:]); return Stackguard() }
-func stack468() (uintptr, uintptr) { var buf [468]byte; use(buf[:]); return Stackguard() }
-func stack472() (uintptr, uintptr) { var buf [472]byte; use(buf[:]); return Stackguard() }
-func stack476() (uintptr, uintptr) { var buf [476]byte; use(buf[:]); return Stackguard() }
-func stack480() (uintptr, uintptr) { var buf [480]byte; use(buf[:]); return Stackguard() }
-func stack484() (uintptr, uintptr) { var buf [484]byte; use(buf[:]); return Stackguard() }
-func stack488() (uintptr, uintptr) { var buf [488]byte; use(buf[:]); return Stackguard() }
-func stack492() (uintptr, uintptr) { var buf [492]byte; use(buf[:]); return Stackguard() }
-func stack496() (uintptr, uintptr) { var buf [496]byte; use(buf[:]); return Stackguard() }
-func stack500() (uintptr, uintptr) { var buf [500]byte; use(buf[:]); return Stackguard() }
-func stack504() (uintptr, uintptr) { var buf [504]byte; use(buf[:]); return Stackguard() }
-func stack508() (uintptr, uintptr) { var buf [508]byte; use(buf[:]); return Stackguard() }
-func stack512() (uintptr, uintptr) { var buf [512]byte; use(buf[:]); return Stackguard() }
-func stack516() (uintptr, uintptr) { var buf [516]byte; use(buf[:]); return Stackguard() }
-func stack520() (uintptr, uintptr) { var buf [520]byte; use(buf[:]); return Stackguard() }
-func stack524() (uintptr, uintptr) { var buf [524]byte; use(buf[:]); return Stackguard() }
-func stack528() (uintptr, uintptr) { var buf [528]byte; use(buf[:]); return Stackguard() }
-func stack532() (uintptr, uintptr) { var buf [532]byte; use(buf[:]); return Stackguard() }
-func stack536() (uintptr, uintptr) { var buf [536]byte; use(buf[:]); return Stackguard() }
-func stack540() (uintptr, uintptr) { var buf [540]byte; use(buf[:]); return Stackguard() }
-func stack544() (uintptr, uintptr) { var buf [544]byte; use(buf[:]); return Stackguard() }
-func stack548() (uintptr, uintptr) { var buf [548]byte; use(buf[:]); return Stackguard() }
-func stack552() (uintptr, uintptr) { var buf [552]byte; use(buf[:]); return Stackguard() }
-func stack556() (uintptr, uintptr) { var buf [556]byte; use(buf[:]); return Stackguard() }
-func stack560() (uintptr, uintptr) { var buf [560]byte; use(buf[:]); return Stackguard() }
-func stack564() (uintptr, uintptr) { var buf [564]byte; use(buf[:]); return Stackguard() }
-func stack568() (uintptr, uintptr) { var buf [568]byte; use(buf[:]); return Stackguard() }
-func stack572() (uintptr, uintptr) { var buf [572]byte; use(buf[:]); return Stackguard() }
-func stack576() (uintptr, uintptr) { var buf [576]byte; use(buf[:]); return Stackguard() }
-func stack580() (uintptr, uintptr) { var buf [580]byte; use(buf[:]); return Stackguard() }
-func stack584() (uintptr, uintptr) { var buf [584]byte; use(buf[:]); return Stackguard() }
-func stack588() (uintptr, uintptr) { var buf [588]byte; use(buf[:]); return Stackguard() }
-func stack592() (uintptr, uintptr) { var buf [592]byte; use(buf[:]); return Stackguard() }
-func stack596() (uintptr, uintptr) { var buf [596]byte; use(buf[:]); return Stackguard() }
-func stack600() (uintptr, uintptr) { var buf [600]byte; use(buf[:]); return Stackguard() }
-func stack604() (uintptr, uintptr) { var buf [604]byte; use(buf[:]); return Stackguard() }
-func stack608() (uintptr, uintptr) { var buf [608]byte; use(buf[:]); return Stackguard() }
-func stack612() (uintptr, uintptr) { var buf [612]byte; use(buf[:]); return Stackguard() }
-func stack616() (uintptr, uintptr) { var buf [616]byte; use(buf[:]); return Stackguard() }
-func stack620() (uintptr, uintptr) { var buf [620]byte; use(buf[:]); return Stackguard() }
-func stack624() (uintptr, uintptr) { var buf [624]byte; use(buf[:]); return Stackguard() }
-func stack628() (uintptr, uintptr) { var buf [628]byte; use(buf[:]); return Stackguard() }
-func stack632() (uintptr, uintptr) { var buf [632]byte; use(buf[:]); return Stackguard() }
-func stack636() (uintptr, uintptr) { var buf [636]byte; use(buf[:]); return Stackguard() }
-func stack640() (uintptr, uintptr) { var buf [640]byte; use(buf[:]); return Stackguard() }
-func stack644() (uintptr, uintptr) { var buf [644]byte; use(buf[:]); return Stackguard() }
-func stack648() (uintptr, uintptr) { var buf [648]byte; use(buf[:]); return Stackguard() }
-func stack652() (uintptr, uintptr) { var buf [652]byte; use(buf[:]); return Stackguard() }
-func stack656() (uintptr, uintptr) { var buf [656]byte; use(buf[:]); return Stackguard() }
-func stack660() (uintptr, uintptr) { var buf [660]byte; use(buf[:]); return Stackguard() }
-func stack664() (uintptr, uintptr) { var buf [664]byte; use(buf[:]); return Stackguard() }
-func stack668() (uintptr, uintptr) { var buf [668]byte; use(buf[:]); return Stackguard() }
-func stack672() (uintptr, uintptr) { var buf [672]byte; use(buf[:]); return Stackguard() }
-func stack676() (uintptr, uintptr) { var buf [676]byte; use(buf[:]); return Stackguard() }
-func stack680() (uintptr, uintptr) { var buf [680]byte; use(buf[:]); return Stackguard() }
-func stack684() (uintptr, uintptr) { var buf [684]byte; use(buf[:]); return Stackguard() }
-func stack688() (uintptr, uintptr) { var buf [688]byte; use(buf[:]); return Stackguard() }
-func stack692() (uintptr, uintptr) { var buf [692]byte; use(buf[:]); return Stackguard() }
-func stack696() (uintptr, uintptr) { var buf [696]byte; use(buf[:]); return Stackguard() }
-func stack700() (uintptr, uintptr) { var buf [700]byte; use(buf[:]); return Stackguard() }
-func stack704() (uintptr, uintptr) { var buf [704]byte; use(buf[:]); return Stackguard() }
-func stack708() (uintptr, uintptr) { var buf [708]byte; use(buf[:]); return Stackguard() }
-func stack712() (uintptr, uintptr) { var buf [712]byte; use(buf[:]); return Stackguard() }
-func stack716() (uintptr, uintptr) { var buf [716]byte; use(buf[:]); return Stackguard() }
-func stack720() (uintptr, uintptr) { var buf [720]byte; use(buf[:]); return Stackguard() }
-func stack724() (uintptr, uintptr) { var buf [724]byte; use(buf[:]); return Stackguard() }
-func stack728() (uintptr, uintptr) { var buf [728]byte; use(buf[:]); return Stackguard() }
-func stack732() (uintptr, uintptr) { var buf [732]byte; use(buf[:]); return Stackguard() }
-func stack736() (uintptr, uintptr) { var buf [736]byte; use(buf[:]); return Stackguard() }
-func stack740() (uintptr, uintptr) { var buf [740]byte; use(buf[:]); return Stackguard() }
-func stack744() (uintptr, uintptr) { var buf [744]byte; use(buf[:]); return Stackguard() }
-func stack748() (uintptr, uintptr) { var buf [748]byte; use(buf[:]); return Stackguard() }
-func stack752() (uintptr, uintptr) { var buf [752]byte; use(buf[:]); return Stackguard() }
-func stack756() (uintptr, uintptr) { var buf [756]byte; use(buf[:]); return Stackguard() }
-func stack760() (uintptr, uintptr) { var buf [760]byte; use(buf[:]); return Stackguard() }
-func stack764() (uintptr, uintptr) { var buf [764]byte; use(buf[:]); return Stackguard() }
-func stack768() (uintptr, uintptr) { var buf [768]byte; use(buf[:]); return Stackguard() }
-func stack772() (uintptr, uintptr) { var buf [772]byte; use(buf[:]); return Stackguard() }
-func stack776() (uintptr, uintptr) { var buf [776]byte; use(buf[:]); return Stackguard() }
-func stack780() (uintptr, uintptr) { var buf [780]byte; use(buf[:]); return Stackguard() }
-func stack784() (uintptr, uintptr) { var buf [784]byte; use(buf[:]); return Stackguard() }
-func stack788() (uintptr, uintptr) { var buf [788]byte; use(buf[:]); return Stackguard() }
-func stack792() (uintptr, uintptr) { var buf [792]byte; use(buf[:]); return Stackguard() }
-func stack796() (uintptr, uintptr) { var buf [796]byte; use(buf[:]); return Stackguard() }
-func stack800() (uintptr, uintptr) { var buf [800]byte; use(buf[:]); return Stackguard() }
-func stack804() (uintptr, uintptr) { var buf [804]byte; use(buf[:]); return Stackguard() }
-func stack808() (uintptr, uintptr) { var buf [808]byte; use(buf[:]); return Stackguard() }
-func stack812() (uintptr, uintptr) { var buf [812]byte; use(buf[:]); return Stackguard() }
-func stack816() (uintptr, uintptr) { var buf [816]byte; use(buf[:]); return Stackguard() }
-func stack820() (uintptr, uintptr) { var buf [820]byte; use(buf[:]); return Stackguard() }
-func stack824() (uintptr, uintptr) { var buf [824]byte; use(buf[:]); return Stackguard() }
-func stack828() (uintptr, uintptr) { var buf [828]byte; use(buf[:]); return Stackguard() }
-func stack832() (uintptr, uintptr) { var buf [832]byte; use(buf[:]); return Stackguard() }
-func stack836() (uintptr, uintptr) { var buf [836]byte; use(buf[:]); return Stackguard() }
-func stack840() (uintptr, uintptr) { var buf [840]byte; use(buf[:]); return Stackguard() }
-func stack844() (uintptr, uintptr) { var buf [844]byte; use(buf[:]); return Stackguard() }
-func stack848() (uintptr, uintptr) { var buf [848]byte; use(buf[:]); return Stackguard() }
-func stack852() (uintptr, uintptr) { var buf [852]byte; use(buf[:]); return Stackguard() }
-func stack856() (uintptr, uintptr) { var buf [856]byte; use(buf[:]); return Stackguard() }
-func stack860() (uintptr, uintptr) { var buf [860]byte; use(buf[:]); return Stackguard() }
-func stack864() (uintptr, uintptr) { var buf [864]byte; use(buf[:]); return Stackguard() }
-func stack868() (uintptr, uintptr) { var buf [868]byte; use(buf[:]); return Stackguard() }
-func stack872() (uintptr, uintptr) { var buf [872]byte; use(buf[:]); return Stackguard() }
-func stack876() (uintptr, uintptr) { var buf [876]byte; use(buf[:]); return Stackguard() }
-func stack880() (uintptr, uintptr) { var buf [880]byte; use(buf[:]); return Stackguard() }
-func stack884() (uintptr, uintptr) { var buf [884]byte; use(buf[:]); return Stackguard() }
-func stack888() (uintptr, uintptr) { var buf [888]byte; use(buf[:]); return Stackguard() }
-func stack892() (uintptr, uintptr) { var buf [892]byte; use(buf[:]); return Stackguard() }
-func stack896() (uintptr, uintptr) { var buf [896]byte; use(buf[:]); return Stackguard() }
-func stack900() (uintptr, uintptr) { var buf [900]byte; use(buf[:]); return Stackguard() }
-func stack904() (uintptr, uintptr) { var buf [904]byte; use(buf[:]); return Stackguard() }
-func stack908() (uintptr, uintptr) { var buf [908]byte; use(buf[:]); return Stackguard() }
-func stack912() (uintptr, uintptr) { var buf [912]byte; use(buf[:]); return Stackguard() }
-func stack916() (uintptr, uintptr) { var buf [916]byte; use(buf[:]); return Stackguard() }
-func stack920() (uintptr, uintptr) { var buf [920]byte; use(buf[:]); return Stackguard() }
-func stack924() (uintptr, uintptr) { var buf [924]byte; use(buf[:]); return Stackguard() }
-func stack928() (uintptr, uintptr) { var buf [928]byte; use(buf[:]); return Stackguard() }
-func stack932() (uintptr, uintptr) { var buf [932]byte; use(buf[:]); return Stackguard() }
-func stack936() (uintptr, uintptr) { var buf [936]byte; use(buf[:]); return Stackguard() }
-func stack940() (uintptr, uintptr) { var buf [940]byte; use(buf[:]); return Stackguard() }
-func stack944() (uintptr, uintptr) { var buf [944]byte; use(buf[:]); return Stackguard() }
-func stack948() (uintptr, uintptr) { var buf [948]byte; use(buf[:]); return Stackguard() }
-func stack952() (uintptr, uintptr) { var buf [952]byte; use(buf[:]); return Stackguard() }
-func stack956() (uintptr, uintptr) { var buf [956]byte; use(buf[:]); return Stackguard() }
-func stack960() (uintptr, uintptr) { var buf [960]byte; use(buf[:]); return Stackguard() }
-func stack964() (uintptr, uintptr) { var buf [964]byte; use(buf[:]); return Stackguard() }
-func stack968() (uintptr, uintptr) { var buf [968]byte; use(buf[:]); return Stackguard() }
-func stack972() (uintptr, uintptr) { var buf [972]byte; use(buf[:]); return Stackguard() }
-func stack976() (uintptr, uintptr) { var buf [976]byte; use(buf[:]); return Stackguard() }
-func stack980() (uintptr, uintptr) { var buf [980]byte; use(buf[:]); return Stackguard() }
-func stack984() (uintptr, uintptr) { var buf [984]byte; use(buf[:]); return Stackguard() }
-func stack988() (uintptr, uintptr) { var buf [988]byte; use(buf[:]); return Stackguard() }
-func stack992() (uintptr, uintptr) { var buf [992]byte; use(buf[:]); return Stackguard() }
-func stack996() (uintptr, uintptr) { var buf [996]byte; use(buf[:]); return Stackguard() }
-func stack1000() (uintptr, uintptr) { var buf [1000]byte; use(buf[:]); return Stackguard() }
-func stack1004() (uintptr, uintptr) { var buf [1004]byte; use(buf[:]); return Stackguard() }
-func stack1008() (uintptr, uintptr) { var buf [1008]byte; use(buf[:]); return Stackguard() }
-func stack1012() (uintptr, uintptr) { var buf [1012]byte; use(buf[:]); return Stackguard() }
-func stack1016() (uintptr, uintptr) { var buf [1016]byte; use(buf[:]); return Stackguard() }
-func stack1020() (uintptr, uintptr) { var buf [1020]byte; use(buf[:]); return Stackguard() }
-func stack1024() (uintptr, uintptr) { var buf [1024]byte; use(buf[:]); return Stackguard() }
-func stack1028() (uintptr, uintptr) { var buf [1028]byte; use(buf[:]); return Stackguard() }
-func stack1032() (uintptr, uintptr) { var buf [1032]byte; use(buf[:]); return Stackguard() }
-func stack1036() (uintptr, uintptr) { var buf [1036]byte; use(buf[:]); return Stackguard() }
-func stack1040() (uintptr, uintptr) { var buf [1040]byte; use(buf[:]); return Stackguard() }
-func stack1044() (uintptr, uintptr) { var buf [1044]byte; use(buf[:]); return Stackguard() }
-func stack1048() (uintptr, uintptr) { var buf [1048]byte; use(buf[:]); return Stackguard() }
-func stack1052() (uintptr, uintptr) { var buf [1052]byte; use(buf[:]); return Stackguard() }
-func stack1056() (uintptr, uintptr) { var buf [1056]byte; use(buf[:]); return Stackguard() }
-func stack1060() (uintptr, uintptr) { var buf [1060]byte; use(buf[:]); return Stackguard() }
-func stack1064() (uintptr, uintptr) { var buf [1064]byte; use(buf[:]); return Stackguard() }
-func stack1068() (uintptr, uintptr) { var buf [1068]byte; use(buf[:]); return Stackguard() }
-func stack1072() (uintptr, uintptr) { var buf [1072]byte; use(buf[:]); return Stackguard() }
-func stack1076() (uintptr, uintptr) { var buf [1076]byte; use(buf[:]); return Stackguard() }
-func stack1080() (uintptr, uintptr) { var buf [1080]byte; use(buf[:]); return Stackguard() }
-func stack1084() (uintptr, uintptr) { var buf [1084]byte; use(buf[:]); return Stackguard() }
-func stack1088() (uintptr, uintptr) { var buf [1088]byte; use(buf[:]); return Stackguard() }
-func stack1092() (uintptr, uintptr) { var buf [1092]byte; use(buf[:]); return Stackguard() }
-func stack1096() (uintptr, uintptr) { var buf [1096]byte; use(buf[:]); return Stackguard() }
-func stack1100() (uintptr, uintptr) { var buf [1100]byte; use(buf[:]); return Stackguard() }
-func stack1104() (uintptr, uintptr) { var buf [1104]byte; use(buf[:]); return Stackguard() }
-func stack1108() (uintptr, uintptr) { var buf [1108]byte; use(buf[:]); return Stackguard() }
-func stack1112() (uintptr, uintptr) { var buf [1112]byte; use(buf[:]); return Stackguard() }
-func stack1116() (uintptr, uintptr) { var buf [1116]byte; use(buf[:]); return Stackguard() }
-func stack1120() (uintptr, uintptr) { var buf [1120]byte; use(buf[:]); return Stackguard() }
-func stack1124() (uintptr, uintptr) { var buf [1124]byte; use(buf[:]); return Stackguard() }
-func stack1128() (uintptr, uintptr) { var buf [1128]byte; use(buf[:]); return Stackguard() }
-func stack1132() (uintptr, uintptr) { var buf [1132]byte; use(buf[:]); return Stackguard() }
-func stack1136() (uintptr, uintptr) { var buf [1136]byte; use(buf[:]); return Stackguard() }
-func stack1140() (uintptr, uintptr) { var buf [1140]byte; use(buf[:]); return Stackguard() }
-func stack1144() (uintptr, uintptr) { var buf [1144]byte; use(buf[:]); return Stackguard() }
-func stack1148() (uintptr, uintptr) { var buf [1148]byte; use(buf[:]); return Stackguard() }
-func stack1152() (uintptr, uintptr) { var buf [1152]byte; use(buf[:]); return Stackguard() }
-func stack1156() (uintptr, uintptr) { var buf [1156]byte; use(buf[:]); return Stackguard() }
-func stack1160() (uintptr, uintptr) { var buf [1160]byte; use(buf[:]); return Stackguard() }
-func stack1164() (uintptr, uintptr) { var buf [1164]byte; use(buf[:]); return Stackguard() }
-func stack1168() (uintptr, uintptr) { var buf [1168]byte; use(buf[:]); return Stackguard() }
-func stack1172() (uintptr, uintptr) { var buf [1172]byte; use(buf[:]); return Stackguard() }
-func stack1176() (uintptr, uintptr) { var buf [1176]byte; use(buf[:]); return Stackguard() }
-func stack1180() (uintptr, uintptr) { var buf [1180]byte; use(buf[:]); return Stackguard() }
-func stack1184() (uintptr, uintptr) { var buf [1184]byte; use(buf[:]); return Stackguard() }
-func stack1188() (uintptr, uintptr) { var buf [1188]byte; use(buf[:]); return Stackguard() }
-func stack1192() (uintptr, uintptr) { var buf [1192]byte; use(buf[:]); return Stackguard() }
-func stack1196() (uintptr, uintptr) { var buf [1196]byte; use(buf[:]); return Stackguard() }
-func stack1200() (uintptr, uintptr) { var buf [1200]byte; use(buf[:]); return Stackguard() }
-func stack1204() (uintptr, uintptr) { var buf [1204]byte; use(buf[:]); return Stackguard() }
-func stack1208() (uintptr, uintptr) { var buf [1208]byte; use(buf[:]); return Stackguard() }
-func stack1212() (uintptr, uintptr) { var buf [1212]byte; use(buf[:]); return Stackguard() }
-func stack1216() (uintptr, uintptr) { var buf [1216]byte; use(buf[:]); return Stackguard() }
-func stack1220() (uintptr, uintptr) { var buf [1220]byte; use(buf[:]); return Stackguard() }
-func stack1224() (uintptr, uintptr) { var buf [1224]byte; use(buf[:]); return Stackguard() }
-func stack1228() (uintptr, uintptr) { var buf [1228]byte; use(buf[:]); return Stackguard() }
-func stack1232() (uintptr, uintptr) { var buf [1232]byte; use(buf[:]); return Stackguard() }
-func stack1236() (uintptr, uintptr) { var buf [1236]byte; use(buf[:]); return Stackguard() }
-func stack1240() (uintptr, uintptr) { var buf [1240]byte; use(buf[:]); return Stackguard() }
-func stack1244() (uintptr, uintptr) { var buf [1244]byte; use(buf[:]); return Stackguard() }
-func stack1248() (uintptr, uintptr) { var buf [1248]byte; use(buf[:]); return Stackguard() }
-func stack1252() (uintptr, uintptr) { var buf [1252]byte; use(buf[:]); return Stackguard() }
-func stack1256() (uintptr, uintptr) { var buf [1256]byte; use(buf[:]); return Stackguard() }
-func stack1260() (uintptr, uintptr) { var buf [1260]byte; use(buf[:]); return Stackguard() }
-func stack1264() (uintptr, uintptr) { var buf [1264]byte; use(buf[:]); return Stackguard() }
-func stack1268() (uintptr, uintptr) { var buf [1268]byte; use(buf[:]); return Stackguard() }
-func stack1272() (uintptr, uintptr) { var buf [1272]byte; use(buf[:]); return Stackguard() }
-func stack1276() (uintptr, uintptr) { var buf [1276]byte; use(buf[:]); return Stackguard() }
-func stack1280() (uintptr, uintptr) { var buf [1280]byte; use(buf[:]); return Stackguard() }
-func stack1284() (uintptr, uintptr) { var buf [1284]byte; use(buf[:]); return Stackguard() }
-func stack1288() (uintptr, uintptr) { var buf [1288]byte; use(buf[:]); return Stackguard() }
-func stack1292() (uintptr, uintptr) { var buf [1292]byte; use(buf[:]); return Stackguard() }
-func stack1296() (uintptr, uintptr) { var buf [1296]byte; use(buf[:]); return Stackguard() }
-func stack1300() (uintptr, uintptr) { var buf [1300]byte; use(buf[:]); return Stackguard() }
-func stack1304() (uintptr, uintptr) { var buf [1304]byte; use(buf[:]); return Stackguard() }
-func stack1308() (uintptr, uintptr) { var buf [1308]byte; use(buf[:]); return Stackguard() }
-func stack1312() (uintptr, uintptr) { var buf [1312]byte; use(buf[:]); return Stackguard() }
-func stack1316() (uintptr, uintptr) { var buf [1316]byte; use(buf[:]); return Stackguard() }
-func stack1320() (uintptr, uintptr) { var buf [1320]byte; use(buf[:]); return Stackguard() }
-func stack1324() (uintptr, uintptr) { var buf [1324]byte; use(buf[:]); return Stackguard() }
-func stack1328() (uintptr, uintptr) { var buf [1328]byte; use(buf[:]); return Stackguard() }
-func stack1332() (uintptr, uintptr) { var buf [1332]byte; use(buf[:]); return Stackguard() }
-func stack1336() (uintptr, uintptr) { var buf [1336]byte; use(buf[:]); return Stackguard() }
-func stack1340() (uintptr, uintptr) { var buf [1340]byte; use(buf[:]); return Stackguard() }
-func stack1344() (uintptr, uintptr) { var buf [1344]byte; use(buf[:]); return Stackguard() }
-func stack1348() (uintptr, uintptr) { var buf [1348]byte; use(buf[:]); return Stackguard() }
-func stack1352() (uintptr, uintptr) { var buf [1352]byte; use(buf[:]); return Stackguard() }
-func stack1356() (uintptr, uintptr) { var buf [1356]byte; use(buf[:]); return Stackguard() }
-func stack1360() (uintptr, uintptr) { var buf [1360]byte; use(buf[:]); return Stackguard() }
-func stack1364() (uintptr, uintptr) { var buf [1364]byte; use(buf[:]); return Stackguard() }
-func stack1368() (uintptr, uintptr) { var buf [1368]byte; use(buf[:]); return Stackguard() }
-func stack1372() (uintptr, uintptr) { var buf [1372]byte; use(buf[:]); return Stackguard() }
-func stack1376() (uintptr, uintptr) { var buf [1376]byte; use(buf[:]); return Stackguard() }
-func stack1380() (uintptr, uintptr) { var buf [1380]byte; use(buf[:]); return Stackguard() }
-func stack1384() (uintptr, uintptr) { var buf [1384]byte; use(buf[:]); return Stackguard() }
-func stack1388() (uintptr, uintptr) { var buf [1388]byte; use(buf[:]); return Stackguard() }
-func stack1392() (uintptr, uintptr) { var buf [1392]byte; use(buf[:]); return Stackguard() }
-func stack1396() (uintptr, uintptr) { var buf [1396]byte; use(buf[:]); return Stackguard() }
-func stack1400() (uintptr, uintptr) { var buf [1400]byte; use(buf[:]); return Stackguard() }
-func stack1404() (uintptr, uintptr) { var buf [1404]byte; use(buf[:]); return Stackguard() }
-func stack1408() (uintptr, uintptr) { var buf [1408]byte; use(buf[:]); return Stackguard() }
-func stack1412() (uintptr, uintptr) { var buf [1412]byte; use(buf[:]); return Stackguard() }
-func stack1416() (uintptr, uintptr) { var buf [1416]byte; use(buf[:]); return Stackguard() }
-func stack1420() (uintptr, uintptr) { var buf [1420]byte; use(buf[:]); return Stackguard() }
-func stack1424() (uintptr, uintptr) { var buf [1424]byte; use(buf[:]); return Stackguard() }
-func stack1428() (uintptr, uintptr) { var buf [1428]byte; use(buf[:]); return Stackguard() }
-func stack1432() (uintptr, uintptr) { var buf [1432]byte; use(buf[:]); return Stackguard() }
-func stack1436() (uintptr, uintptr) { var buf [1436]byte; use(buf[:]); return Stackguard() }
-func stack1440() (uintptr, uintptr) { var buf [1440]byte; use(buf[:]); return Stackguard() }
-func stack1444() (uintptr, uintptr) { var buf [1444]byte; use(buf[:]); return Stackguard() }
-func stack1448() (uintptr, uintptr) { var buf [1448]byte; use(buf[:]); return Stackguard() }
-func stack1452() (uintptr, uintptr) { var buf [1452]byte; use(buf[:]); return Stackguard() }
-func stack1456() (uintptr, uintptr) { var buf [1456]byte; use(buf[:]); return Stackguard() }
-func stack1460() (uintptr, uintptr) { var buf [1460]byte; use(buf[:]); return Stackguard() }
-func stack1464() (uintptr, uintptr) { var buf [1464]byte; use(buf[:]); return Stackguard() }
-func stack1468() (uintptr, uintptr) { var buf [1468]byte; use(buf[:]); return Stackguard() }
-func stack1472() (uintptr, uintptr) { var buf [1472]byte; use(buf[:]); return Stackguard() }
-func stack1476() (uintptr, uintptr) { var buf [1476]byte; use(buf[:]); return Stackguard() }
-func stack1480() (uintptr, uintptr) { var buf [1480]byte; use(buf[:]); return Stackguard() }
-func stack1484() (uintptr, uintptr) { var buf [1484]byte; use(buf[:]); return Stackguard() }
-func stack1488() (uintptr, uintptr) { var buf [1488]byte; use(buf[:]); return Stackguard() }
-func stack1492() (uintptr, uintptr) { var buf [1492]byte; use(buf[:]); return Stackguard() }
-func stack1496() (uintptr, uintptr) { var buf [1496]byte; use(buf[:]); return Stackguard() }
-func stack1500() (uintptr, uintptr) { var buf [1500]byte; use(buf[:]); return Stackguard() }
-func stack1504() (uintptr, uintptr) { var buf [1504]byte; use(buf[:]); return Stackguard() }
-func stack1508() (uintptr, uintptr) { var buf [1508]byte; use(buf[:]); return Stackguard() }
-func stack1512() (uintptr, uintptr) { var buf [1512]byte; use(buf[:]); return Stackguard() }
-func stack1516() (uintptr, uintptr) { var buf [1516]byte; use(buf[:]); return Stackguard() }
-func stack1520() (uintptr, uintptr) { var buf [1520]byte; use(buf[:]); return Stackguard() }
-func stack1524() (uintptr, uintptr) { var buf [1524]byte; use(buf[:]); return Stackguard() }
-func stack1528() (uintptr, uintptr) { var buf [1528]byte; use(buf[:]); return Stackguard() }
-func stack1532() (uintptr, uintptr) { var buf [1532]byte; use(buf[:]); return Stackguard() }
-func stack1536() (uintptr, uintptr) { var buf [1536]byte; use(buf[:]); return Stackguard() }
-func stack1540() (uintptr, uintptr) { var buf [1540]byte; use(buf[:]); return Stackguard() }
-func stack1544() (uintptr, uintptr) { var buf [1544]byte; use(buf[:]); return Stackguard() }
-func stack1548() (uintptr, uintptr) { var buf [1548]byte; use(buf[:]); return Stackguard() }
-func stack1552() (uintptr, uintptr) { var buf [1552]byte; use(buf[:]); return Stackguard() }
-func stack1556() (uintptr, uintptr) { var buf [1556]byte; use(buf[:]); return Stackguard() }
-func stack1560() (uintptr, uintptr) { var buf [1560]byte; use(buf[:]); return Stackguard() }
-func stack1564() (uintptr, uintptr) { var buf [1564]byte; use(buf[:]); return Stackguard() }
-func stack1568() (uintptr, uintptr) { var buf [1568]byte; use(buf[:]); return Stackguard() }
-func stack1572() (uintptr, uintptr) { var buf [1572]byte; use(buf[:]); return Stackguard() }
-func stack1576() (uintptr, uintptr) { var buf [1576]byte; use(buf[:]); return Stackguard() }
-func stack1580() (uintptr, uintptr) { var buf [1580]byte; use(buf[:]); return Stackguard() }
-func stack1584() (uintptr, uintptr) { var buf [1584]byte; use(buf[:]); return Stackguard() }
-func stack1588() (uintptr, uintptr) { var buf [1588]byte; use(buf[:]); return Stackguard() }
-func stack1592() (uintptr, uintptr) { var buf [1592]byte; use(buf[:]); return Stackguard() }
-func stack1596() (uintptr, uintptr) { var buf [1596]byte; use(buf[:]); return Stackguard() }
-func stack1600() (uintptr, uintptr) { var buf [1600]byte; use(buf[:]); return Stackguard() }
-func stack1604() (uintptr, uintptr) { var buf [1604]byte; use(buf[:]); return Stackguard() }
-func stack1608() (uintptr, uintptr) { var buf [1608]byte; use(buf[:]); return Stackguard() }
-func stack1612() (uintptr, uintptr) { var buf [1612]byte; use(buf[:]); return Stackguard() }
-func stack1616() (uintptr, uintptr) { var buf [1616]byte; use(buf[:]); return Stackguard() }
-func stack1620() (uintptr, uintptr) { var buf [1620]byte; use(buf[:]); return Stackguard() }
-func stack1624() (uintptr, uintptr) { var buf [1624]byte; use(buf[:]); return Stackguard() }
-func stack1628() (uintptr, uintptr) { var buf [1628]byte; use(buf[:]); return Stackguard() }
-func stack1632() (uintptr, uintptr) { var buf [1632]byte; use(buf[:]); return Stackguard() }
-func stack1636() (uintptr, uintptr) { var buf [1636]byte; use(buf[:]); return Stackguard() }
-func stack1640() (uintptr, uintptr) { var buf [1640]byte; use(buf[:]); return Stackguard() }
-func stack1644() (uintptr, uintptr) { var buf [1644]byte; use(buf[:]); return Stackguard() }
-func stack1648() (uintptr, uintptr) { var buf [1648]byte; use(buf[:]); return Stackguard() }
-func stack1652() (uintptr, uintptr) { var buf [1652]byte; use(buf[:]); return Stackguard() }
-func stack1656() (uintptr, uintptr) { var buf [1656]byte; use(buf[:]); return Stackguard() }
-func stack1660() (uintptr, uintptr) { var buf [1660]byte; use(buf[:]); return Stackguard() }
-func stack1664() (uintptr, uintptr) { var buf [1664]byte; use(buf[:]); return Stackguard() }
-func stack1668() (uintptr, uintptr) { var buf [1668]byte; use(buf[:]); return Stackguard() }
-func stack1672() (uintptr, uintptr) { var buf [1672]byte; use(buf[:]); return Stackguard() }
-func stack1676() (uintptr, uintptr) { var buf [1676]byte; use(buf[:]); return Stackguard() }
-func stack1680() (uintptr, uintptr) { var buf [1680]byte; use(buf[:]); return Stackguard() }
-func stack1684() (uintptr, uintptr) { var buf [1684]byte; use(buf[:]); return Stackguard() }
-func stack1688() (uintptr, uintptr) { var buf [1688]byte; use(buf[:]); return Stackguard() }
-func stack1692() (uintptr, uintptr) { var buf [1692]byte; use(buf[:]); return Stackguard() }
-func stack1696() (uintptr, uintptr) { var buf [1696]byte; use(buf[:]); return Stackguard() }
-func stack1700() (uintptr, uintptr) { var buf [1700]byte; use(buf[:]); return Stackguard() }
-func stack1704() (uintptr, uintptr) { var buf [1704]byte; use(buf[:]); return Stackguard() }
-func stack1708() (uintptr, uintptr) { var buf [1708]byte; use(buf[:]); return Stackguard() }
-func stack1712() (uintptr, uintptr) { var buf [1712]byte; use(buf[:]); return Stackguard() }
-func stack1716() (uintptr, uintptr) { var buf [1716]byte; use(buf[:]); return Stackguard() }
-func stack1720() (uintptr, uintptr) { var buf [1720]byte; use(buf[:]); return Stackguard() }
-func stack1724() (uintptr, uintptr) { var buf [1724]byte; use(buf[:]); return Stackguard() }
-func stack1728() (uintptr, uintptr) { var buf [1728]byte; use(buf[:]); return Stackguard() }
-func stack1732() (uintptr, uintptr) { var buf [1732]byte; use(buf[:]); return Stackguard() }
-func stack1736() (uintptr, uintptr) { var buf [1736]byte; use(buf[:]); return Stackguard() }
-func stack1740() (uintptr, uintptr) { var buf [1740]byte; use(buf[:]); return Stackguard() }
-func stack1744() (uintptr, uintptr) { var buf [1744]byte; use(buf[:]); return Stackguard() }
-func stack1748() (uintptr, uintptr) { var buf [1748]byte; use(buf[:]); return Stackguard() }
-func stack1752() (uintptr, uintptr) { var buf [1752]byte; use(buf[:]); return Stackguard() }
-func stack1756() (uintptr, uintptr) { var buf [1756]byte; use(buf[:]); return Stackguard() }
-func stack1760() (uintptr, uintptr) { var buf [1760]byte; use(buf[:]); return Stackguard() }
-func stack1764() (uintptr, uintptr) { var buf [1764]byte; use(buf[:]); return Stackguard() }
-func stack1768() (uintptr, uintptr) { var buf [1768]byte; use(buf[:]); return Stackguard() }
-func stack1772() (uintptr, uintptr) { var buf [1772]byte; use(buf[:]); return Stackguard() }
-func stack1776() (uintptr, uintptr) { var buf [1776]byte; use(buf[:]); return Stackguard() }
-func stack1780() (uintptr, uintptr) { var buf [1780]byte; use(buf[:]); return Stackguard() }
-func stack1784() (uintptr, uintptr) { var buf [1784]byte; use(buf[:]); return Stackguard() }
-func stack1788() (uintptr, uintptr) { var buf [1788]byte; use(buf[:]); return Stackguard() }
-func stack1792() (uintptr, uintptr) { var buf [1792]byte; use(buf[:]); return Stackguard() }
-func stack1796() (uintptr, uintptr) { var buf [1796]byte; use(buf[:]); return Stackguard() }
-func stack1800() (uintptr, uintptr) { var buf [1800]byte; use(buf[:]); return Stackguard() }
-func stack1804() (uintptr, uintptr) { var buf [1804]byte; use(buf[:]); return Stackguard() }
-func stack1808() (uintptr, uintptr) { var buf [1808]byte; use(buf[:]); return Stackguard() }
-func stack1812() (uintptr, uintptr) { var buf [1812]byte; use(buf[:]); return Stackguard() }
-func stack1816() (uintptr, uintptr) { var buf [1816]byte; use(buf[:]); return Stackguard() }
-func stack1820() (uintptr, uintptr) { var buf [1820]byte; use(buf[:]); return Stackguard() }
-func stack1824() (uintptr, uintptr) { var buf [1824]byte; use(buf[:]); return Stackguard() }
-func stack1828() (uintptr, uintptr) { var buf [1828]byte; use(buf[:]); return Stackguard() }
-func stack1832() (uintptr, uintptr) { var buf [1832]byte; use(buf[:]); return Stackguard() }
-func stack1836() (uintptr, uintptr) { var buf [1836]byte; use(buf[:]); return Stackguard() }
-func stack1840() (uintptr, uintptr) { var buf [1840]byte; use(buf[:]); return Stackguard() }
-func stack1844() (uintptr, uintptr) { var buf [1844]byte; use(buf[:]); return Stackguard() }
-func stack1848() (uintptr, uintptr) { var buf [1848]byte; use(buf[:]); return Stackguard() }
-func stack1852() (uintptr, uintptr) { var buf [1852]byte; use(buf[:]); return Stackguard() }
-func stack1856() (uintptr, uintptr) { var buf [1856]byte; use(buf[:]); return Stackguard() }
-func stack1860() (uintptr, uintptr) { var buf [1860]byte; use(buf[:]); return Stackguard() }
-func stack1864() (uintptr, uintptr) { var buf [1864]byte; use(buf[:]); return Stackguard() }
-func stack1868() (uintptr, uintptr) { var buf [1868]byte; use(buf[:]); return Stackguard() }
-func stack1872() (uintptr, uintptr) { var buf [1872]byte; use(buf[:]); return Stackguard() }
-func stack1876() (uintptr, uintptr) { var buf [1876]byte; use(buf[:]); return Stackguard() }
-func stack1880() (uintptr, uintptr) { var buf [1880]byte; use(buf[:]); return Stackguard() }
-func stack1884() (uintptr, uintptr) { var buf [1884]byte; use(buf[:]); return Stackguard() }
-func stack1888() (uintptr, uintptr) { var buf [1888]byte; use(buf[:]); return Stackguard() }
-func stack1892() (uintptr, uintptr) { var buf [1892]byte; use(buf[:]); return Stackguard() }
-func stack1896() (uintptr, uintptr) { var buf [1896]byte; use(buf[:]); return Stackguard() }
-func stack1900() (uintptr, uintptr) { var buf [1900]byte; use(buf[:]); return Stackguard() }
-func stack1904() (uintptr, uintptr) { var buf [1904]byte; use(buf[:]); return Stackguard() }
-func stack1908() (uintptr, uintptr) { var buf [1908]byte; use(buf[:]); return Stackguard() }
-func stack1912() (uintptr, uintptr) { var buf [1912]byte; use(buf[:]); return Stackguard() }
-func stack1916() (uintptr, uintptr) { var buf [1916]byte; use(buf[:]); return Stackguard() }
-func stack1920() (uintptr, uintptr) { var buf [1920]byte; use(buf[:]); return Stackguard() }
-func stack1924() (uintptr, uintptr) { var buf [1924]byte; use(buf[:]); return Stackguard() }
-func stack1928() (uintptr, uintptr) { var buf [1928]byte; use(buf[:]); return Stackguard() }
-func stack1932() (uintptr, uintptr) { var buf [1932]byte; use(buf[:]); return Stackguard() }
-func stack1936() (uintptr, uintptr) { var buf [1936]byte; use(buf[:]); return Stackguard() }
-func stack1940() (uintptr, uintptr) { var buf [1940]byte; use(buf[:]); return Stackguard() }
-func stack1944() (uintptr, uintptr) { var buf [1944]byte; use(buf[:]); return Stackguard() }
-func stack1948() (uintptr, uintptr) { var buf [1948]byte; use(buf[:]); return Stackguard() }
-func stack1952() (uintptr, uintptr) { var buf [1952]byte; use(buf[:]); return Stackguard() }
-func stack1956() (uintptr, uintptr) { var buf [1956]byte; use(buf[:]); return Stackguard() }
-func stack1960() (uintptr, uintptr) { var buf [1960]byte; use(buf[:]); return Stackguard() }
-func stack1964() (uintptr, uintptr) { var buf [1964]byte; use(buf[:]); return Stackguard() }
-func stack1968() (uintptr, uintptr) { var buf [1968]byte; use(buf[:]); return Stackguard() }
-func stack1972() (uintptr, uintptr) { var buf [1972]byte; use(buf[:]); return Stackguard() }
-func stack1976() (uintptr, uintptr) { var buf [1976]byte; use(buf[:]); return Stackguard() }
-func stack1980() (uintptr, uintptr) { var buf [1980]byte; use(buf[:]); return Stackguard() }
-func stack1984() (uintptr, uintptr) { var buf [1984]byte; use(buf[:]); return Stackguard() }
-func stack1988() (uintptr, uintptr) { var buf [1988]byte; use(buf[:]); return Stackguard() }
-func stack1992() (uintptr, uintptr) { var buf [1992]byte; use(buf[:]); return Stackguard() }
-func stack1996() (uintptr, uintptr) { var buf [1996]byte; use(buf[:]); return Stackguard() }
-func stack2000() (uintptr, uintptr) { var buf [2000]byte; use(buf[:]); return Stackguard() }
-func stack2004() (uintptr, uintptr) { var buf [2004]byte; use(buf[:]); return Stackguard() }
-func stack2008() (uintptr, uintptr) { var buf [2008]byte; use(buf[:]); return Stackguard() }
-func stack2012() (uintptr, uintptr) { var buf [2012]byte; use(buf[:]); return Stackguard() }
-func stack2016() (uintptr, uintptr) { var buf [2016]byte; use(buf[:]); return Stackguard() }
-func stack2020() (uintptr, uintptr) { var buf [2020]byte; use(buf[:]); return Stackguard() }
-func stack2024() (uintptr, uintptr) { var buf [2024]byte; use(buf[:]); return Stackguard() }
-func stack2028() (uintptr, uintptr) { var buf [2028]byte; use(buf[:]); return Stackguard() }
-func stack2032() (uintptr, uintptr) { var buf [2032]byte; use(buf[:]); return Stackguard() }
-func stack2036() (uintptr, uintptr) { var buf [2036]byte; use(buf[:]); return Stackguard() }
-func stack2040() (uintptr, uintptr) { var buf [2040]byte; use(buf[:]); return Stackguard() }
-func stack2044() (uintptr, uintptr) { var buf [2044]byte; use(buf[:]); return Stackguard() }
-func stack2048() (uintptr, uintptr) { var buf [2048]byte; use(buf[:]); return Stackguard() }
-func stack2052() (uintptr, uintptr) { var buf [2052]byte; use(buf[:]); return Stackguard() }
-func stack2056() (uintptr, uintptr) { var buf [2056]byte; use(buf[:]); return Stackguard() }
-func stack2060() (uintptr, uintptr) { var buf [2060]byte; use(buf[:]); return Stackguard() }
-func stack2064() (uintptr, uintptr) { var buf [2064]byte; use(buf[:]); return Stackguard() }
-func stack2068() (uintptr, uintptr) { var buf [2068]byte; use(buf[:]); return Stackguard() }
-func stack2072() (uintptr, uintptr) { var buf [2072]byte; use(buf[:]); return Stackguard() }
-func stack2076() (uintptr, uintptr) { var buf [2076]byte; use(buf[:]); return Stackguard() }
-func stack2080() (uintptr, uintptr) { var buf [2080]byte; use(buf[:]); return Stackguard() }
-func stack2084() (uintptr, uintptr) { var buf [2084]byte; use(buf[:]); return Stackguard() }
-func stack2088() (uintptr, uintptr) { var buf [2088]byte; use(buf[:]); return Stackguard() }
-func stack2092() (uintptr, uintptr) { var buf [2092]byte; use(buf[:]); return Stackguard() }
-func stack2096() (uintptr, uintptr) { var buf [2096]byte; use(buf[:]); return Stackguard() }
-func stack2100() (uintptr, uintptr) { var buf [2100]byte; use(buf[:]); return Stackguard() }
-func stack2104() (uintptr, uintptr) { var buf [2104]byte; use(buf[:]); return Stackguard() }
-func stack2108() (uintptr, uintptr) { var buf [2108]byte; use(buf[:]); return Stackguard() }
-func stack2112() (uintptr, uintptr) { var buf [2112]byte; use(buf[:]); return Stackguard() }
-func stack2116() (uintptr, uintptr) { var buf [2116]byte; use(buf[:]); return Stackguard() }
-func stack2120() (uintptr, uintptr) { var buf [2120]byte; use(buf[:]); return Stackguard() }
-func stack2124() (uintptr, uintptr) { var buf [2124]byte; use(buf[:]); return Stackguard() }
-func stack2128() (uintptr, uintptr) { var buf [2128]byte; use(buf[:]); return Stackguard() }
-func stack2132() (uintptr, uintptr) { var buf [2132]byte; use(buf[:]); return Stackguard() }
-func stack2136() (uintptr, uintptr) { var buf [2136]byte; use(buf[:]); return Stackguard() }
-func stack2140() (uintptr, uintptr) { var buf [2140]byte; use(buf[:]); return Stackguard() }
-func stack2144() (uintptr, uintptr) { var buf [2144]byte; use(buf[:]); return Stackguard() }
-func stack2148() (uintptr, uintptr) { var buf [2148]byte; use(buf[:]); return Stackguard() }
-func stack2152() (uintptr, uintptr) { var buf [2152]byte; use(buf[:]); return Stackguard() }
-func stack2156() (uintptr, uintptr) { var buf [2156]byte; use(buf[:]); return Stackguard() }
-func stack2160() (uintptr, uintptr) { var buf [2160]byte; use(buf[:]); return Stackguard() }
-func stack2164() (uintptr, uintptr) { var buf [2164]byte; use(buf[:]); return Stackguard() }
-func stack2168() (uintptr, uintptr) { var buf [2168]byte; use(buf[:]); return Stackguard() }
-func stack2172() (uintptr, uintptr) { var buf [2172]byte; use(buf[:]); return Stackguard() }
-func stack2176() (uintptr, uintptr) { var buf [2176]byte; use(buf[:]); return Stackguard() }
-func stack2180() (uintptr, uintptr) { var buf [2180]byte; use(buf[:]); return Stackguard() }
-func stack2184() (uintptr, uintptr) { var buf [2184]byte; use(buf[:]); return Stackguard() }
-func stack2188() (uintptr, uintptr) { var buf [2188]byte; use(buf[:]); return Stackguard() }
-func stack2192() (uintptr, uintptr) { var buf [2192]byte; use(buf[:]); return Stackguard() }
-func stack2196() (uintptr, uintptr) { var buf [2196]byte; use(buf[:]); return Stackguard() }
-func stack2200() (uintptr, uintptr) { var buf [2200]byte; use(buf[:]); return Stackguard() }
-func stack2204() (uintptr, uintptr) { var buf [2204]byte; use(buf[:]); return Stackguard() }
-func stack2208() (uintptr, uintptr) { var buf [2208]byte; use(buf[:]); return Stackguard() }
-func stack2212() (uintptr, uintptr) { var buf [2212]byte; use(buf[:]); return Stackguard() }
-func stack2216() (uintptr, uintptr) { var buf [2216]byte; use(buf[:]); return Stackguard() }
-func stack2220() (uintptr, uintptr) { var buf [2220]byte; use(buf[:]); return Stackguard() }
-func stack2224() (uintptr, uintptr) { var buf [2224]byte; use(buf[:]); return Stackguard() }
-func stack2228() (uintptr, uintptr) { var buf [2228]byte; use(buf[:]); return Stackguard() }
-func stack2232() (uintptr, uintptr) { var buf [2232]byte; use(buf[:]); return Stackguard() }
-func stack2236() (uintptr, uintptr) { var buf [2236]byte; use(buf[:]); return Stackguard() }
-func stack2240() (uintptr, uintptr) { var buf [2240]byte; use(buf[:]); return Stackguard() }
-func stack2244() (uintptr, uintptr) { var buf [2244]byte; use(buf[:]); return Stackguard() }
-func stack2248() (uintptr, uintptr) { var buf [2248]byte; use(buf[:]); return Stackguard() }
-func stack2252() (uintptr, uintptr) { var buf [2252]byte; use(buf[:]); return Stackguard() }
-func stack2256() (uintptr, uintptr) { var buf [2256]byte; use(buf[:]); return Stackguard() }
-func stack2260() (uintptr, uintptr) { var buf [2260]byte; use(buf[:]); return Stackguard() }
-func stack2264() (uintptr, uintptr) { var buf [2264]byte; use(buf[:]); return Stackguard() }
-func stack2268() (uintptr, uintptr) { var buf [2268]byte; use(buf[:]); return Stackguard() }
-func stack2272() (uintptr, uintptr) { var buf [2272]byte; use(buf[:]); return Stackguard() }
-func stack2276() (uintptr, uintptr) { var buf [2276]byte; use(buf[:]); return Stackguard() }
-func stack2280() (uintptr, uintptr) { var buf [2280]byte; use(buf[:]); return Stackguard() }
-func stack2284() (uintptr, uintptr) { var buf [2284]byte; use(buf[:]); return Stackguard() }
-func stack2288() (uintptr, uintptr) { var buf [2288]byte; use(buf[:]); return Stackguard() }
-func stack2292() (uintptr, uintptr) { var buf [2292]byte; use(buf[:]); return Stackguard() }
-func stack2296() (uintptr, uintptr) { var buf [2296]byte; use(buf[:]); return Stackguard() }
-func stack2300() (uintptr, uintptr) { var buf [2300]byte; use(buf[:]); return Stackguard() }
-func stack2304() (uintptr, uintptr) { var buf [2304]byte; use(buf[:]); return Stackguard() }
-func stack2308() (uintptr, uintptr) { var buf [2308]byte; use(buf[:]); return Stackguard() }
-func stack2312() (uintptr, uintptr) { var buf [2312]byte; use(buf[:]); return Stackguard() }
-func stack2316() (uintptr, uintptr) { var buf [2316]byte; use(buf[:]); return Stackguard() }
-func stack2320() (uintptr, uintptr) { var buf [2320]byte; use(buf[:]); return Stackguard() }
-func stack2324() (uintptr, uintptr) { var buf [2324]byte; use(buf[:]); return Stackguard() }
-func stack2328() (uintptr, uintptr) { var buf [2328]byte; use(buf[:]); return Stackguard() }
-func stack2332() (uintptr, uintptr) { var buf [2332]byte; use(buf[:]); return Stackguard() }
-func stack2336() (uintptr, uintptr) { var buf [2336]byte; use(buf[:]); return Stackguard() }
-func stack2340() (uintptr, uintptr) { var buf [2340]byte; use(buf[:]); return Stackguard() }
-func stack2344() (uintptr, uintptr) { var buf [2344]byte; use(buf[:]); return Stackguard() }
-func stack2348() (uintptr, uintptr) { var buf [2348]byte; use(buf[:]); return Stackguard() }
-func stack2352() (uintptr, uintptr) { var buf [2352]byte; use(buf[:]); return Stackguard() }
-func stack2356() (uintptr, uintptr) { var buf [2356]byte; use(buf[:]); return Stackguard() }
-func stack2360() (uintptr, uintptr) { var buf [2360]byte; use(buf[:]); return Stackguard() }
-func stack2364() (uintptr, uintptr) { var buf [2364]byte; use(buf[:]); return Stackguard() }
-func stack2368() (uintptr, uintptr) { var buf [2368]byte; use(buf[:]); return Stackguard() }
-func stack2372() (uintptr, uintptr) { var buf [2372]byte; use(buf[:]); return Stackguard() }
-func stack2376() (uintptr, uintptr) { var buf [2376]byte; use(buf[:]); return Stackguard() }
-func stack2380() (uintptr, uintptr) { var buf [2380]byte; use(buf[:]); return Stackguard() }
-func stack2384() (uintptr, uintptr) { var buf [2384]byte; use(buf[:]); return Stackguard() }
-func stack2388() (uintptr, uintptr) { var buf [2388]byte; use(buf[:]); return Stackguard() }
-func stack2392() (uintptr, uintptr) { var buf [2392]byte; use(buf[:]); return Stackguard() }
-func stack2396() (uintptr, uintptr) { var buf [2396]byte; use(buf[:]); return Stackguard() }
-func stack2400() (uintptr, uintptr) { var buf [2400]byte; use(buf[:]); return Stackguard() }
-func stack2404() (uintptr, uintptr) { var buf [2404]byte; use(buf[:]); return Stackguard() }
-func stack2408() (uintptr, uintptr) { var buf [2408]byte; use(buf[:]); return Stackguard() }
-func stack2412() (uintptr, uintptr) { var buf [2412]byte; use(buf[:]); return Stackguard() }
-func stack2416() (uintptr, uintptr) { var buf [2416]byte; use(buf[:]); return Stackguard() }
-func stack2420() (uintptr, uintptr) { var buf [2420]byte; use(buf[:]); return Stackguard() }
-func stack2424() (uintptr, uintptr) { var buf [2424]byte; use(buf[:]); return Stackguard() }
-func stack2428() (uintptr, uintptr) { var buf [2428]byte; use(buf[:]); return Stackguard() }
-func stack2432() (uintptr, uintptr) { var buf [2432]byte; use(buf[:]); return Stackguard() }
-func stack2436() (uintptr, uintptr) { var buf [2436]byte; use(buf[:]); return Stackguard() }
-func stack2440() (uintptr, uintptr) { var buf [2440]byte; use(buf[:]); return Stackguard() }
-func stack2444() (uintptr, uintptr) { var buf [2444]byte; use(buf[:]); return Stackguard() }
-func stack2448() (uintptr, uintptr) { var buf [2448]byte; use(buf[:]); return Stackguard() }
-func stack2452() (uintptr, uintptr) { var buf [2452]byte; use(buf[:]); return Stackguard() }
-func stack2456() (uintptr, uintptr) { var buf [2456]byte; use(buf[:]); return Stackguard() }
-func stack2460() (uintptr, uintptr) { var buf [2460]byte; use(buf[:]); return Stackguard() }
-func stack2464() (uintptr, uintptr) { var buf [2464]byte; use(buf[:]); return Stackguard() }
-func stack2468() (uintptr, uintptr) { var buf [2468]byte; use(buf[:]); return Stackguard() }
-func stack2472() (uintptr, uintptr) { var buf [2472]byte; use(buf[:]); return Stackguard() }
-func stack2476() (uintptr, uintptr) { var buf [2476]byte; use(buf[:]); return Stackguard() }
-func stack2480() (uintptr, uintptr) { var buf [2480]byte; use(buf[:]); return Stackguard() }
-func stack2484() (uintptr, uintptr) { var buf [2484]byte; use(buf[:]); return Stackguard() }
-func stack2488() (uintptr, uintptr) { var buf [2488]byte; use(buf[:]); return Stackguard() }
-func stack2492() (uintptr, uintptr) { var buf [2492]byte; use(buf[:]); return Stackguard() }
-func stack2496() (uintptr, uintptr) { var buf [2496]byte; use(buf[:]); return Stackguard() }
-func stack2500() (uintptr, uintptr) { var buf [2500]byte; use(buf[:]); return Stackguard() }
-func stack2504() (uintptr, uintptr) { var buf [2504]byte; use(buf[:]); return Stackguard() }
-func stack2508() (uintptr, uintptr) { var buf [2508]byte; use(buf[:]); return Stackguard() }
-func stack2512() (uintptr, uintptr) { var buf [2512]byte; use(buf[:]); return Stackguard() }
-func stack2516() (uintptr, uintptr) { var buf [2516]byte; use(buf[:]); return Stackguard() }
-func stack2520() (uintptr, uintptr) { var buf [2520]byte; use(buf[:]); return Stackguard() }
-func stack2524() (uintptr, uintptr) { var buf [2524]byte; use(buf[:]); return Stackguard() }
-func stack2528() (uintptr, uintptr) { var buf [2528]byte; use(buf[:]); return Stackguard() }
-func stack2532() (uintptr, uintptr) { var buf [2532]byte; use(buf[:]); return Stackguard() }
-func stack2536() (uintptr, uintptr) { var buf [2536]byte; use(buf[:]); return Stackguard() }
-func stack2540() (uintptr, uintptr) { var buf [2540]byte; use(buf[:]); return Stackguard() }
-func stack2544() (uintptr, uintptr) { var buf [2544]byte; use(buf[:]); return Stackguard() }
-func stack2548() (uintptr, uintptr) { var buf [2548]byte; use(buf[:]); return Stackguard() }
-func stack2552() (uintptr, uintptr) { var buf [2552]byte; use(buf[:]); return Stackguard() }
-func stack2556() (uintptr, uintptr) { var buf [2556]byte; use(buf[:]); return Stackguard() }
-func stack2560() (uintptr, uintptr) { var buf [2560]byte; use(buf[:]); return Stackguard() }
-func stack2564() (uintptr, uintptr) { var buf [2564]byte; use(buf[:]); return Stackguard() }
-func stack2568() (uintptr, uintptr) { var buf [2568]byte; use(buf[:]); return Stackguard() }
-func stack2572() (uintptr, uintptr) { var buf [2572]byte; use(buf[:]); return Stackguard() }
-func stack2576() (uintptr, uintptr) { var buf [2576]byte; use(buf[:]); return Stackguard() }
-func stack2580() (uintptr, uintptr) { var buf [2580]byte; use(buf[:]); return Stackguard() }
-func stack2584() (uintptr, uintptr) { var buf [2584]byte; use(buf[:]); return Stackguard() }
-func stack2588() (uintptr, uintptr) { var buf [2588]byte; use(buf[:]); return Stackguard() }
-func stack2592() (uintptr, uintptr) { var buf [2592]byte; use(buf[:]); return Stackguard() }
-func stack2596() (uintptr, uintptr) { var buf [2596]byte; use(buf[:]); return Stackguard() }
-func stack2600() (uintptr, uintptr) { var buf [2600]byte; use(buf[:]); return Stackguard() }
-func stack2604() (uintptr, uintptr) { var buf [2604]byte; use(buf[:]); return Stackguard() }
-func stack2608() (uintptr, uintptr) { var buf [2608]byte; use(buf[:]); return Stackguard() }
-func stack2612() (uintptr, uintptr) { var buf [2612]byte; use(buf[:]); return Stackguard() }
-func stack2616() (uintptr, uintptr) { var buf [2616]byte; use(buf[:]); return Stackguard() }
-func stack2620() (uintptr, uintptr) { var buf [2620]byte; use(buf[:]); return Stackguard() }
-func stack2624() (uintptr, uintptr) { var buf [2624]byte; use(buf[:]); return Stackguard() }
-func stack2628() (uintptr, uintptr) { var buf [2628]byte; use(buf[:]); return Stackguard() }
-func stack2632() (uintptr, uintptr) { var buf [2632]byte; use(buf[:]); return Stackguard() }
-func stack2636() (uintptr, uintptr) { var buf [2636]byte; use(buf[:]); return Stackguard() }
-func stack2640() (uintptr, uintptr) { var buf [2640]byte; use(buf[:]); return Stackguard() }
-func stack2644() (uintptr, uintptr) { var buf [2644]byte; use(buf[:]); return Stackguard() }
-func stack2648() (uintptr, uintptr) { var buf [2648]byte; use(buf[:]); return Stackguard() }
-func stack2652() (uintptr, uintptr) { var buf [2652]byte; use(buf[:]); return Stackguard() }
-func stack2656() (uintptr, uintptr) { var buf [2656]byte; use(buf[:]); return Stackguard() }
-func stack2660() (uintptr, uintptr) { var buf [2660]byte; use(buf[:]); return Stackguard() }
-func stack2664() (uintptr, uintptr) { var buf [2664]byte; use(buf[:]); return Stackguard() }
-func stack2668() (uintptr, uintptr) { var buf [2668]byte; use(buf[:]); return Stackguard() }
-func stack2672() (uintptr, uintptr) { var buf [2672]byte; use(buf[:]); return Stackguard() }
-func stack2676() (uintptr, uintptr) { var buf [2676]byte; use(buf[:]); return Stackguard() }
-func stack2680() (uintptr, uintptr) { var buf [2680]byte; use(buf[:]); return Stackguard() }
-func stack2684() (uintptr, uintptr) { var buf [2684]byte; use(buf[:]); return Stackguard() }
-func stack2688() (uintptr, uintptr) { var buf [2688]byte; use(buf[:]); return Stackguard() }
-func stack2692() (uintptr, uintptr) { var buf [2692]byte; use(buf[:]); return Stackguard() }
-func stack2696() (uintptr, uintptr) { var buf [2696]byte; use(buf[:]); return Stackguard() }
-func stack2700() (uintptr, uintptr) { var buf [2700]byte; use(buf[:]); return Stackguard() }
-func stack2704() (uintptr, uintptr) { var buf [2704]byte; use(buf[:]); return Stackguard() }
-func stack2708() (uintptr, uintptr) { var buf [2708]byte; use(buf[:]); return Stackguard() }
-func stack2712() (uintptr, uintptr) { var buf [2712]byte; use(buf[:]); return Stackguard() }
-func stack2716() (uintptr, uintptr) { var buf [2716]byte; use(buf[:]); return Stackguard() }
-func stack2720() (uintptr, uintptr) { var buf [2720]byte; use(buf[:]); return Stackguard() }
-func stack2724() (uintptr, uintptr) { var buf [2724]byte; use(buf[:]); return Stackguard() }
-func stack2728() (uintptr, uintptr) { var buf [2728]byte; use(buf[:]); return Stackguard() }
-func stack2732() (uintptr, uintptr) { var buf [2732]byte; use(buf[:]); return Stackguard() }
-func stack2736() (uintptr, uintptr) { var buf [2736]byte; use(buf[:]); return Stackguard() }
-func stack2740() (uintptr, uintptr) { var buf [2740]byte; use(buf[:]); return Stackguard() }
-func stack2744() (uintptr, uintptr) { var buf [2744]byte; use(buf[:]); return Stackguard() }
-func stack2748() (uintptr, uintptr) { var buf [2748]byte; use(buf[:]); return Stackguard() }
-func stack2752() (uintptr, uintptr) { var buf [2752]byte; use(buf[:]); return Stackguard() }
-func stack2756() (uintptr, uintptr) { var buf [2756]byte; use(buf[:]); return Stackguard() }
-func stack2760() (uintptr, uintptr) { var buf [2760]byte; use(buf[:]); return Stackguard() }
-func stack2764() (uintptr, uintptr) { var buf [2764]byte; use(buf[:]); return Stackguard() }
-func stack2768() (uintptr, uintptr) { var buf [2768]byte; use(buf[:]); return Stackguard() }
-func stack2772() (uintptr, uintptr) { var buf [2772]byte; use(buf[:]); return Stackguard() }
-func stack2776() (uintptr, uintptr) { var buf [2776]byte; use(buf[:]); return Stackguard() }
-func stack2780() (uintptr, uintptr) { var buf [2780]byte; use(buf[:]); return Stackguard() }
-func stack2784() (uintptr, uintptr) { var buf [2784]byte; use(buf[:]); return Stackguard() }
-func stack2788() (uintptr, uintptr) { var buf [2788]byte; use(buf[:]); return Stackguard() }
-func stack2792() (uintptr, uintptr) { var buf [2792]byte; use(buf[:]); return Stackguard() }
-func stack2796() (uintptr, uintptr) { var buf [2796]byte; use(buf[:]); return Stackguard() }
-func stack2800() (uintptr, uintptr) { var buf [2800]byte; use(buf[:]); return Stackguard() }
-func stack2804() (uintptr, uintptr) { var buf [2804]byte; use(buf[:]); return Stackguard() }
-func stack2808() (uintptr, uintptr) { var buf [2808]byte; use(buf[:]); return Stackguard() }
-func stack2812() (uintptr, uintptr) { var buf [2812]byte; use(buf[:]); return Stackguard() }
-func stack2816() (uintptr, uintptr) { var buf [2816]byte; use(buf[:]); return Stackguard() }
-func stack2820() (uintptr, uintptr) { var buf [2820]byte; use(buf[:]); return Stackguard() }
-func stack2824() (uintptr, uintptr) { var buf [2824]byte; use(buf[:]); return Stackguard() }
-func stack2828() (uintptr, uintptr) { var buf [2828]byte; use(buf[:]); return Stackguard() }
-func stack2832() (uintptr, uintptr) { var buf [2832]byte; use(buf[:]); return Stackguard() }
-func stack2836() (uintptr, uintptr) { var buf [2836]byte; use(buf[:]); return Stackguard() }
-func stack2840() (uintptr, uintptr) { var buf [2840]byte; use(buf[:]); return Stackguard() }
-func stack2844() (uintptr, uintptr) { var buf [2844]byte; use(buf[:]); return Stackguard() }
-func stack2848() (uintptr, uintptr) { var buf [2848]byte; use(buf[:]); return Stackguard() }
-func stack2852() (uintptr, uintptr) { var buf [2852]byte; use(buf[:]); return Stackguard() }
-func stack2856() (uintptr, uintptr) { var buf [2856]byte; use(buf[:]); return Stackguard() }
-func stack2860() (uintptr, uintptr) { var buf [2860]byte; use(buf[:]); return Stackguard() }
-func stack2864() (uintptr, uintptr) { var buf [2864]byte; use(buf[:]); return Stackguard() }
-func stack2868() (uintptr, uintptr) { var buf [2868]byte; use(buf[:]); return Stackguard() }
-func stack2872() (uintptr, uintptr) { var buf [2872]byte; use(buf[:]); return Stackguard() }
-func stack2876() (uintptr, uintptr) { var buf [2876]byte; use(buf[:]); return Stackguard() }
-func stack2880() (uintptr, uintptr) { var buf [2880]byte; use(buf[:]); return Stackguard() }
-func stack2884() (uintptr, uintptr) { var buf [2884]byte; use(buf[:]); return Stackguard() }
-func stack2888() (uintptr, uintptr) { var buf [2888]byte; use(buf[:]); return Stackguard() }
-func stack2892() (uintptr, uintptr) { var buf [2892]byte; use(buf[:]); return Stackguard() }
-func stack2896() (uintptr, uintptr) { var buf [2896]byte; use(buf[:]); return Stackguard() }
-func stack2900() (uintptr, uintptr) { var buf [2900]byte; use(buf[:]); return Stackguard() }
-func stack2904() (uintptr, uintptr) { var buf [2904]byte; use(buf[:]); return Stackguard() }
-func stack2908() (uintptr, uintptr) { var buf [2908]byte; use(buf[:]); return Stackguard() }
-func stack2912() (uintptr, uintptr) { var buf [2912]byte; use(buf[:]); return Stackguard() }
-func stack2916() (uintptr, uintptr) { var buf [2916]byte; use(buf[:]); return Stackguard() }
-func stack2920() (uintptr, uintptr) { var buf [2920]byte; use(buf[:]); return Stackguard() }
-func stack2924() (uintptr, uintptr) { var buf [2924]byte; use(buf[:]); return Stackguard() }
-func stack2928() (uintptr, uintptr) { var buf [2928]byte; use(buf[:]); return Stackguard() }
-func stack2932() (uintptr, uintptr) { var buf [2932]byte; use(buf[:]); return Stackguard() }
-func stack2936() (uintptr, uintptr) { var buf [2936]byte; use(buf[:]); return Stackguard() }
-func stack2940() (uintptr, uintptr) { var buf [2940]byte; use(buf[:]); return Stackguard() }
-func stack2944() (uintptr, uintptr) { var buf [2944]byte; use(buf[:]); return Stackguard() }
-func stack2948() (uintptr, uintptr) { var buf [2948]byte; use(buf[:]); return Stackguard() }
-func stack2952() (uintptr, uintptr) { var buf [2952]byte; use(buf[:]); return Stackguard() }
-func stack2956() (uintptr, uintptr) { var buf [2956]byte; use(buf[:]); return Stackguard() }
-func stack2960() (uintptr, uintptr) { var buf [2960]byte; use(buf[:]); return Stackguard() }
-func stack2964() (uintptr, uintptr) { var buf [2964]byte; use(buf[:]); return Stackguard() }
-func stack2968() (uintptr, uintptr) { var buf [2968]byte; use(buf[:]); return Stackguard() }
-func stack2972() (uintptr, uintptr) { var buf [2972]byte; use(buf[:]); return Stackguard() }
-func stack2976() (uintptr, uintptr) { var buf [2976]byte; use(buf[:]); return Stackguard() }
-func stack2980() (uintptr, uintptr) { var buf [2980]byte; use(buf[:]); return Stackguard() }
-func stack2984() (uintptr, uintptr) { var buf [2984]byte; use(buf[:]); return Stackguard() }
-func stack2988() (uintptr, uintptr) { var buf [2988]byte; use(buf[:]); return Stackguard() }
-func stack2992() (uintptr, uintptr) { var buf [2992]byte; use(buf[:]); return Stackguard() }
-func stack2996() (uintptr, uintptr) { var buf [2996]byte; use(buf[:]); return Stackguard() }
-func stack3000() (uintptr, uintptr) { var buf [3000]byte; use(buf[:]); return Stackguard() }
-func stack3004() (uintptr, uintptr) { var buf [3004]byte; use(buf[:]); return Stackguard() }
-func stack3008() (uintptr, uintptr) { var buf [3008]byte; use(buf[:]); return Stackguard() }
-func stack3012() (uintptr, uintptr) { var buf [3012]byte; use(buf[:]); return Stackguard() }
-func stack3016() (uintptr, uintptr) { var buf [3016]byte; use(buf[:]); return Stackguard() }
-func stack3020() (uintptr, uintptr) { var buf [3020]byte; use(buf[:]); return Stackguard() }
-func stack3024() (uintptr, uintptr) { var buf [3024]byte; use(buf[:]); return Stackguard() }
-func stack3028() (uintptr, uintptr) { var buf [3028]byte; use(buf[:]); return Stackguard() }
-func stack3032() (uintptr, uintptr) { var buf [3032]byte; use(buf[:]); return Stackguard() }
-func stack3036() (uintptr, uintptr) { var buf [3036]byte; use(buf[:]); return Stackguard() }
-func stack3040() (uintptr, uintptr) { var buf [3040]byte; use(buf[:]); return Stackguard() }
-func stack3044() (uintptr, uintptr) { var buf [3044]byte; use(buf[:]); return Stackguard() }
-func stack3048() (uintptr, uintptr) { var buf [3048]byte; use(buf[:]); return Stackguard() }
-func stack3052() (uintptr, uintptr) { var buf [3052]byte; use(buf[:]); return Stackguard() }
-func stack3056() (uintptr, uintptr) { var buf [3056]byte; use(buf[:]); return Stackguard() }
-func stack3060() (uintptr, uintptr) { var buf [3060]byte; use(buf[:]); return Stackguard() }
-func stack3064() (uintptr, uintptr) { var buf [3064]byte; use(buf[:]); return Stackguard() }
-func stack3068() (uintptr, uintptr) { var buf [3068]byte; use(buf[:]); return Stackguard() }
-func stack3072() (uintptr, uintptr) { var buf [3072]byte; use(buf[:]); return Stackguard() }
-func stack3076() (uintptr, uintptr) { var buf [3076]byte; use(buf[:]); return Stackguard() }
-func stack3080() (uintptr, uintptr) { var buf [3080]byte; use(buf[:]); return Stackguard() }
-func stack3084() (uintptr, uintptr) { var buf [3084]byte; use(buf[:]); return Stackguard() }
-func stack3088() (uintptr, uintptr) { var buf [3088]byte; use(buf[:]); return Stackguard() }
-func stack3092() (uintptr, uintptr) { var buf [3092]byte; use(buf[:]); return Stackguard() }
-func stack3096() (uintptr, uintptr) { var buf [3096]byte; use(buf[:]); return Stackguard() }
-func stack3100() (uintptr, uintptr) { var buf [3100]byte; use(buf[:]); return Stackguard() }
-func stack3104() (uintptr, uintptr) { var buf [3104]byte; use(buf[:]); return Stackguard() }
-func stack3108() (uintptr, uintptr) { var buf [3108]byte; use(buf[:]); return Stackguard() }
-func stack3112() (uintptr, uintptr) { var buf [3112]byte; use(buf[:]); return Stackguard() }
-func stack3116() (uintptr, uintptr) { var buf [3116]byte; use(buf[:]); return Stackguard() }
-func stack3120() (uintptr, uintptr) { var buf [3120]byte; use(buf[:]); return Stackguard() }
-func stack3124() (uintptr, uintptr) { var buf [3124]byte; use(buf[:]); return Stackguard() }
-func stack3128() (uintptr, uintptr) { var buf [3128]byte; use(buf[:]); return Stackguard() }
-func stack3132() (uintptr, uintptr) { var buf [3132]byte; use(buf[:]); return Stackguard() }
-func stack3136() (uintptr, uintptr) { var buf [3136]byte; use(buf[:]); return Stackguard() }
-func stack3140() (uintptr, uintptr) { var buf [3140]byte; use(buf[:]); return Stackguard() }
-func stack3144() (uintptr, uintptr) { var buf [3144]byte; use(buf[:]); return Stackguard() }
-func stack3148() (uintptr, uintptr) { var buf [3148]byte; use(buf[:]); return Stackguard() }
-func stack3152() (uintptr, uintptr) { var buf [3152]byte; use(buf[:]); return Stackguard() }
-func stack3156() (uintptr, uintptr) { var buf [3156]byte; use(buf[:]); return Stackguard() }
-func stack3160() (uintptr, uintptr) { var buf [3160]byte; use(buf[:]); return Stackguard() }
-func stack3164() (uintptr, uintptr) { var buf [3164]byte; use(buf[:]); return Stackguard() }
-func stack3168() (uintptr, uintptr) { var buf [3168]byte; use(buf[:]); return Stackguard() }
-func stack3172() (uintptr, uintptr) { var buf [3172]byte; use(buf[:]); return Stackguard() }
-func stack3176() (uintptr, uintptr) { var buf [3176]byte; use(buf[:]); return Stackguard() }
-func stack3180() (uintptr, uintptr) { var buf [3180]byte; use(buf[:]); return Stackguard() }
-func stack3184() (uintptr, uintptr) { var buf [3184]byte; use(buf[:]); return Stackguard() }
-func stack3188() (uintptr, uintptr) { var buf [3188]byte; use(buf[:]); return Stackguard() }
-func stack3192() (uintptr, uintptr) { var buf [3192]byte; use(buf[:]); return Stackguard() }
-func stack3196() (uintptr, uintptr) { var buf [3196]byte; use(buf[:]); return Stackguard() }
-func stack3200() (uintptr, uintptr) { var buf [3200]byte; use(buf[:]); return Stackguard() }
-func stack3204() (uintptr, uintptr) { var buf [3204]byte; use(buf[:]); return Stackguard() }
-func stack3208() (uintptr, uintptr) { var buf [3208]byte; use(buf[:]); return Stackguard() }
-func stack3212() (uintptr, uintptr) { var buf [3212]byte; use(buf[:]); return Stackguard() }
-func stack3216() (uintptr, uintptr) { var buf [3216]byte; use(buf[:]); return Stackguard() }
-func stack3220() (uintptr, uintptr) { var buf [3220]byte; use(buf[:]); return Stackguard() }
-func stack3224() (uintptr, uintptr) { var buf [3224]byte; use(buf[:]); return Stackguard() }
-func stack3228() (uintptr, uintptr) { var buf [3228]byte; use(buf[:]); return Stackguard() }
-func stack3232() (uintptr, uintptr) { var buf [3232]byte; use(buf[:]); return Stackguard() }
-func stack3236() (uintptr, uintptr) { var buf [3236]byte; use(buf[:]); return Stackguard() }
-func stack3240() (uintptr, uintptr) { var buf [3240]byte; use(buf[:]); return Stackguard() }
-func stack3244() (uintptr, uintptr) { var buf [3244]byte; use(buf[:]); return Stackguard() }
-func stack3248() (uintptr, uintptr) { var buf [3248]byte; use(buf[:]); return Stackguard() }
-func stack3252() (uintptr, uintptr) { var buf [3252]byte; use(buf[:]); return Stackguard() }
-func stack3256() (uintptr, uintptr) { var buf [3256]byte; use(buf[:]); return Stackguard() }
-func stack3260() (uintptr, uintptr) { var buf [3260]byte; use(buf[:]); return Stackguard() }
-func stack3264() (uintptr, uintptr) { var buf [3264]byte; use(buf[:]); return Stackguard() }
-func stack3268() (uintptr, uintptr) { var buf [3268]byte; use(buf[:]); return Stackguard() }
-func stack3272() (uintptr, uintptr) { var buf [3272]byte; use(buf[:]); return Stackguard() }
-func stack3276() (uintptr, uintptr) { var buf [3276]byte; use(buf[:]); return Stackguard() }
-func stack3280() (uintptr, uintptr) { var buf [3280]byte; use(buf[:]); return Stackguard() }
-func stack3284() (uintptr, uintptr) { var buf [3284]byte; use(buf[:]); return Stackguard() }
-func stack3288() (uintptr, uintptr) { var buf [3288]byte; use(buf[:]); return Stackguard() }
-func stack3292() (uintptr, uintptr) { var buf [3292]byte; use(buf[:]); return Stackguard() }
-func stack3296() (uintptr, uintptr) { var buf [3296]byte; use(buf[:]); return Stackguard() }
-func stack3300() (uintptr, uintptr) { var buf [3300]byte; use(buf[:]); return Stackguard() }
-func stack3304() (uintptr, uintptr) { var buf [3304]byte; use(buf[:]); return Stackguard() }
-func stack3308() (uintptr, uintptr) { var buf [3308]byte; use(buf[:]); return Stackguard() }
-func stack3312() (uintptr, uintptr) { var buf [3312]byte; use(buf[:]); return Stackguard() }
-func stack3316() (uintptr, uintptr) { var buf [3316]byte; use(buf[:]); return Stackguard() }
-func stack3320() (uintptr, uintptr) { var buf [3320]byte; use(buf[:]); return Stackguard() }
-func stack3324() (uintptr, uintptr) { var buf [3324]byte; use(buf[:]); return Stackguard() }
-func stack3328() (uintptr, uintptr) { var buf [3328]byte; use(buf[:]); return Stackguard() }
-func stack3332() (uintptr, uintptr) { var buf [3332]byte; use(buf[:]); return Stackguard() }
-func stack3336() (uintptr, uintptr) { var buf [3336]byte; use(buf[:]); return Stackguard() }
-func stack3340() (uintptr, uintptr) { var buf [3340]byte; use(buf[:]); return Stackguard() }
-func stack3344() (uintptr, uintptr) { var buf [3344]byte; use(buf[:]); return Stackguard() }
-func stack3348() (uintptr, uintptr) { var buf [3348]byte; use(buf[:]); return Stackguard() }
-func stack3352() (uintptr, uintptr) { var buf [3352]byte; use(buf[:]); return Stackguard() }
-func stack3356() (uintptr, uintptr) { var buf [3356]byte; use(buf[:]); return Stackguard() }
-func stack3360() (uintptr, uintptr) { var buf [3360]byte; use(buf[:]); return Stackguard() }
-func stack3364() (uintptr, uintptr) { var buf [3364]byte; use(buf[:]); return Stackguard() }
-func stack3368() (uintptr, uintptr) { var buf [3368]byte; use(buf[:]); return Stackguard() }
-func stack3372() (uintptr, uintptr) { var buf [3372]byte; use(buf[:]); return Stackguard() }
-func stack3376() (uintptr, uintptr) { var buf [3376]byte; use(buf[:]); return Stackguard() }
-func stack3380() (uintptr, uintptr) { var buf [3380]byte; use(buf[:]); return Stackguard() }
-func stack3384() (uintptr, uintptr) { var buf [3384]byte; use(buf[:]); return Stackguard() }
-func stack3388() (uintptr, uintptr) { var buf [3388]byte; use(buf[:]); return Stackguard() }
-func stack3392() (uintptr, uintptr) { var buf [3392]byte; use(buf[:]); return Stackguard() }
-func stack3396() (uintptr, uintptr) { var buf [3396]byte; use(buf[:]); return Stackguard() }
-func stack3400() (uintptr, uintptr) { var buf [3400]byte; use(buf[:]); return Stackguard() }
-func stack3404() (uintptr, uintptr) { var buf [3404]byte; use(buf[:]); return Stackguard() }
-func stack3408() (uintptr, uintptr) { var buf [3408]byte; use(buf[:]); return Stackguard() }
-func stack3412() (uintptr, uintptr) { var buf [3412]byte; use(buf[:]); return Stackguard() }
-func stack3416() (uintptr, uintptr) { var buf [3416]byte; use(buf[:]); return Stackguard() }
-func stack3420() (uintptr, uintptr) { var buf [3420]byte; use(buf[:]); return Stackguard() }
-func stack3424() (uintptr, uintptr) { var buf [3424]byte; use(buf[:]); return Stackguard() }
-func stack3428() (uintptr, uintptr) { var buf [3428]byte; use(buf[:]); return Stackguard() }
-func stack3432() (uintptr, uintptr) { var buf [3432]byte; use(buf[:]); return Stackguard() }
-func stack3436() (uintptr, uintptr) { var buf [3436]byte; use(buf[:]); return Stackguard() }
-func stack3440() (uintptr, uintptr) { var buf [3440]byte; use(buf[:]); return Stackguard() }
-func stack3444() (uintptr, uintptr) { var buf [3444]byte; use(buf[:]); return Stackguard() }
-func stack3448() (uintptr, uintptr) { var buf [3448]byte; use(buf[:]); return Stackguard() }
-func stack3452() (uintptr, uintptr) { var buf [3452]byte; use(buf[:]); return Stackguard() }
-func stack3456() (uintptr, uintptr) { var buf [3456]byte; use(buf[:]); return Stackguard() }
-func stack3460() (uintptr, uintptr) { var buf [3460]byte; use(buf[:]); return Stackguard() }
-func stack3464() (uintptr, uintptr) { var buf [3464]byte; use(buf[:]); return Stackguard() }
-func stack3468() (uintptr, uintptr) { var buf [3468]byte; use(buf[:]); return Stackguard() }
-func stack3472() (uintptr, uintptr) { var buf [3472]byte; use(buf[:]); return Stackguard() }
-func stack3476() (uintptr, uintptr) { var buf [3476]byte; use(buf[:]); return Stackguard() }
-func stack3480() (uintptr, uintptr) { var buf [3480]byte; use(buf[:]); return Stackguard() }
-func stack3484() (uintptr, uintptr) { var buf [3484]byte; use(buf[:]); return Stackguard() }
-func stack3488() (uintptr, uintptr) { var buf [3488]byte; use(buf[:]); return Stackguard() }
-func stack3492() (uintptr, uintptr) { var buf [3492]byte; use(buf[:]); return Stackguard() }
-func stack3496() (uintptr, uintptr) { var buf [3496]byte; use(buf[:]); return Stackguard() }
-func stack3500() (uintptr, uintptr) { var buf [3500]byte; use(buf[:]); return Stackguard() }
-func stack3504() (uintptr, uintptr) { var buf [3504]byte; use(buf[:]); return Stackguard() }
-func stack3508() (uintptr, uintptr) { var buf [3508]byte; use(buf[:]); return Stackguard() }
-func stack3512() (uintptr, uintptr) { var buf [3512]byte; use(buf[:]); return Stackguard() }
-func stack3516() (uintptr, uintptr) { var buf [3516]byte; use(buf[:]); return Stackguard() }
-func stack3520() (uintptr, uintptr) { var buf [3520]byte; use(buf[:]); return Stackguard() }
-func stack3524() (uintptr, uintptr) { var buf [3524]byte; use(buf[:]); return Stackguard() }
-func stack3528() (uintptr, uintptr) { var buf [3528]byte; use(buf[:]); return Stackguard() }
-func stack3532() (uintptr, uintptr) { var buf [3532]byte; use(buf[:]); return Stackguard() }
-func stack3536() (uintptr, uintptr) { var buf [3536]byte; use(buf[:]); return Stackguard() }
-func stack3540() (uintptr, uintptr) { var buf [3540]byte; use(buf[:]); return Stackguard() }
-func stack3544() (uintptr, uintptr) { var buf [3544]byte; use(buf[:]); return Stackguard() }
-func stack3548() (uintptr, uintptr) { var buf [3548]byte; use(buf[:]); return Stackguard() }
-func stack3552() (uintptr, uintptr) { var buf [3552]byte; use(buf[:]); return Stackguard() }
-func stack3556() (uintptr, uintptr) { var buf [3556]byte; use(buf[:]); return Stackguard() }
-func stack3560() (uintptr, uintptr) { var buf [3560]byte; use(buf[:]); return Stackguard() }
-func stack3564() (uintptr, uintptr) { var buf [3564]byte; use(buf[:]); return Stackguard() }
-func stack3568() (uintptr, uintptr) { var buf [3568]byte; use(buf[:]); return Stackguard() }
-func stack3572() (uintptr, uintptr) { var buf [3572]byte; use(buf[:]); return Stackguard() }
-func stack3576() (uintptr, uintptr) { var buf [3576]byte; use(buf[:]); return Stackguard() }
-func stack3580() (uintptr, uintptr) { var buf [3580]byte; use(buf[:]); return Stackguard() }
-func stack3584() (uintptr, uintptr) { var buf [3584]byte; use(buf[:]); return Stackguard() }
-func stack3588() (uintptr, uintptr) { var buf [3588]byte; use(buf[:]); return Stackguard() }
-func stack3592() (uintptr, uintptr) { var buf [3592]byte; use(buf[:]); return Stackguard() }
-func stack3596() (uintptr, uintptr) { var buf [3596]byte; use(buf[:]); return Stackguard() }
-func stack3600() (uintptr, uintptr) { var buf [3600]byte; use(buf[:]); return Stackguard() }
-func stack3604() (uintptr, uintptr) { var buf [3604]byte; use(buf[:]); return Stackguard() }
-func stack3608() (uintptr, uintptr) { var buf [3608]byte; use(buf[:]); return Stackguard() }
-func stack3612() (uintptr, uintptr) { var buf [3612]byte; use(buf[:]); return Stackguard() }
-func stack3616() (uintptr, uintptr) { var buf [3616]byte; use(buf[:]); return Stackguard() }
-func stack3620() (uintptr, uintptr) { var buf [3620]byte; use(buf[:]); return Stackguard() }
-func stack3624() (uintptr, uintptr) { var buf [3624]byte; use(buf[:]); return Stackguard() }
-func stack3628() (uintptr, uintptr) { var buf [3628]byte; use(buf[:]); return Stackguard() }
-func stack3632() (uintptr, uintptr) { var buf [3632]byte; use(buf[:]); return Stackguard() }
-func stack3636() (uintptr, uintptr) { var buf [3636]byte; use(buf[:]); return Stackguard() }
-func stack3640() (uintptr, uintptr) { var buf [3640]byte; use(buf[:]); return Stackguard() }
-func stack3644() (uintptr, uintptr) { var buf [3644]byte; use(buf[:]); return Stackguard() }
-func stack3648() (uintptr, uintptr) { var buf [3648]byte; use(buf[:]); return Stackguard() }
-func stack3652() (uintptr, uintptr) { var buf [3652]byte; use(buf[:]); return Stackguard() }
-func stack3656() (uintptr, uintptr) { var buf [3656]byte; use(buf[:]); return Stackguard() }
-func stack3660() (uintptr, uintptr) { var buf [3660]byte; use(buf[:]); return Stackguard() }
-func stack3664() (uintptr, uintptr) { var buf [3664]byte; use(buf[:]); return Stackguard() }
-func stack3668() (uintptr, uintptr) { var buf [3668]byte; use(buf[:]); return Stackguard() }
-func stack3672() (uintptr, uintptr) { var buf [3672]byte; use(buf[:]); return Stackguard() }
-func stack3676() (uintptr, uintptr) { var buf [3676]byte; use(buf[:]); return Stackguard() }
-func stack3680() (uintptr, uintptr) { var buf [3680]byte; use(buf[:]); return Stackguard() }
-func stack3684() (uintptr, uintptr) { var buf [3684]byte; use(buf[:]); return Stackguard() }
-func stack3688() (uintptr, uintptr) { var buf [3688]byte; use(buf[:]); return Stackguard() }
-func stack3692() (uintptr, uintptr) { var buf [3692]byte; use(buf[:]); return Stackguard() }
-func stack3696() (uintptr, uintptr) { var buf [3696]byte; use(buf[:]); return Stackguard() }
-func stack3700() (uintptr, uintptr) { var buf [3700]byte; use(buf[:]); return Stackguard() }
-func stack3704() (uintptr, uintptr) { var buf [3704]byte; use(buf[:]); return Stackguard() }
-func stack3708() (uintptr, uintptr) { var buf [3708]byte; use(buf[:]); return Stackguard() }
-func stack3712() (uintptr, uintptr) { var buf [3712]byte; use(buf[:]); return Stackguard() }
-func stack3716() (uintptr, uintptr) { var buf [3716]byte; use(buf[:]); return Stackguard() }
-func stack3720() (uintptr, uintptr) { var buf [3720]byte; use(buf[:]); return Stackguard() }
-func stack3724() (uintptr, uintptr) { var buf [3724]byte; use(buf[:]); return Stackguard() }
-func stack3728() (uintptr, uintptr) { var buf [3728]byte; use(buf[:]); return Stackguard() }
-func stack3732() (uintptr, uintptr) { var buf [3732]byte; use(buf[:]); return Stackguard() }
-func stack3736() (uintptr, uintptr) { var buf [3736]byte; use(buf[:]); return Stackguard() }
-func stack3740() (uintptr, uintptr) { var buf [3740]byte; use(buf[:]); return Stackguard() }
-func stack3744() (uintptr, uintptr) { var buf [3744]byte; use(buf[:]); return Stackguard() }
-func stack3748() (uintptr, uintptr) { var buf [3748]byte; use(buf[:]); return Stackguard() }
-func stack3752() (uintptr, uintptr) { var buf [3752]byte; use(buf[:]); return Stackguard() }
-func stack3756() (uintptr, uintptr) { var buf [3756]byte; use(buf[:]); return Stackguard() }
-func stack3760() (uintptr, uintptr) { var buf [3760]byte; use(buf[:]); return Stackguard() }
-func stack3764() (uintptr, uintptr) { var buf [3764]byte; use(buf[:]); return Stackguard() }
-func stack3768() (uintptr, uintptr) { var buf [3768]byte; use(buf[:]); return Stackguard() }
-func stack3772() (uintptr, uintptr) { var buf [3772]byte; use(buf[:]); return Stackguard() }
-func stack3776() (uintptr, uintptr) { var buf [3776]byte; use(buf[:]); return Stackguard() }
-func stack3780() (uintptr, uintptr) { var buf [3780]byte; use(buf[:]); return Stackguard() }
-func stack3784() (uintptr, uintptr) { var buf [3784]byte; use(buf[:]); return Stackguard() }
-func stack3788() (uintptr, uintptr) { var buf [3788]byte; use(buf[:]); return Stackguard() }
-func stack3792() (uintptr, uintptr) { var buf [3792]byte; use(buf[:]); return Stackguard() }
-func stack3796() (uintptr, uintptr) { var buf [3796]byte; use(buf[:]); return Stackguard() }
-func stack3800() (uintptr, uintptr) { var buf [3800]byte; use(buf[:]); return Stackguard() }
-func stack3804() (uintptr, uintptr) { var buf [3804]byte; use(buf[:]); return Stackguard() }
-func stack3808() (uintptr, uintptr) { var buf [3808]byte; use(buf[:]); return Stackguard() }
-func stack3812() (uintptr, uintptr) { var buf [3812]byte; use(buf[:]); return Stackguard() }
-func stack3816() (uintptr, uintptr) { var buf [3816]byte; use(buf[:]); return Stackguard() }
-func stack3820() (uintptr, uintptr) { var buf [3820]byte; use(buf[:]); return Stackguard() }
-func stack3824() (uintptr, uintptr) { var buf [3824]byte; use(buf[:]); return Stackguard() }
-func stack3828() (uintptr, uintptr) { var buf [3828]byte; use(buf[:]); return Stackguard() }
-func stack3832() (uintptr, uintptr) { var buf [3832]byte; use(buf[:]); return Stackguard() }
-func stack3836() (uintptr, uintptr) { var buf [3836]byte; use(buf[:]); return Stackguard() }
-func stack3840() (uintptr, uintptr) { var buf [3840]byte; use(buf[:]); return Stackguard() }
-func stack3844() (uintptr, uintptr) { var buf [3844]byte; use(buf[:]); return Stackguard() }
-func stack3848() (uintptr, uintptr) { var buf [3848]byte; use(buf[:]); return Stackguard() }
-func stack3852() (uintptr, uintptr) { var buf [3852]byte; use(buf[:]); return Stackguard() }
-func stack3856() (uintptr, uintptr) { var buf [3856]byte; use(buf[:]); return Stackguard() }
-func stack3860() (uintptr, uintptr) { var buf [3860]byte; use(buf[:]); return Stackguard() }
-func stack3864() (uintptr, uintptr) { var buf [3864]byte; use(buf[:]); return Stackguard() }
-func stack3868() (uintptr, uintptr) { var buf [3868]byte; use(buf[:]); return Stackguard() }
-func stack3872() (uintptr, uintptr) { var buf [3872]byte; use(buf[:]); return Stackguard() }
-func stack3876() (uintptr, uintptr) { var buf [3876]byte; use(buf[:]); return Stackguard() }
-func stack3880() (uintptr, uintptr) { var buf [3880]byte; use(buf[:]); return Stackguard() }
-func stack3884() (uintptr, uintptr) { var buf [3884]byte; use(buf[:]); return Stackguard() }
-func stack3888() (uintptr, uintptr) { var buf [3888]byte; use(buf[:]); return Stackguard() }
-func stack3892() (uintptr, uintptr) { var buf [3892]byte; use(buf[:]); return Stackguard() }
-func stack3896() (uintptr, uintptr) { var buf [3896]byte; use(buf[:]); return Stackguard() }
-func stack3900() (uintptr, uintptr) { var buf [3900]byte; use(buf[:]); return Stackguard() }
-func stack3904() (uintptr, uintptr) { var buf [3904]byte; use(buf[:]); return Stackguard() }
-func stack3908() (uintptr, uintptr) { var buf [3908]byte; use(buf[:]); return Stackguard() }
-func stack3912() (uintptr, uintptr) { var buf [3912]byte; use(buf[:]); return Stackguard() }
-func stack3916() (uintptr, uintptr) { var buf [3916]byte; use(buf[:]); return Stackguard() }
-func stack3920() (uintptr, uintptr) { var buf [3920]byte; use(buf[:]); return Stackguard() }
-func stack3924() (uintptr, uintptr) { var buf [3924]byte; use(buf[:]); return Stackguard() }
-func stack3928() (uintptr, uintptr) { var buf [3928]byte; use(buf[:]); return Stackguard() }
-func stack3932() (uintptr, uintptr) { var buf [3932]byte; use(buf[:]); return Stackguard() }
-func stack3936() (uintptr, uintptr) { var buf [3936]byte; use(buf[:]); return Stackguard() }
-func stack3940() (uintptr, uintptr) { var buf [3940]byte; use(buf[:]); return Stackguard() }
-func stack3944() (uintptr, uintptr) { var buf [3944]byte; use(buf[:]); return Stackguard() }
-func stack3948() (uintptr, uintptr) { var buf [3948]byte; use(buf[:]); return Stackguard() }
-func stack3952() (uintptr, uintptr) { var buf [3952]byte; use(buf[:]); return Stackguard() }
-func stack3956() (uintptr, uintptr) { var buf [3956]byte; use(buf[:]); return Stackguard() }
-func stack3960() (uintptr, uintptr) { var buf [3960]byte; use(buf[:]); return Stackguard() }
-func stack3964() (uintptr, uintptr) { var buf [3964]byte; use(buf[:]); return Stackguard() }
-func stack3968() (uintptr, uintptr) { var buf [3968]byte; use(buf[:]); return Stackguard() }
-func stack3972() (uintptr, uintptr) { var buf [3972]byte; use(buf[:]); return Stackguard() }
-func stack3976() (uintptr, uintptr) { var buf [3976]byte; use(buf[:]); return Stackguard() }
-func stack3980() (uintptr, uintptr) { var buf [3980]byte; use(buf[:]); return Stackguard() }
-func stack3984() (uintptr, uintptr) { var buf [3984]byte; use(buf[:]); return Stackguard() }
-func stack3988() (uintptr, uintptr) { var buf [3988]byte; use(buf[:]); return Stackguard() }
-func stack3992() (uintptr, uintptr) { var buf [3992]byte; use(buf[:]); return Stackguard() }
-func stack3996() (uintptr, uintptr) { var buf [3996]byte; use(buf[:]); return Stackguard() }
-func stack4000() (uintptr, uintptr) { var buf [4000]byte; use(buf[:]); return Stackguard() }
-func stack4004() (uintptr, uintptr) { var buf [4004]byte; use(buf[:]); return Stackguard() }
-func stack4008() (uintptr, uintptr) { var buf [4008]byte; use(buf[:]); return Stackguard() }
-func stack4012() (uintptr, uintptr) { var buf [4012]byte; use(buf[:]); return Stackguard() }
-func stack4016() (uintptr, uintptr) { var buf [4016]byte; use(buf[:]); return Stackguard() }
-func stack4020() (uintptr, uintptr) { var buf [4020]byte; use(buf[:]); return Stackguard() }
-func stack4024() (uintptr, uintptr) { var buf [4024]byte; use(buf[:]); return Stackguard() }
-func stack4028() (uintptr, uintptr) { var buf [4028]byte; use(buf[:]); return Stackguard() }
-func stack4032() (uintptr, uintptr) { var buf [4032]byte; use(buf[:]); return Stackguard() }
-func stack4036() (uintptr, uintptr) { var buf [4036]byte; use(buf[:]); return Stackguard() }
-func stack4040() (uintptr, uintptr) { var buf [4040]byte; use(buf[:]); return Stackguard() }
-func stack4044() (uintptr, uintptr) { var buf [4044]byte; use(buf[:]); return Stackguard() }
-func stack4048() (uintptr, uintptr) { var buf [4048]byte; use(buf[:]); return Stackguard() }
-func stack4052() (uintptr, uintptr) { var buf [4052]byte; use(buf[:]); return Stackguard() }
-func stack4056() (uintptr, uintptr) { var buf [4056]byte; use(buf[:]); return Stackguard() }
-func stack4060() (uintptr, uintptr) { var buf [4060]byte; use(buf[:]); return Stackguard() }
-func stack4064() (uintptr, uintptr) { var buf [4064]byte; use(buf[:]); return Stackguard() }
-func stack4068() (uintptr, uintptr) { var buf [4068]byte; use(buf[:]); return Stackguard() }
-func stack4072() (uintptr, uintptr) { var buf [4072]byte; use(buf[:]); return Stackguard() }
-func stack4076() (uintptr, uintptr) { var buf [4076]byte; use(buf[:]); return Stackguard() }
-func stack4080() (uintptr, uintptr) { var buf [4080]byte; use(buf[:]); return Stackguard() }
-func stack4084() (uintptr, uintptr) { var buf [4084]byte; use(buf[:]); return Stackguard() }
-func stack4088() (uintptr, uintptr) { var buf [4088]byte; use(buf[:]); return Stackguard() }
-func stack4092() (uintptr, uintptr) { var buf [4092]byte; use(buf[:]); return Stackguard() }
-func stack4096() (uintptr, uintptr) { var buf [4096]byte; use(buf[:]); return Stackguard() }
-func stack4100() (uintptr, uintptr) { var buf [4100]byte; use(buf[:]); return Stackguard() }
-func stack4104() (uintptr, uintptr) { var buf [4104]byte; use(buf[:]); return Stackguard() }
-func stack4108() (uintptr, uintptr) { var buf [4108]byte; use(buf[:]); return Stackguard() }
-func stack4112() (uintptr, uintptr) { var buf [4112]byte; use(buf[:]); return Stackguard() }
-func stack4116() (uintptr, uintptr) { var buf [4116]byte; use(buf[:]); return Stackguard() }
-func stack4120() (uintptr, uintptr) { var buf [4120]byte; use(buf[:]); return Stackguard() }
-func stack4124() (uintptr, uintptr) { var buf [4124]byte; use(buf[:]); return Stackguard() }
-func stack4128() (uintptr, uintptr) { var buf [4128]byte; use(buf[:]); return Stackguard() }
-func stack4132() (uintptr, uintptr) { var buf [4132]byte; use(buf[:]); return Stackguard() }
-func stack4136() (uintptr, uintptr) { var buf [4136]byte; use(buf[:]); return Stackguard() }
-func stack4140() (uintptr, uintptr) { var buf [4140]byte; use(buf[:]); return Stackguard() }
-func stack4144() (uintptr, uintptr) { var buf [4144]byte; use(buf[:]); return Stackguard() }
-func stack4148() (uintptr, uintptr) { var buf [4148]byte; use(buf[:]); return Stackguard() }
-func stack4152() (uintptr, uintptr) { var buf [4152]byte; use(buf[:]); return Stackguard() }
-func stack4156() (uintptr, uintptr) { var buf [4156]byte; use(buf[:]); return Stackguard() }
-func stack4160() (uintptr, uintptr) { var buf [4160]byte; use(buf[:]); return Stackguard() }
-func stack4164() (uintptr, uintptr) { var buf [4164]byte; use(buf[:]); return Stackguard() }
-func stack4168() (uintptr, uintptr) { var buf [4168]byte; use(buf[:]); return Stackguard() }
-func stack4172() (uintptr, uintptr) { var buf [4172]byte; use(buf[:]); return Stackguard() }
-func stack4176() (uintptr, uintptr) { var buf [4176]byte; use(buf[:]); return Stackguard() }
-func stack4180() (uintptr, uintptr) { var buf [4180]byte; use(buf[:]); return Stackguard() }
-func stack4184() (uintptr, uintptr) { var buf [4184]byte; use(buf[:]); return Stackguard() }
-func stack4188() (uintptr, uintptr) { var buf [4188]byte; use(buf[:]); return Stackguard() }
-func stack4192() (uintptr, uintptr) { var buf [4192]byte; use(buf[:]); return Stackguard() }
-func stack4196() (uintptr, uintptr) { var buf [4196]byte; use(buf[:]); return Stackguard() }
-func stack4200() (uintptr, uintptr) { var buf [4200]byte; use(buf[:]); return Stackguard() }
-func stack4204() (uintptr, uintptr) { var buf [4204]byte; use(buf[:]); return Stackguard() }
-func stack4208() (uintptr, uintptr) { var buf [4208]byte; use(buf[:]); return Stackguard() }
-func stack4212() (uintptr, uintptr) { var buf [4212]byte; use(buf[:]); return Stackguard() }
-func stack4216() (uintptr, uintptr) { var buf [4216]byte; use(buf[:]); return Stackguard() }
-func stack4220() (uintptr, uintptr) { var buf [4220]byte; use(buf[:]); return Stackguard() }
-func stack4224() (uintptr, uintptr) { var buf [4224]byte; use(buf[:]); return Stackguard() }
-func stack4228() (uintptr, uintptr) { var buf [4228]byte; use(buf[:]); return Stackguard() }
-func stack4232() (uintptr, uintptr) { var buf [4232]byte; use(buf[:]); return Stackguard() }
-func stack4236() (uintptr, uintptr) { var buf [4236]byte; use(buf[:]); return Stackguard() }
-func stack4240() (uintptr, uintptr) { var buf [4240]byte; use(buf[:]); return Stackguard() }
-func stack4244() (uintptr, uintptr) { var buf [4244]byte; use(buf[:]); return Stackguard() }
-func stack4248() (uintptr, uintptr) { var buf [4248]byte; use(buf[:]); return Stackguard() }
-func stack4252() (uintptr, uintptr) { var buf [4252]byte; use(buf[:]); return Stackguard() }
-func stack4256() (uintptr, uintptr) { var buf [4256]byte; use(buf[:]); return Stackguard() }
-func stack4260() (uintptr, uintptr) { var buf [4260]byte; use(buf[:]); return Stackguard() }
-func stack4264() (uintptr, uintptr) { var buf [4264]byte; use(buf[:]); return Stackguard() }
-func stack4268() (uintptr, uintptr) { var buf [4268]byte; use(buf[:]); return Stackguard() }
-func stack4272() (uintptr, uintptr) { var buf [4272]byte; use(buf[:]); return Stackguard() }
-func stack4276() (uintptr, uintptr) { var buf [4276]byte; use(buf[:]); return Stackguard() }
-func stack4280() (uintptr, uintptr) { var buf [4280]byte; use(buf[:]); return Stackguard() }
-func stack4284() (uintptr, uintptr) { var buf [4284]byte; use(buf[:]); return Stackguard() }
-func stack4288() (uintptr, uintptr) { var buf [4288]byte; use(buf[:]); return Stackguard() }
-func stack4292() (uintptr, uintptr) { var buf [4292]byte; use(buf[:]); return Stackguard() }
-func stack4296() (uintptr, uintptr) { var buf [4296]byte; use(buf[:]); return Stackguard() }
-func stack4300() (uintptr, uintptr) { var buf [4300]byte; use(buf[:]); return Stackguard() }
-func stack4304() (uintptr, uintptr) { var buf [4304]byte; use(buf[:]); return Stackguard() }
-func stack4308() (uintptr, uintptr) { var buf [4308]byte; use(buf[:]); return Stackguard() }
-func stack4312() (uintptr, uintptr) { var buf [4312]byte; use(buf[:]); return Stackguard() }
-func stack4316() (uintptr, uintptr) { var buf [4316]byte; use(buf[:]); return Stackguard() }
-func stack4320() (uintptr, uintptr) { var buf [4320]byte; use(buf[:]); return Stackguard() }
-func stack4324() (uintptr, uintptr) { var buf [4324]byte; use(buf[:]); return Stackguard() }
-func stack4328() (uintptr, uintptr) { var buf [4328]byte; use(buf[:]); return Stackguard() }
-func stack4332() (uintptr, uintptr) { var buf [4332]byte; use(buf[:]); return Stackguard() }
-func stack4336() (uintptr, uintptr) { var buf [4336]byte; use(buf[:]); return Stackguard() }
-func stack4340() (uintptr, uintptr) { var buf [4340]byte; use(buf[:]); return Stackguard() }
-func stack4344() (uintptr, uintptr) { var buf [4344]byte; use(buf[:]); return Stackguard() }
-func stack4348() (uintptr, uintptr) { var buf [4348]byte; use(buf[:]); return Stackguard() }
-func stack4352() (uintptr, uintptr) { var buf [4352]byte; use(buf[:]); return Stackguard() }
-func stack4356() (uintptr, uintptr) { var buf [4356]byte; use(buf[:]); return Stackguard() }
-func stack4360() (uintptr, uintptr) { var buf [4360]byte; use(buf[:]); return Stackguard() }
-func stack4364() (uintptr, uintptr) { var buf [4364]byte; use(buf[:]); return Stackguard() }
-func stack4368() (uintptr, uintptr) { var buf [4368]byte; use(buf[:]); return Stackguard() }
-func stack4372() (uintptr, uintptr) { var buf [4372]byte; use(buf[:]); return Stackguard() }
-func stack4376() (uintptr, uintptr) { var buf [4376]byte; use(buf[:]); return Stackguard() }
-func stack4380() (uintptr, uintptr) { var buf [4380]byte; use(buf[:]); return Stackguard() }
-func stack4384() (uintptr, uintptr) { var buf [4384]byte; use(buf[:]); return Stackguard() }
-func stack4388() (uintptr, uintptr) { var buf [4388]byte; use(buf[:]); return Stackguard() }
-func stack4392() (uintptr, uintptr) { var buf [4392]byte; use(buf[:]); return Stackguard() }
-func stack4396() (uintptr, uintptr) { var buf [4396]byte; use(buf[:]); return Stackguard() }
-func stack4400() (uintptr, uintptr) { var buf [4400]byte; use(buf[:]); return Stackguard() }
-func stack4404() (uintptr, uintptr) { var buf [4404]byte; use(buf[:]); return Stackguard() }
-func stack4408() (uintptr, uintptr) { var buf [4408]byte; use(buf[:]); return Stackguard() }
-func stack4412() (uintptr, uintptr) { var buf [4412]byte; use(buf[:]); return Stackguard() }
-func stack4416() (uintptr, uintptr) { var buf [4416]byte; use(buf[:]); return Stackguard() }
-func stack4420() (uintptr, uintptr) { var buf [4420]byte; use(buf[:]); return Stackguard() }
-func stack4424() (uintptr, uintptr) { var buf [4424]byte; use(buf[:]); return Stackguard() }
-func stack4428() (uintptr, uintptr) { var buf [4428]byte; use(buf[:]); return Stackguard() }
-func stack4432() (uintptr, uintptr) { var buf [4432]byte; use(buf[:]); return Stackguard() }
-func stack4436() (uintptr, uintptr) { var buf [4436]byte; use(buf[:]); return Stackguard() }
-func stack4440() (uintptr, uintptr) { var buf [4440]byte; use(buf[:]); return Stackguard() }
-func stack4444() (uintptr, uintptr) { var buf [4444]byte; use(buf[:]); return Stackguard() }
-func stack4448() (uintptr, uintptr) { var buf [4448]byte; use(buf[:]); return Stackguard() }
-func stack4452() (uintptr, uintptr) { var buf [4452]byte; use(buf[:]); return Stackguard() }
-func stack4456() (uintptr, uintptr) { var buf [4456]byte; use(buf[:]); return Stackguard() }
-func stack4460() (uintptr, uintptr) { var buf [4460]byte; use(buf[:]); return Stackguard() }
-func stack4464() (uintptr, uintptr) { var buf [4464]byte; use(buf[:]); return Stackguard() }
-func stack4468() (uintptr, uintptr) { var buf [4468]byte; use(buf[:]); return Stackguard() }
-func stack4472() (uintptr, uintptr) { var buf [4472]byte; use(buf[:]); return Stackguard() }
-func stack4476() (uintptr, uintptr) { var buf [4476]byte; use(buf[:]); return Stackguard() }
-func stack4480() (uintptr, uintptr) { var buf [4480]byte; use(buf[:]); return Stackguard() }
-func stack4484() (uintptr, uintptr) { var buf [4484]byte; use(buf[:]); return Stackguard() }
-func stack4488() (uintptr, uintptr) { var buf [4488]byte; use(buf[:]); return Stackguard() }
-func stack4492() (uintptr, uintptr) { var buf [4492]byte; use(buf[:]); return Stackguard() }
-func stack4496() (uintptr, uintptr) { var buf [4496]byte; use(buf[:]); return Stackguard() }
-func stack4500() (uintptr, uintptr) { var buf [4500]byte; use(buf[:]); return Stackguard() }
-func stack4504() (uintptr, uintptr) { var buf [4504]byte; use(buf[:]); return Stackguard() }
-func stack4508() (uintptr, uintptr) { var buf [4508]byte; use(buf[:]); return Stackguard() }
-func stack4512() (uintptr, uintptr) { var buf [4512]byte; use(buf[:]); return Stackguard() }
-func stack4516() (uintptr, uintptr) { var buf [4516]byte; use(buf[:]); return Stackguard() }
-func stack4520() (uintptr, uintptr) { var buf [4520]byte; use(buf[:]); return Stackguard() }
-func stack4524() (uintptr, uintptr) { var buf [4524]byte; use(buf[:]); return Stackguard() }
-func stack4528() (uintptr, uintptr) { var buf [4528]byte; use(buf[:]); return Stackguard() }
-func stack4532() (uintptr, uintptr) { var buf [4532]byte; use(buf[:]); return Stackguard() }
-func stack4536() (uintptr, uintptr) { var buf [4536]byte; use(buf[:]); return Stackguard() }
-func stack4540() (uintptr, uintptr) { var buf [4540]byte; use(buf[:]); return Stackguard() }
-func stack4544() (uintptr, uintptr) { var buf [4544]byte; use(buf[:]); return Stackguard() }
-func stack4548() (uintptr, uintptr) { var buf [4548]byte; use(buf[:]); return Stackguard() }
-func stack4552() (uintptr, uintptr) { var buf [4552]byte; use(buf[:]); return Stackguard() }
-func stack4556() (uintptr, uintptr) { var buf [4556]byte; use(buf[:]); return Stackguard() }
-func stack4560() (uintptr, uintptr) { var buf [4560]byte; use(buf[:]); return Stackguard() }
-func stack4564() (uintptr, uintptr) { var buf [4564]byte; use(buf[:]); return Stackguard() }
-func stack4568() (uintptr, uintptr) { var buf [4568]byte; use(buf[:]); return Stackguard() }
-func stack4572() (uintptr, uintptr) { var buf [4572]byte; use(buf[:]); return Stackguard() }
-func stack4576() (uintptr, uintptr) { var buf [4576]byte; use(buf[:]); return Stackguard() }
-func stack4580() (uintptr, uintptr) { var buf [4580]byte; use(buf[:]); return Stackguard() }
-func stack4584() (uintptr, uintptr) { var buf [4584]byte; use(buf[:]); return Stackguard() }
-func stack4588() (uintptr, uintptr) { var buf [4588]byte; use(buf[:]); return Stackguard() }
-func stack4592() (uintptr, uintptr) { var buf [4592]byte; use(buf[:]); return Stackguard() }
-func stack4596() (uintptr, uintptr) { var buf [4596]byte; use(buf[:]); return Stackguard() }
-func stack4600() (uintptr, uintptr) { var buf [4600]byte; use(buf[:]); return Stackguard() }
-func stack4604() (uintptr, uintptr) { var buf [4604]byte; use(buf[:]); return Stackguard() }
-func stack4608() (uintptr, uintptr) { var buf [4608]byte; use(buf[:]); return Stackguard() }
-func stack4612() (uintptr, uintptr) { var buf [4612]byte; use(buf[:]); return Stackguard() }
-func stack4616() (uintptr, uintptr) { var buf [4616]byte; use(buf[:]); return Stackguard() }
-func stack4620() (uintptr, uintptr) { var buf [4620]byte; use(buf[:]); return Stackguard() }
-func stack4624() (uintptr, uintptr) { var buf [4624]byte; use(buf[:]); return Stackguard() }
-func stack4628() (uintptr, uintptr) { var buf [4628]byte; use(buf[:]); return Stackguard() }
-func stack4632() (uintptr, uintptr) { var buf [4632]byte; use(buf[:]); return Stackguard() }
-func stack4636() (uintptr, uintptr) { var buf [4636]byte; use(buf[:]); return Stackguard() }
-func stack4640() (uintptr, uintptr) { var buf [4640]byte; use(buf[:]); return Stackguard() }
-func stack4644() (uintptr, uintptr) { var buf [4644]byte; use(buf[:]); return Stackguard() }
-func stack4648() (uintptr, uintptr) { var buf [4648]byte; use(buf[:]); return Stackguard() }
-func stack4652() (uintptr, uintptr) { var buf [4652]byte; use(buf[:]); return Stackguard() }
-func stack4656() (uintptr, uintptr) { var buf [4656]byte; use(buf[:]); return Stackguard() }
-func stack4660() (uintptr, uintptr) { var buf [4660]byte; use(buf[:]); return Stackguard() }
-func stack4664() (uintptr, uintptr) { var buf [4664]byte; use(buf[:]); return Stackguard() }
-func stack4668() (uintptr, uintptr) { var buf [4668]byte; use(buf[:]); return Stackguard() }
-func stack4672() (uintptr, uintptr) { var buf [4672]byte; use(buf[:]); return Stackguard() }
-func stack4676() (uintptr, uintptr) { var buf [4676]byte; use(buf[:]); return Stackguard() }
-func stack4680() (uintptr, uintptr) { var buf [4680]byte; use(buf[:]); return Stackguard() }
-func stack4684() (uintptr, uintptr) { var buf [4684]byte; use(buf[:]); return Stackguard() }
-func stack4688() (uintptr, uintptr) { var buf [4688]byte; use(buf[:]); return Stackguard() }
-func stack4692() (uintptr, uintptr) { var buf [4692]byte; use(buf[:]); return Stackguard() }
-func stack4696() (uintptr, uintptr) { var buf [4696]byte; use(buf[:]); return Stackguard() }
-func stack4700() (uintptr, uintptr) { var buf [4700]byte; use(buf[:]); return Stackguard() }
-func stack4704() (uintptr, uintptr) { var buf [4704]byte; use(buf[:]); return Stackguard() }
-func stack4708() (uintptr, uintptr) { var buf [4708]byte; use(buf[:]); return Stackguard() }
-func stack4712() (uintptr, uintptr) { var buf [4712]byte; use(buf[:]); return Stackguard() }
-func stack4716() (uintptr, uintptr) { var buf [4716]byte; use(buf[:]); return Stackguard() }
-func stack4720() (uintptr, uintptr) { var buf [4720]byte; use(buf[:]); return Stackguard() }
-func stack4724() (uintptr, uintptr) { var buf [4724]byte; use(buf[:]); return Stackguard() }
-func stack4728() (uintptr, uintptr) { var buf [4728]byte; use(buf[:]); return Stackguard() }
-func stack4732() (uintptr, uintptr) { var buf [4732]byte; use(buf[:]); return Stackguard() }
-func stack4736() (uintptr, uintptr) { var buf [4736]byte; use(buf[:]); return Stackguard() }
-func stack4740() (uintptr, uintptr) { var buf [4740]byte; use(buf[:]); return Stackguard() }
-func stack4744() (uintptr, uintptr) { var buf [4744]byte; use(buf[:]); return Stackguard() }
-func stack4748() (uintptr, uintptr) { var buf [4748]byte; use(buf[:]); return Stackguard() }
-func stack4752() (uintptr, uintptr) { var buf [4752]byte; use(buf[:]); return Stackguard() }
-func stack4756() (uintptr, uintptr) { var buf [4756]byte; use(buf[:]); return Stackguard() }
-func stack4760() (uintptr, uintptr) { var buf [4760]byte; use(buf[:]); return Stackguard() }
-func stack4764() (uintptr, uintptr) { var buf [4764]byte; use(buf[:]); return Stackguard() }
-func stack4768() (uintptr, uintptr) { var buf [4768]byte; use(buf[:]); return Stackguard() }
-func stack4772() (uintptr, uintptr) { var buf [4772]byte; use(buf[:]); return Stackguard() }
-func stack4776() (uintptr, uintptr) { var buf [4776]byte; use(buf[:]); return Stackguard() }
-func stack4780() (uintptr, uintptr) { var buf [4780]byte; use(buf[:]); return Stackguard() }
-func stack4784() (uintptr, uintptr) { var buf [4784]byte; use(buf[:]); return Stackguard() }
-func stack4788() (uintptr, uintptr) { var buf [4788]byte; use(buf[:]); return Stackguard() }
-func stack4792() (uintptr, uintptr) { var buf [4792]byte; use(buf[:]); return Stackguard() }
-func stack4796() (uintptr, uintptr) { var buf [4796]byte; use(buf[:]); return Stackguard() }
-func stack4800() (uintptr, uintptr) { var buf [4800]byte; use(buf[:]); return Stackguard() }
-func stack4804() (uintptr, uintptr) { var buf [4804]byte; use(buf[:]); return Stackguard() }
-func stack4808() (uintptr, uintptr) { var buf [4808]byte; use(buf[:]); return Stackguard() }
-func stack4812() (uintptr, uintptr) { var buf [4812]byte; use(buf[:]); return Stackguard() }
-func stack4816() (uintptr, uintptr) { var buf [4816]byte; use(buf[:]); return Stackguard() }
-func stack4820() (uintptr, uintptr) { var buf [4820]byte; use(buf[:]); return Stackguard() }
-func stack4824() (uintptr, uintptr) { var buf [4824]byte; use(buf[:]); return Stackguard() }
-func stack4828() (uintptr, uintptr) { var buf [4828]byte; use(buf[:]); return Stackguard() }
-func stack4832() (uintptr, uintptr) { var buf [4832]byte; use(buf[:]); return Stackguard() }
-func stack4836() (uintptr, uintptr) { var buf [4836]byte; use(buf[:]); return Stackguard() }
-func stack4840() (uintptr, uintptr) { var buf [4840]byte; use(buf[:]); return Stackguard() }
-func stack4844() (uintptr, uintptr) { var buf [4844]byte; use(buf[:]); return Stackguard() }
-func stack4848() (uintptr, uintptr) { var buf [4848]byte; use(buf[:]); return Stackguard() }
-func stack4852() (uintptr, uintptr) { var buf [4852]byte; use(buf[:]); return Stackguard() }
-func stack4856() (uintptr, uintptr) { var buf [4856]byte; use(buf[:]); return Stackguard() }
-func stack4860() (uintptr, uintptr) { var buf [4860]byte; use(buf[:]); return Stackguard() }
-func stack4864() (uintptr, uintptr) { var buf [4864]byte; use(buf[:]); return Stackguard() }
-func stack4868() (uintptr, uintptr) { var buf [4868]byte; use(buf[:]); return Stackguard() }
-func stack4872() (uintptr, uintptr) { var buf [4872]byte; use(buf[:]); return Stackguard() }
-func stack4876() (uintptr, uintptr) { var buf [4876]byte; use(buf[:]); return Stackguard() }
-func stack4880() (uintptr, uintptr) { var buf [4880]byte; use(buf[:]); return Stackguard() }
-func stack4884() (uintptr, uintptr) { var buf [4884]byte; use(buf[:]); return Stackguard() }
-func stack4888() (uintptr, uintptr) { var buf [4888]byte; use(buf[:]); return Stackguard() }
-func stack4892() (uintptr, uintptr) { var buf [4892]byte; use(buf[:]); return Stackguard() }
-func stack4896() (uintptr, uintptr) { var buf [4896]byte; use(buf[:]); return Stackguard() }
-func stack4900() (uintptr, uintptr) { var buf [4900]byte; use(buf[:]); return Stackguard() }
-func stack4904() (uintptr, uintptr) { var buf [4904]byte; use(buf[:]); return Stackguard() }
-func stack4908() (uintptr, uintptr) { var buf [4908]byte; use(buf[:]); return Stackguard() }
-func stack4912() (uintptr, uintptr) { var buf [4912]byte; use(buf[:]); return Stackguard() }
-func stack4916() (uintptr, uintptr) { var buf [4916]byte; use(buf[:]); return Stackguard() }
-func stack4920() (uintptr, uintptr) { var buf [4920]byte; use(buf[:]); return Stackguard() }
-func stack4924() (uintptr, uintptr) { var buf [4924]byte; use(buf[:]); return Stackguard() }
-func stack4928() (uintptr, uintptr) { var buf [4928]byte; use(buf[:]); return Stackguard() }
-func stack4932() (uintptr, uintptr) { var buf [4932]byte; use(buf[:]); return Stackguard() }
-func stack4936() (uintptr, uintptr) { var buf [4936]byte; use(buf[:]); return Stackguard() }
-func stack4940() (uintptr, uintptr) { var buf [4940]byte; use(buf[:]); return Stackguard() }
-func stack4944() (uintptr, uintptr) { var buf [4944]byte; use(buf[:]); return Stackguard() }
-func stack4948() (uintptr, uintptr) { var buf [4948]byte; use(buf[:]); return Stackguard() }
-func stack4952() (uintptr, uintptr) { var buf [4952]byte; use(buf[:]); return Stackguard() }
-func stack4956() (uintptr, uintptr) { var buf [4956]byte; use(buf[:]); return Stackguard() }
-func stack4960() (uintptr, uintptr) { var buf [4960]byte; use(buf[:]); return Stackguard() }
-func stack4964() (uintptr, uintptr) { var buf [4964]byte; use(buf[:]); return Stackguard() }
-func stack4968() (uintptr, uintptr) { var buf [4968]byte; use(buf[:]); return Stackguard() }
-func stack4972() (uintptr, uintptr) { var buf [4972]byte; use(buf[:]); return Stackguard() }
-func stack4976() (uintptr, uintptr) { var buf [4976]byte; use(buf[:]); return Stackguard() }
-func stack4980() (uintptr, uintptr) { var buf [4980]byte; use(buf[:]); return Stackguard() }
-func stack4984() (uintptr, uintptr) { var buf [4984]byte; use(buf[:]); return Stackguard() }
-func stack4988() (uintptr, uintptr) { var buf [4988]byte; use(buf[:]); return Stackguard() }
-func stack4992() (uintptr, uintptr) { var buf [4992]byte; use(buf[:]); return Stackguard() }
-func stack4996() (uintptr, uintptr) { var buf [4996]byte; use(buf[:]); return Stackguard() }
-func stack5000() (uintptr, uintptr) { var buf [5000]byte; use(buf[:]); return Stackguard() }
-
// TestStackMem measures per-thread stack segment cache behavior.
// The test consumed up to 500MB in the past.
func TestStackMem(t *testing.T) {
@@ -1576,9 +112,172 @@ func TestStackMem(t *testing.T) {
if consumed > estimate {
t.Fatalf("Stack mem: want %v, got %v", estimate, consumed)
}
- inuse := s1.StackInuse - s0.StackInuse
+ // Due to broken stack memory accounting (http://golang.org/issue/7468),
+ // StackInuse can decrease during function execution, so we cast the values to int64.
+ inuse := int64(s1.StackInuse) - int64(s0.StackInuse)
t.Logf("Inuse %vMB for stack mem", inuse>>20)
if inuse > 4<<20 {
t.Fatalf("Stack inuse: want %v, got %v", 4<<20, inuse)
}
}
+
+// Test stack growing in different contexts.
+func TestStackGrowth(t *testing.T) {
+ switch GOARCH {
+ case "386", "arm":
+ t.Skipf("skipping test on %q; see issue 8083", GOARCH)
+ }
+ t.Parallel()
+ var wg sync.WaitGroup
+
+ // in a normal goroutine
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ growStack()
+ }()
+ wg.Wait()
+
+ // in locked goroutine
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ LockOSThread()
+ growStack()
+ UnlockOSThread()
+ }()
+ wg.Wait()
+
+ // in finalizer
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ done := make(chan bool)
+ go func() {
+ s := new(string)
+ SetFinalizer(s, func(ss *string) {
+ growStack()
+ done <- true
+ })
+ s = nil
+ done <- true
+ }()
+ <-done
+ GC()
+ select {
+ case <-done:
+ case <-time.After(20 * time.Second):
+ t.Fatal("finalizer did not run")
+ }
+ }()
+ wg.Wait()
+}
+
+// ... and in init
+//func init() {
+// growStack()
+//}
+
+func growStack() {
+ n := 1 << 10
+ if testing.Short() {
+ n = 1 << 8
+ }
+ for i := 0; i < n; i++ {
+ x := 0
+ growStackIter(&x, i)
+ if x != i+1 {
+ panic("stack is corrupted")
+ }
+ }
+ GC()
+}
+
+// This function is not an anonimous func, so that the compiler can do escape
+// analysis and place x on stack (and subsequently stack growth update the pointer).
+func growStackIter(p *int, n int) {
+ if n == 0 {
+ *p = n + 1
+ GC()
+ return
+ }
+ *p = n + 1
+ x := 0
+ growStackIter(&x, n-1)
+ if x != n {
+ panic("stack is corrupted")
+ }
+}
+
+func TestStackGrowthCallback(t *testing.T) {
+ t.Parallel()
+ var wg sync.WaitGroup
+
+ // test stack growth at chan op
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ c := make(chan int, 1)
+ growStackWithCallback(func() {
+ c <- 1
+ <-c
+ })
+ }()
+
+ // test stack growth at map op
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ m := make(map[int]int)
+ growStackWithCallback(func() {
+ _, _ = m[1]
+ m[1] = 1
+ })
+ }()
+
+ // test stack growth at goroutine creation
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ growStackWithCallback(func() {
+ done := make(chan bool)
+ go func() {
+ done <- true
+ }()
+ <-done
+ })
+ }()
+
+ wg.Wait()
+}
+
+func growStackWithCallback(cb func()) {
+ var f func(n int)
+ f = func(n int) {
+ if n == 0 {
+ cb()
+ return
+ }
+ f(n - 1)
+ }
+ for i := 0; i < 1<<10; i++ {
+ f(i)
+ }
+}
+
+// TestDeferPtrs tests the adjustment of Defer's argument pointers (p aka &y)
+// during a stack copy.
+func set(p *int, x int) {
+ *p = x
+}
+func TestDeferPtrs(t *testing.T) {
+ var y int
+
+ defer func() {
+ if y != 42 {
+ t.Errorf("defer's stack references were not adjusted appropriately")
+ }
+ }()
+ defer set(&y, 42)
+ growStack()
+}
diff --git a/src/pkg/runtime/string.goc b/src/pkg/runtime/string.goc
index b79acbe1c..97a69d07b 100644
--- a/src/pkg/runtime/string.goc
+++ b/src/pkg/runtime/string.goc
@@ -46,10 +46,8 @@ gostringsize(intgo l)
if(l == 0)
return runtime·emptystring;
- // leave room for NUL for C runtime (e.g., callers of getenv)
- s.str = runtime·mallocgc(l+1, 0, FlagNoScan|FlagNoZero);
+ s.str = runtime·mallocgc(l, 0, FlagNoScan|FlagNoZero);
s.len = l;
- s.str[l] = 0;
for(;;) {
ms = runtime·maxstring;
if((uintptr)l <= ms || runtime·casp((void**)&runtime·maxstring, (void*)ms, (void*)l))
@@ -80,6 +78,7 @@ runtime·gostringn(byte *str, intgo l)
return s;
}
+// used by cmd/cgo
Slice
runtime·gobytes(byte *p, intgo n)
{
@@ -102,11 +101,8 @@ runtime·gostringnocopy(byte *str)
return s;
}
-void
-runtime·cstringToGo(byte *str, String s)
-{
+func cstringToGo(str *byte) (s String) {
s = runtime·gostringnocopy(str);
- FLUSH(&s);
}
String
@@ -179,14 +175,35 @@ concatstring(intgo n, String *s)
return out;
}
-// NOTE: Cannot use func syntax, because we need the ...,
-// to signal to the garbage collector that this function does
-// not have a fixed size argument count.
#pragma textflag NOSPLIT
-void
-runtime·concatstring(intgo n, String s1, ...)
-{
- (&s1)[n] = concatstring(n, &s1);
+func concatstring2(s1 String, s2 String) (res String) {
+ USED(&s2);
+ res = concatstring(2, &s1);
+}
+#pragma textflag NOSPLIT
+func concatstring3(s1 String, s2 String, s3 String) (res String) {
+ USED(&s2);
+ USED(&s3);
+ res = concatstring(3, &s1);
+}
+#pragma textflag NOSPLIT
+func concatstring4(s1 String, s2 String, s3 String, s4 String) (res String) {
+ USED(&s2);
+ USED(&s3);
+ USED(&s4);
+ res = concatstring(4, &s1);
+}
+#pragma textflag NOSPLIT
+func concatstring5(s1 String, s2 String, s3 String, s4 String, s5 String) (res String) {
+ USED(&s2);
+ USED(&s3);
+ USED(&s4);
+ USED(&s5);
+ res = concatstring(5, &s1);
+}
+#pragma textflag NOSPLIT
+func concatstrings(s Slice) (res String) {
+ res = concatstring(s.len, (String*)s.array);
}
func eqstring(s1 String, s2 String) (v bool) {
@@ -219,6 +236,25 @@ runtime·strcmp(byte *s1, byte *s2)
}
}
+int32
+runtime·strncmp(byte *s1, byte *s2, uintptr n)
+{
+ uintptr i;
+ byte c1, c2;
+
+ for(i=0; i<n; i++) {
+ c1 = s1[i];
+ c2 = s2[i];
+ if(c1 < c2)
+ return -1;
+ if(c1 > c2)
+ return +1;
+ if(c1 == 0)
+ break;
+ }
+ return 0;
+}
+
byte*
runtime·strstr(byte *s1, byte *s2)
{
@@ -258,11 +294,35 @@ func slicebytetostring(b Slice) (s String) {
runtime·memmove(s.str, b.array, s.len);
}
+func slicebytetostringtmp(b Slice) (s String) {
+ void *pc;
+
+ if(raceenabled) {
+ pc = runtime·getcallerpc(&b);
+ runtime·racereadrangepc(b.array, b.len, pc, runtime·slicebytetostringtmp);
+ }
+
+ // 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.
+ s.str = b.array;
+ s.len = b.len;
+}
+
func stringtoslicebyte(s String) (b Slice) {
- b.array = runtime·mallocgc(s.len, 0, FlagNoScan|FlagNoZero);
+ uintptr cap;
+
+ cap = runtime·roundupsize(s.len);
+ b.array = runtime·mallocgc(cap, 0, FlagNoScan|FlagNoZero);
b.len = s.len;
- b.cap = s.len;
+ b.cap = cap;
runtime·memmove(b.array, s.str, s.len);
+ if(cap != b.len)
+ runtime·memclr(b.array+b.len, cap-b.len);
}
func slicerunetostring(b Slice) (s String) {
@@ -297,6 +357,7 @@ func stringtoslicerune(s String) (b Slice) {
intgo n;
int32 dum, *r;
uint8 *p, *ep;
+ uintptr mem;
// two passes.
// unlike slicerunetostring, no race because strings are immutable.
@@ -308,13 +369,18 @@ func stringtoslicerune(s String) (b Slice) {
n++;
}
- b.array = runtime·mallocgc(n*sizeof(r[0]), 0, FlagNoScan|FlagNoZero);
+ if(n > MaxMem/sizeof(r[0]))
+ runtime·throw("out of memory");
+ mem = runtime·roundupsize(n*sizeof(r[0]));
+ b.array = runtime·mallocgc(mem, 0, FlagNoScan|FlagNoZero);
b.len = n;
- b.cap = n;
+ b.cap = mem/sizeof(r[0]);
p = s.str;
r = (int32*)b.array;
while(p < ep)
p += runtime·charntorune(r++, p, ep-p);
+ if(b.cap > b.len)
+ runtime·memclr(b.array+b.len*sizeof(r[0]), (b.cap-b.len)*sizeof(r[0]));
}
enum
diff --git a/src/pkg/runtime/symtab.c b/src/pkg/runtime/symtab.goc
index dd0015aee..15e1d28fa 100644
--- a/src/pkg/runtime/symtab.c
+++ b/src/pkg/runtime/symtab.goc
@@ -5,6 +5,7 @@
// Runtime symbol table parsing.
// See http://golang.org/s/go12symtab for an overview.
+package runtime
#include "runtime.h"
#include "defs_GOOS_GOARCH.h"
#include "os_GOOS.h"
@@ -38,7 +39,7 @@ runtime·symtabinit(void)
// two zero bytes, a byte giving the PC quantum,
// and a byte giving the pointer width in bytes.
if(*(uint32*)pclntab != 0xfffffffb || pclntab[4] != 0 || pclntab[5] != 0 || pclntab[6] != PCQuantum || pclntab[7] != sizeof(void*)) {
- runtime·printf("runtime: function symbol table header: 0x%x 0x%x\n", *(uint32*)pclntab, *(uint32*)(pclntab+4));
+ runtime·printf("runtime: function symbol table header: %x %x\n", *(uint32*)pclntab, *(uint32*)(pclntab+4));
runtime·throw("invalid function symbol table\n");
}
@@ -86,8 +87,11 @@ runtime·funcdata(Func *f, int32 i)
if(i < 0 || i >= f->nfuncdata)
return nil;
p = (byte*)&f->nfuncdata + 4 + f->npcdata*4;
- if(sizeof(void*) == 8 && ((uintptr)p & 4))
+ if(sizeof(void*) == 8 && ((uintptr)p & 4)) {
+ if(((uintptr)f & 4))
+ runtime·printf("misaligned func %p\n", f);
p += 4;
+ }
return ((void**)p)[i];
}
@@ -224,27 +228,18 @@ runtime·funcarglen(Func *f, uintptr targetpc)
return runtime·pcdatavalue(f, PCDATA_ArgSize, targetpc-PCQuantum);
}
-void
-runtime·funcline_go(Func *f, uintptr targetpc, String retfile, intgo retline)
-{
+func funcline_go(f *Func, targetpc uintptr) (retfile String, retline int) {
// Pass strict=false here, because anyone can call this function,
// and they might just be wrong about targetpc belonging to f.
retline = funcline(f, targetpc, &retfile, false);
- FLUSH(&retline);
}
-void
-runtime·funcname_go(Func *f, String ret)
-{
+func funcname_go(f *Func) (ret String) {
ret = runtime·gostringnocopy((uint8*)runtime·funcname(f));
- FLUSH(&ret);
}
-void
-runtime·funcentry_go(Func *f, uintptr ret)
-{
+func funcentry_go(f *Func) (ret uintptr) {
ret = f->entry;
- FLUSH(&ret);
}
Func*
@@ -281,6 +276,10 @@ runtime·findfunc(uintptr addr)
return nil;
}
+func FuncForPC(pc uintptr) (ret *Func) {
+ ret = runtime·findfunc(pc);
+}
+
static bool
hasprefix(String s, int8 *p)
{
diff --git a/src/pkg/runtime/sys_darwin_386.s b/src/pkg/runtime/sys_darwin_386.s
index c2a259e5b..bfaaa00a7 100644
--- a/src/pkg/runtime/sys_darwin_386.s
+++ b/src/pkg/runtime/sys_darwin_386.s
@@ -457,8 +457,7 @@ TEXT runtime·setldt(SB),NOSPLIT,$32
* we use its pthread_create and let it set up %gs
* for us. When we do that, the private storage
* we get is not at 0(GS) but at 0x468(GS).
- * To insulate the rest of the tool chain from this ugliness,
- * 8l rewrites 0(GS) into 0x468(GS) for us.
+ * 8l rewrites 0(TLS) into 0x468(GS) for us.
* To accommodate that rewrite, we translate the
* address and limit here so that 0x468(GS) maps to 0(address).
*
diff --git a/src/pkg/runtime/sys_dragonfly_386.s b/src/pkg/runtime/sys_dragonfly_386.s
index 9085ded6f..20e699966 100644
--- a/src/pkg/runtime/sys_dragonfly_386.s
+++ b/src/pkg/runtime/sys_dragonfly_386.s
@@ -155,7 +155,7 @@ TEXT runtime·setitimer(SB), NOSPLIT, $-4
TEXT time·now(SB), NOSPLIT, $32
MOVL $232, AX
LEAL 12(SP), BX
- MOVL $0, 4(SP)
+ MOVL $0, 4(SP) // CLOCK_REALTIME
MOVL BX, 8(SP)
INT $0x80
MOVL 12(SP), AX // sec
@@ -172,7 +172,7 @@ TEXT time·now(SB), NOSPLIT, $32
TEXT runtime·nanotime(SB), NOSPLIT, $32
MOVL $232, AX
LEAL 12(SP), BX
- MOVL $0, 4(SP)
+ MOVL $4, 4(SP) // CLOCK_MONOTONIC
MOVL BX, 8(SP)
INT $0x80
MOVL 12(SP), AX // sec
diff --git a/src/pkg/runtime/sys_dragonfly_amd64.s b/src/pkg/runtime/sys_dragonfly_amd64.s
index 2fa97f207..d70d2e80c 100644
--- a/src/pkg/runtime/sys_dragonfly_amd64.s
+++ b/src/pkg/runtime/sys_dragonfly_amd64.s
@@ -125,7 +125,7 @@ TEXT runtime·setitimer(SB), NOSPLIT, $-8
// func now() (sec int64, nsec int32)
TEXT time·now(SB), NOSPLIT, $32
MOVL $232, AX
- MOVQ $0, DI
+ MOVQ $0, DI // CLOCK_REALTIME
LEAQ 8(SP), SI
SYSCALL
MOVQ 8(SP), AX // sec
@@ -138,7 +138,7 @@ TEXT time·now(SB), NOSPLIT, $32
TEXT runtime·nanotime(SB), NOSPLIT, $32
MOVL $232, AX
- MOVQ $0, DI
+ MOVQ $4, DI // CLOCK_MONOTONIC
LEAQ 8(SP), SI
SYSCALL
MOVQ 8(SP), AX // sec
diff --git a/src/pkg/runtime/sys_freebsd_386.s b/src/pkg/runtime/sys_freebsd_386.s
index 8b4d2317d..4c97eec7b 100644
--- a/src/pkg/runtime/sys_freebsd_386.s
+++ b/src/pkg/runtime/sys_freebsd_386.s
@@ -135,7 +135,7 @@ TEXT runtime·setitimer(SB), NOSPLIT, $-4
TEXT time·now(SB), NOSPLIT, $32
MOVL $232, AX
LEAL 12(SP), BX
- MOVL $0, 4(SP)
+ MOVL $0, 4(SP) // CLOCK_REALTIME
MOVL BX, 8(SP)
INT $0x80
MOVL 12(SP), AX // sec
@@ -152,7 +152,9 @@ TEXT time·now(SB), NOSPLIT, $32
TEXT runtime·nanotime(SB), NOSPLIT, $32
MOVL $232, AX
LEAL 12(SP), BX
- MOVL $0, 4(SP)
+ // We can use CLOCK_MONOTONIC_FAST here when we drop
+ // support for FreeBSD 8-STABLE.
+ MOVL $4, 4(SP) // CLOCK_MONOTONIC
MOVL BX, 8(SP)
INT $0x80
MOVL 12(SP), AX // sec
@@ -307,8 +309,7 @@ TEXT runtime·i386_set_ldt(SB),NOSPLIT,$16
MOVL AX, 8(SP)
MOVL $165, AX
INT $0x80
- CMPL AX, $0xfffff001
- JLS 2(PC)
+ JAE 2(PC)
INT $3
RET
@@ -324,7 +325,7 @@ TEXT runtime·sysctl(SB),NOSPLIT,$28
MOVSL // arg 6 - newlen
MOVL $202, AX // sys___sysctl
INT $0x80
- JCC 3(PC)
+ JAE 3(PC)
NEGL AX
RET
MOVL $0, AX
diff --git a/src/pkg/runtime/sys_freebsd_amd64.s b/src/pkg/runtime/sys_freebsd_amd64.s
index 63cd3ac07..4c5b32504 100644
--- a/src/pkg/runtime/sys_freebsd_amd64.s
+++ b/src/pkg/runtime/sys_freebsd_amd64.s
@@ -144,7 +144,7 @@ TEXT runtime·setitimer(SB), NOSPLIT, $-8
// func now() (sec int64, nsec int32)
TEXT time·now(SB), NOSPLIT, $32
MOVL $232, AX
- MOVQ $0, DI
+ MOVQ $0, DI // CLOCK_REALTIME
LEAQ 8(SP), SI
SYSCALL
MOVQ 8(SP), AX // sec
@@ -157,7 +157,9 @@ TEXT time·now(SB), NOSPLIT, $32
TEXT runtime·nanotime(SB), NOSPLIT, $32
MOVL $232, AX
- MOVQ $0, DI
+ // We can use CLOCK_MONOTONIC_FAST here when we drop
+ // support for FreeBSD 8-STABLE.
+ MOVQ $4, DI // CLOCK_MONOTONIC
LEAQ 8(SP), SI
SYSCALL
MOVQ 8(SP), AX // sec
diff --git a/src/pkg/runtime/sys_freebsd_arm.s b/src/pkg/runtime/sys_freebsd_arm.s
index 106d72799..3ec95a651 100644
--- a/src/pkg/runtime/sys_freebsd_arm.s
+++ b/src/pkg/runtime/sys_freebsd_arm.s
@@ -162,7 +162,9 @@ TEXT time·now(SB), NOSPLIT, $32
// int64 nanotime(void) so really
// void nanotime(int64 *nsec)
TEXT runtime·nanotime(SB), NOSPLIT, $32
- MOVW $0, R0 // CLOCK_REALTIME
+ // We can use CLOCK_MONOTONIC_FAST here when we drop
+ // support for FreeBSD 8-STABLE.
+ MOVW $4, R0 // CLOCK_MONOTONIC
MOVW $8(R13), R1
MOVW $SYS_clock_gettime, R7
SWI $0
@@ -365,6 +367,7 @@ TEXT runtime·casp(SB),NOSPLIT,$0
TEXT runtime·cas(SB),NOSPLIT,$0
B runtime·armcas(SB)
+// TODO(minux): this only supports ARMv6K+.
TEXT runtime·read_tls_fallback(SB),NOSPLIT,$-4
- MOVW $0xffff1000, R0
- MOVW (R0), R0
+ WORD $0xee1d0f70 // mrc p15, 0, r0, c13, c0, 3
+ RET
diff --git a/src/pkg/runtime/sys_linux_386.s b/src/pkg/runtime/sys_linux_386.s
index fcda739db..b7896f178 100644
--- a/src/pkg/runtime/sys_linux_386.s
+++ b/src/pkg/runtime/sys_linux_386.s
@@ -106,7 +106,7 @@ TEXT runtime·mincore(SB),NOSPLIT,$0-24
// func now() (sec int64, nsec int32)
TEXT time·now(SB), NOSPLIT, $32
MOVL $265, AX // syscall - clock_gettime
- MOVL $0, BX
+ MOVL $0, BX // CLOCK_REALTIME
LEAL 8(SP), CX
MOVL $0, DX
CALL *runtime·_vdso(SB)
@@ -123,7 +123,7 @@ TEXT time·now(SB), NOSPLIT, $32
// void nanotime(int64 *nsec)
TEXT runtime·nanotime(SB), NOSPLIT, $32
MOVL $265, AX // syscall - clock_gettime
- MOVL $0, BX
+ MOVL $1, BX // CLOCK_MONOTONIC
LEAL 8(SP), CX
MOVL $0, DX
CALL *runtime·_vdso(SB)
@@ -383,7 +383,7 @@ TEXT runtime·setldt(SB),NOSPLIT,$32
* for us. When we do that, the private storage
* we get is not at 0(GS), 4(GS), but -8(GS), -4(GS).
* To insulate the rest of the tool chain from this
- * ugliness, 8l rewrites 0(GS) into -8(GS) for us.
+ * ugliness, 8l rewrites 0(TLS) into -8(GS) for us.
* To accommodate that rewrite, we translate
* the address here and bump the limit to 0xffffffff (no limit)
* so that -8(GS) maps to 0(address).
diff --git a/src/pkg/runtime/sys_linux_amd64.s b/src/pkg/runtime/sys_linux_amd64.s
index 481841a67..b340c4f2c 100644
--- a/src/pkg/runtime/sys_linux_amd64.s
+++ b/src/pkg/runtime/sys_linux_amd64.s
@@ -76,7 +76,7 @@ TEXT runtime·usleep(SB),NOSPLIT,$16
SYSCALL
RET
-TEXT runtime·raise(SB),NOSPLIT,$12
+TEXT runtime·raise(SB),NOSPLIT,$0
MOVL $186, AX // syscall - gettid
SYSCALL
MOVL AX, DI // arg 1 tid
@@ -136,7 +136,7 @@ TEXT runtime·nanotime(SB),NOSPLIT,$16
MOVQ runtime·__vdso_clock_gettime_sym(SB), AX
CMPQ AX, $0
JEQ fallback_gtod_nt
- MOVL $0, DI // CLOCK_REALTIME
+ MOVL $1, DI // CLOCK_MONOTONIC
LEAQ 0(SP), SI
CALL AX
MOVQ 0(SP), AX // sec
diff --git a/src/pkg/runtime/sys_linux_arm.s b/src/pkg/runtime/sys_linux_arm.s
index 42aef56a7..c537a8722 100644
--- a/src/pkg/runtime/sys_linux_arm.s
+++ b/src/pkg/runtime/sys_linux_arm.s
@@ -175,7 +175,7 @@ TEXT time·now(SB), NOSPLIT, $32
// int64 nanotime(void) so really
// void nanotime(int64 *nsec)
TEXT runtime·nanotime(SB),NOSPLIT,$32
- MOVW $0, R0 // CLOCK_REALTIME
+ MOVW $1, R0 // CLOCK_MONOTONIC
MOVW $8(R13), R1 // timespec
MOVW $SYS_clock_gettime, R7
SWI $0
diff --git a/src/pkg/runtime/sys_nacl_386.s b/src/pkg/runtime/sys_nacl_386.s
new file mode 100644
index 000000000..42ba0e0ed
--- /dev/null
+++ b/src/pkg/runtime/sys_nacl_386.s
@@ -0,0 +1,243 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "zasm_GOOS_GOARCH.h"
+#include "../../cmd/ld/textflag.h"
+#include "syscall_nacl.h"
+
+#define NACL_SYSCALL(code) \
+ MOVL $(0x10000 + ((code)<<5)), AX; CALL AX
+
+#define NACL_SYSJMP(code) \
+ MOVL $(0x10000 + ((code)<<5)), AX; JMP AX
+
+TEXT runtime·exit(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_exit)
+
+TEXT runtime·exit1(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_thread_exit)
+
+TEXT runtime·open(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_open)
+
+TEXT runtime·close(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_close)
+
+TEXT runtime·read(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_read)
+
+TEXT syscall·naclWrite(SB), NOSPLIT, $12-16
+ MOVL arg1+0(FP), DI
+ MOVL arg2+4(FP), SI
+ MOVL arg3+8(FP), DX
+ MOVL DI, 0(SP)
+ MOVL SI, 4(SP)
+ MOVL DX, 8(SP)
+ CALL runtime·write(SB)
+ MOVL AX, ret+16(FP)
+ RET
+
+TEXT runtime·write(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_write)
+
+TEXT runtime·nacl_exception_stack(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_exception_stack)
+
+TEXT runtime·nacl_exception_handler(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_exception_handler)
+
+TEXT runtime·nacl_sem_create(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_sem_create)
+
+TEXT runtime·nacl_sem_wait(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_sem_wait)
+
+TEXT runtime·nacl_sem_post(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_sem_post)
+
+TEXT runtime·nacl_mutex_create(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_mutex_create)
+
+TEXT runtime·nacl_mutex_lock(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_mutex_lock)
+
+TEXT runtime·nacl_mutex_trylock(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_mutex_trylock)
+
+TEXT runtime·nacl_mutex_unlock(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_mutex_unlock)
+
+TEXT runtime·nacl_cond_create(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_cond_create)
+
+TEXT runtime·nacl_cond_wait(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_cond_wait)
+
+TEXT runtime·nacl_cond_signal(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_cond_signal)
+
+TEXT runtime·nacl_cond_broadcast(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_cond_broadcast)
+
+TEXT runtime·nacl_cond_timed_wait_abs(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_cond_timed_wait_abs)
+
+TEXT runtime·nacl_thread_create(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_thread_create)
+
+TEXT runtime·mstart_nacl(SB),NOSPLIT,$0
+ JMP runtime·mstart(SB)
+
+TEXT runtime·nacl_nanosleep(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_nanosleep)
+
+TEXT runtime·osyield(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_sched_yield)
+
+TEXT runtime·mmap(SB),NOSPLIT,$32
+ MOVL arg1+0(FP), AX
+ MOVL AX, 0(SP)
+ MOVL arg2+4(FP), AX
+ MOVL AX, 4(SP)
+ MOVL arg3+8(FP), AX
+ MOVL AX, 8(SP)
+ MOVL arg4+12(FP), AX
+ MOVL AX, 12(SP)
+ MOVL arg5+16(FP), AX
+ MOVL AX, 16(SP)
+ MOVL arg6+20(FP), AX
+ MOVL AX, 24(SP)
+ MOVL $0, 28(SP)
+ LEAL 24(SP), AX
+ MOVL AX, 20(SP)
+ NACL_SYSCALL(SYS_mmap)
+ RET
+
+TEXT time·now(SB),NOSPLIT,$20
+ MOVL $0, 0(SP) // real time clock
+ LEAL 8(SP), AX
+ MOVL AX, 4(SP) // timespec
+ NACL_SYSCALL(SYS_clock_gettime)
+ MOVL 8(SP), AX // low 32 sec
+ MOVL 12(SP), CX // high 32 sec
+ MOVL 16(SP), BX // nsec
+
+ // sec is in AX, nsec in BX
+ MOVL AX, sec+0(FP)
+ MOVL CX, sec+4(FP)
+ MOVL BX, nsec+8(FP)
+ RET
+
+TEXT syscall·now(SB),NOSPLIT,$0
+ JMP time·now(SB)
+
+TEXT runtime·nacl_clock_gettime(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_clock_gettime)
+
+TEXT runtime·nanotime(SB),NOSPLIT,$20
+ MOVL $0, 0(SP) // real time clock
+ LEAL 8(SP), AX
+ MOVL AX, 4(SP) // timespec
+ NACL_SYSCALL(SYS_clock_gettime)
+ MOVL 8(SP), AX // low 32 sec
+ MOVL 16(SP), BX // nsec
+
+ // sec is in AX, nsec in BX
+ // convert to DX:AX nsec
+ MOVL $1000000000, CX
+ MULL CX
+ ADDL BX, AX
+ ADCL $0, DX
+
+ MOVL ret+0(FP), DI
+ MOVL AX, 0(DI)
+ MOVL DX, 4(DI)
+ RET
+
+TEXT runtime·setldt(SB),NOSPLIT,$8
+ MOVL addr+4(FP), BX // aka base
+ ADDL $0x8, BX
+ MOVL BX, 0(SP)
+ NACL_SYSCALL(SYS_tls_init)
+ RET
+
+TEXT runtime·sigtramp(SB),NOSPLIT,$0
+ get_tls(CX)
+
+ // check that m exists
+ MOVL m(CX), BX
+ CMPL BX, $0
+ JNE 6(PC)
+ MOVL $11, BX
+ MOVL BX, 0(SP)
+ MOVL $runtime·badsignal(SB), AX
+ CALL AX
+ JMP sigtramp_ret
+
+ // save g
+ MOVL g(CX), DI
+ MOVL DI, 20(SP)
+
+ // g = m->gsignal
+ MOVL m_gsignal(BX), BX
+ MOVL BX, g(CX)
+
+ // copy arguments for sighandler
+ MOVL $11, 0(SP) // signal
+ MOVL $0, 4(SP) // siginfo
+ LEAL ctxt+4(FP), AX
+ MOVL AX, 8(SP) // context
+ MOVL DI, 12(SP) // g
+
+ CALL runtime·sighandler(SB)
+
+ // restore g
+ get_tls(CX)
+ MOVL 20(SP), BX
+ MOVL BX, g(CX)
+
+sigtramp_ret:
+ // Enable exceptions again.
+ NACL_SYSCALL(SYS_exception_clear_flag)
+
+ // NaCl has abidcated its traditional operating system responsibility
+ // and declined to implement 'sigreturn'. Instead the only way to return
+ // to the execution of our program is to restore the registers ourselves.
+ // Unfortunately, that is impossible to do with strict fidelity, because
+ // there is no way to do the final update of PC that ends the sequence
+ // without either (1) jumping to a register, in which case the register ends
+ // holding the PC value instead of its intended value or (2) storing the PC
+ // on the stack and using RET, which imposes the requirement that SP is
+ // valid and that is okay to smash the word below it. The second would
+ // normally be the lesser of the two evils, except that on NaCl, the linker
+ // must rewrite RET into "POP reg; AND $~31, reg; JMP reg", so either way
+ // we are going to lose a register as a result of the incoming signal.
+ // Similarly, there is no way to restore EFLAGS; the usual way is to use
+ // POPFL, but NaCl rejects that instruction. We could inspect the bits and
+ // execute a sequence of instructions designed to recreate those flag
+ // settings, but that's a lot of work.
+ //
+ // Thankfully, Go's signal handlers never try to return directly to the
+ // executing code, so all the registers and EFLAGS are dead and can be
+ // smashed. The only registers that matter are the ones that are setting
+ // up for the simulated call that the signal handler has created.
+ // Today those registers are just PC and SP, but in case additional registers
+ // are relevant in the future (for example DX is the Go func context register)
+ // we restore as many registers as possible.
+ //
+ // We smash BP, because that's what the linker smashes during RET.
+ //
+ LEAL ctxt+4(FP), BP
+ ADDL $64, BP
+ MOVL 0(BP), AX
+ MOVL 4(BP), CX
+ MOVL 8(BP), DX
+ MOVL 12(BP), BX
+ MOVL 16(BP), SP
+ // 20(BP) is saved BP, never to be seen again
+ MOVL 24(BP), SI
+ MOVL 28(BP), DI
+ // 36(BP) is saved EFLAGS, never to be seen again
+ MOVL 32(BP), BP // saved PC
+ JMP BP
diff --git a/src/pkg/runtime/sys_nacl_amd64p32.s b/src/pkg/runtime/sys_nacl_amd64p32.s
new file mode 100644
index 000000000..43c172372
--- /dev/null
+++ b/src/pkg/runtime/sys_nacl_amd64p32.s
@@ -0,0 +1,413 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "zasm_GOOS_GOARCH.h"
+#include "../../cmd/ld/textflag.h"
+#include "syscall_nacl.h"
+
+#define NACL_SYSCALL(code) \
+ MOVL $(0x10000 + ((code)<<5)), AX; CALL AX
+
+#define NACL_SYSJMP(code) \
+ MOVL $(0x10000 + ((code)<<5)), AX; JMP AX
+
+TEXT runtime·settls(SB),NOSPLIT,$0
+ MOVL DI, TLS // really BP
+ RET
+
+TEXT runtime·exit(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ NACL_SYSJMP(SYS_exit)
+
+TEXT runtime·exit1(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ NACL_SYSJMP(SYS_thread_exit)
+
+TEXT runtime·open(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ MOVL arg2+4(FP), SI
+ MOVL arg3+8(FP), DX
+ NACL_SYSJMP(SYS_open)
+
+TEXT runtime·close(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ NACL_SYSJMP(SYS_close)
+
+TEXT runtime·read(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ MOVL arg2+4(FP), SI
+ MOVL arg3+8(FP), DX
+ NACL_SYSJMP(SYS_read)
+
+TEXT syscall·naclWrite(SB), NOSPLIT, $16-20
+ MOVL arg1+0(FP), DI
+ MOVL arg2+4(FP), SI
+ MOVL arg3+8(FP), DX
+ MOVL DI, 0(SP)
+ MOVL SI, 4(SP)
+ MOVL DX, 8(SP)
+ CALL runtime·write(SB)
+ MOVL AX, ret+16(FP)
+ RET
+
+TEXT runtime·write(SB),NOSPLIT,$16-12
+ // If using fake time and writing to stdout or stderr,
+ // emit playback header before actual data.
+ MOVQ runtime·timens(SB), AX
+ CMPQ AX, $0
+ JEQ write
+ MOVL arg1+0(FP), DI
+ CMPL DI, $1
+ JEQ playback
+ CMPL DI, $2
+ JEQ playback
+
+write:
+ // Ordinary write.
+ MOVL arg1+0(FP), DI
+ MOVL arg2+4(FP), SI
+ MOVL arg3+8(FP), DX
+ NACL_SYSCALL(SYS_write)
+ RET
+
+ // Write with playback header.
+ // First, lock to avoid interleaving writes.
+playback:
+ MOVL $1, BX
+ XCHGL runtime·writelock(SB), BX
+ CMPL BX, $0
+ JNE playback
+
+ // Playback header: 0 0 P B <8-byte time> <4-byte data length>
+ MOVL $(('B'<<24) | ('P'<<16)), 0(SP)
+ BSWAPQ AX
+ MOVQ AX, 4(SP)
+ MOVL arg3+8(FP), DX
+ BSWAPL DX
+ MOVL DX, 12(SP)
+ MOVL $1, DI // standard output
+ MOVL SP, SI
+ MOVL $16, DX
+ NACL_SYSCALL(SYS_write)
+
+ // Write actual data.
+ MOVL $1, DI // standard output
+ MOVL arg2+4(FP), SI
+ MOVL arg3+8(FP), DX
+ NACL_SYSCALL(SYS_write)
+
+ // Unlock.
+ MOVL $0, runtime·writelock(SB)
+
+ RET
+
+TEXT runtime·nacl_exception_stack(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ MOVL arg2+4(FP), SI
+ NACL_SYSJMP(SYS_exception_stack)
+
+TEXT runtime·nacl_exception_handler(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ MOVL arg2+4(FP), SI
+ NACL_SYSJMP(SYS_exception_handler)
+
+TEXT runtime·nacl_sem_create(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ NACL_SYSJMP(SYS_sem_create)
+
+TEXT runtime·nacl_sem_wait(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ NACL_SYSJMP(SYS_sem_wait)
+
+TEXT runtime·nacl_sem_post(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ NACL_SYSJMP(SYS_sem_post)
+
+TEXT runtime·nacl_mutex_create(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ NACL_SYSJMP(SYS_mutex_create)
+
+TEXT runtime·nacl_mutex_lock(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ NACL_SYSJMP(SYS_mutex_lock)
+
+TEXT runtime·nacl_mutex_trylock(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ NACL_SYSJMP(SYS_mutex_trylock)
+
+TEXT runtime·nacl_mutex_unlock(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ NACL_SYSJMP(SYS_mutex_unlock)
+
+TEXT runtime·nacl_cond_create(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ NACL_SYSJMP(SYS_cond_create)
+
+TEXT runtime·nacl_cond_wait(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ MOVL arg2+4(FP), SI
+ NACL_SYSJMP(SYS_cond_wait)
+
+TEXT runtime·nacl_cond_signal(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ NACL_SYSJMP(SYS_cond_signal)
+
+TEXT runtime·nacl_cond_broadcast(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ NACL_SYSJMP(SYS_cond_broadcast)
+
+TEXT runtime·nacl_cond_timed_wait_abs(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ MOVL arg2+4(FP), SI
+ MOVL arg3+8(FP), DX
+ NACL_SYSJMP(SYS_cond_timed_wait_abs)
+
+TEXT runtime·nacl_thread_create(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ MOVL arg2+4(FP), SI
+ MOVL arg3+8(FP), DX
+ MOVL arg4+12(FP), CX
+ NACL_SYSJMP(SYS_thread_create)
+
+TEXT runtime·mstart_nacl(SB),NOSPLIT,$0
+ NACL_SYSCALL(SYS_tls_get)
+ SUBL $8, AX
+ MOVL AX, TLS
+ JMP runtime·mstart(SB)
+
+TEXT runtime·nacl_nanosleep(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ MOVL arg2+4(FP), SI
+ NACL_SYSJMP(SYS_nanosleep)
+
+TEXT runtime·osyield(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_sched_yield)
+
+TEXT runtime·mmap(SB),NOSPLIT,$8
+ MOVL arg1+0(FP), DI
+ MOVL arg2+4(FP), SI
+ MOVL arg3+8(FP), DX
+ MOVL arg4+12(FP), CX
+ MOVL arg5+16(FP), R8
+ MOVL arg6+20(FP), AX
+ MOVQ AX, 0(SP)
+ MOVL SP, R9
+ NACL_SYSCALL(SYS_mmap)
+ CMPL AX, $-4095
+ JNA 2(PC)
+ NEGL AX
+ RET
+
+TEXT time·now(SB),NOSPLIT,$16
+ MOVQ runtime·timens(SB), AX
+ CMPQ AX, $0
+ JEQ realtime
+ MOVQ $0, DX
+ MOVQ $1000000000, CX
+ DIVQ CX
+ MOVQ AX, sec+0(FP)
+ MOVL DX, nsec+8(FP)
+ RET
+realtime:
+ MOVL $0, DI // real time clock
+ LEAL 0(SP), AX
+ MOVL AX, SI // timespec
+ NACL_SYSCALL(SYS_clock_gettime)
+ MOVL 0(SP), AX // low 32 sec
+ MOVL 4(SP), CX // high 32 sec
+ MOVL 8(SP), BX // nsec
+
+ // sec is in AX, nsec in BX
+ MOVL AX, sec+0(FP)
+ MOVL CX, sec+4(FP)
+ MOVL BX, nsec+8(FP)
+ RET
+
+TEXT syscall·now(SB),NOSPLIT,$0
+ JMP time·now(SB)
+
+TEXT runtime·nacl_clock_gettime(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ MOVL arg2+4(FP), SI
+ NACL_SYSJMP(SYS_clock_gettime)
+
+TEXT runtime·nanotime(SB),NOSPLIT,$16
+ MOVQ runtime·timens(SB), AX
+ CMPQ AX, $0
+ JEQ 2(PC)
+ RET
+ MOVL $0, DI // real time clock
+ LEAL 0(SP), AX
+ MOVL AX, SI // timespec
+ NACL_SYSCALL(SYS_clock_gettime)
+ MOVQ 0(SP), AX // sec
+ MOVL 8(SP), DX // nsec
+
+ // sec is in AX, nsec in DX
+ // return nsec in AX
+ IMULQ $1000000000, AX
+ ADDQ DX, AX
+ RET
+
+TEXT runtime·sigtramp(SB),NOSPLIT,$80
+ // restore TLS register at time of execution,
+ // in case it's been smashed.
+ // the TLS register is really BP, but for consistency
+ // with non-NaCl systems it is referred to here as TLS.
+ // NOTE: Cannot use SYS_tls_get here (like we do in mstart_nacl),
+ // because the main thread never calls tls_set.
+ LEAL ctxt+0(FP), AX
+ MOVL (16*4+5*8)(AX), AX
+ MOVL AX, TLS
+
+ // check that m exists
+ get_tls(CX)
+ MOVL m(CX), BX
+
+ CMPL BX, $0
+ JEQ nom
+
+ // save g
+ MOVL g(CX), DI
+ MOVL DI, 20(SP)
+
+ // g = m->gsignal
+ MOVL m_gsignal(BX), BX
+ MOVL BX, g(CX)
+
+//JMP debughandler
+
+ // copy arguments for sighandler
+ MOVL $11, 0(SP) // signal
+ MOVL $0, 4(SP) // siginfo
+ LEAL ctxt+0(FP), AX
+ MOVL AX, 8(SP) // context
+ MOVL DI, 12(SP) // g
+
+ CALL runtime·sighandler(SB)
+
+ // restore g
+ get_tls(CX)
+ MOVL 20(SP), BX
+ MOVL BX, g(CX)
+
+sigtramp_ret:
+ // Enable exceptions again.
+ NACL_SYSCALL(SYS_exception_clear_flag)
+
+ // Restore registers as best we can. Impossible to do perfectly.
+ // See comment in sys_nacl_386.s for extended rationale.
+ LEAL ctxt+0(FP), SI
+ ADDL $64, SI
+ MOVQ 0(SI), AX
+ MOVQ 8(SI), CX
+ MOVQ 16(SI), DX
+ MOVQ 24(SI), BX
+ MOVL 32(SI), SP // MOVL for SP sandboxing
+ // 40(SI) is saved BP aka TLS, already restored above
+ // 48(SI) is saved SI, never to be seen again
+ MOVQ 56(SI), DI
+ MOVQ 64(SI), R8
+ MOVQ 72(SI), R9
+ MOVQ 80(SI), R10
+ MOVQ 88(SI), R11
+ MOVQ 96(SI), R12
+ MOVQ 104(SI), R13
+ MOVQ 112(SI), R14
+ // 120(SI) is R15, which is owned by Native Client and must not be modified
+ MOVQ 128(SI), SI // saved PC
+ // 136(SI) is saved EFLAGS, never to be seen again
+ JMP SI
+
+debughandler:
+ // print basic information
+ LEAL ctxt+0(FP), DI
+ MOVL $runtime·sigtrampf(SB), AX
+ MOVL AX, 0(SP)
+ MOVQ (16*4+16*8)(DI), BX // rip
+ MOVQ BX, 8(SP)
+ MOVQ (16*4+0*8)(DI), BX // rax
+ MOVQ BX, 16(SP)
+ MOVQ (16*4+1*8)(DI), BX // rcx
+ MOVQ BX, 24(SP)
+ MOVQ (16*4+2*8)(DI), BX // rdx
+ MOVQ BX, 32(SP)
+ MOVQ (16*4+3*8)(DI), BX // rbx
+ MOVQ BX, 40(SP)
+ MOVQ (16*4+7*8)(DI), BX // rdi
+ MOVQ BX, 48(SP)
+ MOVQ (16*4+15*8)(DI), BX // r15
+ MOVQ BX, 56(SP)
+ MOVQ (16*4+4*8)(DI), BX // rsp
+ MOVQ 0(BX), BX
+ MOVQ BX, 64(SP)
+ CALL runtime·printf(SB)
+
+ LEAL ctxt+0(FP), DI
+ MOVQ (16*4+16*8)(DI), BX // rip
+ MOVL BX, 0(SP)
+ MOVQ (16*4+4*8)(DI), BX // rsp
+ MOVL BX, 4(SP)
+ MOVL $0, 8(SP) // lr
+ get_tls(CX)
+ MOVL g(CX), BX
+ MOVL BX, 12(SP) // gp
+ CALL runtime·traceback(SB)
+
+notls:
+ MOVL 0, AX
+ RET
+
+nom:
+ MOVL 0, AX
+ RET
+
+// cannot do real signal handling yet, because gsignal has not been allocated.
+MOVL $1, DI; NACL_SYSCALL(SYS_exit)
+
+TEXT runtime·nacl_sysinfo(SB),NOSPLIT,$16
+/*
+ MOVL di+0(FP), DI
+ LEAL 12(DI), BX
+ MOVL 8(DI), AX
+ ADDL 4(DI), AX
+ ADDL $2, AX
+ LEAL (BX)(AX*4), BX
+ MOVL BX, runtime·nacl_irt_query(SB)
+auxloop:
+ MOVL 0(BX), DX
+ CMPL DX, $0
+ JNE 2(PC)
+ RET
+ CMPL DX, $32
+ JEQ auxfound
+ ADDL $8, BX
+ JMP auxloop
+auxfound:
+ MOVL 4(BX), BX
+ MOVL BX, runtime·nacl_irt_query(SB)
+
+ LEAL runtime·nacl_irt_basic_v0_1_str(SB), DI
+ LEAL runtime·nacl_irt_basic_v0_1(SB), SI
+ MOVL runtime·nacl_irt_basic_v0_1_size(SB), DX
+ MOVL runtime·nacl_irt_query(SB), BX
+ CALL BX
+
+ LEAL runtime·nacl_irt_memory_v0_3_str(SB), DI
+ LEAL runtime·nacl_irt_memory_v0_3(SB), SI
+ MOVL runtime·nacl_irt_memory_v0_3_size(SB), DX
+ MOVL runtime·nacl_irt_query(SB), BX
+ CALL BX
+
+ LEAL runtime·nacl_irt_thread_v0_1_str(SB), DI
+ LEAL runtime·nacl_irt_thread_v0_1(SB), SI
+ MOVL runtime·nacl_irt_thread_v0_1_size(SB), DX
+ MOVL runtime·nacl_irt_query(SB), BX
+ CALL BX
+
+ // TODO: Once we have a NaCl SDK with futex syscall support,
+ // try switching to futex syscalls and here load the
+ // nacl-irt-futex-0.1 table.
+*/
+ RET
diff --git a/src/pkg/runtime/sys_openbsd_386.s b/src/pkg/runtime/sys_openbsd_386.s
index e1ec5337a..8f0da5c0e 100644
--- a/src/pkg/runtime/sys_openbsd_386.s
+++ b/src/pkg/runtime/sys_openbsd_386.s
@@ -9,6 +9,8 @@
#include "zasm_GOOS_GOARCH.h"
#include "../../cmd/ld/textflag.h"
+#define CLOCK_MONOTONIC $3
+
// Exit the entire program (like C exit)
TEXT runtime·exit(SB),NOSPLIT,$-4
MOVL $1, AX
@@ -45,21 +47,22 @@ TEXT runtime·write(SB),NOSPLIT,$-4
INT $0x80
RET
-TEXT runtime·usleep(SB),NOSPLIT,$20
+TEXT runtime·usleep(SB),NOSPLIT,$24
MOVL $0, DX
MOVL usec+0(FP), AX
MOVL $1000000, CX
DIVL CX
- MOVL AX, 12(SP) // tv_sec
+ MOVL AX, 12(SP) // tv_sec - l32
+ MOVL $0, 16(SP) // tv_sec - h32
MOVL $1000, AX
MULL DX
- MOVL AX, 16(SP) // tv_nsec
+ MOVL AX, 20(SP) // tv_nsec
MOVL $0, 0(SP)
LEAL 12(SP), AX
MOVL AX, 4(SP) // arg 1 - rqtp
MOVL $0, 8(SP) // arg 2 - rmtp
- MOVL $240, AX // sys_nanosleep
+ MOVL $91, AX // sys_nanosleep
INT $0x80
RET
@@ -107,43 +110,46 @@ TEXT runtime·madvise(SB),NOSPLIT,$-4
RET
TEXT runtime·setitimer(SB),NOSPLIT,$-4
- MOVL $83, AX
+ MOVL $69, AX
INT $0x80
RET
// func now() (sec int64, nsec int32)
TEXT time·now(SB), NOSPLIT, $32
- MOVL $232, AX
LEAL 12(SP), BX
- MOVL $0, 4(SP)
- MOVL BX, 8(SP)
+ MOVL $0, 4(SP) // arg 1 - clock_id
+ MOVL BX, 8(SP) // arg 2 - tp
+ MOVL $87, AX // sys_clock_gettime
INT $0x80
- MOVL 12(SP), AX // sec
- MOVL 16(SP), BX // nsec
- // sec is in AX, nsec in BX
+ MOVL 12(SP), AX // sec - l32
MOVL AX, sec+0(FP)
- MOVL $0, sec+4(FP)
+ MOVL 16(SP), AX // sec - h32
+ MOVL AX, sec+4(FP)
+
+ MOVL 20(SP), BX // nsec
MOVL BX, nsec+8(FP)
RET
// int64 nanotime(void) so really
// void nanotime(int64 *nsec)
TEXT runtime·nanotime(SB),NOSPLIT,$32
- MOVL $232, AX
LEAL 12(SP), BX
- MOVL $0, 4(SP)
- MOVL BX, 8(SP)
+ MOVL CLOCK_MONOTONIC, 4(SP) // arg 1 - clock_id
+ MOVL BX, 8(SP) // arg 2 - tp
+ MOVL $87, AX // sys_clock_gettime
INT $0x80
- MOVL 12(SP), AX // sec
- MOVL 16(SP), BX // nsec
- // sec is in AX, nsec in BX
- // convert to DX:AX nsec
- MOVL $1000000000, CX
- MULL CX
+ MOVL 16(SP), CX // sec - h32
+ IMULL $1000000000, CX
+
+ MOVL 12(SP), AX // sec - l32
+ MOVL $1000000000, BX
+ MULL BX // result in dx:ax
+
+ MOVL 20(SP), BX // nsec
ADDL BX, AX
- ADCL $0, DX
+ ADCL CX, DX // add high bits with carry
MOVL ret+0(FP), DI
MOVL AX, 0(DI)
@@ -325,7 +331,7 @@ TEXT runtime·osyield(SB),NOSPLIT,$-4
RET
TEXT runtime·thrsleep(SB),NOSPLIT,$-4
- MOVL $300, AX // sys___thrsleep
+ MOVL $94, AX // sys___thrsleep
INT $0x80
RET
@@ -362,7 +368,7 @@ TEXT runtime·kqueue(SB),NOSPLIT,$0
// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int nevents, Timespec *timeout);
TEXT runtime·kevent(SB),NOSPLIT,$0
- MOVL $270, AX
+ MOVL $72, AX // sys_kevent
INT $0x80
JAE 2(PC)
NEGL AX
@@ -370,7 +376,7 @@ TEXT runtime·kevent(SB),NOSPLIT,$0
// int32 runtime·closeonexec(int32 fd);
TEXT runtime·closeonexec(SB),NOSPLIT,$32
- MOVL $92, AX // fcntl
+ MOVL $92, AX // sys_fcntl
// 0(SP) is where the caller PC would be; kernel skips it
MOVL fd+0(FP), BX
MOVL BX, 4(SP) // fd
diff --git a/src/pkg/runtime/sys_openbsd_amd64.s b/src/pkg/runtime/sys_openbsd_amd64.s
index 26dc61f71..b2a61820a 100644
--- a/src/pkg/runtime/sys_openbsd_amd64.s
+++ b/src/pkg/runtime/sys_openbsd_amd64.s
@@ -9,6 +9,8 @@
#include "zasm_GOOS_GOARCH.h"
#include "../../cmd/ld/textflag.h"
+#define CLOCK_MONOTONIC $3
+
// int64 tfork(void *param, uintptr psize, M *mp, G *gp, void (*fn)(void));
TEXT runtime·tfork(SB),NOSPLIT,$32
@@ -62,7 +64,7 @@ TEXT runtime·thrsleep(SB),NOSPLIT,$0
MOVQ 24(SP), DX // arg 3 - tp
MOVQ 32(SP), R10 // arg 4 - lock
MOVQ 40(SP), R8 // arg 5 - abort
- MOVL $300, AX // sys___thrsleep
+ MOVL $94, AX // sys___thrsleep
SYSCALL
RET
@@ -130,7 +132,7 @@ TEXT runtime·usleep(SB),NOSPLIT,$16
MOVQ SP, DI // arg 1 - rqtp
MOVQ $0, SI // arg 2 - rmtp
- MOVL $240, AX // sys_nanosleep
+ MOVL $91, AX // sys_nanosleep
SYSCALL
RET
@@ -138,7 +140,7 @@ TEXT runtime·raise(SB),NOSPLIT,$16
MOVL $299, AX // sys_getthrid
SYSCALL
MOVQ AX, DI // arg 1 - pid
- MOVL sig+0(FP), SI // arg 2 - signum
+ MOVL sig+0(FP), SI // arg 2 - signum
MOVL $37, AX // sys_kill
SYSCALL
RET
@@ -147,7 +149,7 @@ TEXT runtime·setitimer(SB),NOSPLIT,$-8
MOVL 8(SP), DI // arg 1 - which
MOVQ 16(SP), SI // arg 2 - itv
MOVQ 24(SP), DX // arg 3 - oitv
- MOVL $83, AX // sys_setitimer
+ MOVL $69, AX // sys_setitimer
SYSCALL
RET
@@ -155,9 +157,9 @@ TEXT runtime·setitimer(SB),NOSPLIT,$-8
TEXT time·now(SB), NOSPLIT, $32
MOVQ $0, DI // arg 1 - clock_id
LEAQ 8(SP), SI // arg 2 - tp
- MOVL $232, AX // sys_clock_gettime
+ MOVL $87, AX // sys_clock_gettime
SYSCALL
- MOVL 8(SP), AX // sec
+ MOVQ 8(SP), AX // sec
MOVQ 16(SP), DX // nsec
// sec is in AX, nsec in DX
@@ -166,11 +168,11 @@ TEXT time·now(SB), NOSPLIT, $32
RET
TEXT runtime·nanotime(SB),NOSPLIT,$24
- MOVQ $0, DI // arg 1 - clock_id
+ MOVQ CLOCK_MONOTONIC, DI // arg 1 - clock_id
LEAQ 8(SP), SI // arg 2 - tp
- MOVL $232, AX // sys_clock_gettime
+ MOVL $87, AX // sys_clock_gettime
SYSCALL
- MOVL 8(SP), AX // sec
+ MOVQ 8(SP), AX // sec
MOVQ 16(SP), DX // nsec
// sec is in AX, nsec in DX
@@ -318,7 +320,7 @@ TEXT runtime·kevent(SB),NOSPLIT,$0
MOVQ 32(SP), R10
MOVL 40(SP), R8
MOVQ 48(SP), R9
- MOVL $270, AX
+ MOVL $72, AX
SYSCALL
JCC 2(PC)
NEGQ AX
diff --git a/src/pkg/runtime/sys_plan9_386.s b/src/pkg/runtime/sys_plan9_386.s
index bed0f7ebe..143cd2e49 100644
--- a/src/pkg/runtime/sys_plan9_386.s
+++ b/src/pkg/runtime/sys_plan9_386.s
@@ -81,6 +81,10 @@ TEXT runtime·plan9_semrelease(SB),NOSPLIT,$0
TEXT runtime·rfork(SB),NOSPLIT,$0
MOVL $19, AX // rfork
+ MOVL stack+8(SP), CX
+ MOVL mm+12(SP), BX // m
+ MOVL gg+16(SP), DX // g
+ MOVL fn+20(SP), SI // fn
INT $64
// In parent, return.
@@ -88,13 +92,7 @@ TEXT runtime·rfork(SB),NOSPLIT,$0
JEQ 2(PC)
RET
- // In child on old stack.
- MOVL mm+12(SP), BX // m
- MOVL gg+16(SP), DX // g
- MOVL fn+20(SP), SI // fn
-
// set SP to be on the new child stack
- MOVL stack+8(SP), CX
MOVL CX, SP
// Initialize m, g.
@@ -102,8 +100,9 @@ TEXT runtime·rfork(SB),NOSPLIT,$0
MOVL DX, g(AX)
MOVL BX, m(AX)
- // Initialize AX from TOS struct.
- MOVL procid(AX), AX
+ // Initialize procid from TOS struct.
+ // TODO: Be explicit and insert a new MOVL _tos(SB), AX here.
+ MOVL 48(AX), AX // procid
MOVL AX, m_procid(BX) // save pid as m->procid
CALL runtime·stackcheck(SB) // smashes AX, CX
diff --git a/src/pkg/runtime/sys_plan9_amd64.s b/src/pkg/runtime/sys_plan9_amd64.s
index d6702e865..e60459cb8 100644
--- a/src/pkg/runtime/sys_plan9_amd64.s
+++ b/src/pkg/runtime/sys_plan9_amd64.s
@@ -136,7 +136,7 @@ TEXT runtime·rfork(SB),NOSPLIT,$0
MOVQ BX, m(AX)
// Initialize AX from pid in TLS.
- MOVQ procid(AX), AX
+ MOVQ 0(FS), AX
MOVQ AX, m_procid(BX) // save pid as m->procid
CALL runtime·stackcheck(SB) // smashes AX, CX
diff --git a/src/pkg/runtime/sys_solaris_amd64.s b/src/pkg/runtime/sys_solaris_amd64.s
new file mode 100644
index 000000000..21517693b
--- /dev/null
+++ b/src/pkg/runtime/sys_solaris_amd64.s
@@ -0,0 +1,267 @@
+// 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.
+//
+// System calls and other sys.stuff for AMD64, SunOS
+// /usr/include/sys/syscall.h for syscall numbers.
+//
+
+#include "zasm_GOOS_GOARCH.h"
+#include "../../cmd/ld/textflag.h"
+
+// This is needed by asm_amd64.s
+TEXT runtime·settls(SB),NOSPLIT,$8
+ RET
+
+// void libc·miniterrno(void *(*___errno)(void));
+//
+// Set the TLS errno pointer in M.
+//
+// Called using runtime·asmcgocall from os_solaris.c:/minit.
+TEXT runtime·miniterrno(SB),NOSPLIT,$0
+ // asmcgocall will put first argument into DI.
+ CALL DI // SysV ABI so returns in AX
+ get_tls(CX)
+ MOVQ m(CX), BX
+ MOVQ AX, m_perrno(BX)
+ RET
+
+// int64 runtime·nanotime1(void);
+//
+// clock_gettime(3c) wrapper because Timespec is too large for
+// runtime·nanotime stack.
+//
+// Called using runtime·sysvicall6 from os_solaris.c:/nanotime.
+TEXT runtime·nanotime1(SB),NOSPLIT,$0
+ // need space for the timespec argument.
+ SUBQ $64, SP // 16 bytes will do, but who knows in the future?
+ MOVQ $3, DI // CLOCK_REALTIME from <sys/time_impl.h>
+ MOVQ SP, SI
+ MOVQ libc·clock_gettime(SB), AX
+ CALL AX
+ MOVQ (SP), AX // tv_sec from struct timespec
+ IMULQ $1000000000, AX // multiply into nanoseconds
+ ADDQ 8(SP), AX // tv_nsec, offset should be stable.
+ ADDQ $64, SP
+ RET
+
+// pipe(3c) wrapper that returns fds in AX, DX.
+TEXT runtime·pipe1(SB),NOSPLIT,$0
+ SUBQ $16, SP // 8 bytes will do, but stack has to be 16-byte alligned
+ MOVQ SP, DI
+ MOVQ libc·pipe(SB), AX
+ CALL AX
+ MOVL 0(SP), AX
+ MOVL 4(SP), DX
+ ADDQ $16, SP
+ RET
+
+// Call a library function with SysV calling conventions.
+// The called function can take a maximum of 6 INTEGER class arguments,
+// see
+// Michael Matz, Jan Hubicka, Andreas Jaeger, and Mark Mitchell
+// System V Application Binary Interface
+// AMD64 Architecture Processor Supplement
+// section 3.2.3.
+//
+// Called by runtime·asmcgocall or runtime·cgocall.
+TEXT runtime·asmsysvicall6(SB),NOSPLIT,$0
+ // asmcgocall will put first argument into DI.
+ PUSHQ DI // save for later
+ MOVQ libcall_fn(DI), AX
+ MOVQ libcall_args(DI), R11
+ MOVQ libcall_n(DI), R10
+
+ get_tls(CX)
+ MOVQ m(CX), BX
+ MOVQ m_perrno(BX), DX
+ CMPQ DX, $0
+ JEQ skiperrno1
+ MOVL $0, 0(DX)
+
+skiperrno1:
+ CMPQ R11, $0
+ JEQ skipargs
+ // Load 6 args into correspondent registers.
+ MOVQ 0(R11), DI
+ MOVQ 8(R11), SI
+ MOVQ 16(R11), DX
+ MOVQ 24(R11), CX
+ MOVQ 32(R11), R8
+ MOVQ 40(R11), R9
+skipargs:
+
+ // Call SysV function
+ CALL AX
+
+ // Return result
+ POPQ DI
+ MOVQ AX, libcall_r1(DI)
+ MOVQ DX, libcall_r2(DI)
+
+ get_tls(CX)
+ MOVQ m(CX), BX
+ MOVQ m_perrno(BX), AX
+ CMPQ AX, $0
+ JEQ skiperrno2
+ MOVL 0(AX), AX
+ MOVQ AX, libcall_err(DI)
+
+skiperrno2:
+ RET
+
+// uint32 tstart_sysvicall(M *newm);
+TEXT runtime·tstart_sysvicall(SB),NOSPLIT,$0
+ // DI contains first arg newm
+ MOVQ m_g0(DI), DX // g
+
+ // Make TLS entries point at g and m.
+ get_tls(BX)
+ MOVQ DX, g(BX)
+ MOVQ DI, m(BX)
+
+ // Layout new m scheduler stack on os stack.
+ MOVQ SP, AX
+ MOVQ AX, g_stackbase(DX)
+ SUBQ $(0x100000), AX // stack size
+ MOVQ AX, g_stackguard(DX)
+ MOVQ AX, g_stackguard0(DX)
+
+ // Someday the convention will be D is always cleared.
+ CLD
+
+ CALL runtime·stackcheck(SB) // clobbers AX,CX
+ CALL runtime·mstart(SB)
+
+ XORL AX, AX // return 0 == success
+ RET
+
+// Careful, this is called by __sighndlr, a libc function. We must preserve
+// registers as per AMD 64 ABI.
+TEXT runtime·sigtramp(SB),NOSPLIT,$0
+ // Note that we are executing on altsigstack here, so we have
+ // more stack available than NOSPLIT would have us believe.
+ // To defeat the linker, we make our own stack frame with
+ // more space:
+ SUBQ $184, SP
+
+ // save registers
+ MOVQ BX, 32(SP)
+ MOVQ BP, 40(SP)
+ MOVQ R12, 48(SP)
+ MOVQ R13, 56(SP)
+ MOVQ R14, 64(SP)
+ MOVQ R15, 72(SP)
+
+ get_tls(BX)
+ // check that m exists
+ MOVQ m(BX), BP
+ CMPQ BP, $0
+ JNE allgood
+ MOVQ DI, 0(SP)
+ MOVQ $runtime·badsignal(SB), AX
+ CALL AX
+ RET
+
+allgood:
+ // save g
+ MOVQ g(BX), R10
+ MOVQ R10, 80(SP)
+
+ // Save m->libcall and m->scratch. We need to do this because we
+ // might get interrupted by a signal in runtime·asmcgocall.
+
+ // save m->libcall
+ LEAQ m_libcall(BP), R11
+ MOVQ libcall_fn(R11), R10
+ MOVQ R10, 88(SP)
+ MOVQ libcall_args(R11), R10
+ MOVQ R10, 96(SP)
+ MOVQ libcall_n(R11), R10
+ MOVQ R10, 104(SP)
+ MOVQ libcall_r1(R11), R10
+ MOVQ R10, 168(SP)
+ MOVQ libcall_r2(R11), R10
+ MOVQ R10, 176(SP)
+
+ // save m->scratch
+ LEAQ m_scratch(BP), R11
+ MOVQ 0(R11), R10
+ MOVQ R10, 112(SP)
+ MOVQ 8(R11), R10
+ MOVQ R10, 120(SP)
+ MOVQ 16(R11), R10
+ MOVQ R10, 128(SP)
+ MOVQ 24(R11), R10
+ MOVQ R10, 136(SP)
+ MOVQ 32(R11), R10
+ MOVQ R10, 144(SP)
+ MOVQ 40(R11), R10
+ MOVQ R10, 152(SP)
+
+ // save errno, it might be EINTR; stuff we do here might reset it.
+ MOVQ m_perrno(BP), R10
+ MOVL 0(R10), R10
+ MOVQ R10, 160(SP)
+
+ MOVQ g(BX), R10
+ // g = m->gsignal
+ MOVQ m_gsignal(BP), BP
+ MOVQ BP, g(BX)
+
+ // prepare call
+ MOVQ DI, 0(SP)
+ MOVQ SI, 8(SP)
+ MOVQ DX, 16(SP)
+ MOVQ R10, 24(SP)
+ CALL runtime·sighandler(SB)
+
+ get_tls(BX)
+ MOVQ m(BX), BP
+ // restore libcall
+ LEAQ m_libcall(BP), R11
+ MOVQ 88(SP), R10
+ MOVQ R10, libcall_fn(R11)
+ MOVQ 96(SP), R10
+ MOVQ R10, libcall_args(R11)
+ MOVQ 104(SP), R10
+ MOVQ R10, libcall_n(R11)
+ MOVQ 168(SP), R10
+ MOVQ R10, libcall_r1(R11)
+ MOVQ 176(SP), R10
+ MOVQ R10, libcall_r2(R11)
+
+ // restore scratch
+ LEAQ m_scratch(BP), R11
+ MOVQ 112(SP), R10
+ MOVQ R10, 0(R11)
+ MOVQ 120(SP), R10
+ MOVQ R10, 8(R11)
+ MOVQ 128(SP), R10
+ MOVQ R10, 16(R11)
+ MOVQ 136(SP), R10
+ MOVQ R10, 24(R11)
+ MOVQ 144(SP), R10
+ MOVQ R10, 32(R11)
+ MOVQ 152(SP), R10
+ MOVQ R10, 40(R11)
+
+ // restore errno
+ MOVQ m_perrno(BP), R11
+ MOVQ 160(SP), R10
+ MOVL R10, 0(R11)
+
+ // restore g
+ MOVQ 80(SP), R10
+ MOVQ R10, g(BX)
+
+ // restore registers
+ MOVQ 32(SP), BX
+ MOVQ 40(SP), BP
+ MOVQ 48(SP), R12
+ MOVQ 56(SP), R13
+ MOVQ 64(SP), R14
+ MOVQ 72(SP), R15
+
+ ADDQ $184, SP
+ RET
diff --git a/src/pkg/runtime/sys_windows_386.s b/src/pkg/runtime/sys_windows_386.s
index 20753638e..e0c0631cf 100644
--- a/src/pkg/runtime/sys_windows_386.s
+++ b/src/pkg/runtime/sys_windows_386.s
@@ -14,28 +14,28 @@ TEXT runtime·asmstdcall(SB),NOSPLIT,$0
// Copy args to the stack.
MOVL SP, BP
- MOVL wincall_n(BX), CX // words
+ MOVL libcall_n(BX), CX // words
MOVL CX, AX
SALL $2, AX
SUBL AX, SP // room for args
MOVL SP, DI
- MOVL wincall_args(BX), SI
+ MOVL libcall_args(BX), SI
CLD
REP; MOVSL
// Call stdcall or cdecl function.
// DI SI BP BX are preserved, SP is not
- CALL wincall_fn(BX)
+ CALL libcall_fn(BX)
MOVL BP, SP
// Return result.
MOVL c+0(FP), BX
- MOVL AX, wincall_r1(BX)
- MOVL DX, wincall_r2(BX)
+ MOVL AX, libcall_r1(BX)
+ MOVL DX, libcall_r2(BX)
// GetLastError().
MOVL 0x34(FS), AX
- MOVL AX, wincall_err(BX)
+ MOVL AX, libcall_err(BX)
RET
@@ -69,43 +69,47 @@ TEXT runtime·setlasterror(SB),NOSPLIT,$0
MOVL AX, 0x34(FS)
RET
-TEXT runtime·sigtramp(SB),NOSPLIT,$28
- // unwinding?
- MOVL info+0(FP), CX
- TESTL $6, 4(CX) // exception flags
- MOVL $1, AX
- JNZ sigdone
-
- // copy arguments for call to sighandler
- MOVL CX, 0(SP)
- MOVL context+8(FP), CX
- MOVL CX, 4(SP)
-
- get_tls(CX)
-
- // check that m exists
- MOVL m(CX), AX
- CMPL AX, $0
- JNE 2(PC)
- CALL runtime·badsignal2(SB)
-
- MOVL g(CX), CX
- MOVL CX, 8(SP)
+// Called by Windows as a Vectored Exception Handler (VEH).
+// First argument is pointer to struct containing
+// exception record and context pointers.
+// Return 0 for 'not handled', -1 for handled.
+TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
+ MOVL ptrs+0(FP), CX
+ SUBL $28, SP
+ // save callee-saved registers
MOVL BX, 12(SP)
MOVL BP, 16(SP)
MOVL SI, 20(SP)
MOVL DI, 24(SP)
+ MOVL 0(CX), BX // ExceptionRecord*
+ MOVL 4(CX), CX // Context*
+
+ // fetch g
+ get_tls(DX)
+ MOVL m(DX), AX
+ CMPL AX, $0
+ JNE 2(PC)
+ CALL runtime·badsignal2(SB)
+ MOVL g(DX), DX
+ // call sighandler(ExceptionRecord*, Context*, G*)
+ MOVL BX, 0(SP)
+ MOVL CX, 4(SP)
+ MOVL DX, 8(SP)
CALL runtime·sighandler(SB)
// AX is set to report result back to Windows
+ // restore callee-saved registers
MOVL 24(SP), DI
MOVL 20(SP), SI
MOVL 16(SP), BP
MOVL 12(SP), BX
-sigdone:
- RET
+
+ ADDL $28, SP
+ // RET 4 (return and pop 4 bytes parameters)
+ BYTE $0xC2; WORD $4
+ RET // unreached; make assembler happy
TEXT runtime·ctrlhandler(SB),NOSPLIT,$0
PUSHL $runtime·ctrlhandler1(SB)
@@ -182,11 +186,6 @@ TEXT runtime·callbackasm1+0(SB),NOSPLIT,$0
PUSHL BP
PUSHL BX
- // set up SEH frame again
- PUSHL $runtime·sigtramp(SB)
- PUSHL 0(FS)
- MOVL SP, 0(FS)
-
// determine index into runtime·cbctxts table
SUBL $runtime·callbackasm(SB), AX
MOVL $0, DX
@@ -232,10 +231,6 @@ TEXT runtime·callbackasm1+0(SB),NOSPLIT,$0
MOVL BX, CX // cannot use BX anymore
- // pop SEH frame
- POPL 0(FS)
- POPL BX
-
// restore registers as required for windows callback
POPL BX
POPL BP
@@ -299,35 +294,6 @@ TEXT runtime·setldt(SB),NOSPLIT,$0
MOVL CX, 0x14(FS)
RET
-// void install_exception_handler()
-TEXT runtime·install_exception_handler(SB),NOSPLIT,$0
- get_tls(CX)
- MOVL m(CX), CX // m
-
- // Set up SEH frame
- MOVL m_seh(CX), DX
- MOVL $runtime·sigtramp(SB), AX
- MOVL AX, seh_handler(DX)
- MOVL 0(FS), AX
- MOVL AX, seh_prev(DX)
-
- // Install it
- MOVL DX, 0(FS)
-
- RET
-
-// void remove_exception_handler()
-TEXT runtime·remove_exception_handler(SB),NOSPLIT,$0
- get_tls(CX)
- MOVL m(CX), CX // m
-
- // Remove SEH frame
- MOVL m_seh(CX), DX
- MOVL seh_prev(DX), AX
- MOVL AX, 0(FS)
-
- RET
-
// Sleep duration is in 100ns units.
TEXT runtime·usleep1(SB),NOSPLIT,$0
MOVL duration+0(FP), BX
@@ -343,19 +309,36 @@ TEXT runtime·usleep1(SB),NOSPLIT,$0
RET
MOVL m(CX), BP
+
+ // leave pc/sp for cpu profiler
+ MOVL (SP), SI
+ MOVL SI, m_libcallpc(BP)
+ MOVL g(CX), SI
+ MOVL SI, m_libcallg(BP)
+ // sp must be the last, because once async cpu profiler finds
+ // all three values to be non-zero, it will use them
+ LEAL 4(SP), SI
+ MOVL SI, m_libcallsp(BP)
+
MOVL m_g0(BP), SI
CMPL g(CX), SI
- JNE 3(PC)
+ JNE usleep1_switch
// executing on m->g0 already
CALL AX
- RET
+ JMP usleep1_ret
+usleep1_switch:
// Switch to m->g0 stack and back.
MOVL (g_sched+gobuf_sp)(SI), SI
MOVL SP, -4(SI)
LEAL -4(SI), SP
CALL AX
MOVL 0(SP), SP
+
+usleep1_ret:
+ get_tls(CX)
+ MOVL m(CX), BP
+ MOVL $0, m_libcallsp(BP)
RET
// Runs on OS stack. duration (in 100ns units) is in BX.
diff --git a/src/pkg/runtime/sys_windows_amd64.s b/src/pkg/runtime/sys_windows_amd64.s
index 8c4caf867..94845903e 100644
--- a/src/pkg/runtime/sys_windows_amd64.s
+++ b/src/pkg/runtime/sys_windows_amd64.s
@@ -13,9 +13,9 @@
TEXT runtime·asmstdcall(SB),NOSPLIT,$0
// asmcgocall will put first argument into CX.
PUSHQ CX // save for later
- MOVQ wincall_fn(CX), AX
- MOVQ wincall_args(CX), SI
- MOVQ wincall_n(CX), CX
+ MOVQ libcall_fn(CX), AX
+ MOVQ libcall_args(CX), SI
+ MOVQ libcall_n(CX), CX
// SetLastError(0).
MOVQ 0x30(GS), DI
@@ -52,12 +52,12 @@ loadregs:
// Return result.
POPQ CX
- MOVQ AX, wincall_r1(CX)
+ MOVQ AX, libcall_r1(CX)
// GetLastError().
MOVQ 0x30(GS), DI
MOVL 0x68(DI), AX
- MOVQ AX, wincall_err(CX)
+ MOVQ AX, libcall_err(CX)
RET
@@ -95,49 +95,55 @@ TEXT runtime·setlasterror(SB),NOSPLIT,$0
MOVL AX, 0x68(CX)
RET
-TEXT runtime·sigtramp(SB),NOSPLIT,$0
- // CX: exception record
- // R8: context
+// Called by Windows as a Vectored Exception Handler (VEH).
+// First argument is pointer to struct containing
+// exception record and context pointers.
+// Return 0 for 'not handled', -1 for handled.
+TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
+ // CX: PEXCEPTION_POINTERS ExceptionInfo
- // unwinding?
- TESTL $6, 4(CX) // exception flags
- MOVL $1, AX
- JNZ sigdone
-
- // copy arguments for call to sighandler.
-
- // Stack adjustment is here to hide from 6l,
- // which doesn't understand that sigtramp
- // runs on essentially unlimited stack.
- SUBQ $56, SP
- MOVQ CX, 0(SP)
- MOVQ R8, 8(SP)
-
- get_tls(CX)
-
- // check that m exists
- MOVQ m(CX), AX
+ // DI SI BP BX R12 R13 R14 R15 registers and DF flag are preserved
+ // as required by windows callback convention.
+ PUSHFQ
+ SUBQ $88, SP
+ MOVQ DI, 80(SP)
+ MOVQ SI, 72(SP)
+ MOVQ BP, 64(SP)
+ MOVQ BX, 56(SP)
+ MOVQ R12, 48(SP)
+ MOVQ R13, 40(SP)
+ MOVQ R14, 32(SP)
+ MOVQ R15, 24(SP)
+
+ MOVQ 0(CX), BX // ExceptionRecord*
+ MOVQ 8(CX), CX // Context*
+
+ // fetch g
+ get_tls(DX)
+ MOVQ m(DX), AX
CMPQ AX, $0
JNE 2(PC)
CALL runtime·badsignal2(SB)
-
- MOVQ g(CX), CX
- MOVQ CX, 16(SP)
-
- MOVQ BX, 24(SP)
- MOVQ BP, 32(SP)
- MOVQ SI, 40(SP)
- MOVQ DI, 48(SP)
-
+ MOVQ g(DX), DX
+ // call sighandler(ExceptionRecord*, Context*, G*)
+ MOVQ BX, 0(SP)
+ MOVQ CX, 8(SP)
+ MOVQ DX, 16(SP)
CALL runtime·sighandler(SB)
+ // AX is set to report result back to Windows
- MOVQ 24(SP), BX
- MOVQ 32(SP), BP
- MOVQ 40(SP), SI
- MOVQ 48(SP), DI
- ADDQ $56, SP
+ // restore registers as required for windows callback
+ MOVQ 24(SP), R15
+ MOVQ 32(SP), R14
+ MOVQ 40(SP), R13
+ MOVQ 48(SP), R12
+ MOVQ 56(SP), BX
+ MOVQ 64(SP), BP
+ MOVQ 72(SP), SI
+ MOVQ 80(SP), DI
+ ADDQ $88, SP
+ POPFQ
-sigdone:
RET
TEXT runtime·ctrlhandler(SB),NOSPLIT,$8
@@ -277,13 +283,6 @@ TEXT runtime·callbackasm1(SB),NOSPLIT,$0
POPQ -8(CX)(DX*1) // restore bytes just after the args
RET
-TEXT runtime·setstacklimits(SB),NOSPLIT,$0
- MOVQ 0x30(GS), CX
- MOVQ $0, 0x10(CX)
- MOVQ $0xffffffffffff, AX
- MOVQ AX, 0x08(CX)
- RET
-
// uint32 tstart_stdcall(M *newm);
TEXT runtime·tstart_stdcall(SB),NOSPLIT,$0
// CX contains first arg newm
@@ -315,14 +314,6 @@ TEXT runtime·settls(SB),NOSPLIT,$0
MOVQ DI, 0x28(GS)
RET
-// void install_exception_handler()
-TEXT runtime·install_exception_handler(SB),NOSPLIT,$0
- CALL runtime·setstacklimits(SB)
- RET
-
-TEXT runtime·remove_exception_handler(SB),NOSPLIT,$0
- RET
-
// Sleep duration is in 100ns units.
TEXT runtime·usleep1(SB),NOSPLIT,$0
MOVL duration+0(FP), BX
@@ -337,20 +328,35 @@ TEXT runtime·usleep1(SB),NOSPLIT,$0
CALL AX
RET
- MOVQ m(R15), R14
- MOVQ m_g0(R14), R14
+ MOVQ m(R15), R13
+
+ // leave pc/sp for cpu profiler
+ MOVQ (SP), R12
+ MOVQ R12, m_libcallpc(R13)
+ MOVQ g(R15), R12
+ MOVQ R12, m_libcallg(R13)
+ // sp must be the last, because once async cpu profiler finds
+ // all three values to be non-zero, it will use them
+ LEAQ 8(SP), R12
+ MOVQ R12, m_libcallsp(R13)
+
+ MOVQ m_g0(R13), R14
CMPQ g(R15), R14
- JNE 3(PC)
+ JNE usleep1_switch
// executing on m->g0 already
CALL AX
- RET
+ JMP usleep1_ret
+usleep1_switch:
// Switch to m->g0 stack and back.
MOVQ (g_sched+gobuf_sp)(R14), R14
MOVQ SP, -8(R14)
LEAQ -8(R14), SP
CALL AX
MOVQ 0(SP), SP
+
+usleep1_ret:
+ MOVQ $0, m_libcallsp(R13)
RET
// Runs on OS stack. duration (in 100ns units) is in BX.
diff --git a/src/pkg/runtime/sys_x86.c b/src/pkg/runtime/sys_x86.c
index 0df6dfbbd..a450b3e58 100644
--- a/src/pkg/runtime/sys_x86.c
+++ b/src/pkg/runtime/sys_x86.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 amd64 386
+// +build amd64 amd64p32 386
#include "runtime.h"
@@ -14,6 +14,8 @@ runtime·gostartcall(Gobuf *gobuf, void (*fn)(void), void *ctxt)
uintptr *sp;
sp = (uintptr*)gobuf->sp;
+ if(sizeof(uintreg) > sizeof(uintptr))
+ *--sp = 0;
*--sp = (uintptr)gobuf->pc;
gobuf->sp = (uintptr)sp;
gobuf->pc = (uintptr)fn;
@@ -27,7 +29,7 @@ void
runtime·rewindmorestack(Gobuf *gobuf)
{
byte *pc;
-
+
pc = (byte*)gobuf->pc;
if(pc[0] == 0xe9) { // jmp 4-byte offset
gobuf->pc = gobuf->pc + 5 + *(int32*)(pc+1);
@@ -37,18 +39,18 @@ runtime·rewindmorestack(Gobuf *gobuf)
gobuf->pc = gobuf->pc + 2 + *(int8*)(pc+1);
return;
}
- if(pc[0] == 0xcc) {
- // This is a breakpoint inserted by gdb. We could use
- // runtime·findfunc to find the function. But if we
- // do that, then we will continue execution at the
- // function entry point, and we will not hit the gdb
- // breakpoint. So for this case we don't change
- // gobuf->pc, so that when we return we will execute
- // the jump instruction and carry on. This means that
- // stack unwinding may not work entirely correctly
- // (http://golang.org/issue/5723) but the user is
- // running under gdb anyhow.
- return;
+ if(pc[0] == 0xcc) {
+ // This is a breakpoint inserted by gdb. We could use
+ // runtime·findfunc to find the function. But if we
+ // do that, then we will continue execution at the
+ // function entry point, and we will not hit the gdb
+ // breakpoint. So for this case we don't change
+ // gobuf->pc, so that when we return we will execute
+ // the jump instruction and carry on. This means that
+ // stack unwinding may not work entirely correctly
+ // (http://golang.org/issue/5723) but the user is
+ // running under gdb anyhow.
+ return;
}
runtime·printf("runtime: pc=%p %x %x %x %x %x\n", pc, pc[0], pc[1], pc[2], pc[3], pc[4]);
runtime·throw("runtime: misuse of rewindmorestack");
diff --git a/src/pkg/runtime/syscall_nacl.h b/src/pkg/runtime/syscall_nacl.h
new file mode 100644
index 000000000..b33852ec8
--- /dev/null
+++ b/src/pkg/runtime/syscall_nacl.h
@@ -0,0 +1,71 @@
+// generated by mknacl.sh - do not edit
+#define SYS_null 1
+#define SYS_nameservice 2
+#define SYS_dup 8
+#define SYS_dup2 9
+#define SYS_open 10
+#define SYS_close 11
+#define SYS_read 12
+#define SYS_write 13
+#define SYS_lseek 14
+#define SYS_ioctl 15
+#define SYS_stat 16
+#define SYS_fstat 17
+#define SYS_chmod 18
+#define SYS_brk 20
+#define SYS_mmap 21
+#define SYS_munmap 22
+#define SYS_getdents 23
+#define SYS_mprotect 24
+#define SYS_list_mappings 25
+#define SYS_exit 30
+#define SYS_getpid 31
+#define SYS_sched_yield 32
+#define SYS_sysconf 33
+#define SYS_gettimeofday 40
+#define SYS_clock 41
+#define SYS_nanosleep 42
+#define SYS_clock_getres 43
+#define SYS_clock_gettime 44
+#define SYS_mkdir 45
+#define SYS_rmdir 46
+#define SYS_chdir 47
+#define SYS_getcwd 48
+#define SYS_unlink 49
+#define SYS_imc_makeboundsock 60
+#define SYS_imc_accept 61
+#define SYS_imc_connect 62
+#define SYS_imc_sendmsg 63
+#define SYS_imc_recvmsg 64
+#define SYS_imc_mem_obj_create 65
+#define SYS_imc_socketpair 66
+#define SYS_mutex_create 70
+#define SYS_mutex_lock 71
+#define SYS_mutex_trylock 72
+#define SYS_mutex_unlock 73
+#define SYS_cond_create 74
+#define SYS_cond_wait 75
+#define SYS_cond_signal 76
+#define SYS_cond_broadcast 77
+#define SYS_cond_timed_wait_abs 79
+#define SYS_thread_create 80
+#define SYS_thread_exit 81
+#define SYS_tls_init 82
+#define SYS_thread_nice 83
+#define SYS_tls_get 84
+#define SYS_second_tls_set 85
+#define SYS_second_tls_get 86
+#define SYS_exception_handler 87
+#define SYS_exception_stack 88
+#define SYS_exception_clear_flag 89
+#define SYS_sem_create 100
+#define SYS_sem_wait 101
+#define SYS_sem_post 102
+#define SYS_sem_get_value 103
+#define SYS_dyncode_create 104
+#define SYS_dyncode_modify 105
+#define SYS_dyncode_delete 106
+#define SYS_test_infoleak 109
+#define SYS_test_crash 110
+#define SYS_test_syscall_1 111
+#define SYS_test_syscall_2 112
diff --git a/src/pkg/runtime/syscall_solaris.goc b/src/pkg/runtime/syscall_solaris.goc
new file mode 100644
index 000000000..21bcce4d1
--- /dev/null
+++ b/src/pkg/runtime/syscall_solaris.goc
@@ -0,0 +1,374 @@
+// 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
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "cgocall.h"
+#include "../../cmd/ld/textflag.h"
+
+#pragma dynimport libc·chdir chdir "libc.so"
+#pragma dynimport libc·chroot chroot "libc.so"
+#pragma dynimport libc·close close "libc.so"
+#pragma dynimport libc·dlclose dlclose "libc.so"
+#pragma dynimport libc·dlopen dlopen "libc.so"
+#pragma dynimport libc·dlsym dlsym "libc.so"
+#pragma dynimport libc·execve execve "libc.so"
+#pragma dynimport libc·fcntl fcntl "libc.so"
+#pragma dynimport libc·gethostname gethostname "libc.so"
+#pragma dynimport libc·ioctl ioctl "libc.so"
+#pragma dynimport libc·pipe pipe "libc.so"
+#pragma dynimport libc·setgid setgid "libc.so"
+#pragma dynimport libc·setgroups setgroups "libc.so"
+#pragma dynimport libc·setsid setsid "libc.so"
+#pragma dynimport libc·setuid setuid "libc.so"
+#pragma dynimport libc·setpgid setsid "libc.so"
+#pragma dynimport libc·syscall syscall "libc.so"
+#pragma dynimport libc·forkx forkx "libc.so"
+#pragma dynimport libc·wait4 wait4 "libc.so"
+extern uintptr libc·chdir;
+extern uintptr libc·chroot;
+extern uintptr libc·close;
+extern uintptr libc·dlclose;
+extern uintptr libc·dlopen;
+extern uintptr libc·dlsym;
+extern uintptr libc·execve;
+extern uintptr libc·exit;
+extern uintptr libc·fcntl;
+extern uintptr libc·gethostname;
+extern uintptr libc·ioctl;
+extern uintptr libc·pipe;
+extern uintptr libc·setgid;
+extern uintptr libc·setgroups;
+extern uintptr libc·setsid;
+extern uintptr libc·setuid;
+extern uintptr libc·setpgid;
+extern uintptr libc·syscall;
+extern uintptr libc·forkx;
+extern uintptr libc·wait4;
+extern uintptr libc·write;
+
+func sysvicall6(func uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr) (r1 uintptr, r2 uintptr, err uintptr)
+{
+ LibCall c;
+
+ USED(a2);
+ USED(a3);
+ USED(a4);
+ USED(a5);
+ USED(a6);
+ c.fn = (void*)func;
+ c.n = nargs;
+ c.args = (void*)&a1;
+ runtime·cgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+ r1 = c.r1;
+ r2 = c.r2;
+}
+
+#pragma textflag NOSPLIT
+func rawSysvicall6(func uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr) (r1 uintptr, r2 uintptr, err uintptr)
+{
+ LibCall c;
+
+ USED(a2);
+ USED(a3);
+ USED(a4);
+ USED(a5);
+ USED(a6);
+ c.fn = (void*)func;
+ c.n = nargs;
+ c.args = (void*)&a1;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+ r1 = c.r1;
+ r2 = c.r2;
+}
+
+#pragma textflag NOSPLIT
+func chdir(path uintptr) (err uintptr) {
+ LibCall c;
+
+ c.fn = (void*)libc·chdir;
+ c.n = 1;
+ c.args = (void*)&path;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+}
+
+#pragma textflag NOSPLIT
+func chroot1(path uintptr) (err uintptr) {
+ LibCall c;
+
+ c.fn = (void*)libc·chroot;
+ c.n = 1;
+ c.args = (void*)&path;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+}
+
+#pragma textflag NOSPLIT
+func close(fd uintptr) (err uintptr) {
+ LibCall c;
+
+ c.fn = (void*)libc·close;
+ c.n = 1;
+ c.args = (void*)&fd;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+}
+
+func dlclose(handle uintptr) (err uintptr) {
+ LibCall c;
+
+ USED(handle);
+ c.fn = (void*)libc·dlclose;
+ c.n = 1;
+ c.args = (void*)&handle;
+ runtime·cgocall(runtime·asmsysvicall6, &c);
+ err = c.r1;
+}
+
+func dlopen(name *uint8, mode uintptr) (handle uintptr, err uintptr) {
+ LibCall c;
+
+ USED(mode);
+ c.fn = (void*)libc·dlopen;
+ c.n = 2;
+ c.args = (void*)&name;
+ runtime·cgocall(runtime·asmsysvicall6, &c);
+ handle = c.r1;
+ if(handle == 0)
+ err = c.err;
+ else
+ err = 0;
+}
+
+func dlsym(handle uintptr, name *uint8) (proc uintptr, err uintptr) {
+ LibCall c;
+
+ USED(name);
+ c.fn = (void*)libc·dlsym;
+ c.n = 2;
+ c.args = &handle;
+ runtime·cgocall(runtime·asmsysvicall6, &c);
+ proc = c.r1;
+ if(proc == 0)
+ err = c.err;
+ else
+ err = 0;
+}
+
+#pragma textflag NOSPLIT
+func execve(path uintptr, argv uintptr, envp uintptr) (err uintptr) {
+ LibCall c;
+
+ USED(argv);
+ USED(envp);
+ c.fn = (void*)libc·execve;
+ c.n = 3;
+ c.args = (void*)&path;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+}
+
+#pragma textflag NOSPLIT
+func exit(code uintptr) {
+ LibCall c;
+
+ c.fn = (void*)libc·exit;
+ c.n = 1;
+ c.args = (void*)&code;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+}
+
+#pragma textflag NOSPLIT
+func fcntl1(fd uintptr, cmd uintptr, arg uintptr) (val uintptr, err uintptr) {
+ LibCall c;
+
+ USED(cmd);
+ USED(arg);
+ c.fn = (void*)libc·fcntl;
+ c.n = 3;
+ c.args = (void*)&fd;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+ val = c.r1;
+}
+
+func gethostname() (name String, err uintptr) {
+ struct { uintptr v[2]; } args;
+ uint8 cname[MAXHOSTNAMELEN];
+ LibCall c;
+
+ c.fn = (void*)libc·gethostname;
+ c.n = 2;
+ args.v[0] = (uintptr)&cname[0];
+ args.v[1] = MAXHOSTNAMELEN;
+ c.args = (void*)&args;
+ runtime·cgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+ if(c.r1) {
+ name = runtime·emptystring;
+ return;
+ }
+ cname[MAXHOSTNAMELEN - 1] = 0;
+ name = runtime·gostring(cname);
+}
+
+#pragma textflag NOSPLIT
+func ioctl(fd uintptr, req uintptr, arg uintptr) (err uintptr) {
+ LibCall c;
+
+ USED(req);
+ USED(arg);
+ c.fn = (void*)libc·ioctl;
+ c.n = 3;
+ c.args = (void*)&fd;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+}
+
+func wait4(pid uintptr, wstatus *uint32, options uintptr, rusage *void) (wpid int, err uintptr) {
+ LibCall c;
+
+ USED(wstatus);
+ USED(options);
+ USED(rusage);
+ c.fn = (void*)libc·wait4;
+ c.n = 4;
+ c.args = (void*)&pid;
+ runtime·cgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+ wpid = c.r1;
+}
+
+#pragma textflag NOSPLIT
+func setgid(gid uintptr) (err uintptr) {
+ LibCall c;
+
+ c.fn = (void*)libc·setgid;
+ c.n = 1;
+ c.args = (void*)&gid;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+}
+
+#pragma textflag NOSPLIT
+func setgroups1(ngid uintptr, gid uintptr) (err uintptr) {
+ LibCall c;
+
+ USED(gid);
+ c.fn = (void*)libc·setgroups;
+ c.n = 2;
+ c.args = (void*)&ngid;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+}
+
+#pragma textflag NOSPLIT
+func setsid() (pid uintptr, err uintptr) {
+ LibCall c;
+
+ c.fn = (void*)libc·setsid;
+ c.n = 0;
+ c.args = (void*)0;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+ pid = c.r1;
+}
+
+#pragma textflag NOSPLIT
+func setuid(uid uintptr) (err uintptr) {
+ LibCall c;
+
+ c.fn = (void*)libc·setuid;
+ c.n = 1;
+ c.args = (void*)&uid;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+}
+
+#pragma textflag NOSPLIT
+func setpgid(pid uintptr, pgid uintptr) (err uintptr) {
+ LibCall c;
+
+ USED(pgid);
+ c.fn = (void*)libc·setpgid;
+ c.n = 2;
+ c.args = (void*)&pid;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+}
+
+#pragma textflag NOSPLIT
+func forkx(flags uintptr) (pid uintptr, err uintptr) {
+ LibCall c;
+
+ c.fn = (void*)libc·forkx;
+ c.n = 1;
+ c.args = (void*)&flags;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+ pid = c.r1;
+}
+
+void runtime·pipe1(void);
+
+func pipe() (r uintptr, w uintptr, err uintptr) {
+ LibCall c;
+
+ c.fn = (void*)runtime·pipe1;
+ c.n = 0;
+ c.args = (void*)0;
+ runtime·cgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+ r = c.r1;
+ w = c.r2;
+}
+
+#pragma textflag NOSPLIT
+func write1(fd uintptr, buf uintptr, nbyte uintptr) (n uintptr, err uintptr) {
+ LibCall c;
+
+ USED(buf);
+ USED(nbyte);
+ c.fn = (void*)libc·write;
+ c.n = 3;
+ c.args = (void*)fd;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+ n = c.r1;
+}
+
+func Syscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
+ LibCall c;
+
+ USED(a1);
+ USED(a2);
+ USED(a3);
+ c.fn = (void*)libc·syscall;
+ c.n = 4;
+ c.args = &trap;
+ runtime·cgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+ r1 = c.r1;
+ r2 = c.r2;
+}
+
+func RawSyscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
+ LibCall c;
+
+ USED(a1);
+ USED(a2);
+ USED(a3);
+ c.fn = (void*)libc·syscall;
+ c.n = 4;
+ c.args = &trap;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+ r1 = c.r1;
+ r2 = c.r2;
+}
diff --git a/src/pkg/runtime/syscall_windows.goc b/src/pkg/runtime/syscall_windows.goc
index 173d3ed6a..528245363 100644
--- a/src/pkg/runtime/syscall_windows.goc
+++ b/src/pkg/runtime/syscall_windows.goc
@@ -8,7 +8,7 @@ package syscall
#include "cgocall.h"
func loadlibrary(filename *uint16) (handle uintptr, err uintptr) {
- WinCall c;
+ LibCall c;
c.fn = runtime·LoadLibrary;
c.n = 1;
@@ -22,7 +22,7 @@ func loadlibrary(filename *uint16) (handle uintptr, err uintptr) {
}
func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err uintptr) {
- WinCall c;
+ LibCall c;
USED(procname);
c.fn = runtime·GetProcAddress;
@@ -40,17 +40,12 @@ func NewCallback(fn Eface) (code uintptr) {
code = (uintptr)runtime·compilecallback(fn, true);
}
-/*
- * If this is needed, uncomment here and add a declaration in package syscall
- * next to the NewCallback declaration.
- *
func NewCallbackCDecl(fn Eface) (code uintptr) {
code = (uintptr)runtime·compilecallback(fn, false);
}
- */
func Syscall(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
- WinCall c;
+ LibCall c;
USED(a2);
USED(a3);
@@ -64,7 +59,7 @@ func Syscall(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr) (r1
}
func Syscall6(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
- WinCall c;
+ LibCall c;
USED(a2);
USED(a3);
@@ -81,7 +76,7 @@ func Syscall6(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4
}
func Syscall9(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr, a7 uintptr, a8 uintptr, a9 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
- WinCall c;
+ LibCall c;
USED(a2);
USED(a3);
@@ -101,7 +96,7 @@ func Syscall9(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4
}
func Syscall12(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr, a7 uintptr, a8 uintptr, a9 uintptr, a10 uintptr, a11 uintptr, a12 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
- WinCall c;
+ LibCall c;
USED(a2);
USED(a3);
@@ -124,7 +119,7 @@ func Syscall12(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4
}
func Syscall15(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr, a7 uintptr, a8 uintptr, a9 uintptr, a10 uintptr, a11 uintptr, a12 uintptr, a13 uintptr, a14 uintptr, a15 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
- WinCall c;
+ LibCall c;
USED(a2);
USED(a3);
diff --git a/src/pkg/runtime/syscall_windows_test.go b/src/pkg/runtime/syscall_windows_test.go
index f04d2cd54..fabf935d8 100644
--- a/src/pkg/runtime/syscall_windows_test.go
+++ b/src/pkg/runtime/syscall_windows_test.go
@@ -5,7 +5,13 @@
package runtime_test
import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
"runtime"
+ "strings"
"syscall"
"testing"
"unsafe"
@@ -171,10 +177,12 @@ func TestCallbackGC(t *testing.T) {
nestedCall(t, runtime.GC)
}
-func TestCallbackPanic(t *testing.T) {
- // Make sure panic during callback unwinds properly.
- if runtime.LockedOSThread() {
- t.Fatal("locked OS thread on entry to TestCallbackPanic")
+func TestCallbackPanicLocked(t *testing.T) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ if !runtime.LockedOSThread() {
+ t.Fatal("runtime.LockOSThread didn't")
}
defer func() {
s := recover()
@@ -184,27 +192,18 @@ func TestCallbackPanic(t *testing.T) {
if s.(string) != "callback panic" {
t.Fatal("wrong panic:", s)
}
- if runtime.LockedOSThread() {
- t.Fatal("locked OS thread on exit from TestCallbackPanic")
+ if !runtime.LockedOSThread() {
+ t.Fatal("lost lock on OS thread after panic")
}
}()
nestedCall(t, func() { panic("callback panic") })
panic("nestedCall returned")
}
-func TestCallbackPanicLoop(t *testing.T) {
- // Make sure we don't blow out m->g0 stack.
- for i := 0; i < 100000; i++ {
- TestCallbackPanic(t)
- }
-}
-
-func TestCallbackPanicLocked(t *testing.T) {
- runtime.LockOSThread()
- defer runtime.UnlockOSThread()
-
- if !runtime.LockedOSThread() {
- t.Fatal("runtime.LockOSThread didn't")
+func TestCallbackPanic(t *testing.T) {
+ // Make sure panic during callback unwinds properly.
+ if runtime.LockedOSThread() {
+ t.Fatal("locked OS thread on entry to TestCallbackPanic")
}
defer func() {
s := recover()
@@ -214,14 +213,21 @@ func TestCallbackPanicLocked(t *testing.T) {
if s.(string) != "callback panic" {
t.Fatal("wrong panic:", s)
}
- if !runtime.LockedOSThread() {
- t.Fatal("lost lock on OS thread after panic")
+ if runtime.LockedOSThread() {
+ t.Fatal("locked OS thread on exit from TestCallbackPanic")
}
}()
nestedCall(t, func() { panic("callback panic") })
panic("nestedCall returned")
}
+func TestCallbackPanicLoop(t *testing.T) {
+ // Make sure we don't blow out m->g0 stack.
+ for i := 0; i < 100000; i++ {
+ TestCallbackPanic(t)
+ }
+}
+
func TestBlockingCallback(t *testing.T) {
c := make(chan int)
go func() {
@@ -242,3 +248,204 @@ func TestBlockingCallback(t *testing.T) {
func TestCallbackInAnotherThread(t *testing.T) {
// TODO: test a function which calls back in another thread: QueueUserAPC() or CreateThread()
}
+
+type cbDLLFunc int // int determines number of callback parameters
+
+func (f cbDLLFunc) stdcallName() string {
+ return fmt.Sprintf("stdcall%d", f)
+}
+
+func (f cbDLLFunc) cdeclName() string {
+ return fmt.Sprintf("cdecl%d", f)
+}
+
+func (f cbDLLFunc) buildOne(stdcall bool) string {
+ var funcname, attr string
+ if stdcall {
+ funcname = f.stdcallName()
+ attr = "__stdcall"
+ } else {
+ funcname = f.cdeclName()
+ attr = "__cdecl"
+ }
+ typename := "t" + funcname
+ p := make([]string, f)
+ for i := range p {
+ p[i] = "void*"
+ }
+ params := strings.Join(p, ",")
+ for i := range p {
+ p[i] = fmt.Sprintf("%d", i+1)
+ }
+ args := strings.Join(p, ",")
+ return fmt.Sprintf(`
+typedef void %s (*%s)(%s);
+void %s(%s f, void *n) {
+ int i;
+ for(i=0;i<(int)n;i++){
+ f(%s);
+ }
+}
+ `, attr, typename, params, funcname, typename, args)
+}
+
+func (f cbDLLFunc) build() string {
+ return f.buildOne(false) + f.buildOne(true)
+}
+
+var cbFuncs = [...]interface{}{
+ 2: func(i1, i2 uintptr) uintptr {
+ if i1+i2 != 3 {
+ panic("bad input")
+ }
+ return 0
+ },
+ 3: func(i1, i2, i3 uintptr) uintptr {
+ if i1+i2+i3 != 6 {
+ panic("bad input")
+ }
+ return 0
+ },
+ 4: func(i1, i2, i3, i4 uintptr) uintptr {
+ if i1+i2+i3+i4 != 10 {
+ panic("bad input")
+ }
+ return 0
+ },
+ 5: func(i1, i2, i3, i4, i5 uintptr) uintptr {
+ if i1+i2+i3+i4+i5 != 15 {
+ panic("bad input")
+ }
+ return 0
+ },
+ 6: func(i1, i2, i3, i4, i5, i6 uintptr) uintptr {
+ if i1+i2+i3+i4+i5+i6 != 21 {
+ panic("bad input")
+ }
+ return 0
+ },
+ 7: func(i1, i2, i3, i4, i5, i6, i7 uintptr) uintptr {
+ if i1+i2+i3+i4+i5+i6+i7 != 28 {
+ panic("bad input")
+ }
+ return 0
+ },
+ 8: func(i1, i2, i3, i4, i5, i6, i7, i8 uintptr) uintptr {
+ if i1+i2+i3+i4+i5+i6+i7+i8 != 36 {
+ panic("bad input")
+ }
+ return 0
+ },
+ 9: func(i1, i2, i3, i4, i5, i6, i7, i8, i9 uintptr) uintptr {
+ if i1+i2+i3+i4+i5+i6+i7+i8+i9 != 45 {
+ panic("bad input")
+ }
+ return 0
+ },
+}
+
+type cbDLL struct {
+ name string
+ buildArgs func(out, src string) []string
+}
+
+func (d *cbDLL) buildSrc(t *testing.T, path string) {
+ f, err := os.Create(path)
+ if err != nil {
+ t.Fatalf("failed to create source file: %v", err)
+ }
+ defer f.Close()
+
+ for i := 2; i < 10; i++ {
+ fmt.Fprint(f, cbDLLFunc(i).build())
+ }
+}
+
+func (d *cbDLL) build(t *testing.T, dir string) string {
+ srcname := d.name + ".c"
+ d.buildSrc(t, filepath.Join(dir, srcname))
+ outname := d.name + ".dll"
+ args := d.buildArgs(outname, srcname)
+ cmd := exec.Command(args[0], args[1:]...)
+ cmd.Dir = dir
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("failed to build dll: %v - %v", err, string(out))
+ }
+ return filepath.Join(dir, outname)
+}
+
+var cbDLLs = []cbDLL{
+ {
+ "test",
+ func(out, src string) []string {
+ return []string{"gcc", "-shared", "-s", "-o", out, src}
+ },
+ },
+ {
+ "testO2",
+ func(out, src string) []string {
+ return []string{"gcc", "-shared", "-s", "-o", out, "-O2", src}
+ },
+ },
+}
+
+type cbTest struct {
+ n int // number of callback parameters
+ param uintptr // dll function parameter
+}
+
+func (test *cbTest) run(t *testing.T, dllpath string) {
+ dll := syscall.MustLoadDLL(dllpath)
+ defer dll.Release()
+ cb := cbFuncs[test.n]
+ stdcall := syscall.NewCallback(cb)
+ f := cbDLLFunc(test.n)
+ test.runOne(t, dll, f.stdcallName(), stdcall)
+ cdecl := syscall.NewCallbackCDecl(cb)
+ test.runOne(t, dll, f.cdeclName(), cdecl)
+}
+
+func (test *cbTest) runOne(t *testing.T, dll *syscall.DLL, proc string, cb uintptr) {
+ defer func() {
+ if r := recover(); r != nil {
+ t.Errorf("dll call %v(..., %d) failed: %v", proc, test.param, r)
+ }
+ }()
+ dll.MustFindProc(proc).Call(cb, test.param)
+}
+
+var cbTests = []cbTest{
+ {2, 1},
+ {2, 10000},
+ {3, 3},
+ {4, 5},
+ {4, 6},
+ {5, 2},
+ {6, 7},
+ {6, 8},
+ {7, 6},
+ {8, 1},
+ {9, 8},
+ {9, 10000},
+ {3, 4},
+ {5, 3},
+ {7, 7},
+ {8, 2},
+ {9, 9},
+}
+
+func TestStdcallAndCDeclCallbacks(t *testing.T) {
+ tmp, err := ioutil.TempDir("", "TestCDeclCallback")
+ if err != nil {
+ t.Fatal("TempDir failed: ", err)
+ }
+ defer os.RemoveAll(tmp)
+
+ for _, dll := range cbDLLs {
+ dllPath := dll.build(t, tmp)
+ for _, test := range cbTests {
+ test.run(t, dllPath)
+ }
+ }
+}
diff --git a/src/pkg/runtime/time.goc b/src/pkg/runtime/time.goc
index b575696f7..712e03e83 100644
--- a/src/pkg/runtime/time.goc
+++ b/src/pkg/runtime/time.goc
@@ -21,11 +21,19 @@ static Timers timers;
static void addtimer(Timer*);
static void dumptimers(int8*);
+// 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");
@@ -46,6 +54,16 @@ func stopTimer(t *Timer) (stopped bool) {
// C runtime.
+void runtime·gc_unixnanotime(int64 *now);
+
+int64 runtime·unixnanotime(void)
+{
+ int64 now;
+
+ runtime·gc_unixnanotime(&now);
+ return now;
+}
+
static void timerproc(void);
static void siftup(int32);
static void siftdown(int32);
@@ -76,7 +94,7 @@ runtime·tsleep(int64 ns, int8 *reason)
t.arg.data = g;
runtime·lock(&timers);
addtimer(&t);
- runtime·park(runtime·unlock, &timers, reason);
+ runtime·parkunlock(&timers, reason);
}
static FuncVal timerprocv = {timerproc};
@@ -217,12 +235,22 @@ timerproc(void)
if(raceenabled)
runtime·raceacquire(t);
f(now, arg);
+
+ // clear f and arg to avoid leak while sleeping for next timer
+ f = nil;
+ USED(f);
+ arg.type = nil;
+ arg.data = 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)");
+ g->isbackground = true;
+ runtime·parkunlock(&timers, "timer goroutine (idle)");
+ g->isbackground = false;
continue;
}
// At least one timer pending. Sleep until then.
diff --git a/src/pkg/runtime/traceback_arm.c b/src/pkg/runtime/traceback_arm.c
index 8a3685e76..d15244c2a 100644
--- a/src/pkg/runtime/traceback_arm.c
+++ b/src/pkg/runtime/traceback_arm.c
@@ -8,17 +8,23 @@
#include "funcdata.h"
void runtime·sigpanic(void);
+void runtime·newproc(void);
+void runtime·deferproc(void);
int32
-runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max, void (*callback)(Stkframe*, void*), void *v, bool printall)
+runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max, bool (*callback)(Stkframe*, void*), void *v, bool printall)
{
- int32 i, n, nprint, line;
- uintptr x, tracepc;
- bool waspanic, printing;
+ int32 i, n, nprint, line, gotraceback;
+ uintptr x, tracepc, sparg;
+ bool waspanic, wasnewproc, printing;
Func *f, *flr;
Stkframe frame;
Stktop *stk;
String file;
+ Panic *panic;
+ Defer *defer;
+
+ gotraceback = runtime·gotraceback(nil);
if(pc0 == ~(uintptr)0 && sp0 == ~(uintptr)0) { // Signal to fetch saved values from gp.
if(gp->syscallstack != (uintptr)nil) {
@@ -38,8 +44,17 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
frame.lr = lr0;
frame.sp = sp0;
waspanic = false;
+ wasnewproc = false;
printing = pcbuf==nil && callback==nil;
+ panic = gp->panic;
+ defer = gp->defer;
+
+ while(defer != nil && defer->argp == NoArgs)
+ defer = defer->link;
+ while(panic != nil && panic->defer == nil)
+ panic = panic->link;
+
// If the PC is zero, it's likely a nil function call.
// Start in the caller's frame.
if(frame.pc == 0) {
@@ -95,6 +110,19 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
if(runtime·topofstack(f)) {
frame.lr = 0;
flr = nil;
+ } else if(f->entry == (uintptr)runtime·jmpdefer) {
+ // jmpdefer modifies SP/LR/PC non-atomically.
+ // If a profiling interrupt arrives during jmpdefer,
+ // the stack unwind may see a mismatched register set
+ // and get confused. Stop if we see PC within jmpdefer
+ // to avoid that confusion.
+ // See golang.org/issue/8153.
+ // This check can be deleted if jmpdefer is changed
+ // to restore all three atomically using pop.
+ if(callback != nil)
+ runtime·throw("traceback_arm: found jmpdefer when tracing with callback");
+ frame.lr = 0;
+ flr = nil;
} else {
if((n == 0 && frame.sp < frame.fp) || frame.lr == 0)
frame.lr = *(uintptr*)frame.sp;
@@ -133,6 +161,47 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
}
}
+ // Determine function SP where deferproc would find its arguments.
+ // On ARM that's just the standard bottom-of-stack plus 1 word for
+ // the saved LR. If the previous frame was a direct call to newproc/deferproc,
+ // however, the SP is three words lower than normal.
+ // If the function has no frame at all - perhaps it just started, or perhaps
+ // it is a leaf with no local variables - then we cannot possibly find its
+ // SP in a defer, and we might confuse its SP for its caller's SP, so
+ // set sparg=0 in that case.
+ sparg = 0;
+ if(frame.fp != frame.sp) {
+ sparg = frame.sp + sizeof(uintreg);
+ if(wasnewproc)
+ sparg += 3*sizeof(uintreg);
+ }
+
+ // Determine frame's 'continuation PC', where it can continue.
+ // Normally this is the return address on the stack, but if sigpanic
+ // is immediately below this function on the stack, then the frame
+ // stopped executing due to a trap, and frame.pc is probably not
+ // a safe point for looking up liveness information. In this panicking case,
+ // the function either doesn't return at all (if it has no defers or if the
+ // defers do not recover) or it returns from one of the calls to
+ // deferproc a second time (if the corresponding deferred func recovers).
+ // It suffices to assume that the most recent deferproc is the one that
+ // returns; everything live at earlier deferprocs is still live at that one.
+ frame.continpc = frame.pc;
+ if(waspanic) {
+ if(panic != nil && panic->defer->argp == (byte*)sparg)
+ frame.continpc = (uintptr)panic->defer->pc;
+ else if(defer != nil && defer->argp == (byte*)sparg)
+ frame.continpc = (uintptr)defer->pc;
+ else
+ frame.continpc = 0;
+ }
+
+ // Unwind our local panic & defer stacks past this frame.
+ while(panic != nil && (panic->defer == nil || panic->defer->argp == (byte*)sparg || panic->defer->argp == NoArgs))
+ panic = panic->link;
+ while(defer != nil && (defer->argp == (byte*)sparg || defer->argp == NoArgs))
+ defer = defer->link;
+
if(skip > 0) {
skip--;
goto skipped;
@@ -140,8 +209,10 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
if(pcbuf != nil)
pcbuf[n] = frame.pc;
- if(callback != nil)
- callback(&frame, v);
+ if(callback != nil) {
+ if(!callback(&frame, v))
+ return n;
+ }
if(printing) {
if(printall || runtime·showframe(f, gp)) {
// Print during crash.
@@ -152,7 +223,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
tracepc -= sizeof(uintptr);
runtime·printf("%s(", runtime·funcname(f));
for(i = 0; i < frame.arglen/sizeof(uintptr); i++) {
- if(i >= 5) {
+ if(i >= 10) {
runtime·prints(", ...");
break;
}
@@ -165,8 +236,8 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
runtime·printf("\t%S:%d", file, line);
if(frame.pc > f->entry)
runtime·printf(" +%p", (uintptr)(frame.pc - f->entry));
- if(m->throwing > 0 && gp == m->curg)
- runtime·printf(" fp=%p", frame.fp);
+ if(m->throwing > 0 && gp == m->curg || gotraceback >= 2)
+ runtime·printf(" fp=%p sp=%p", frame.fp, frame.sp);
runtime·printf("\n");
nprint++;
}
@@ -175,6 +246,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
skipped:
waspanic = f->entry == (uintptr)runtime·sigpanic;
+ wasnewproc = f->entry == (uintptr)runtime·newproc || f->entry == (uintptr)runtime·deferproc;
// Do not unwind past the bottom of the stack.
if(flr == nil)
@@ -202,6 +274,23 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
if(pcbuf == nil && callback == nil)
n = nprint;
+ // For rationale, see long comment in traceback_x86.c.
+ if(callback != nil && n < max && defer != nil) {
+ if(defer != nil)
+ runtime·printf("runtime: g%D: leftover defer argp=%p pc=%p\n", gp->goid, defer->argp, defer->pc);
+ if(panic != nil)
+ runtime·printf("runtime: g%D: leftover panic argp=%p pc=%p\n", gp->goid, panic->defer->argp, panic->defer->pc);
+ for(defer = gp->defer; defer != nil; defer = defer->link)
+ runtime·printf("\tdefer %p argp=%p pc=%p\n", defer, defer->argp, defer->pc);
+ for(panic = gp->panic; panic != nil; panic = panic->link) {
+ runtime·printf("\tpanic %p defer %p", panic, panic->defer);
+ if(panic->defer != nil)
+ runtime·printf(" argp=%p pc=%p", panic->defer->argp, panic->defer->pc);
+ runtime·printf("\n");
+ }
+ runtime·throw("traceback has leftover defers or panics");
+ }
+
return n;
}
@@ -231,6 +320,8 @@ runtime·printcreatedby(G *gp)
void
runtime·traceback(uintptr pc, uintptr sp, uintptr lr, G *gp)
{
+ int32 n;
+
if(gp->status == Gsyscall) {
// Override signal registers if blocked in system call.
pc = gp->syscallpc;
@@ -240,8 +331,11 @@ runtime·traceback(uintptr pc, uintptr sp, uintptr lr, G *gp)
// Print traceback. By default, omits runtime frames.
// If that means we print nothing at all, repeat forcing all frames printed.
- if(runtime·gentraceback(pc, sp, lr, gp, 0, nil, 100, nil, nil, false) == 0)
- runtime·gentraceback(pc, sp, lr, gp, 0, nil, 100, nil, nil, true);
+ n = runtime·gentraceback(pc, sp, lr, gp, 0, nil, TracebackMaxFrames, nil, nil, false);
+ if(n == 0)
+ runtime·gentraceback(pc, sp, lr, gp, 0, nil, TracebackMaxFrames, nil, nil, true);
+ if(n == TracebackMaxFrames)
+ runtime·printf("...additional frames elided...\n");
runtime·printcreatedby(gp);
}
diff --git a/src/pkg/runtime/traceback_x86.c b/src/pkg/runtime/traceback_x86.c
index 8e3063f43..851504f52 100644
--- a/src/pkg/runtime/traceback_x86.c
+++ b/src/pkg/runtime/traceback_x86.c
@@ -2,14 +2,23 @@
// 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 386
#include "runtime.h"
#include "arch_GOARCH.h"
#include "malloc.h"
#include "funcdata.h"
+#ifdef GOOS_windows
+#include "defs_GOOS_GOARCH.h"
+#endif
void runtime·sigpanic(void);
+void runtime·newproc(void);
+void runtime·deferproc(void);
+
+#ifdef GOOS_windows
+void runtime·sigtramp(void);
+#endif
// This code is also used for the 386 tracebacks.
// Use uintptr for an appropriate word-sized integer.
@@ -19,18 +28,22 @@ void runtime·sigpanic(void);
// collector (callback != nil). A little clunky to merge these, but avoids
// duplicating the code and all its subtlety.
int32
-runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max, void (*callback)(Stkframe*, void*), void *v, bool printall)
+runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max, bool (*callback)(Stkframe*, void*), void *v, bool printall)
{
- int32 i, n, nprint, line;
- uintptr tracepc;
- bool waspanic, printing;
+ int32 i, n, nprint, line, gotraceback;
+ uintptr tracepc, sparg;
+ bool waspanic, wasnewproc, printing;
Func *f, *flr;
Stkframe frame;
Stktop *stk;
String file;
+ Panic *panic;
+ Defer *defer;
USED(lr0);
+ gotraceback = runtime·gotraceback(nil);
+
if(pc0 == ~(uintptr)0 && sp0 == ~(uintptr)0) { // Signal to fetch saved values from gp.
if(gp->syscallstack != (uintptr)nil) {
pc0 = gp->syscallpc;
@@ -46,13 +59,21 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
frame.pc = pc0;
frame.sp = sp0;
waspanic = false;
+ wasnewproc = false;
printing = pcbuf==nil && callback==nil;
-
+ panic = gp->panic;
+ defer = gp->defer;
+
+ while(defer != nil && defer->argp == NoArgs)
+ defer = defer->link;
+ while(panic != nil && panic->defer == nil)
+ panic = panic->link;
+
// If the PC is zero, it's likely a nil function call.
// Start in the caller's frame.
if(frame.pc == 0) {
frame.pc = *(uintptr*)frame.sp;
- frame.sp += sizeof(uintptr);
+ frame.sp += sizeof(uintreg);
}
f = runtime·findfunc(frame.pc);
@@ -95,20 +116,63 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
frame.fn = f;
continue;
}
+
f = frame.fn;
+#ifdef GOOS_windows
+ // Windows exception handlers run on the actual g stack (there is room
+ // dedicated to this below the usual "bottom of stack"), not on a separate
+ // stack. As a result, we have to be able to unwind past the exception
+ // handler when called to unwind during stack growth inside the handler.
+ // Recognize the frame at the call to sighandler in sigtramp and unwind
+ // using the context argument passed to the call. This is awful.
+ if(f != nil && f->entry == (uintptr)runtime·sigtramp && frame.pc > f->entry) {
+ Context *r;
+
+ // Invoke callback so that stack copier sees an uncopyable frame.
+ if(callback != nil) {
+ frame.continpc = frame.pc;
+ frame.argp = nil;
+ frame.arglen = 0;
+ if(!callback(&frame, v))
+ return n;
+ }
+ r = (Context*)((uintptr*)frame.sp)[1];
+#ifdef GOARCH_amd64
+ frame.pc = r->Rip;
+ frame.sp = r->Rsp;
+#else
+ frame.pc = r->Eip;
+ frame.sp = r->Esp;
+#endif
+ frame.lr = 0;
+ frame.fp = 0;
+ frame.fn = nil;
+ if(printing && runtime·showframe(nil, gp))
+ runtime·printf("----- exception handler -----\n");
+ f = runtime·findfunc(frame.pc);
+ if(f == nil) {
+ runtime·printf("runtime: unknown pc %p after exception handler\n", frame.pc);
+ if(callback != nil)
+ runtime·throw("unknown pc");
+ }
+ frame.fn = f;
+ continue;
+ }
+#endif
+
// Found an actual function.
// Derive frame pointer and link register.
if(frame.fp == 0) {
frame.fp = frame.sp + runtime·funcspdelta(f, frame.pc);
- frame.fp += sizeof(uintptr); // caller PC
+ frame.fp += sizeof(uintreg); // caller PC
}
if(runtime·topofstack(f)) {
frame.lr = 0;
flr = nil;
} else {
if(frame.lr == 0)
- frame.lr = ((uintptr*)frame.fp)[-1];
+ frame.lr = ((uintreg*)frame.fp)[-1];
flr = runtime·findfunc(frame.lr);
if(flr == nil) {
runtime·printf("runtime: unexpected return pc for %s called from %p\n", runtime·funcname(f), frame.lr);
@@ -117,7 +181,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
}
}
- frame.varp = (byte*)frame.fp - sizeof(uintptr);
+ frame.varp = (byte*)frame.fp - sizeof(uintreg);
// Derive size of arguments.
// Most functions have a fixed-size argument block,
@@ -143,6 +207,40 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
frame.arglen = 0;
}
}
+
+ // Determine function SP where deferproc would find its arguments.
+ // On x86 that's just the standard bottom-of-stack, so SP exactly.
+ // If the previous frame was a direct call to newproc/deferproc, however,
+ // the SP is two words lower than normal.
+ sparg = frame.sp;
+ if(wasnewproc)
+ sparg += 2*sizeof(uintreg);
+
+ // Determine frame's 'continuation PC', where it can continue.
+ // Normally this is the return address on the stack, but if sigpanic
+ // is immediately below this function on the stack, then the frame
+ // stopped executing due to a trap, and frame.pc is probably not
+ // a safe point for looking up liveness information. In this panicking case,
+ // the function either doesn't return at all (if it has no defers or if the
+ // defers do not recover) or it returns from one of the calls to
+ // deferproc a second time (if the corresponding deferred func recovers).
+ // It suffices to assume that the most recent deferproc is the one that
+ // returns; everything live at earlier deferprocs is still live at that one.
+ frame.continpc = frame.pc;
+ if(waspanic) {
+ if(panic != nil && panic->defer->argp == (byte*)sparg)
+ frame.continpc = (uintptr)panic->defer->pc;
+ else if(defer != nil && defer->argp == (byte*)sparg)
+ frame.continpc = (uintptr)defer->pc;
+ else
+ frame.continpc = 0;
+ }
+
+ // Unwind our local panic & defer stacks past this frame.
+ while(panic != nil && (panic->defer == nil || panic->defer->argp == (byte*)sparg || panic->defer->argp == NoArgs))
+ panic = panic->link;
+ while(defer != nil && (defer->argp == (byte*)sparg || defer->argp == NoArgs))
+ defer = defer->link;
if(skip > 0) {
skip--;
@@ -151,8 +249,10 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
if(pcbuf != nil)
pcbuf[n] = frame.pc;
- if(callback != nil)
- callback(&frame, v);
+ if(callback != nil) {
+ if(!callback(&frame, v))
+ return n;
+ }
if(printing) {
if(printall || runtime·showframe(f, gp)) {
// Print during crash.
@@ -164,7 +264,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
tracepc--;
runtime·printf("%s(", runtime·funcname(f));
for(i = 0; i < frame.arglen/sizeof(uintptr); i++) {
- if(i >= 5) {
+ if(i >= 10) {
runtime·prints(", ...");
break;
}
@@ -177,8 +277,8 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
runtime·printf("\t%S:%d", file, line);
if(frame.pc > f->entry)
runtime·printf(" +%p", (uintptr)(frame.pc - f->entry));
- if(m->throwing > 0 && gp == m->curg)
- runtime·printf(" fp=%p", frame.fp);
+ if(m->throwing > 0 && gp == m->curg || gotraceback >= 2)
+ runtime·printf(" fp=%p sp=%p", frame.fp, frame.sp);
runtime·printf("\n");
nprint++;
}
@@ -187,6 +287,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
skipped:
waspanic = f->entry == (uintptr)runtime·sigpanic;
+ wasnewproc = f->entry == (uintptr)runtime·newproc || f->entry == (uintptr)runtime·deferproc;
// Do not unwind past the bottom of the stack.
if(flr == nil)
@@ -202,7 +303,72 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
if(pcbuf == nil && callback == nil)
n = nprint;
-
+
+ // If callback != nil, we're being called to gather stack information during
+ // garbage collection or stack growth. In that context, require that we used
+ // up the entire defer stack. If not, then there is a bug somewhere and the
+ // garbage collection or stack growth may not have seen the correct picture
+ // of the stack. Crash now instead of silently executing the garbage collection
+ // or stack copy incorrectly and setting up for a mysterious crash later.
+ //
+ // Note that panic != nil is okay here: there can be leftover panics,
+ // because the defers on the panic stack do not nest in frame order as
+ // they do on the defer stack. If you have:
+ //
+ // frame 1 defers d1
+ // frame 2 defers d2
+ // frame 3 defers d3
+ // frame 4 panics
+ // frame 4's panic starts running defers
+ // frame 5, running d3, defers d4
+ // frame 5 panics
+ // frame 5's panic starts running defers
+ // frame 6, running d4, garbage collects
+ // frame 6, running d2, garbage collects
+ //
+ // During the execution of d4, the panic stack is d4 -> d3, which
+ // is nested properly, and we'll treat frame 3 as resumable, because we
+ // can find d3. (And in fact frame 3 is resumable. If d4 recovers
+ // and frame 5 continues running, d3, d3 can recover and we'll
+ // resume execution in (returning from) frame 3.)
+ //
+ // During the execution of d2, however, the panic stack is d2 -> d3,
+ // which is inverted. The scan will match d2 to frame 2 but having
+ // d2 on the stack until then means it will not match d3 to frame 3.
+ // This is okay: if we're running d2, then all the defers after d2 have
+ // completed and their corresponding frames are dead. Not finding d3
+ // for frame 3 means we'll set frame 3's continpc == 0, which is correct
+ // (frame 3 is dead). At the end of the walk the panic stack can thus
+ // contain defers (d3 in this case) for dead frames. The inversion here
+ // always indicates a dead frame, and the effect of the inversion on the
+ // scan is to hide those dead frames, so the scan is still okay:
+ // what's left on the panic stack are exactly (and only) the dead frames.
+ //
+ // We require callback != nil here because only when callback != nil
+ // do we know that gentraceback is being called in a "must be correct"
+ // context as opposed to a "best effort" context. The tracebacks with
+ // callbacks only happen when everything is stopped nicely.
+ // At other times, such as when gathering a stack for a profiling signal
+ // or when printing a traceback during a crash, everything may not be
+ // stopped nicely, and the stack walk may not be able to complete.
+ // It's okay in those situations not to use up the entire defer stack:
+ // incomplete information then is still better than nothing.
+ if(callback != nil && n < max && defer != nil) {
+ if(defer != nil)
+ runtime·printf("runtime: g%D: leftover defer argp=%p pc=%p\n", gp->goid, defer->argp, defer->pc);
+ if(panic != nil)
+ runtime·printf("runtime: g%D: leftover panic argp=%p pc=%p\n", gp->goid, panic->defer->argp, panic->defer->pc);
+ for(defer = gp->defer; defer != nil; defer = defer->link)
+ runtime·printf("\tdefer %p argp=%p pc=%p\n", defer, defer->argp, defer->pc);
+ for(panic = gp->panic; panic != nil; panic = panic->link) {
+ runtime·printf("\tpanic %p defer %p", panic, panic->defer);
+ if(panic->defer != nil)
+ runtime·printf(" argp=%p pc=%p", panic->defer->argp, panic->defer->pc);
+ runtime·printf("\n");
+ }
+ runtime·throw("traceback has leftover defers or panics");
+ }
+
return n;
}
@@ -232,6 +398,8 @@ runtime·printcreatedby(G *gp)
void
runtime·traceback(uintptr pc, uintptr sp, uintptr lr, G *gp)
{
+ int32 n;
+
USED(lr);
if(gp->status == Gsyscall) {
@@ -242,8 +410,11 @@ runtime·traceback(uintptr pc, uintptr sp, uintptr lr, G *gp)
// Print traceback. By default, omits runtime frames.
// If that means we print nothing at all, repeat forcing all frames printed.
- if(runtime·gentraceback(pc, sp, 0, gp, 0, nil, 100, nil, nil, false) == 0)
- runtime·gentraceback(pc, sp, 0, gp, 0, nil, 100, nil, nil, true);
+ n = runtime·gentraceback(pc, sp, 0, gp, 0, nil, TracebackMaxFrames, nil, nil, false);
+ if(n == 0)
+ n = runtime·gentraceback(pc, sp, 0, gp, 0, nil, TracebackMaxFrames, nil, nil, true);
+ if(n == TracebackMaxFrames)
+ runtime·printf("...additional frames elided...\n");
runtime·printcreatedby(gp);
}
diff --git a/src/pkg/runtime/type.go b/src/pkg/runtime/type.go
index 374754afa..276dbc0c9 100644
--- a/src/pkg/runtime/type.go
+++ b/src/pkg/runtime/type.go
@@ -26,6 +26,7 @@ type rtype struct {
string *string
*uncommonType
ptrToThis *rtype
+ zero unsafe.Pointer
}
type _method struct {
diff --git a/src/pkg/runtime/type.h b/src/pkg/runtime/type.h
index 30936046c..1598acc18 100644
--- a/src/pkg/runtime/type.h
+++ b/src/pkg/runtime/type.h
@@ -15,9 +15,8 @@ typedef struct Method Method;
typedef struct IMethod IMethod;
typedef struct SliceType SliceType;
typedef struct FuncType FuncType;
-typedef struct PtrType PtrType;
-// Needs to be in sync with typekind.h/CommonSize
+// Needs to be in sync with ../../cmd/ld/decodesym.c:/^commonsize
struct Type
{
uintptr size;
@@ -31,6 +30,7 @@ struct Type
String *string;
UncommonType *x;
Type *ptrto;
+ byte *zero; // ptr to the zero value for this type
};
struct Method
@@ -100,7 +100,3 @@ struct PtrType
Type;
Type *elem;
};
-
-// Here instead of in runtime.h because it uses the type names.
-bool runtime·addfinalizer(void*, FuncVal *fn, uintptr, Type*, PtrType*);
-bool runtime·getfinalizer(void *p, bool del, FuncVal **fn, uintptr *nret, Type**, PtrType**);
diff --git a/src/pkg/runtime/typekind.h b/src/pkg/runtime/typekind.h
index 9bae2a871..3f0ba9acb 100644
--- a/src/pkg/runtime/typekind.h
+++ b/src/pkg/runtime/typekind.h
@@ -34,8 +34,5 @@ enum {
KindUnsafePointer,
KindNoPointers = 1<<7,
-
- // size of Type structure.
- CommonSize = 6*PtrSize + 8,
};
diff --git a/src/pkg/runtime/vlop_arm.s b/src/pkg/runtime/vlop_arm.s
index d7c566afb..80f516ec4 100644
--- a/src/pkg/runtime/vlop_arm.s
+++ b/src/pkg/runtime/vlop_arm.s
@@ -75,10 +75,14 @@ TEXT _sfloat(SB), NOSPLIT, $64-0 // 4 arg + 14*4 saved regs + cpsr
MOVW m_locks(m), R1
ADD $1, R1
MOVW R1, m_locks(m)
+ MOVW $1, R1
+ MOVW R1, m_softfloat(m)
BL runtime·_sfloat2(SB)
MOVW m_locks(m), R1
SUB $1, R1
MOVW R1, m_locks(m)
+ MOVW $0, R1
+ MOVW R1, m_softfloat(m)
MOVW R0, 0(R13)
MOVW 64(R13), R1
WORD $0xe128f001 // msr cpsr_f, r1
@@ -255,7 +259,7 @@ TEXT _div(SB),NOSPLIT,$16
d0:
BL udiv<>(SB) /* none/both neg */
MOVW R(q), R(TMP)
- B out
+ B out1
d1:
CMP $0, R(q)
BGE d0
@@ -263,7 +267,12 @@ d1:
d2:
BL udiv<>(SB) /* one neg */
RSB $0, R(q), R(TMP)
- B out
+out1:
+ MOVW 4(R13), R(q)
+ MOVW 8(R13), R(r)
+ MOVW 12(R13), R(s)
+ MOVW 16(R13), R(M)
+ RET
TEXT _mod(SB),NOSPLIT,$16
MOVW R(q), 4(R13)
diff --git a/src/pkg/runtime/vlrt_386.c b/src/pkg/runtime/vlrt_386.c
index 8d965c086..ace1beb4c 100644
--- a/src/pkg/runtime/vlrt_386.c
+++ b/src/pkg/runtime/vlrt_386.c
@@ -32,6 +32,8 @@
* to generate the code directly now. Find and remove.
*/
+extern void runtime·panicdivide(void);
+
typedef unsigned long ulong;
typedef unsigned int uint;
typedef unsigned short ushort;
@@ -240,6 +242,8 @@ dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp)
}
} else {
if(num.hi >= den.lo){
+ if(den.lo == 0)
+ runtime·panicdivide();
q.hi = n = num.hi/den.lo;
num.hi -= den.lo*n;
} else {
@@ -263,6 +267,8 @@ _divvu(Vlong *q, Vlong n, Vlong d)
{
if(n.hi == 0 && d.hi == 0) {
+ if(d.lo == 0)
+ runtime·panicdivide();
q->hi = 0;
q->lo = n.lo / d.lo;
return;
@@ -281,6 +287,8 @@ _modvu(Vlong *r, Vlong n, Vlong d)
{
if(n.hi == 0 && d.hi == 0) {
+ if(d.lo == 0)
+ runtime·panicdivide();
r->hi = 0;
r->lo = n.lo % d.lo;
return;
@@ -319,6 +327,8 @@ _divv(Vlong *q, Vlong n, Vlong d)
q->hi = 0;
return;
}
+ if(d.lo == 0)
+ runtime·panicdivide();
q->lo = (long)n.lo / (long)d.lo;
q->hi = ((long)q->lo) >> 31;
return;
@@ -353,6 +363,8 @@ _modv(Vlong *r, Vlong n, Vlong d)
r->hi = 0;
return;
}
+ if(d.lo == 0)
+ runtime·panicdivide();
r->lo = (long)n.lo % (long)d.lo;
r->hi = ((long)r->lo) >> 31;
return;
diff --git a/src/pkg/runtime/vlrt_arm.c b/src/pkg/runtime/vlrt_arm.c
index 219163c60..7dd71b40e 100644
--- a/src/pkg/runtime/vlrt_arm.c
+++ b/src/pkg/runtime/vlrt_arm.c
@@ -27,6 +27,7 @@
// declared here to avoid include of runtime.h
void runtime·panicstring(char*);
+void runtime·panicdivide(void);
typedef unsigned long ulong;
typedef unsigned int uint;
@@ -36,12 +37,6 @@ typedef signed char schar;
#define SIGN(n) (1UL<<(n-1))
-void
-runtime·panicdivide(void)
-{
- runtime·panicstring("integer divide by zero");
-}
-
typedef struct Vlong Vlong;
struct Vlong
{
diff --git a/src/pkg/sort/sort.go b/src/pkg/sort/sort.go
index f06eb3827..e980c295c 100644
--- a/src/pkg/sort/sort.go
+++ b/src/pkg/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/src/pkg/strconv/atob_test.go b/src/pkg/strconv/atob_test.go
index a7c1454eb..28f469f58 100644
--- a/src/pkg/strconv/atob_test.go
+++ b/src/pkg/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/src/pkg/strconv/atof.go b/src/pkg/strconv/atof.go
index 1b3f8fb33..286206481 100644
--- a/src/pkg/strconv/atof.go
+++ b/src/pkg/strconv/atof.go
@@ -353,17 +353,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/src/pkg/strconv/atoi.go b/src/pkg/strconv/atoi.go
index 2d0db7155..cbf0380ec 100644
--- a/src/pkg/strconv/atoi.go
+++ b/src/pkg/strconv/atoi.go
@@ -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/src/pkg/strconv/isprint.go b/src/pkg/strconv/isprint.go
index db5f0fbae..91f179535 100644
--- a/src/pkg/strconv/isprint.go
+++ b/src/pkg/strconv/isprint.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.
+
// DO NOT EDIT. GENERATED BY
// go run makeisprint.go >x && mv x isprint.go
diff --git a/src/pkg/strconv/makeisprint.go b/src/pkg/strconv/makeisprint.go
index 8a6699bdb..216159cc0 100644
--- a/src/pkg/strconv/makeisprint.go
+++ b/src/pkg/strconv/makeisprint.go
@@ -122,6 +122,9 @@ func main() {
}
}
+ fmt.Printf(`// 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.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")
diff --git a/src/pkg/strconv/quote.go b/src/pkg/strconv/quote.go
index 7d6cdcf0b..aded7e593 100644
--- a/src/pkg/strconv/quote.go
+++ b/src/pkg/strconv/quote.go
@@ -144,7 +144,8 @@ func AppendQuoteRuneToASCII(dst []byte, r rune) []byte {
// characters other than space and tab.
func CanBackquote(s string) bool {
for i := 0; i < len(s); i++ {
- if (s[i] < ' ' && s[i] != '\t') || s[i] == '`' {
+ c := s[i]
+ if (c < ' ' && c != '\t') || c == '`' || c == '\u007F' {
return false
}
}
diff --git a/src/pkg/strconv/quote_example_test.go b/src/pkg/strconv/quote_example_test.go
new file mode 100644
index 000000000..405a57eb5
--- /dev/null
+++ b/src/pkg/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/src/pkg/strconv/quote_test.go b/src/pkg/strconv/quote_test.go
index 61d9bf9a5..e4b5b6b9f 100644
--- a/src/pkg/strconv/quote_test.go
+++ b/src/pkg/strconv/quote_test.go
@@ -140,6 +140,7 @@ var canbackquotetests = []canBackquoteTest{
{string(29), false},
{string(30), false},
{string(31), false},
+ {string(0x7F), false},
{`' !"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, true},
{`0123456789`, true},
{`ABCDEFGHIJKLMNOPQRSTUVWXYZ`, true},
diff --git a/src/pkg/strings/example_test.go b/src/pkg/strings/example_test.go
index 36e0a42fb..7243e16b1 100644
--- a/src/pkg/strings/example_test.go
+++ b/src/pkg/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/src/pkg/strings/reader.go b/src/pkg/strings/reader.go
index 11240efc0..82df97439 100644
--- a/src/pkg/strings/reader.go
+++ b/src/pkg/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/src/pkg/strings/reader_test.go b/src/pkg/strings/reader_test.go
index 4fdddcdb5..bee90eb25 100644
--- a/src/pkg/strings/reader_test.go
+++ b/src/pkg/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/src/pkg/strings/replace.go b/src/pkg/strings/replace.go
index 54c9323e0..3e05d2057 100644
--- a/src/pkg/strings/replace.go
+++ b/src/pkg/strings/replace.go
@@ -492,7 +492,7 @@ func (r *byteStringReplacer) Replace(s string) string {
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])
+ n := copy(bi, r.new[b])
bi = bi[n:]
} else {
bi[0] = b
diff --git a/src/pkg/strings/strings_test.go b/src/pkg/strings/strings_test.go
index df0dd7165..e40a18015 100644
--- a/src/pkg/strings/strings_test.go
+++ b/src/pkg/strings/strings_test.go
@@ -652,7 +652,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 +858,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 +929,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) {
diff --git a/src/pkg/sync/atomic/asm_386.s b/src/pkg/sync/atomic/asm_386.s
index eaa72eabb..807c2f873 100644
--- a/src/pkg/sync/atomic/asm_386.s
+++ b/src/pkg/sync/atomic/asm_386.s
@@ -13,7 +13,7 @@ TEXT ·SwapUint32(SB),NOSPLIT,$0-12
MOVL addr+0(FP), BP
MOVL new+4(FP), AX
XCHGL AX, 0(BP)
- MOVL AX, new+8(FP)
+ MOVL AX, old+8(FP)
RET
TEXT ·SwapInt64(SB),NOSPLIT,$0-20
@@ -43,8 +43,8 @@ swaploop:
// success
// return DX:AX
- MOVL AX, new_lo+12(FP)
- MOVL DX, new_hi+16(FP)
+ MOVL AX, old_lo+12(FP)
+ MOVL DX, old_hi+16(FP)
RET
TEXT ·SwapUintptr(SB),NOSPLIT,$0-12
@@ -155,10 +155,10 @@ TEXT ·LoadUint32(SB),NOSPLIT,$0-8
MOVL AX, val+4(FP)
RET
-TEXT ·LoadInt64(SB),NOSPLIT,$0-16
+TEXT ·LoadInt64(SB),NOSPLIT,$0-12
JMP ·LoadUint64(SB)
-TEXT ·LoadUint64(SB),NOSPLIT,$0-16
+TEXT ·LoadUint64(SB),NOSPLIT,$0-12
MOVL addr+0(FP), AX
TESTL $7, AX
JZ 2(PC)
@@ -186,10 +186,10 @@ TEXT ·StoreUint32(SB),NOSPLIT,$0-8
XCHGL AX, 0(BP)
RET
-TEXT ·StoreInt64(SB),NOSPLIT,$0-16
+TEXT ·StoreInt64(SB),NOSPLIT,$0-12
JMP ·StoreUint64(SB)
-TEXT ·StoreUint64(SB),NOSPLIT,$0-16
+TEXT ·StoreUint64(SB),NOSPLIT,$0-12
MOVL addr+0(FP), AX
TESTL $7, AX
JZ 2(PC)
diff --git a/src/pkg/sync/atomic/asm_amd64.s b/src/pkg/sync/atomic/asm_amd64.s
index 0900492dc..77afa129e 100644
--- a/src/pkg/sync/atomic/asm_amd64.s
+++ b/src/pkg/sync/atomic/asm_amd64.s
@@ -13,7 +13,7 @@ TEXT ·SwapUint32(SB),NOSPLIT,$0-20
MOVQ addr+0(FP), BP
MOVL new+8(FP), AX
XCHGL AX, 0(BP)
- MOVL AX, new+16(FP)
+ MOVL AX, old+16(FP)
RET
TEXT ·SwapInt64(SB),NOSPLIT,$0-24
@@ -23,7 +23,7 @@ TEXT ·SwapUint64(SB),NOSPLIT,$0-24
MOVQ addr+0(FP), BP
MOVQ new+8(FP), AX
XCHGQ AX, 0(BP)
- MOVQ AX, new+16(FP)
+ MOVQ AX, old+16(FP)
RET
TEXT ·SwapUintptr(SB),NOSPLIT,$0-24
diff --git a/src/pkg/sync/atomic/asm_amd64p32.s b/src/pkg/sync/atomic/asm_amd64p32.s
new file mode 100644
index 000000000..b24ae7a59
--- /dev/null
+++ b/src/pkg/sync/atomic/asm_amd64p32.s
@@ -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.
+
+#include "../../../cmd/ld/textflag.h"
+
+TEXT ·SwapInt32(SB),NOSPLIT,$0-12
+ JMP ·SwapUint32(SB)
+
+TEXT ·SwapUint32(SB),NOSPLIT,$0-12
+ MOVL addr+0(FP), BX
+ MOVL new+4(FP), AX
+ XCHGL AX, 0(BX)
+ MOVL AX, old+8(FP)
+ RET
+
+TEXT ·SwapInt64(SB),NOSPLIT,$0-24
+ JMP ·SwapUint64(SB)
+
+TEXT ·SwapUint64(SB),NOSPLIT,$0-24
+ MOVL addr+0(FP), BX
+ TESTL $7, BX
+ JZ 2(PC)
+ MOVL 0, BX // crash with nil ptr deref
+ MOVQ new+8(FP), AX
+ XCHGQ AX, 0(BX)
+ MOVQ AX, old+16(FP)
+ RET
+
+TEXT ·SwapUintptr(SB),NOSPLIT,$0-12
+ JMP ·SwapUint32(SB)
+
+TEXT ·SwapPointer(SB),NOSPLIT,$0-12
+ JMP ·SwapUint32(SB)
+
+TEXT ·CompareAndSwapInt32(SB),NOSPLIT,$0-17
+ JMP ·CompareAndSwapUint32(SB)
+
+TEXT ·CompareAndSwapUint32(SB),NOSPLIT,$0-17
+ MOVL addr+0(FP), BX
+ MOVL old+4(FP), AX
+ MOVL new+8(FP), CX
+ LOCK
+ CMPXCHGL CX, 0(BX)
+ SETEQ swapped+16(FP)
+ RET
+
+TEXT ·CompareAndSwapUintptr(SB),NOSPLIT,$0-17
+ JMP ·CompareAndSwapUint32(SB)
+
+TEXT ·CompareAndSwapPointer(SB),NOSPLIT,$0-17
+ JMP ·CompareAndSwapUint32(SB)
+
+TEXT ·CompareAndSwapInt64(SB),NOSPLIT,$0-25
+ JMP ·CompareAndSwapUint64(SB)
+
+TEXT ·CompareAndSwapUint64(SB),NOSPLIT,$0-25
+ MOVL addr+0(FP), BX
+ TESTL $7, BX
+ JZ 2(PC)
+ MOVL 0, BX // crash with nil ptr deref
+ MOVQ old+8(FP), AX
+ MOVQ new+16(FP), CX
+ LOCK
+ CMPXCHGQ CX, 0(BX)
+ SETEQ swapped+24(FP)
+ RET
+
+TEXT ·AddInt32(SB),NOSPLIT,$0-12
+ JMP ·AddUint32(SB)
+
+TEXT ·AddUint32(SB),NOSPLIT,$0-12
+ MOVL addr+0(FP), BX
+ MOVL delta+4(FP), AX
+ MOVL AX, CX
+ LOCK
+ XADDL AX, 0(BX)
+ ADDL AX, CX
+ MOVL CX, new+8(FP)
+ RET
+
+TEXT ·AddUintptr(SB),NOSPLIT,$0-12
+ JMP ·AddUint32(SB)
+
+TEXT ·AddInt64(SB),NOSPLIT,$0-24
+ JMP ·AddUint64(SB)
+
+TEXT ·AddUint64(SB),NOSPLIT,$0-24
+ MOVL addr+0(FP), BX
+ TESTL $7, BX
+ JZ 2(PC)
+ MOVL 0, BX // crash with nil ptr deref
+ MOVQ delta+8(FP), AX
+ MOVQ AX, CX
+ LOCK
+ XADDQ AX, 0(BX)
+ ADDQ AX, CX
+ MOVQ CX, new+16(FP)
+ RET
+
+TEXT ·LoadInt32(SB),NOSPLIT,$0-12
+ JMP ·LoadUint32(SB)
+
+TEXT ·LoadUint32(SB),NOSPLIT,$0-12
+ MOVL addr+0(FP), AX
+ MOVL 0(AX), AX
+ MOVL AX, val+8(FP)
+ RET
+
+TEXT ·LoadInt64(SB),NOSPLIT,$0-16
+ JMP ·LoadUint64(SB)
+
+TEXT ·LoadUint64(SB),NOSPLIT,$0-16
+ MOVL addr+0(FP), AX
+ TESTL $7, AX
+ JZ 2(PC)
+ MOVL 0, AX // crash with nil ptr deref
+ MOVQ 0(AX), AX
+ MOVQ AX, val+8(FP)
+ RET
+
+TEXT ·LoadUintptr(SB),NOSPLIT,$0-12
+ JMP ·LoadPointer(SB)
+
+TEXT ·LoadPointer(SB),NOSPLIT,$0-12
+ MOVL addr+0(FP), AX
+ MOVL 0(AX), AX
+ MOVL AX, val+8(FP)
+ RET
+
+TEXT ·StoreInt32(SB),NOSPLIT,$0-8
+ JMP ·StoreUint32(SB)
+
+TEXT ·StoreUint32(SB),NOSPLIT,$0-8
+ MOVL addr+0(FP), BX
+ MOVL val+4(FP), AX
+ XCHGL AX, 0(BX)
+ RET
+
+TEXT ·StoreInt64(SB),NOSPLIT,$0-16
+ JMP ·StoreUint64(SB)
+
+TEXT ·StoreUint64(SB),NOSPLIT,$0-16
+ MOVL addr+0(FP), BX
+ TESTL $7, BX
+ JZ 2(PC)
+ MOVL 0, BX // crash with nil ptr deref
+ MOVQ val+8(FP), AX
+ XCHGQ AX, 0(BX)
+ RET
+
+TEXT ·StoreUintptr(SB),NOSPLIT,$0-8
+ JMP ·StorePointer(SB)
+
+TEXT ·StorePointer(SB),NOSPLIT,$0-8
+ MOVL addr+0(FP), BX
+ MOVL val+4(FP), AX
+ XCHGL AX, 0(BX)
+ RET
diff --git a/src/pkg/sync/atomic/asm_linux_arm.s b/src/pkg/sync/atomic/asm_linux_arm.s
index b85ca0a13..27be57aa1 100644
--- a/src/pkg/sync/atomic/asm_linux_arm.s
+++ b/src/pkg/sync/atomic/asm_linux_arm.s
@@ -42,7 +42,7 @@ casagain:
BCC cascheck
MOVW $1, R0
casret:
- MOVW R0, ret+12(FP)
+ MOVB R0, swapped+12(FP)
RET
cascheck:
// Kernel lies; double-check.
@@ -73,7 +73,7 @@ addloop1:
ADD R4, R1
BL cas<>(SB)
BCC addloop1
- MOVW R1, ret+8(FP)
+ MOVW R1, new+8(FP)
RET
TEXT ·AddUintptr(SB),NOSPLIT,$0
@@ -132,13 +132,13 @@ TEXT ·generalCAS64(SB),NOSPLIT,$20-21
BEQ 2(PC)
MOVW R1, (R1)
MOVW R0, 4(R13)
- MOVW oldlo+4(FP), R1
+ MOVW old_lo+4(FP), R1
MOVW R1, 8(R13)
- MOVW oldhi+8(FP), R1
+ MOVW old_hi+8(FP), R1
MOVW R1, 12(R13)
- MOVW newlo+12(FP), R2
+ MOVW new_lo+12(FP), R2
MOVW R2, 16(R13)
- MOVW newhi+16(FP), R3
+ MOVW new_hi+16(FP), R3
MOVW R3, 20(R13)
BL runtime·cas64(SB)
MOVB R0, ret+20(FP)
diff --git a/src/pkg/sync/atomic/atomic_test.go b/src/pkg/sync/atomic/atomic_test.go
index e10effe7e..a5f44f70d 100644
--- a/src/pkg/sync/atomic/atomic_test.go
+++ b/src/pkg/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))
}
}
}
@@ -1463,6 +1463,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/src/pkg/sync/atomic/export_linux_arm_test.go b/src/pkg/sync/atomic/export_linux_arm_test.go
index 8c0b5a75c..5cd43353e 100644
--- a/src/pkg/sync/atomic/export_linux_arm_test.go
+++ b/src/pkg/sync/atomic/export_linux_arm_test.go
@@ -4,6 +4,6 @@
package atomic
-func generalCAS64(*uint64, uint64, uint64) bool
+func generalCAS64(addr *uint64, old uint64, new uint64) bool
var GeneralCAS64 = generalCAS64
diff --git a/src/pkg/sync/mutex_test.go b/src/pkg/sync/mutex_test.go
index bf78c6f60..151b25c10 100644
--- a/src/pkg/sync/mutex_test.go
+++ b/src/pkg/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/src/pkg/sync/once_test.go b/src/pkg/sync/once_test.go
index 183069a1a..8afda82f3 100644
--- a/src/pkg/sync/once_test.go
+++ b/src/pkg/sync/once_test.go
@@ -5,9 +5,7 @@
package sync_test
import (
- "runtime"
. "sync"
- "sync/atomic"
"testing"
)
@@ -62,24 +60,11 @@ func TestOncePanic(t *testing.T) {
}
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/src/pkg/sync/pool.go b/src/pkg/sync/pool.go
new file mode 100644
index 000000000..1f08707cd
--- /dev/null
+++ b/src/pkg/sync/pool.go
@@ -0,0 +1,223 @@
+// 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
+ }
+ }
+ 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/src/pkg/sync/pool_test.go b/src/pkg/sync/pool_test.go
new file mode 100644
index 000000000..509448b62
--- /dev/null
+++ b/src/pkg/sync/pool_test.go
@@ -0,0 +1,151 @@
+// 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) {
+ var p Pool
+ var fin uint32
+ const N = 100
+ for i := 0; i < N; i++ {
+ v := new(string)
+ runtime.SetFinalizer(v, func(vv *string) {
+ atomic.AddUint32(&fin, 1)
+ })
+ p.Put(v)
+ }
+ for i := 0; i < N; i++ {
+ p.Get()
+ }
+ for i := 0; i < 5; i++ {
+ runtime.GC()
+ time.Sleep(time.Duration(i*100+10) * time.Millisecond)
+ // 1 pointer can remain on stack or elsewhere
+ if atomic.LoadUint32(&fin) >= N-1 {
+ return
+ }
+ }
+ t.Fatalf("only %v out of %v resources are finalized",
+ atomic.LoadUint32(&fin), N)
+}
+
+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 BenchmarkPoolOverlflow(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/src/pkg/sync/runtime_sema_test.go b/src/pkg/sync/runtime_sema_test.go
index 57a8dbee7..5b7dd3df3 100644
--- a/src/pkg/sync/runtime_sema_test.go
+++ b/src/pkg/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/src/pkg/sync/rwmutex_test.go b/src/pkg/sync/rwmutex_test.go
index 39d5d6540..0436f9723 100644
--- a/src/pkg/sync/rwmutex_test.go
+++ b/src/pkg/sync/rwmutex_test.go
@@ -160,64 +160,39 @@ func BenchmarkRWMutexUncontended(b *testing.B) {
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/src/pkg/sync/waitgroup.go b/src/pkg/sync/waitgroup.go
index 22681115c..4c64dca39 100644
--- a/src/pkg/sync/waitgroup.go
+++ b/src/pkg/sync/waitgroup.go
@@ -67,11 +67,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/src/pkg/sync/waitgroup_test.go b/src/pkg/sync/waitgroup_test.go
index 84c4cfc37..4c0a043c0 100644
--- a/src/pkg/sync/waitgroup_test.go
+++ b/src/pkg/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/src/pkg/syscall/asm_darwin_386.s b/src/pkg/syscall/asm_darwin_386.s
index 2ddfb3bbd..9b4dfa81d 100644
--- a/src/pkg/syscall/asm_darwin_386.s
+++ b/src/pkg/syscall/asm_darwin_386.s
@@ -2,6 +2,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.
+
#include "../../cmd/ld/textflag.h"
//
@@ -12,7 +15,7 @@
// func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
// Trap # in AX, args on stack above caller pc.
-TEXT ·Syscall(SB),NOSPLIT,$0-32
+TEXT ·Syscall(SB),NOSPLIT,$0-28
CALL runtime·entersyscall(SB)
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
@@ -36,7 +39,7 @@ ok:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall6(SB),NOSPLIT,$0-44
+TEXT ·Syscall6(SB),NOSPLIT,$0-40
CALL runtime·entersyscall(SB)
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
@@ -63,7 +66,7 @@ ok6:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall9(SB),NOSPLIT,$0-56
+TEXT ·Syscall9(SB),NOSPLIT,$0-52
CALL runtime·entersyscall(SB)
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
@@ -93,7 +96,7 @@ ok9:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·RawSyscall(SB),NOSPLIT,$0-32
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
LEAL 8(SP), SI
@@ -114,7 +117,7 @@ ok1:
MOVL $0, 28(SP) // errno
RET
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-44
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
LEAL 8(SP), SI
diff --git a/src/pkg/syscall/asm_darwin_amd64.s b/src/pkg/syscall/asm_darwin_amd64.s
index c1970b71d..19ea05be7 100644
--- a/src/pkg/syscall/asm_darwin_amd64.s
+++ b/src/pkg/syscall/asm_darwin_amd64.s
@@ -2,6 +2,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.
+
#include "../../cmd/ld/textflag.h"
//
@@ -12,7 +15,7 @@
// func Syscall6(trap int64, a1, a2, a3, a4, a5, a6 int64) (r1, r2, err int64);
// Trap # in AX, args in DI SI DX, return in AX DX
-TEXT ·Syscall(SB),NOSPLIT,$0-64
+TEXT ·Syscall(SB),NOSPLIT,$0-56
CALL runtime·entersyscall(SB)
MOVQ 16(SP), DI
MOVQ 24(SP), SI
@@ -36,7 +39,7 @@ ok:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall6(SB),NOSPLIT,$0-88
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
CALL runtime·entersyscall(SB)
MOVQ 16(SP), DI
MOVQ 24(SP), SI
@@ -60,7 +63,7 @@ ok6:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·RawSyscall(SB),NOSPLIT,$0-64
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
MOVQ 16(SP), DI
MOVQ 24(SP), SI
MOVQ 32(SP), DX
@@ -81,7 +84,7 @@ ok1:
MOVQ $0, 56(SP) // errno
RET
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-88
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
MOVQ 16(SP), DI
MOVQ 24(SP), SI
MOVQ 32(SP), DX
diff --git a/src/pkg/syscall/asm_freebsd_386.s b/src/pkg/syscall/asm_freebsd_386.s
index d24216fdd..91a46b106 100644
--- a/src/pkg/syscall/asm_freebsd_386.s
+++ b/src/pkg/syscall/asm_freebsd_386.s
@@ -2,6 +2,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.
+
#include "../../cmd/ld/textflag.h"
//
@@ -12,7 +15,7 @@
// func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
// Trap # in AX, args on stack above caller pc.
-TEXT ·Syscall(SB),NOSPLIT,$0-32
+TEXT ·Syscall(SB),NOSPLIT,$0-28
CALL runtime·entersyscall(SB)
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
@@ -36,7 +39,7 @@ ok:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall6(SB),NOSPLIT,$0-44
+TEXT ·Syscall6(SB),NOSPLIT,$0-40
CALL runtime·entersyscall(SB)
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
@@ -63,7 +66,7 @@ ok6:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall9(SB),NOSPLIT,$0-56
+TEXT ·Syscall9(SB),NOSPLIT,$0-52
CALL runtime·entersyscall(SB)
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
@@ -93,7 +96,7 @@ ok9:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·RawSyscall(SB),NOSPLIT,$0-32
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
LEAL 8(SP), SI
@@ -114,7 +117,7 @@ ok1:
MOVL $0, 28(SP) // errno
RET
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-44
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
LEAL 8(SP), SI
diff --git a/src/pkg/syscall/asm_freebsd_amd64.s b/src/pkg/syscall/asm_freebsd_amd64.s
index fca7f371e..7abb36828 100644
--- a/src/pkg/syscall/asm_freebsd_amd64.s
+++ b/src/pkg/syscall/asm_freebsd_amd64.s
@@ -2,6 +2,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.
+
#include "../../cmd/ld/textflag.h"
//
@@ -18,7 +21,7 @@
// func Syscall9(trap int64, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int64)
// Trap # in AX, args in DI SI DX, return in AX DX
-TEXT ·Syscall(SB),NOSPLIT,$0-64
+TEXT ·Syscall(SB),NOSPLIT,$0-56
CALL runtime·entersyscall(SB)
MOVQ 16(SP), DI
MOVQ 24(SP), SI
@@ -41,7 +44,7 @@ ok:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall6(SB),NOSPLIT,$0-88
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
CALL runtime·entersyscall(SB)
MOVQ 16(SP), DI
MOVQ 24(SP), SI
@@ -64,7 +67,7 @@ ok6:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall9(SB),NOSPLIT,$0-112
+TEXT ·Syscall9(SB),NOSPLIT,$0-104
CALL runtime·entersyscall(SB)
MOVQ 8(SP), AX
MOVQ 16(SP), DI
@@ -97,7 +100,7 @@ ok9:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·RawSyscall(SB),NOSPLIT,$0-64
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
MOVQ 16(SP), DI
MOVQ 24(SP), SI
MOVQ 32(SP), DX
@@ -117,7 +120,7 @@ ok1:
MOVQ $0, 56(SP) // errno
RET
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-88
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
MOVQ 16(SP), DI
MOVQ 24(SP), SI
MOVQ 32(SP), DX
diff --git a/src/pkg/syscall/asm_freebsd_arm.s b/src/pkg/syscall/asm_freebsd_arm.s
index 9283d079b..c01ce6feb 100644
--- a/src/pkg/syscall/asm_freebsd_arm.s
+++ b/src/pkg/syscall/asm_freebsd_arm.s
@@ -8,13 +8,13 @@
// System call support for ARM, FreeBSD
//
-// func Syscall(trap int32, a1, a2, a3 int32) (r1, r2, err int32);
-// func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
-// func Syscall9(trap int32, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int32)
+// func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, errno uintptr);
+// func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, errno uintptr);
+// func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, errno uintptr)
TEXT ·Syscall(SB),NOSPLIT,$0-28
BL runtime·entersyscall(SB)
- MOVW 0(FP), R7 // sigcall num
+ MOVW 0(FP), R7 // syscall number
MOVW 4(FP), R0 // a1
MOVW 8(FP), R1 // a2
MOVW 12(FP), R2 // a3
@@ -23,69 +23,71 @@ TEXT ·Syscall(SB),NOSPLIT,$0-28
BCS error
MOVW R0, 16(FP) // r1
MOVW R1, 20(FP) // r2
- MOVW R2, 24(FP) // err
+ MOVW R2, 24(FP) // errno
BL runtime·exitsyscall(SB)
RET
error:
MOVW $-1, R3
MOVW R3, 16(FP) // r1
MOVW R2, 20(FP) // r2
- MOVW R0, 24(FP) // err
+ MOVW R0, 24(FP) // errno
BL runtime·exitsyscall(SB)
RET
TEXT ·Syscall6(SB),NOSPLIT,$0-40
BL runtime·entersyscall(SB)
- MOVW 0(FP), R7 // sigcall num
+ MOVW 0(FP), R7 // syscall number
MOVW 4(FP), R0 // a1
MOVW 8(FP), R1 // a2
MOVW 12(FP), R2 // a3
MOVW 16(FP), R3 // a4
- ADD $24, R13 // a5 to a6 are passed on stack
+ MOVW R13, R4
+ MOVW $20(FP), R13 // a5 to a6 are passed on stack
SWI $0 // syscall
- SUB $24, R13
+ MOVW R4, R13
MOVW $0, R2
BCS error6
MOVW R0, 28(FP) // r1
MOVW R1, 32(FP) // r2
- MOVW R2, 36(FP) // err
+ MOVW R2, 36(FP) // errno
BL runtime·exitsyscall(SB)
RET
error6:
MOVW $-1, R3
MOVW R3, 28(FP) // r1
MOVW R2, 32(FP) // r2
- MOVW R0, 36(FP) // err
+ MOVW R0, 36(FP) // errno
BL runtime·exitsyscall(SB)
RET
TEXT ·Syscall9(SB),NOSPLIT,$0-52
BL runtime·entersyscall(SB)
- MOVW 0(FP), R7 // sigcall num
+ MOVW 0(FP), R7 // syscall number
MOVW 4(FP), R0 // a1
MOVW 8(FP), R1 // a2
MOVW 12(FP), R2 // a3
MOVW 16(FP), R3 // a4
- ADD $24, R13 // a5 to a9 are passed on stack
+ MOVW R13, R4
+ MOVW $20(FP), R13 // a5 to a9 are passed on stack
SWI $0 // syscall
- SUB $24, R13
+ MOVW R4, R13
MOVW $0, R2
BCS error9
MOVW R0, 40(FP) // r1
MOVW R1, 44(FP) // r2
- MOVW R2, 48(FP) // err
+ MOVW R2, 48(FP) // errno
BL runtime·exitsyscall(SB)
RET
error9:
MOVW $-1, R3
MOVW R3, 40(FP) // r1
MOVW R2, 44(FP) // r2
- MOVW R0, 48(FP) // err
+ MOVW R0, 48(FP) // errno
BL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
- MOVW 0(FP), R7 // sigcall num
+ MOVW 0(FP), R7 // syscall number
MOVW 4(FP), R0 // a1
MOVW 8(FP), R1 // a2
MOVW 12(FP), R2 // a3
@@ -94,33 +96,34 @@ TEXT ·RawSyscall(SB),NOSPLIT,$0-28
BCS errorr
MOVW R0, 16(FP) // r1
MOVW R1, 20(FP) // r2
- MOVW R2, 24(FP) // err
+ MOVW R2, 24(FP) // errno
RET
errorr:
MOVW $-1, R3
MOVW R3, 16(FP) // r1
MOVW R2, 20(FP) // r2
- MOVW R0, 24(FP) // err
+ MOVW R0, 24(FP) // errno
RET
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
- MOVW 0(FP), R7 // sigcall num
+ MOVW 0(FP), R7 // syscall number
MOVW 4(FP), R0 // a1
MOVW 8(FP), R1 // a2
MOVW 12(FP), R2 // a3
MOVW 16(FP), R3 // a4
- ADD $24, R13 // a5 to a6 are passed on stack
+ MOVW R13, R4
+ MOVW $20(FP), R13 // a5 to a6 are passed on stack
SWI $0 // syscall
- SUB $24, R13
+ MOVW R4, R13
MOVW $0, R2
BCS errorr6
MOVW R0, 28(FP) // r1
MOVW R1, 32(FP) // r2
- MOVW R2, 36(FP) // err
+ MOVW R2, 36(FP) // errno
RET
errorr6:
MOVW $-1, R3
MOVW R3, 28(FP) // r1
MOVW R2, 32(FP) // r2
- MOVW R0, 36(FP) // err
+ MOVW R0, 36(FP) // errno
RET
diff --git a/src/pkg/syscall/asm_linux_386.s b/src/pkg/syscall/asm_linux_386.s
index cf2ab02ab..30b22073d 100644
--- a/src/pkg/syscall/asm_linux_386.s
+++ b/src/pkg/syscall/asm_linux_386.s
@@ -2,6 +2,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.
+
#include "../../cmd/ld/textflag.h"
//
@@ -11,7 +14,7 @@
// func Syscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr);
// Trap # in AX, args in BX CX DX SI DI, return in AX
-TEXT ·Syscall(SB),NOSPLIT,$0-32
+TEXT ·Syscall(SB),NOSPLIT,$0-28
CALL runtime·entersyscall(SB)
MOVL 4(SP), AX // syscall entry
MOVL 8(SP), BX
@@ -36,7 +39,7 @@ ok:
RET
// func Syscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
-TEXT ·Syscall6(SB),NOSPLIT,$0-44
+TEXT ·Syscall6(SB),NOSPLIT,$0-40
CALL runtime·entersyscall(SB)
MOVL 4(SP), AX // syscall entry
MOVL 8(SP), BX
@@ -62,7 +65,7 @@ ok6:
RET
// func RawSyscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr);
-TEXT ·RawSyscall(SB),NOSPLIT,$0-32
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
MOVL 4(SP), AX // syscall entry
MOVL 8(SP), BX
MOVL 12(SP), CX
@@ -84,7 +87,7 @@ ok1:
RET
// func RawSyscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-44
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
MOVL 4(SP), AX // syscall entry
MOVL 8(SP), BX
MOVL 12(SP), CX
@@ -110,7 +113,7 @@ ok2:
// func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, errno int)
// Kernel interface gets call sub-number and pointer to a0.
-TEXT ·socketcall(SB),NOSPLIT,$0-40
+TEXT ·socketcall(SB),NOSPLIT,$0-36
CALL runtime·entersyscall(SB)
MOVL $SYS_SOCKETCALL, AX // syscall entry
MOVL 4(SP), BX // socket call number
@@ -134,7 +137,7 @@ oksock:
// func rawsocketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, errno int)
// Kernel interface gets call sub-number and pointer to a0.
-TEXT ·rawsocketcall(SB),NOSPLIT,$0-40
+TEXT ·rawsocketcall(SB),NOSPLIT,$0-36
MOVL $SYS_SOCKETCALL, AX // syscall entry
MOVL 4(SP), BX // socket call number
LEAL 8(SP), CX // pointer to call arguments
@@ -159,7 +162,7 @@ oksock1:
// taking the address of the return value newoffset.
// Underlying system call is
// llseek(int fd, int offhi, int offlo, int64 *result, int whence)
-TEXT ·Seek(SB),NOSPLIT,$0-32
+TEXT ·seek(SB),NOSPLIT,$0-28
CALL runtime·entersyscall(SB)
MOVL $SYS__LLSEEK, AX // syscall entry
MOVL 4(SP), BX // fd
diff --git a/src/pkg/syscall/asm_linux_amd64.s b/src/pkg/syscall/asm_linux_amd64.s
index 28a2a5809..995b60ecd 100644
--- a/src/pkg/syscall/asm_linux_amd64.s
+++ b/src/pkg/syscall/asm_linux_amd64.s
@@ -2,6 +2,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.
+
#include "../../cmd/ld/textflag.h"
//
@@ -13,7 +16,7 @@
// Note that this differs from "standard" ABI convention, which
// would pass 4th arg in CX, not R10.
-TEXT ·Syscall(SB),NOSPLIT,$0-64
+TEXT ·Syscall(SB),NOSPLIT,$0-56
CALL runtime·entersyscall(SB)
MOVQ 16(SP), DI
MOVQ 24(SP), SI
@@ -38,7 +41,7 @@ ok:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall6(SB),NOSPLIT,$0-88
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
CALL runtime·entersyscall(SB)
MOVQ 16(SP), DI
MOVQ 24(SP), SI
@@ -63,7 +66,7 @@ ok6:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·RawSyscall(SB),NOSPLIT,$0-64
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
MOVQ 16(SP), DI
MOVQ 24(SP), SI
MOVQ 32(SP), DX
@@ -85,7 +88,7 @@ ok1:
MOVQ $0, 56(SP) // errno
RET
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-88
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
MOVQ 16(SP), DI
MOVQ 24(SP), SI
MOVQ 32(SP), DX
@@ -107,7 +110,7 @@ ok2:
MOVQ $0, 80(SP) // errno
RET
-TEXT ·Gettimeofday(SB),NOSPLIT,$0-24
+TEXT ·gettimeofday(SB),NOSPLIT,$0-16
MOVQ 8(SP), DI
MOVQ $0, SI
MOVQ runtime·__vdso_gettimeofday_sym(SB), AX
@@ -121,11 +124,3 @@ TEXT ·Gettimeofday(SB),NOSPLIT,$0-24
ok7:
MOVQ $0, 16(SP) // errno
RET
-
-TEXT ·Time(SB),NOSPLIT,$0-32
- MOVQ 8(SP), DI
- MOVQ runtime·__vdso_time_sym(SB), AX
- CALL AX
- MOVQ AX, 16(SP) // tt
- MOVQ $0, 24(SP) // errno
- RET
diff --git a/src/pkg/syscall/asm_linux_arm.s b/src/pkg/syscall/asm_linux_arm.s
index bf54b4fe6..a28bc6cfc 100644
--- a/src/pkg/syscall/asm_linux_arm.s
+++ b/src/pkg/syscall/asm_linux_arm.s
@@ -98,12 +98,12 @@ ok2:
RET
#define SYS__LLSEEK 140 /* from zsysnum_linux_arm.go */
-// func Seek(fd int, offset int64, whence int) (newoffset int64, errno int)
+// func seek(fd int, offset int64, whence int) (newoffset int64, errno int)
// Implemented in assembly to avoid allocation when
// taking the address of the return value newoffset.
// Underlying system call is
// llseek(int fd, int offhi, int offlo, int64 *result, int whence)
-TEXT ·Seek(SB),NOSPLIT,$0-32
+TEXT ·seek(SB),NOSPLIT,$0-32
BL runtime·entersyscall(SB)
MOVW $SYS__LLSEEK, R7 // syscall entry
MOVW 4(SP), R0 // fd
diff --git a/src/pkg/syscall/asm_nacl_386.s b/src/pkg/syscall/asm_nacl_386.s
new file mode 100644
index 000000000..de7c3cc5d
--- /dev/null
+++ b/src/pkg/syscall/asm_nacl_386.s
@@ -0,0 +1,43 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "../../cmd/ld/textflag.h"
+#include "../runtime/syscall_nacl.h"
+
+//
+// System call support for 386, Native Client
+//
+
+#define NACL_SYSCALL(code) \
+ MOVL $(0x10000 + ((code)<<5)), AX; CALL AX
+
+#define NACL_SYSJMP(code) \
+ MOVL $(0x10000 + ((code)<<5)), AX; JMP AX
+
+TEXT syscall·Syscall(SB),NOSPLIT,$12-28
+ CALL runtime·entersyscall(SB)
+ MOVL trap+0(FP), AX
+ MOVL a1+4(FP), BX
+ MOVL BX, 0(SP)
+ MOVL a2+8(FP), BX
+ MOVL BX, 4(SP)
+ MOVL a3+12(FP), BX
+ MOVL BX, 8(SP)
+ SHLL $5, AX
+ ADDL $0x10000, AX
+ CALL AX
+ CMPL AX, $0
+ JGE ok
+ MOVL $-1, r1+16(FP)
+ MOVL $-1, r2+20(FP)
+ NEGL AX
+ MOVL AX, err+24(FP)
+ CALL runtime·exitsyscall(SB)
+ RET
+ok:
+ MOVL AX, r1+16(FP)
+ MOVL DX, r2+20(FP)
+ MOVL $0, err+24(FP)
+ CALL runtime·exitsyscall(SB)
+ RET
diff --git a/src/pkg/syscall/asm_nacl_amd64p32.s b/src/pkg/syscall/asm_nacl_amd64p32.s
new file mode 100644
index 000000000..de030ec80
--- /dev/null
+++ b/src/pkg/syscall/asm_nacl_amd64p32.s
@@ -0,0 +1,41 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "../../cmd/ld/textflag.h"
+#include "../runtime/syscall_nacl.h"
+
+//
+// System call support for amd64, Native Client
+//
+
+#define NACL_SYSCALL(code) \
+ MOVL $(0x10000 + ((code)<<5)), AX; CALL AX
+
+#define NACL_SYSJMP(code) \
+ MOVL $(0x10000 + ((code)<<5)), AX; JMP AX
+
+TEXT syscall·Syscall(SB),NOSPLIT,$0-28
+ CALL runtime·entersyscall(SB)
+ MOVL trap+0(FP), AX
+ MOVL a1+4(FP), DI
+ MOVL a2+8(FP), SI
+ MOVL a3+12(FP), DX
+ // more args would use CX, R8, R9
+ SHLL $5, AX
+ ADDL $0x10000, AX
+ CALL AX
+ CMPL AX, $0
+ JGE ok
+ MOVL $-1, r1+16(FP)
+ MOVL $-1, r2+20(FP)
+ NEGL AX
+ MOVL AX, err+24(FP)
+ CALL runtime·exitsyscall(SB)
+ RET
+ok:
+ MOVL AX, r1+16(FP)
+ MOVL DX, r2+20(FP)
+ MOVL $0, err+24(FP)
+ CALL runtime·exitsyscall(SB)
+ RET
diff --git a/src/pkg/syscall/asm_netbsd_386.s b/src/pkg/syscall/asm_netbsd_386.s
index 8caade255..40b30b405 100644
--- a/src/pkg/syscall/asm_netbsd_386.s
+++ b/src/pkg/syscall/asm_netbsd_386.s
@@ -2,6 +2,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.
+
#include "../../cmd/ld/textflag.h"
//
@@ -12,7 +15,7 @@
// func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
// Trap # in AX, args on stack above caller pc.
-TEXT ·Syscall(SB),NOSPLIT,$0-32
+TEXT ·Syscall(SB),NOSPLIT,$0-28
CALL runtime·entersyscall(SB)
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
@@ -36,7 +39,7 @@ ok:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall6(SB),NOSPLIT,$0-44
+TEXT ·Syscall6(SB),NOSPLIT,$0-40
CALL runtime·entersyscall(SB)
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
@@ -63,7 +66,7 @@ ok6:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall9(SB),NOSPLIT,$0-56
+TEXT ·Syscall9(SB),NOSPLIT,$0-52
CALL runtime·entersyscall(SB)
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
@@ -93,7 +96,7 @@ ok9:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·RawSyscall(SB),NOSPLIT,$0-32
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
LEAL 8(SP), SI
@@ -114,7 +117,7 @@ ok1:
MOVL $0, 28(SP) // errno
RET
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-44
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
LEAL 8(SP), SI
diff --git a/src/pkg/syscall/asm_netbsd_amd64.s b/src/pkg/syscall/asm_netbsd_amd64.s
index e0b8b3cb8..94ad0284a 100644
--- a/src/pkg/syscall/asm_netbsd_amd64.s
+++ b/src/pkg/syscall/asm_netbsd_amd64.s
@@ -2,6 +2,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.
+
#include "../../cmd/ld/textflag.h"
//
@@ -13,7 +16,7 @@
// func Syscall9(trap int64, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int64);
// Trap # in AX, args in DI SI DX, return in AX DX
-TEXT ·Syscall(SB),NOSPLIT,$0-64
+TEXT ·Syscall(SB),NOSPLIT,$0-56
CALL runtime·entersyscall(SB)
MOVQ 8(SP), AX // syscall entry
MOVQ 16(SP), DI
@@ -36,7 +39,7 @@ ok:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall6(SB),NOSPLIT,$0-88
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
CALL runtime·entersyscall(SB)
MOVQ 8(SP), AX // syscall entry
MOVQ 16(SP), DI
@@ -59,7 +62,7 @@ ok6:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall9(SB),NOSPLIT,$0-112
+TEXT ·Syscall9(SB),NOSPLIT,$0-104
CALL runtime·entersyscall(SB)
MOVQ 8(SP), AX // syscall entry
MOVQ 16(SP), DI
@@ -91,7 +94,7 @@ ok9:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·RawSyscall(SB),NOSPLIT,$0-64
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
MOVQ 16(SP), DI
MOVQ 24(SP), SI
MOVQ 32(SP), DX
@@ -111,7 +114,7 @@ ok1:
MOVQ $0, 56(SP) // errno
RET
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-88
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
MOVQ 16(SP), DI
MOVQ 24(SP), SI
MOVQ 32(SP), DX
diff --git a/src/pkg/syscall/asm_openbsd_386.s b/src/pkg/syscall/asm_openbsd_386.s
index a38349661..7dd2e373f 100644
--- a/src/pkg/syscall/asm_openbsd_386.s
+++ b/src/pkg/syscall/asm_openbsd_386.s
@@ -2,6 +2,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.
+
#include "../../cmd/ld/textflag.h"
//
@@ -12,7 +15,7 @@
// func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
// Trap # in AX, args on stack above caller pc.
-TEXT ·Syscall(SB),NOSPLIT,$0-32
+TEXT ·Syscall(SB),NOSPLIT,$0-28
CALL runtime·entersyscall(SB)
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
@@ -36,7 +39,7 @@ ok:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall6(SB),NOSPLIT,$0-44
+TEXT ·Syscall6(SB),NOSPLIT,$0-40
CALL runtime·entersyscall(SB)
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
@@ -63,7 +66,7 @@ ok6:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall9(SB),NOSPLIT,$0-56
+TEXT ·Syscall9(SB),NOSPLIT,$0-52
CALL runtime·entersyscall(SB)
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
@@ -93,7 +96,7 @@ ok9:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·RawSyscall(SB),NOSPLIT,$0-32
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
LEAL 8(SP), SI
@@ -114,7 +117,7 @@ ok1:
MOVL $0, 28(SP) // errno
RET
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-44
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
LEAL 8(SP), SI
diff --git a/src/pkg/syscall/asm_openbsd_amd64.s b/src/pkg/syscall/asm_openbsd_amd64.s
index 1bf25f1db..e127bf220 100644
--- a/src/pkg/syscall/asm_openbsd_amd64.s
+++ b/src/pkg/syscall/asm_openbsd_amd64.s
@@ -2,6 +2,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.
+
#include "../../cmd/ld/textflag.h"
//
@@ -13,7 +16,7 @@
// func Syscall9(trap int64, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int64);
// Trap # in AX, args in DI SI DX, return in AX DX
-TEXT ·Syscall(SB),NOSPLIT,$0-64
+TEXT ·Syscall(SB),NOSPLIT,$0-56
CALL runtime·entersyscall(SB)
MOVQ 8(SP), AX // syscall entry
MOVQ 16(SP), DI
@@ -36,7 +39,7 @@ ok:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall6(SB),NOSPLIT,$0-88
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
CALL runtime·entersyscall(SB)
MOVQ 8(SP), AX // syscall entry
MOVQ 16(SP), DI
@@ -59,7 +62,7 @@ ok6:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall9(SB),NOSPLIT,$0-112
+TEXT ·Syscall9(SB),NOSPLIT,$0-104
CALL runtime·entersyscall(SB)
MOVQ 8(SP), AX // syscall entry
MOVQ 16(SP), DI
@@ -91,7 +94,7 @@ ok9:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·RawSyscall(SB),NOSPLIT,$0-64
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
MOVQ 16(SP), DI
MOVQ 24(SP), SI
MOVQ 32(SP), DX
@@ -111,7 +114,7 @@ ok1:
MOVQ $0, 56(SP) // errno
RET
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-88
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
MOVQ 16(SP), DI
MOVQ 24(SP), SI
MOVQ 32(SP), DX
diff --git a/src/pkg/syscall/asm_plan9_386.s b/src/pkg/syscall/asm_plan9_386.s
index 7ebd20690..f8c07c407 100644
--- a/src/pkg/syscall/asm_plan9_386.s
+++ b/src/pkg/syscall/asm_plan9_386.s
@@ -2,6 +2,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.
+
#include "../../cmd/ld/textflag.h"
//
@@ -87,7 +90,7 @@ copyresult4:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·RawSyscall(SB),NOSPLIT,$0-32
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
LEAL 8(SP), SI
@@ -102,7 +105,7 @@ TEXT ·RawSyscall(SB),NOSPLIT,$0-32
MOVL AX, err+28(SP)
RET
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-44
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
LEAL 8(SP), SI
@@ -123,7 +126,7 @@ TEXT ·RawSyscall6(SB),NOSPLIT,$0-44
#define SYS_SEEK 39 /* from zsysnum_plan9_386.go */
//func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string)
-TEXT ·seek(SB),NOSPLIT,$0-40
+TEXT ·seek(SB),NOSPLIT,$0-36
LEAL newoffset+24(SP), AX
MOVL AX, placeholder+4(SP)
diff --git a/src/pkg/syscall/asm_plan9_amd64.s b/src/pkg/syscall/asm_plan9_amd64.s
index 880bf7c6f..2154a87d5 100644
--- a/src/pkg/syscall/asm_plan9_amd64.s
+++ b/src/pkg/syscall/asm_plan9_amd64.s
@@ -2,6 +2,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.
+
#include "../../cmd/ld/textflag.h"
//
@@ -91,7 +94,7 @@ copyresult4:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·RawSyscall(SB),NOSPLIT,$0-64
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
MOVQ $0x8000, AX // for NxM
MOVQ 8(SP), BP // syscall entry
// slide args down on top of system call number
@@ -107,7 +110,7 @@ TEXT ·RawSyscall(SB),NOSPLIT,$0-64
MOVQ AX, err+56(SP)
RET
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-88
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
MOVQ $0x8000, AX // for NxM
MOVQ 8(SP), BP // syscall entry
// slide args down on top of system call number
@@ -129,7 +132,7 @@ TEXT ·RawSyscall6(SB),NOSPLIT,$0-88
#define SYS_SEEK 39 /* from zsysnum_plan9_amd64.go */
//func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string)
-TEXT ·seek(SB),NOSPLIT,$0-64
+TEXT ·seek(SB),NOSPLIT,$0-56
LEAQ newoffset+40(SP), AX
MOVQ AX, placeholder+8(SP)
@@ -160,7 +163,7 @@ copyresult6:
//func exit(code int)
// Import runtime·exit for cleanly exiting.
-TEXT ·exit(SB),NOSPLIT,$8-4
+TEXT ·exit(SB),NOSPLIT,$8-8
MOVQ code+0(FP), AX
MOVQ AX, 0(SP)
CALL runtime·exit(SB)
diff --git a/src/pkg/syscall/asm_solaris_amd64.s b/src/pkg/syscall/asm_solaris_amd64.s
new file mode 100644
index 000000000..3735890fa
--- /dev/null
+++ b/src/pkg/syscall/asm_solaris_amd64.s
@@ -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.
+
+//
+// System calls for amd64, Solaris are implemented in ../runtime/syscall_solaris.goc
+//
diff --git a/src/pkg/syscall/consistency_unix_test.go b/src/pkg/syscall/consistency_unix_test.go
deleted file mode 100644
index 73630bc61..000000000
--- a/src/pkg/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/src/pkg/syscall/dir_plan9.go b/src/pkg/syscall/dir_plan9.go
index b7ab4cd10..697bf5499 100644
--- a/src/pkg/syscall/dir_plan9.go
+++ b/src/pkg/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/src/pkg/syscall/env_unix.go b/src/pkg/syscall/env_unix.go
index 5970df8fc..ad354ed05 100644
--- a/src/pkg/syscall/env_unix.go
+++ b/src/pkg/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.
diff --git a/src/pkg/syscall/exec_linux.go b/src/pkg/syscall/exec_linux.go
index a1656e8dc..f27950f73 100644
--- a/src/pkg/syscall/exec_linux.go
+++ b/src/pkg/syscall/exec_linux.go
@@ -131,11 +131,11 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
// User and groups
if cred := sys.Credential; cred != nil {
ngroups := uintptr(len(cred.Groups))
- groups := uintptr(0)
+ var groups unsafe.Pointer
if ngroups > 0 {
- groups = uintptr(unsafe.Pointer(&cred.Groups[0]))
+ groups = unsafe.Pointer(&cred.Groups[0])
}
- _, _, err1 = RawSyscall(SYS_SETGROUPS, ngroups, groups, 0)
+ _, _, err1 = RawSyscall(SYS_SETGROUPS, ngroups, uintptr(groups), 0)
if err1 != 0 {
goto childerror
}
diff --git a/src/pkg/syscall/exec_plan9.go b/src/pkg/syscall/exec_plan9.go
index 99ad2f158..45ee542bb 100644
--- a/src/pkg/syscall/exec_plan9.go
+++ b/src/pkg/syscall/exec_plan9.go
@@ -486,7 +486,7 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error)
if err != nil || n != 0 {
if n != 0 {
- err = NewError(string(errbuf[:]))
+ err = NewError(string(errbuf[:n]))
}
// Child failed; wait for it to exit, to make sure
diff --git a/src/pkg/syscall/exec_solaris.go b/src/pkg/syscall/exec_solaris.go
new file mode 100644
index 000000000..97de6ca00
--- /dev/null
+++ b/src/pkg/syscall/exec_solaris.go
@@ -0,0 +1,243 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+import (
+ "unsafe"
+)
+
+type SysProcAttr struct {
+ Chroot string // Chroot.
+ Credential *Credential // Credential.
+ Setsid bool // Create session.
+ Setpgid bool // Set process group ID to new pid (SYSV setpgrp)
+ Setctty bool // Set controlling terminal to fd 0
+ Noctty bool // Detach fd 0 from controlling terminal
+}
+
+// Implemented in runtime package.
+func runtime_BeforeFork()
+func runtime_AfterFork()
+
+func chdir(path uintptr) (err Errno)
+func chroot1(path uintptr) (err Errno)
+func close(fd uintptr) (err Errno)
+func execve(path uintptr, argv uintptr, envp uintptr) (err Errno)
+func exit(code uintptr)
+func fcntl1(fd uintptr, cmd uintptr, arg uintptr) (val uintptr, err Errno)
+func forkx(flags uintptr) (pid uintptr, err Errno)
+func ioctl(fd uintptr, req uintptr, arg uintptr) (err Errno)
+func setgid(gid uintptr) (err Errno)
+func setgroups1(ngid uintptr, gid uintptr) (err Errno)
+func setsid() (pid uintptr, err Errno)
+func setuid(uid uintptr) (err Errno)
+func setpgid(pid uintptr, pgid uintptr) (err Errno)
+func write1(fd uintptr, buf uintptr, nbyte uintptr) (n uintptr, err Errno)
+
+// Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child.
+// If a dup or exec fails, write the errno error to pipe.
+// (Pipe is close-on-exec so if exec succeeds, it will be closed.)
+// In the child, this function must not acquire any locks, because
+// they might have been locked at the time of the fork. This means
+// no rescheduling, no malloc calls, and no new stack segments.
+//
+// We call hand-crafted syscalls, implemented in
+// ../runtime/syscall_solaris.goc, rather than generated libc wrappers
+// because we need to avoid lazy-loading the functions (might malloc,
+// split the stack, or acquire mutexes). We can't call RawSyscall
+// because it's not safe even for BSD-subsystem calls.
+func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) {
+ // Declare all variables at top in case any
+ // declarations require heap allocation (e.g., err1).
+ var (
+ r1 uintptr
+ err1 Errno
+ nextfd int
+ i int
+ )
+
+ // guard against side effects of shuffling fds below.
+ // Make sure that nextfd is beyond any currently open files so
+ // that we can't run the risk of overwriting any of them.
+ fd := make([]int, len(attr.Files))
+ nextfd = len(attr.Files)
+ for i, ufd := range attr.Files {
+ if nextfd < int(ufd) {
+ nextfd = int(ufd)
+ }
+ fd[i] = int(ufd)
+ }
+ nextfd++
+
+ // About to call fork.
+ // No more allocation or calls of non-assembly functions.
+ runtime_BeforeFork()
+ r1, err1 = forkx(0x1) // FORK_NOSIGCHLD
+ if err1 != 0 {
+ runtime_AfterFork()
+ return 0, err1
+ }
+
+ if r1 != 0 {
+ // parent; return PID
+ runtime_AfterFork()
+ return int(r1), 0
+ }
+
+ // Fork succeeded, now in child.
+
+ // Session ID
+ if sys.Setsid {
+ _, err1 = setsid()
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Set process group
+ if sys.Setpgid {
+ err1 = setpgid(0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Chroot
+ if chroot != nil {
+ err1 = chroot1(uintptr(unsafe.Pointer(chroot)))
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // User and groups
+ if cred := sys.Credential; cred != nil {
+ ngroups := uintptr(len(cred.Groups))
+ groups := uintptr(0)
+ if ngroups > 0 {
+ groups = uintptr(unsafe.Pointer(&cred.Groups[0]))
+ }
+ err1 = setgroups1(ngroups, groups)
+ if err1 != 0 {
+ goto childerror
+ }
+ err1 = setgid(uintptr(cred.Gid))
+ if err1 != 0 {
+ goto childerror
+ }
+ err1 = setuid(uintptr(cred.Uid))
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Chdir
+ if dir != nil {
+ err1 = chdir(uintptr(unsafe.Pointer(dir)))
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Pass 1: look for fd[i] < i and move those up above len(fd)
+ // so that pass 2 won't stomp on an fd it needs later.
+ if pipe < nextfd {
+ _, err1 = fcntl1(uintptr(pipe), F_DUP2FD, uintptr(nextfd))
+ if err1 != 0 {
+ goto childerror
+ }
+ fcntl1(uintptr(nextfd), F_SETFD, FD_CLOEXEC)
+ pipe = nextfd
+ nextfd++
+ }
+ for i = 0; i < len(fd); i++ {
+ if fd[i] >= 0 && fd[i] < int(i) {
+ _, err1 = fcntl1(uintptr(fd[i]), F_DUP2FD, uintptr(nextfd))
+ if err1 != 0 {
+ goto childerror
+ }
+ fcntl1(uintptr(nextfd), F_SETFD, FD_CLOEXEC)
+ fd[i] = nextfd
+ nextfd++
+ if nextfd == pipe { // don't stomp on pipe
+ nextfd++
+ }
+ }
+ }
+
+ // Pass 2: dup fd[i] down onto i.
+ for i = 0; i < len(fd); i++ {
+ if fd[i] == -1 {
+ close(uintptr(i))
+ continue
+ }
+ if fd[i] == int(i) {
+ // dup2(i, i) won't clear close-on-exec flag on Linux,
+ // probably not elsewhere either.
+ _, err1 = fcntl1(uintptr(fd[i]), F_SETFD, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ continue
+ }
+ // The new fd is created NOT close-on-exec,
+ // which is exactly what we want.
+ _, err1 = fcntl1(uintptr(fd[i]), F_DUP2FD, uintptr(i))
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // By convention, we don't close-on-exec the fds we are
+ // started with, so if len(fd) < 3, close 0, 1, 2 as needed.
+ // Programs that know they inherit fds >= 3 will need
+ // to set them close-on-exec.
+ for i = len(fd); i < 3; i++ {
+ close(uintptr(i))
+ }
+
+ // Detach fd 0 from tty
+ if sys.Noctty {
+ err1 = ioctl(0, uintptr(TIOCNOTTY), 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Make fd 0 the tty
+ if sys.Setctty {
+ err1 = ioctl(0, uintptr(TIOCSCTTY), 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Time to exec.
+ err1 = execve(
+ uintptr(unsafe.Pointer(argv0)),
+ uintptr(unsafe.Pointer(&argv[0])),
+ uintptr(unsafe.Pointer(&envv[0])))
+
+childerror:
+ // send error code on pipe
+ write1(uintptr(pipe), uintptr(unsafe.Pointer(&err1)), unsafe.Sizeof(err1))
+ for {
+ exit(253)
+ }
+}
+
+// Try to open a pipe with O_CLOEXEC set on both file descriptors.
+func forkExecPipe(p []int) error {
+ err := Pipe(p)
+ if err != nil {
+ return err
+ }
+ _, err = fcntl(p[0], F_SETFD, FD_CLOEXEC)
+ if err != nil {
+ return err
+ }
+ _, err = fcntl(p[1], F_SETFD, FD_CLOEXEC)
+ return err
+}
diff --git a/src/pkg/syscall/exec_unix.go b/src/pkg/syscall/exec_unix.go
index b82e39701..890bfdc22 100644
--- a/src/pkg/syscall/exec_unix.go
+++ b/src/pkg/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.
@@ -158,7 +158,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
}
diff --git a/src/pkg/syscall/fd_nacl.go b/src/pkg/syscall/fd_nacl.go
new file mode 100644
index 000000000..74324142a
--- /dev/null
+++ b/src/pkg/syscall/fd_nacl.go
@@ -0,0 +1,326 @@
+// 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.
+
+// File descriptor support for Native Client.
+// We want to provide access to a broader range of (simulated) files than
+// Native Client allows, so we maintain our own file descriptor table exposed
+// to higher-level packages.
+
+package syscall
+
+import (
+ "sync"
+)
+
+// files is the table indexed by a file descriptor.
+var files struct {
+ sync.RWMutex
+ tab []*file
+}
+
+// A file is an open file, something with a file descriptor.
+// A particular *file may appear in files multiple times, due to use of Dup or Dup2.
+type file struct {
+ fdref int // uses in files.tab
+ impl fileImpl // underlying implementation
+}
+
+// A fileImpl is the implementation of something that can be a file.
+type fileImpl interface {
+ // Standard operations.
+ // These can be called concurrently from multiple goroutines.
+ stat(*Stat_t) error
+ read([]byte) (int, error)
+ write([]byte) (int, error)
+ seek(int64, int) (int64, error)
+ pread([]byte, int64) (int, error)
+ pwrite([]byte, int64) (int, error)
+
+ // Close is called when the last reference to a *file is removed
+ // from the file descriptor table. It may be called concurrently
+ // with active operations such as blocked read or write calls.
+ close() error
+}
+
+// newFD adds impl to the file descriptor table,
+// returning the new file descriptor.
+// Like Unix, it uses the lowest available descriptor.
+func newFD(impl fileImpl) int {
+ files.Lock()
+ defer files.Unlock()
+ f := &file{impl: impl, fdref: 1}
+ for fd, oldf := range files.tab {
+ if oldf == nil {
+ files.tab[fd] = f
+ return fd
+ }
+ }
+ fd := len(files.tab)
+ files.tab = append(files.tab, f)
+ return fd
+}
+
+// Install Native Client stdin, stdout, stderr.
+func init() {
+ newFD(&naclFile{naclFD: 0})
+ newFD(&naclFile{naclFD: 1})
+ newFD(&naclFile{naclFD: 2})
+}
+
+// fdToFile retrieves the *file corresponding to a file descriptor.
+func fdToFile(fd int) (*file, error) {
+ files.Lock()
+ defer files.Unlock()
+ if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil {
+ return nil, EBADF
+ }
+ return files.tab[fd], nil
+}
+
+func Close(fd int) error {
+ files.Lock()
+ if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil {
+ files.Unlock()
+ return EBADF
+ }
+ f := files.tab[fd]
+ files.tab[fd] = nil
+ f.fdref--
+ fdref := f.fdref
+ files.Unlock()
+ if fdref > 0 {
+ return nil
+ }
+ return f.impl.close()
+}
+
+func CloseOnExec(fd int) {
+ // nothing to do - no exec
+}
+
+func Dup(fd int) (int, error) {
+ files.Lock()
+ defer files.Unlock()
+ if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil {
+ return -1, EBADF
+ }
+ f := files.tab[fd]
+ f.fdref++
+ for newfd, oldf := range files.tab {
+ if oldf == nil {
+ files.tab[newfd] = f
+ return newfd, nil
+ }
+ }
+ newfd := len(files.tab)
+ files.tab = append(files.tab, f)
+ return newfd, nil
+}
+
+func Dup2(fd, newfd int) error {
+ files.Lock()
+ defer files.Unlock()
+ if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil || newfd < 0 || newfd >= len(files.tab)+100 {
+ files.Unlock()
+ return EBADF
+ }
+ f := files.tab[fd]
+ f.fdref++
+ for cap(files.tab) <= newfd {
+ files.tab = append(files.tab[:cap(files.tab)], nil)
+ }
+ oldf := files.tab[newfd]
+ var oldfdref int
+ if oldf != nil {
+ oldf.fdref--
+ oldfdref = oldf.fdref
+ }
+ files.tab[newfd] = f
+ files.Unlock()
+ if oldf != nil {
+ if oldfdref == 0 {
+ oldf.impl.close()
+ }
+ }
+ return nil
+}
+
+func Fstat(fd int, st *Stat_t) error {
+ f, err := fdToFile(fd)
+ if err != nil {
+ return err
+ }
+ return f.impl.stat(st)
+}
+
+func Read(fd int, b []byte) (int, error) {
+ f, err := fdToFile(fd)
+ if err != nil {
+ return 0, err
+ }
+ return f.impl.read(b)
+}
+
+var zerobuf [0]byte
+
+func Write(fd int, b []byte) (int, error) {
+ if b == nil {
+ // avoid nil in syscalls; nacl doesn't like that.
+ b = zerobuf[:]
+ }
+ f, err := fdToFile(fd)
+ if err != nil {
+ return 0, err
+ }
+ return f.impl.write(b)
+}
+
+func Pread(fd int, b []byte, offset int64) (int, error) {
+ f, err := fdToFile(fd)
+ if err != nil {
+ return 0, err
+ }
+ return f.impl.pread(b, offset)
+}
+
+func Pwrite(fd int, b []byte, offset int64) (int, error) {
+ f, err := fdToFile(fd)
+ if err != nil {
+ return 0, err
+ }
+ return f.impl.pwrite(b, offset)
+}
+
+func Seek(fd int, offset int64, whence int) (int64, error) {
+ f, err := fdToFile(fd)
+ if err != nil {
+ return 0, err
+ }
+ return f.impl.seek(offset, whence)
+}
+
+// defaulFileImpl implements fileImpl.
+// It can be embedded to complete a partial fileImpl implementation.
+type defaultFileImpl struct{}
+
+func (*defaultFileImpl) close() error { return nil }
+func (*defaultFileImpl) stat(*Stat_t) error { return ENOSYS }
+func (*defaultFileImpl) read([]byte) (int, error) { return 0, ENOSYS }
+func (*defaultFileImpl) write([]byte) (int, error) { return 0, ENOSYS }
+func (*defaultFileImpl) seek(int64, int) (int64, error) { return 0, ENOSYS }
+func (*defaultFileImpl) pread([]byte, int64) (int, error) { return 0, ENOSYS }
+func (*defaultFileImpl) pwrite([]byte, int64) (int, error) { return 0, ENOSYS }
+
+// naclFile is the fileImpl implementation for a Native Client file descriptor.
+type naclFile struct {
+ defaultFileImpl
+ naclFD int
+}
+
+func (f *naclFile) stat(st *Stat_t) error {
+ return naclFstat(f.naclFD, st)
+}
+
+func (f *naclFile) read(b []byte) (int, error) {
+ n, err := naclRead(f.naclFD, b)
+ if err != nil {
+ n = 0
+ }
+ return n, err
+}
+
+// implemented in package runtime, to add time header on playground
+func naclWrite(fd int, b []byte) int
+
+func (f *naclFile) write(b []byte) (int, error) {
+ n := naclWrite(f.naclFD, b)
+ if n < 0 {
+ return 0, Errno(-n)
+ }
+ return n, nil
+}
+
+func (f *naclFile) seek(off int64, whence int) (int64, error) {
+ old := off
+ err := naclSeek(f.naclFD, &off, whence)
+ if err != nil {
+ return old, err
+ }
+ return off, nil
+}
+
+func (f *naclFile) prw(b []byte, offset int64, rw func([]byte) (int, error)) (int, error) {
+ // NaCl has no pread; simulate with seek and hope for no races.
+ old, err := f.seek(0, 1)
+ if err != nil {
+ return 0, err
+ }
+ if _, err := f.seek(offset, 0); err != nil {
+ return 0, err
+ }
+ n, err := rw(b)
+ f.seek(old, 0)
+ return n, err
+}
+
+func (f *naclFile) pread(b []byte, offset int64) (int, error) {
+ return f.prw(b, offset, f.read)
+}
+
+func (f *naclFile) pwrite(b []byte, offset int64) (int, error) {
+ return f.prw(b, offset, f.write)
+}
+
+func (f *naclFile) close() error {
+ err := naclClose(f.naclFD)
+ f.naclFD = -1
+ return err
+}
+
+// A pipeFile is an in-memory implementation of a pipe.
+// The byteq implementation is in net_nacl.go.
+type pipeFile struct {
+ defaultFileImpl
+ rd *byteq
+ wr *byteq
+}
+
+func (f *pipeFile) close() error {
+ if f.rd != nil {
+ f.rd.close()
+ }
+ if f.wr != nil {
+ f.wr.close()
+ }
+ return nil
+}
+
+func (f *pipeFile) read(b []byte) (int, error) {
+ if f.rd == nil {
+ return 0, EINVAL
+ }
+ n, err := f.rd.read(b, 0)
+ if err == EAGAIN {
+ err = nil
+ }
+ return n, err
+}
+
+func (f *pipeFile) write(b []byte) (int, error) {
+ if f.wr == nil {
+ return 0, EINVAL
+ }
+ n, err := f.wr.write(b, 0)
+ if err == EAGAIN {
+ err = EPIPE
+ }
+ return n, err
+}
+
+func Pipe(fd []int) error {
+ q := newByteq()
+ fd[0] = newFD(&pipeFile{rd: q})
+ fd[1] = newFD(&pipeFile{wr: q})
+ return nil
+}
diff --git a/src/pkg/syscall/flock.go b/src/pkg/syscall/flock.go
new file mode 100644
index 000000000..62736ae9d
--- /dev/null
+++ b/src/pkg/syscall/flock.go
@@ -0,0 +1,22 @@
+// +build linux darwin freebsd openbsd netbsd dragonfly
+
+// 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"
+
+// fcntl64Syscall is usually SYS_FCNTL, but is overridden on 32-bit Linux
+// systems by flock_linux_32bit.go to be SYS_FCNTL64.
+var fcntl64Syscall uintptr = SYS_FCNTL
+
+// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
+func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error {
+ _, _, errno := Syscall(fcntl64Syscall, fd, uintptr(cmd), uintptr(unsafe.Pointer(lk)))
+ if errno == 0 {
+ return nil
+ }
+ return errno
+}
diff --git a/src/pkg/syscall/flock_linux_32bit.go b/src/pkg/syscall/flock_linux_32bit.go
new file mode 100644
index 000000000..500a97344
--- /dev/null
+++ b/src/pkg/syscall/flock_linux_32bit.go
@@ -0,0 +1,13 @@
+// +build linux,386 linux,arm
+
+// 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
+
+func init() {
+ // On 32-bit Linux systems, the fcntl syscall that matches Go's
+ // Flock_t type is SYS_FCNTL64, not SYS_FCNTL.
+ fcntl64Syscall = SYS_FCNTL64
+}
diff --git a/src/pkg/syscall/fs_nacl.go b/src/pkg/syscall/fs_nacl.go
new file mode 100644
index 000000000..ac9239483
--- /dev/null
+++ b/src/pkg/syscall/fs_nacl.go
@@ -0,0 +1,815 @@
+// 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.
+
+// A simulated Unix-like file system for use within NaCl.
+//
+// The simulation is not particularly tied to NaCl other than the reuse
+// of NaCl's definition for the Stat_t structure.
+//
+// The file system need never be written to disk, so it is represented as
+// in-memory Go data structures, never in a serialized form.
+//
+// TODO: Perhaps support symlinks, although they muck everything up.
+
+package syscall
+
+import (
+ "sync"
+ "unsafe"
+)
+
+// Provided by package runtime.
+func now() (sec int64, nsec int32)
+
+// An fsys is a file system.
+// Since there is no I/O (everything is in memory),
+// the global lock mu protects the whole file system state,
+// and that's okay.
+type fsys struct {
+ mu sync.Mutex
+ root *inode // root directory
+ cwd *inode // process current directory
+ inum uint64 // number of inodes created
+ dev []func() (devFile, error) // table for opening devices
+}
+
+// A devFile is the implementation required of device files
+// like /dev/null or /dev/random.
+type devFile interface {
+ pread([]byte, int64) (int, error)
+ pwrite([]byte, int64) (int, error)
+}
+
+// An inode is a (possibly special) file in the file system.
+type inode struct {
+ Stat_t
+ data []byte
+ dir []dirent
+}
+
+// A dirent describes a single directory entry.
+type dirent struct {
+ name string
+ inode *inode
+}
+
+// An fsysFile is the fileImpl implementation backed by the file system.
+type fsysFile struct {
+ defaultFileImpl
+ fsys *fsys
+ inode *inode
+ openmode int
+ offset int64
+ dev devFile
+}
+
+// newFsys creates a new file system.
+func newFsys() *fsys {
+ fs := &fsys{}
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ ip := fs.newInode()
+ ip.Mode = 0555 | S_IFDIR
+ fs.dirlink(ip, ".", ip)
+ fs.dirlink(ip, "..", ip)
+ fs.cwd = ip
+ fs.root = ip
+ return fs
+}
+
+var fs = newFsys()
+
+func init() {
+ Mkdir("/dev", 0555)
+ Mkdir("/tmp", 0777)
+ mkdev("/dev/null", 0666, openNull)
+ mkdev("/dev/random", 0444, openRandom)
+ mkdev("/dev/urandom", 0444, openRandom)
+ mkdev("/dev/zero", 0666, openZero)
+ chdirEnv()
+}
+
+func chdirEnv() {
+ pwd, ok := Getenv("NACLPWD")
+ if ok {
+ Chdir(pwd)
+ }
+}
+
+// Except where indicated otherwise, unexported methods on fsys
+// expect fs.mu to have been locked by the caller.
+
+// newInode creates a new inode.
+func (fs *fsys) newInode() *inode {
+ fs.inum++
+ ip := &inode{
+ Stat_t: Stat_t{
+ Ino: fs.inum,
+ Blksize: 512,
+ },
+ }
+ return ip
+}
+
+// atime sets ip.Atime to the current time.
+func (fs *fsys) atime(ip *inode) {
+ sec, nsec := now()
+ ip.Atime, ip.AtimeNsec = sec, int64(nsec)
+}
+
+// mtime sets ip.Mtime to the current time.
+func (fs *fsys) mtime(ip *inode) {
+ sec, nsec := now()
+ ip.Mtime, ip.MtimeNsec = sec, int64(nsec)
+}
+
+// dirlookup looks for an entry in the directory dp with the given name.
+// It returns the directory entry and its index within the directory.
+func (fs *fsys) dirlookup(dp *inode, name string) (de *dirent, index int, err error) {
+ fs.atime(dp)
+ for i := range dp.dir {
+ de := &dp.dir[i]
+ if de.name == name {
+ fs.atime(de.inode)
+ return de, i, nil
+ }
+ }
+ return nil, 0, ENOENT
+}
+
+// dirlink adds to the directory dp an entry for name pointing at the inode ip.
+// If dp already contains an entry for name, that entry is overwritten.
+func (fs *fsys) dirlink(dp *inode, name string, ip *inode) {
+ fs.mtime(dp)
+ fs.atime(ip)
+ ip.Nlink++
+ for i := range dp.dir {
+ if dp.dir[i].name == name {
+ dp.dir[i] = dirent{name, ip}
+ return
+ }
+ }
+ dp.dir = append(dp.dir, dirent{name, ip})
+ dp.dirSize()
+}
+
+func (dp *inode) dirSize() {
+ dp.Size = int64(len(dp.dir)) * (8 + 8 + 2 + 256) // Dirent
+}
+
+// skipelem splits path into the first element and the remainder.
+// the returned first element contains no slashes, and the returned
+// remainder does not begin with a slash.
+func skipelem(path string) (elem, rest string) {
+ for len(path) > 0 && path[0] == '/' {
+ path = path[1:]
+ }
+ if len(path) == 0 {
+ return "", ""
+ }
+ i := 0
+ for i < len(path) && path[i] != '/' {
+ i++
+ }
+ elem, path = path[:i], path[i:]
+ for len(path) > 0 && path[0] == '/' {
+ path = path[1:]
+ }
+ return elem, path
+}
+
+// namei translates a file system path name into an inode.
+// If parent is false, the returned ip corresponds to the given name, and elem is the empty string.
+// If parent is false, the walk stops at the next-to-last element in the name,
+// so that ip is the parent directory and elem is the final element in the path.
+func (fs *fsys) namei(path string, parent bool) (ip *inode, elem string, err error) {
+ // Reject NUL in name.
+ for i := 0; i < len(path); i++ {
+ if path[i] == '\x00' {
+ return nil, "", EINVAL
+ }
+ }
+
+ // Reject empty name.
+ if path == "" {
+ return nil, "", EINVAL
+ }
+
+ if path[0] == '/' {
+ ip = fs.root
+ } else {
+ ip = fs.cwd
+ }
+
+ for len(path) > 0 && path[len(path)-1] == '/' {
+ path = path[:len(path)-1]
+ }
+
+ for {
+ elem, rest := skipelem(path)
+ if elem == "" {
+ if parent && ip.Mode&S_IFMT == S_IFDIR {
+ return ip, ".", nil
+ }
+ break
+ }
+ if ip.Mode&S_IFMT != S_IFDIR {
+ return nil, "", ENOTDIR
+ }
+ if len(elem) >= 256 {
+ return nil, "", ENAMETOOLONG
+ }
+ if parent && rest == "" {
+ // Stop one level early.
+ return ip, elem, nil
+ }
+ de, _, err := fs.dirlookup(ip, elem)
+ if err != nil {
+ return nil, "", err
+ }
+ ip = de.inode
+ path = rest
+ }
+ if parent {
+ return nil, "", ENOTDIR
+ }
+ return ip, "", nil
+}
+
+// open opens or creates a file with the given name, open mode,
+// and permission mode bits.
+func (fs *fsys) open(name string, openmode int, mode uint32) (fileImpl, error) {
+ dp, elem, err := fs.namei(name, true)
+ if err != nil {
+ return nil, err
+ }
+ var (
+ ip *inode
+ dev devFile
+ )
+ de, _, err := fs.dirlookup(dp, elem)
+ if err != nil {
+ if openmode&O_CREATE == 0 {
+ return nil, err
+ }
+ ip = fs.newInode()
+ ip.Mode = mode
+ fs.dirlink(dp, elem, ip)
+ if ip.Mode&S_IFMT == S_IFDIR {
+ fs.dirlink(ip, ".", ip)
+ fs.dirlink(ip, "..", dp)
+ }
+ } else {
+ ip = de.inode
+ if openmode&(O_CREATE|O_EXCL) == O_CREATE|O_EXCL {
+ return nil, EEXIST
+ }
+ if openmode&O_TRUNC != 0 {
+ if ip.Mode&S_IFMT == S_IFDIR {
+ return nil, EISDIR
+ }
+ ip.data = nil
+ }
+ if ip.Mode&S_IFMT == S_IFCHR {
+ if ip.Rdev < 0 || ip.Rdev >= int64(len(fs.dev)) || fs.dev[ip.Rdev] == nil {
+ return nil, ENODEV
+ }
+ dev, err = fs.dev[ip.Rdev]()
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+
+ switch openmode & O_ACCMODE {
+ case O_WRONLY, O_RDWR:
+ if ip.Mode&S_IFMT == S_IFDIR {
+ return nil, EISDIR
+ }
+ }
+
+ switch ip.Mode & S_IFMT {
+ case S_IFDIR:
+ if openmode&O_ACCMODE != O_RDONLY {
+ return nil, EISDIR
+ }
+
+ case S_IFREG:
+ // ok
+
+ case S_IFCHR:
+ // handled above
+
+ default:
+ // TODO: some kind of special file
+ return nil, EPERM
+ }
+
+ f := &fsysFile{
+ fsys: fs,
+ inode: ip,
+ openmode: openmode,
+ dev: dev,
+ }
+ if openmode&O_APPEND != 0 {
+ f.offset = ip.Size
+ }
+ return f, nil
+}
+
+// fsysFile methods to implement fileImpl.
+
+func (f *fsysFile) stat(st *Stat_t) error {
+ f.fsys.mu.Lock()
+ defer f.fsys.mu.Unlock()
+ *st = f.inode.Stat_t
+ return nil
+}
+
+func (f *fsysFile) read(b []byte) (int, error) {
+ f.fsys.mu.Lock()
+ defer f.fsys.mu.Unlock()
+ n, err := f.preadLocked(b, f.offset)
+ f.offset += int64(n)
+ return n, err
+}
+
+func ReadDirent(fd int, buf []byte) (int, error) {
+ f, err := fdToFsysFile(fd)
+ if err != nil {
+ return 0, err
+ }
+ f.fsys.mu.Lock()
+ defer f.fsys.mu.Unlock()
+ if f.inode.Mode&S_IFMT != S_IFDIR {
+ return 0, EINVAL
+ }
+ n, err := f.preadLocked(buf, f.offset)
+ f.offset += int64(n)
+ return n, err
+}
+
+func (f *fsysFile) write(b []byte) (int, error) {
+ f.fsys.mu.Lock()
+ defer f.fsys.mu.Unlock()
+ n, err := f.pwriteLocked(b, f.offset)
+ f.offset += int64(n)
+ return n, err
+}
+
+func (f *fsysFile) seek(offset int64, whence int) (int64, error) {
+ f.fsys.mu.Lock()
+ defer f.fsys.mu.Unlock()
+ switch whence {
+ case 1:
+ offset += f.offset
+ case 2:
+ offset += f.inode.Size
+ }
+ if offset < 0 {
+ return 0, EINVAL
+ }
+ if offset > f.inode.Size {
+ return 0, EINVAL
+ }
+ f.offset = offset
+ return offset, nil
+}
+
+func (f *fsysFile) pread(b []byte, offset int64) (int, error) {
+ f.fsys.mu.Lock()
+ defer f.fsys.mu.Unlock()
+ return f.preadLocked(b, offset)
+}
+
+func (f *fsysFile) pwrite(b []byte, offset int64) (int, error) {
+ f.fsys.mu.Lock()
+ defer f.fsys.mu.Unlock()
+ return f.pwriteLocked(b, offset)
+}
+
+func (f *fsysFile) preadLocked(b []byte, offset int64) (int, error) {
+ if f.openmode&O_ACCMODE == O_WRONLY {
+ return 0, EINVAL
+ }
+ if offset < 0 {
+ return 0, EINVAL
+ }
+ if f.dev != nil {
+ f.fsys.atime(f.inode)
+ f.fsys.mu.Unlock()
+ defer f.fsys.mu.Lock()
+ return f.dev.pread(b, offset)
+ }
+ if offset > f.inode.Size {
+ return 0, nil
+ }
+ if int64(len(b)) > f.inode.Size-offset {
+ b = b[:f.inode.Size-offset]
+ }
+
+ if f.inode.Mode&S_IFMT == S_IFDIR {
+ if offset%direntSize != 0 || len(b) != 0 && len(b) < direntSize {
+ return 0, EINVAL
+ }
+ fs.atime(f.inode)
+ n := 0
+ for len(b) >= direntSize {
+ src := f.inode.dir[int(offset/direntSize)]
+ dst := (*Dirent)(unsafe.Pointer(&b[0]))
+ dst.Ino = int64(src.inode.Ino)
+ dst.Off = offset
+ dst.Reclen = direntSize
+ for i := range dst.Name {
+ dst.Name[i] = 0
+ }
+ copy(dst.Name[:], src.name)
+ n += direntSize
+ offset += direntSize
+ b = b[direntSize:]
+ }
+ return n, nil
+ }
+
+ fs.atime(f.inode)
+ n := copy(b, f.inode.data[offset:])
+ return n, nil
+}
+
+func (f *fsysFile) pwriteLocked(b []byte, offset int64) (int, error) {
+ if f.openmode&O_ACCMODE == O_RDONLY {
+ return 0, EINVAL
+ }
+ if offset < 0 {
+ return 0, EINVAL
+ }
+ if f.dev != nil {
+ f.fsys.atime(f.inode)
+ f.fsys.mu.Unlock()
+ defer f.fsys.mu.Lock()
+ return f.dev.pwrite(b, offset)
+ }
+ if offset > f.inode.Size {
+ return 0, EINVAL
+ }
+ f.fsys.mtime(f.inode)
+ n := copy(f.inode.data[offset:], b)
+ if n < len(b) {
+ f.inode.data = append(f.inode.data, b[n:]...)
+ f.inode.Size = int64(len(f.inode.data))
+ }
+ return len(b), nil
+}
+
+// Standard Unix system calls.
+
+func Open(path string, openmode int, perm uint32) (fd int, err error) {
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ f, err := fs.open(path, openmode, perm&0777|S_IFREG)
+ if err != nil {
+ return -1, err
+ }
+ return newFD(f), nil
+}
+
+func Mkdir(path string, perm uint32) error {
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ _, err := fs.open(path, O_CREATE|O_EXCL, perm&0777|S_IFDIR)
+ return err
+}
+
+func Getcwd(buf []byte) (n int, err error) {
+ // Force package os to default to the old algorithm using .. and directory reads.
+ return 0, ENOSYS
+}
+
+func Stat(path string, st *Stat_t) error {
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ ip, _, err := fs.namei(path, false)
+ if err != nil {
+ return err
+ }
+ *st = ip.Stat_t
+ return nil
+}
+
+func Lstat(path string, st *Stat_t) error {
+ return Stat(path, st)
+}
+
+func unlink(path string, isdir bool) error {
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ dp, elem, err := fs.namei(path, true)
+ if err != nil {
+ return err
+ }
+ if elem == "." || elem == ".." {
+ return EINVAL
+ }
+ de, _, err := fs.dirlookup(dp, elem)
+ if err != nil {
+ return err
+ }
+ if isdir {
+ if de.inode.Mode&S_IFMT != S_IFDIR {
+ return ENOTDIR
+ }
+ if len(de.inode.dir) != 2 {
+ return ENOTEMPTY
+ }
+ } else {
+ if de.inode.Mode&S_IFMT == S_IFDIR {
+ return EISDIR
+ }
+ }
+ de.inode.Nlink--
+ *de = dp.dir[len(dp.dir)-1]
+ dp.dir = dp.dir[:len(dp.dir)-1]
+ dp.dirSize()
+ return nil
+}
+
+func Unlink(path string) error {
+ return unlink(path, false)
+}
+
+func Rmdir(path string) error {
+ return unlink(path, true)
+}
+
+func Chmod(path string, mode uint32) error {
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ ip, _, err := fs.namei(path, false)
+ if err != nil {
+ return err
+ }
+ ip.Mode = ip.Mode&^0777 | mode&0777
+ return nil
+}
+
+func Fchmod(fd int, mode uint32) error {
+ f, err := fdToFsysFile(fd)
+ if err != nil {
+ return err
+ }
+ f.fsys.mu.Lock()
+ defer f.fsys.mu.Unlock()
+ f.inode.Mode = f.inode.Mode&^0777 | mode&0777
+ return nil
+}
+
+func Chown(path string, uid, gid int) error {
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ ip, _, err := fs.namei(path, false)
+ if err != nil {
+ return err
+ }
+ ip.Uid = uint32(uid)
+ ip.Gid = uint32(gid)
+ return nil
+}
+
+func Fchown(fd int, uid, gid int) error {
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ f, err := fdToFsysFile(fd)
+ if err != nil {
+ return err
+ }
+ f.fsys.mu.Lock()
+ defer f.fsys.mu.Unlock()
+ f.inode.Uid = uint32(uid)
+ f.inode.Gid = uint32(gid)
+ return nil
+}
+
+func Lchown(path string, uid, gid int) error {
+ return Chown(path, uid, gid)
+}
+
+func UtimesNano(path string, ts []Timespec) error {
+ if len(ts) != 2 {
+ return EINVAL
+ }
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ ip, _, err := fs.namei(path, false)
+ if err != nil {
+ return err
+ }
+ ip.Atime = ts[0].Sec
+ ip.AtimeNsec = int64(ts[0].Nsec)
+ ip.Mtime = ts[1].Sec
+ ip.MtimeNsec = int64(ts[1].Nsec)
+ return nil
+}
+
+func Link(path, link string) error {
+ ip, _, err := fs.namei(path, false)
+ if err != nil {
+ return err
+ }
+ dp, elem, err := fs.namei(link, true)
+ if err != nil {
+ return err
+ }
+ if ip.Mode&S_IFMT == S_IFDIR {
+ return EPERM
+ }
+ fs.dirlink(dp, elem, ip)
+ return nil
+}
+
+func Rename(from, to string) error {
+ fdp, felem, err := fs.namei(from, true)
+ if err != nil {
+ return err
+ }
+ fde, _, err := fs.dirlookup(fdp, felem)
+ if err != nil {
+ return err
+ }
+ tdp, telem, err := fs.namei(to, true)
+ if err != nil {
+ return err
+ }
+ fs.dirlink(tdp, telem, fde.inode)
+ fde.inode.Nlink--
+ *fde = fdp.dir[len(fdp.dir)-1]
+ fdp.dir = fdp.dir[:len(fdp.dir)-1]
+ fdp.dirSize()
+ return nil
+}
+
+func (fs *fsys) truncate(ip *inode, length int64) error {
+ if length > 1e9 || ip.Mode&S_IFMT != S_IFREG {
+ return EINVAL
+ }
+ if length < int64(len(ip.data)) {
+ ip.data = ip.data[:length]
+ } else {
+ data := make([]byte, length)
+ copy(data, ip.data)
+ ip.data = data
+ }
+ ip.Size = int64(len(ip.data))
+ return nil
+}
+
+func Truncate(path string, length int64) error {
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ ip, _, err := fs.namei(path, false)
+ if err != nil {
+ return err
+ }
+ return fs.truncate(ip, length)
+}
+
+func Ftruncate(fd int, length int64) error {
+ f, err := fdToFsysFile(fd)
+ if err != nil {
+ return err
+ }
+ f.fsys.mu.Lock()
+ defer f.fsys.mu.Unlock()
+ return f.fsys.truncate(f.inode, length)
+}
+
+func Chdir(path string) error {
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ ip, _, err := fs.namei(path, false)
+ if err != nil {
+ return err
+ }
+ fs.cwd = ip
+ return nil
+}
+
+func Fchdir(fd int) error {
+ f, err := fdToFsysFile(fd)
+ if err != nil {
+ return err
+ }
+ f.fsys.mu.Lock()
+ defer f.fsys.mu.Unlock()
+ if f.inode.Mode&S_IFMT != S_IFDIR {
+ return ENOTDIR
+ }
+ fs.cwd = f.inode
+ return nil
+}
+
+func Readlink(path string, buf []byte) (n int, err error) {
+ return 0, ENOSYS
+}
+
+func Symlink(path, link string) error {
+ return ENOSYS
+}
+
+func Fsync(fd int) error {
+ return nil
+}
+
+// Special devices.
+
+func mkdev(path string, mode uint32, open func() (devFile, error)) error {
+ fs.mu.Lock()
+ fs.mu.Unlock()
+ f, err := fs.open(path, O_CREATE|O_RDONLY|O_EXCL, S_IFCHR|mode)
+ if err != nil {
+ return err
+ }
+ ip := f.(*fsysFile).inode
+ ip.Rdev = int64(len(fs.dev))
+ fs.dev = append(fs.dev, open)
+ return nil
+}
+
+type nullFile struct{}
+
+func openNull() (devFile, error) { return &nullFile{}, nil }
+func (f *nullFile) close() error { return nil }
+func (f *nullFile) pread(b []byte, offset int64) (int, error) { return 0, nil }
+func (f *nullFile) pwrite(b []byte, offset int64) (int, error) { return len(b), nil }
+
+type zeroFile struct{}
+
+func openZero() (devFile, error) { return &zeroFile{}, nil }
+func (f *zeroFile) close() error { return nil }
+func (f *zeroFile) pwrite(b []byte, offset int64) (int, error) { return len(b), nil }
+
+func (f *zeroFile) pread(b []byte, offset int64) (int, error) {
+ for i := range b {
+ b[i] = 0
+ }
+ return len(b), nil
+}
+
+type randomFile struct {
+ naclFD int
+}
+
+func openRandom() (devFile, error) {
+ fd, err := openNamedService("SecureRandom", O_RDONLY)
+ if err != nil {
+ return nil, err
+ }
+ return &randomFile{naclFD: fd}, nil
+}
+
+func (f *randomFile) close() error {
+ naclClose(f.naclFD)
+ f.naclFD = -1
+ return nil
+}
+
+func (f *randomFile) pread(b []byte, offset int64) (int, error) {
+ return naclRead(f.naclFD, b)
+}
+
+func (f *randomFile) pwrite(b []byte, offset int64) (int, error) {
+ return 0, EPERM
+}
+
+func fdToFsysFile(fd int) (*fsysFile, error) {
+ f, err := fdToFile(fd)
+ if err != nil {
+ return nil, err
+ }
+ impl := f.impl
+ fsysf, ok := impl.(*fsysFile)
+ if !ok {
+ return nil, EINVAL
+ }
+ return fsysf, nil
+}
+
+// create creates a file in the file system with the given name, mode, time, and data.
+// It is meant to be called when initializing the file system image.
+func create(name string, mode uint32, sec int64, data []byte) error {
+ fs.mu.Lock()
+ fs.mu.Unlock()
+ f, err := fs.open(name, O_CREATE|O_EXCL, mode)
+ if err != nil {
+ return err
+ }
+ ip := f.(*fsysFile).inode
+ ip.Atime = sec
+ ip.Mtime = sec
+ ip.Ctime = sec
+ if len(data) > 0 {
+ ip.Size = int64(len(data))
+ ip.data = data
+ }
+ return nil
+}
diff --git a/src/pkg/syscall/lsf_linux.go b/src/pkg/syscall/lsf_linux.go
index 05d653b4a..ee07fea3f 100644
--- a/src/pkg/syscall/lsf_linux.go
+++ b/src/pkg/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, uintptr(unsafe.Pointer(&p)), unsafe.Sizeof(p))
+ return setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, unsafe.Pointer(&p), unsafe.Sizeof(p))
}
func DetachLsf(fd int) error {
var dummy int
- return setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, uintptr(unsafe.Pointer(&dummy)), unsafe.Sizeof(dummy))
+ return setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, unsafe.Pointer(&dummy), unsafe.Sizeof(dummy))
}
diff --git a/src/pkg/syscall/mkall.sh b/src/pkg/syscall/mkall.sh
index a3139d603..886db133c 100755
--- a/src/pkg/syscall/mkall.sh
+++ b/src/pkg/syscall/mkall.sh
@@ -81,6 +81,8 @@ mkerrors="./mkerrors.sh"
zerrors="zerrors_$GOOSARCH.go"
mksysctl=""
zsysctl="zsysctl_$GOOSARCH.go"
+mksysnum=
+mktypes=
run="sh"
case "$1" in
@@ -136,19 +138,21 @@ dragonfly_amd64)
freebsd_386)
mkerrors="$mkerrors -m32"
mksyscall="./mksyscall.pl -l32"
- mksysnum="curl -s 'http://svn.freebsd.org/base/head/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
+ mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
freebsd_amd64)
mkerrors="$mkerrors -m64"
- mksysnum="curl -s 'http://svn.freebsd.org/base/head/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
+ mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
freebsd_arm)
mkerrors="$mkerrors"
mksyscall="./mksyscall.pl -l32 -arm"
- mksysnum="curl -s 'http://svn.freebsd.org/base/head/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
- mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
+ # Let the type of C char be singed for making the bare syscall
+ # API consistent across over platforms.
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;;
linux_386)
mkerrors="$mkerrors -m32"
@@ -172,6 +176,18 @@ linux_arm)
mksysnum="curl -s 'http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/plain/arch/arm/include/uapi/asm/unistd.h' | ./mksysnum_linux.pl"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
+nacl_386)
+ mkerrors=""
+ mksyscall="./mksyscall.pl -l32 -nacl"
+ mksysnum=""
+ mktypes=""
+ ;;
+nacl_amd64p32)
+ mkerrors=""
+ mksyscall="./mksyscall.pl -nacl"
+ mksysnum=""
+ mktypes=""
+ ;;
netbsd_386)
mkerrors="$mkerrors -m32"
mksyscall="./mksyscall.pl -l32 -netbsd"
@@ -206,19 +222,16 @@ plan9_386)
mksysnum="./mksysnum_plan9.sh /n/sources/plan9/sys/src/libc/9syscall/sys.h"
mktypes="XXX"
;;
-windows_386)
- mksyscall="./mksyscall_windows.pl -l32"
+solaris_amd64)
+ mksyscall="./mksyscall_solaris.pl"
+ mkerrors="$mkerrors -m64"
mksysnum=
- mktypes=
- mkerrors="./mkerrors_windows.sh -m32"
- zerrors="zerrors_windows.go"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
-windows_amd64)
- mksyscall="./mksyscall_windows.pl"
- mksysnum=
- mktypes=
- mkerrors="./mkerrors_windows.sh -m32"
- zerrors="zerrors_windows.go"
+windows_*)
+ mksyscall=
+ mkerrors=
+ zerrors=
;;
*)
echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2
@@ -228,17 +241,23 @@ esac
(
if [ -n "$mkerrors" ]; then echo "$mkerrors |gofmt >$zerrors"; fi
- syscall_goos="syscall_$GOOS.go"
case "$GOOS" in
- darwin | dragonfly | freebsd | netbsd | openbsd)
- syscall_goos="syscall_bsd.go $syscall_goos"
- ;;
windows)
- syscall_goos="$syscall_goos security_windows.go"
+ echo "GOOS= GOARCH= go build mksyscall_windows.go"
+ echo "./mksyscall_windows syscall_windows.go security_windows.go syscall_$GOOSARCH.go |gofmt >zsyscall_$GOOSARCH.go"
+ echo "rm -f ./mksyscall_windows"
+ ;;
+ *)
+ syscall_goos="syscall_$GOOS.go"
+ case "$GOOS" in
+ darwin | dragonfly | freebsd | netbsd | openbsd)
+ syscall_goos="syscall_bsd.go $syscall_goos"
+ ;;
+ esac
+ if [ -n "$mksyscall" ]; then echo "$mksyscall $syscall_goos syscall_$GOOSARCH.go |gofmt >zsyscall_$GOOSARCH.go"; fi
;;
esac
if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi
- if [ -n "$mksyscall" ]; then echo "$mksyscall $syscall_goos syscall_$GOOSARCH.go |gofmt >zsyscall_$GOOSARCH.go"; fi
if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi
if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go |gofmt >ztypes_$GOOSARCH.go"; fi
) | $run
diff --git a/src/pkg/syscall/mkall_windows.bat b/src/pkg/syscall/mkall_windows.bat
new file mode 100644
index 000000000..a4a3f1674
--- /dev/null
+++ b/src/pkg/syscall/mkall_windows.bat
@@ -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.
+@echo off
+
+if exist mkall.sh goto dirok
+echo mkall_windows.bat must be run from src\pkg\syscall directory
+goto :end
+:dirok
+
+if "%1"=="386" goto :paramok
+if "%1"=="amd64" goto :paramok
+echo parameters must be 386 or amd64
+goto :end
+:paramok
+
+go build mksyscall_windows.go
+.\mksyscall_windows syscall_windows.go security_windows.go syscall_windows_%1.go |gofmt >zsyscall_windows_%1.go
+del mksyscall_windows.exe
+
+:end \ No newline at end of file
diff --git a/src/pkg/syscall/mkerrors.sh b/src/pkg/syscall/mkerrors.sh
index 20b2b9875..cf0afe0bd 100755
--- a/src/pkg/syscall/mkerrors.sh
+++ b/src/pkg/syscall/mkerrors.sh
@@ -11,7 +11,7 @@ unset LANG
export LC_ALL=C
export LC_CTYPE=C
-GCC=gcc
+CC=${CC:-gcc}
uname=$(uname)
@@ -57,6 +57,7 @@ includes_DragonFly='
'
includes_FreeBSD='
+#include <sys/param.h>
#include <sys/types.h>
#include <sys/event.h>
#include <sys/socket.h>
@@ -73,6 +74,14 @@ includes_FreeBSD='
#include <termios.h>
#include <netinet/ip.h>
#include <netinet/ip_mroute.h>
+
+#if __FreeBSD__ >= 10
+#define IFT_CARP 0xf8 // IFT_CARP is deprecated in FreeBSD 10
+#undef SIOCAIFADDR
+#define SIOCAIFADDR _IOW(105, 26, struct oifaliasreq) // ifaliasreq contains if_data
+#undef SIOCSIFPHYADDR
+#define SIOCSIFPHYADDR _IOW(105, 70, struct oifaliasreq) // ifaliasreq contains if_data
+#endif
'
includes_Linux='
@@ -92,9 +101,12 @@ includes_Linux='
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
-#include <linux/if_addr.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/if_tun.h>
+#include <linux/if_packet.h>
+#include <linux/if_addr.h>
#include <linux/filter.h>
#include <linux/netlink.h>
#include <linux/reboot.h>
@@ -103,10 +115,7 @@ includes_Linux='
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/icmpv6.h>
-#include <net/if.h>
-#include <net/if_arp.h>
#include <net/route.h>
-#include <netpacket/packet.h>
#include <termios.h>
#ifndef MSG_FASTOPEN
@@ -118,6 +127,7 @@ includes_NetBSD='
#include <sys/types.h>
#include <sys/param.h>
#include <sys/event.h>
+#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
@@ -142,6 +152,7 @@ includes_OpenBSD='
#include <sys/types.h>
#include <sys/param.h>
#include <sys/event.h>
+#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
@@ -151,6 +162,7 @@ includes_OpenBSD='
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_types.h>
+#include <net/if_var.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
@@ -158,6 +170,36 @@ includes_OpenBSD='
#include <netinet/ip_mroute.h>
#include <netinet/if_ether.h>
#include <net/if_bridge.h>
+
+// We keep some constants not supported in OpenBSD 5.5 and beyond for
+// the promise of compatibility.
+#define EMUL_ENABLED 0x1
+#define EMUL_NATIVE 0x2
+#define IPV6_FAITH 0x1d
+#define IPV6_OPTIONS 0x1
+#define IPV6_RTHDR_STRICT 0x1
+#define IPV6_SOCKOPT_RESERVED1 0x3
+#define SIOCGIFGENERIC 0xc020693a
+#define SIOCSIFGENERIC 0x80206939
+#define WALTSIG 0x4
+'
+
+includes_SunOS='
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <sys/ioctl.h>
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_types.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <termios.h>
+#include <netinet/ip.h>
+#include <netinet/ip_mroute.h>
'
includes='
@@ -192,7 +234,7 @@ ccflags="$@"
# The gcc command line prints all the #defines
# it encounters while processing the input
- echo "${!indirect} $includes" | $GCC -x c - -E -dM $ccflags |
+ echo "${!indirect} $includes" | $CC -x c - -E -dM $ccflags |
awk '
$1 != "#define" || $2 ~ /\(/ || $3 == "" {next}
@@ -240,6 +282,7 @@ ccflags="$@"
$2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P)_/ ||
$2 ~ /^SIOC/ ||
$2 ~ /^TIOC/ ||
+ $2 !~ "RTF_BITS" &&
$2 ~ /^(IFF|IFT|NET_RT|RTM|RTF|RTV|RTA|RTAX)_/ ||
$2 ~ /^BIOC/ ||
$2 ~ /^RUSAGE_(SELF|CHILDREN|THREAD)/ ||
@@ -261,24 +304,24 @@ ccflags="$@"
# Pull out the error names for later.
errors=$(
- echo '#include <errno.h>' | $GCC -x c - -E -dM $ccflags |
+ echo '#include <errno.h>' | $CC -x c - -E -dM $ccflags |
awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print $2 }' |
sort
)
# Pull out the signal names for later.
signals=$(
- echo '#include <signal.h>' | $GCC -x c - -E -dM $ccflags |
+ echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print $2 }' |
egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT)' |
sort
)
# Again, writing regexps to a file.
-echo '#include <errno.h>' | $GCC -x c - -E -dM $ccflags |
+echo '#include <errno.h>' | $CC -x c - -E -dM $ccflags |
awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print "^\t" $2 "[ \t]*=" }' |
sort >_error.grep
-echo '#include <signal.h>' | $GCC -x c - -E -dM $ccflags |
+echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print "^\t" $2 "[ \t]*=" }' |
egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT)' |
sort >_signal.grep
@@ -302,8 +345,9 @@ echo ')'
# Run C program to print error and syscall strings.
(
- /bin/echo "
+ echo -E "
#include <stdio.h>
+#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <string.h>
@@ -317,22 +361,21 @@ int errors[] = {
"
for i in $errors
do
- /bin/echo ' '$i,
+ echo -E ' '$i,
done
- /bin/echo "
+ echo -E "
};
int signals[] = {
"
for i in $signals
do
- /bin/echo ' '$i,
+ echo -E ' '$i,
done
- # Use /bin/echo to avoid builtin echo,
- # which interprets \n itself
- /bin/echo '
+ # Use -E because on some systems bash builtin interprets \n itself.
+ echo -E '
};
static int
@@ -387,4 +430,4 @@ main(void)
'
) >_errors.c
-$GCC $ccflags -o _errors _errors.c && $GORUN ./_errors && rm -f _errors.c _errors _const.go _error.grep _signal.grep _error.out
+$CC $ccflags -o _errors _errors.c && $GORUN ./_errors && rm -f _errors.c _errors _const.go _error.grep _signal.grep _error.out
diff --git a/src/pkg/syscall/mkerrors_windows.sh b/src/pkg/syscall/mkerrors_windows.sh
deleted file mode 100755
index 13badcd92..000000000
--- a/src/pkg/syscall/mkerrors_windows.sh
+++ /dev/null
@@ -1,202 +0,0 @@
-#!/usr/bin/env bash
-# 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.
-
-# Generate Go code listing errors and other #defined constant
-# values (ENAMETOOLONG etc.), by asking the preprocessor
-# about the definitions.
-
-unset LANG
-export LC_ALL=C
-export LC_CTYPE=C
-
-case "$GOARCH" in
-arm)
- GCC=arm-gcc
- ;;
-*)
- GCC=gcc
- ;;
-esac
-
-uname=$(uname)
-
-includes_Linux='
-#define _LARGEFILE_SOURCE
-#define _LARGEFILE64_SOURCE
-#define _FILE_OFFSET_BITS 64
-#define _GNU_SOURCE
-
-#include <sys/types.h>
-#include <sys/epoll.h>
-#include <linux/ptrace.h>
-#include <linux/wait.h>
-'
-
-includes_Darwin='
-#define __DARWIN_UNIX03 0
-#define KERNEL
-#define _DARWIN_USE_64_BIT_INODE
-#include <sys/wait.h>
-#include <sys/event.h>
-'
-
-includes_FreeBSD='
-#include <sys/wait.h>
-#include <sys/event.h>
-'
-
-includes='
-#include <sys/types.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <netinet/ip6.h>
-#include <netinet/tcp.h>
-#include <errno.h>
-#include <sys/signal.h>
-#include <signal.h>
-'
-
-ccflags=""
-next=false
-for i
-do
- if $next; then
- ccflags="$ccflags $i"
- next=false
- elif [ "$i" = "-f" ]; then
- next=true
- fi
-done
-
-# These are go errors that will be mapped directly to windows errors
-goerrors='
-ENOENT:ERROR_FILE_NOT_FOUND
-ENOTDIR:ERROR_PATH_NOT_FOUND
-'
-
-# Pull out just the error names for later.
-i=$(
- for j in "$goerrors"
- do
- echo "$j"
- done |
- awk -F: '
- { if (NR > 1) printf("|") }
- { printf("%s", $1) }
- '
-)
-errors=$(
- echo '#include <errno.h>' | $GCC -x c - -E -dM $ccflags |
- awk '
- $1 != "#define" || $2 ~ /\(/ {next}
- $2 ~ /^('$i')$/ {next}
- $2 ~ /^E[A-Z0-9_]+$/ { print $2 }
- {next}
- ' | sort
-)
-
-echo '// mkerrors_windows.sh' "$@"
-echo '// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT'
-echo
-echo 'package syscall'
-
-# Run C program to print error strings.
-(
- /bin/echo "
-#include <stdio.h>
-#include <errno.h>
-#include <ctype.h>
-#include <string.h>
-
-#define nelem(x) (sizeof(x)/sizeof((x)[0]))
-
-enum { A = 'A', Z = 'Z', a = 'a', z = 'z' }; // avoid need for single quotes below
-
-struct {
- char *goname;
- char *winname;
-} goerrors[] = {
-"
- for i in $goerrors
- do
- j=`echo $i | cut -d: -f1`
- k=`echo $i | cut -d: -f2`
- echo ' {"'$j'", "'$k'"},'
- done
-
- # Use /bin/echo to avoid builtin echo,
- # which interprets \n itself
- /bin/echo '
-};
-
-struct {
- char *name;
- int value;
-} errors[] = {
-'
- for i in $errors
- do
- echo ' {"'$i'",' $i'},'
- done
-
- # Use /bin/echo to avoid builtin echo,
- # which interprets \n itself
- /bin/echo '
-};
-
-int
-main(void)
-{
- int i, e, iota = 1;
- char buf[1024];
-
- printf("\n// Go names for Windows errors.\n");
- printf("const (\n");
- for(i=0; i<nelem(goerrors); i++) {
- printf("\t%s Errno = %s\n", goerrors[i].goname, goerrors[i].winname);
-
- }
- printf(")\n");
-
- printf("\n// Windows reserves errors >= 1<<29 for application use.\n");
- printf("const APPLICATION_ERROR = 1 << 29\n");
-
- printf("\n// Invented values to support what package os and others expects.\n");
- printf("const (\n");
- for(i=0; i<nelem(errors); i++) {
- printf("\t%s", errors[i].name);
- if(iota) {
- printf(" Errno = APPLICATION_ERROR + iota");
- iota = !iota;
- }
- printf("\n");
-
- }
- printf("\tEWINDOWS\n");
- printf(")\n");
-
- printf("\n// Error strings for invented errors\n");
- printf("var errors = [...]string {\n");
- for(i=0; i<nelem(errors); i++) {
- e = errors[i].value;
- strcpy(buf, strerror(e));
- // lowercase first letter: Bad -> bad, but STREAM -> STREAM.
- if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z)
- buf[0] += a - A;
- printf("\t%s - APPLICATION_ERROR: \"%s\",\n", errors[i].name, buf);
- next:;
- }
- printf("\tEWINDOWS - APPLICATION_ERROR: \"not supported by windows\",\n");
- printf("}\n\n");
- return 0;
-}
-
-'
-) >_errors.c
-
-$GCC $ccflags -static -o _errors _errors.c && $GORUN ./_errors && rm -f _errors.c _errors
diff --git a/src/pkg/syscall/mksyscall.pl b/src/pkg/syscall/mksyscall.pl
index b4ece9a54..6d35fa689 100755
--- a/src/pkg/syscall/mksyscall.pl
+++ b/src/pkg/syscall/mksyscall.pl
@@ -28,6 +28,7 @@ my $plan9 = 0;
my $openbsd = 0;
my $netbsd = 0;
my $dragonfly = 0;
+my $nacl = 0;
my $arm = 0; # 64-bit value should use (even, odd)-pair
if($ARGV[0] eq "-b32") {
@@ -53,6 +54,10 @@ if($ARGV[0] eq "-dragonfly") {
$dragonfly = 1;
shift;
}
+if($ARGV[0] eq "-nacl") {
+ $nacl = 1;
+ shift;
+}
if($ARGV[0] eq "-arm") {
$arm = 1;
shift;
@@ -95,7 +100,7 @@ while(<>) {
# Line must be of the form
# func Open(path string, mode int, perm int) (fd int, errno error)
# Split into name, in params, out params.
- if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(SYS_[A-Z0-9_]+))?$/) {
+ if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*((?i)SYS_[A-Z0-9_]+))?$/) {
print STDERR "$ARGV:$.: malformed //sys declaration\n";
$errors = 1;
next;
@@ -219,6 +224,9 @@ while(<>) {
$sysname = "SYS_$func";
$sysname =~ s/([a-z])([A-Z])/${1}_$2/g; # turn FooBar into Foo_Bar
$sysname =~ y/a-z/A-Z/;
+ if($nacl) {
+ $sysname =~ y/A-Z/a-z/;
+ }
}
# Actual call.
diff --git a/src/pkg/syscall/mksyscall_windows.pl b/src/pkg/syscall/mksyscall_solaris.pl
index 65d6efc20..130d043d9 100755
--- a/src/pkg/syscall/mksyscall_windows.pl
+++ b/src/pkg/syscall/mksyscall_solaris.pl
@@ -4,7 +4,7 @@
# license that can be found in the LICENSE file.
# This program reads a file containing function prototypes
-# (like syscall_darwin.go) and generates system call bodies.
+# (like syscall_solaris.go) and generates system call bodies.
# The prototypes are marked by lines beginning with "//sys"
# and read like func declarations if //sys is replaced by func, but:
# * The parameter lists must give a name for each argument.
@@ -12,20 +12,14 @@
# * The parameter lists must give a type for each argument:
# the (x, y, z int) shorthand is not allowed.
# * If the return parameter is an error number, it must be named err.
-# * If go func name needs to be different from it's winapi dll name,
-# the winapi name could be specified at the end, after "=" sign, like
-# //sys LoadLibrary(libname string) (handle uint32, err error) = LoadLibraryA
-# * Each function that returns err needs to supply a condition,
-# that return value of winapi will be tested against to
-# detect failure. This would set err to windows "last-error",
-# otherwise it will be nil. The value can be provided
-# at end of //sys declaration, like
-# //sys LoadLibrary(libname string) (handle uint32, err error) [failretval==-1] = LoadLibraryA
-# and is [failretval==0] by default.
+# * If go func name needs to be different than its libc name,
+# * or the function is not in libc, name could be specified
+# * at the end, after "=" sign, like
+# //sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) = libsocket.getsockopt
use strict;
-my $cmdline = "mksyscall_windows.pl " . join(' ', @ARGV);
+my $cmdline = "mksyscall_solaris.pl " . join(' ', @ARGV);
my $errors = 0;
my $_32bit = "";
@@ -40,7 +34,7 @@ if($ARGV[0] eq "-b32") {
}
if($ARGV[0] =~ /^-/) {
- print STDERR "usage: mksyscall_windows.pl [-b32 | -l32] [file ...]\n";
+ print STDERR "usage: mksyscall_solaris.pl [-b32 | -l32] [file ...]\n";
exit 1;
}
@@ -75,7 +69,8 @@ while(<>) {
s/^\s+//;
s/\s+$//;
$package = $1 if !$package && /^package (\S+)$/;
- next if !/^\/\/sys /;
+ my $nonblock = /^\/\/sysnb /;
+ next if !/^\/\/sys / && !$nonblock;
my $syscalldot = "";
$syscalldot = "syscall." if $package ne "syscall";
@@ -83,25 +78,25 @@ while(<>) {
# Line must be of the form
# func Open(path string, mode int, perm int) (fd int, err error)
# Split into name, in params, out params.
- if(!/^\/\/sys (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:\[failretval(.*)\])?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$/) {
+ if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$/) {
print STDERR "$ARGV:$.: malformed //sys declaration\n";
$errors = 1;
next;
}
- my ($func, $in, $out, $failcond, $modname, $sysname) = ($1, $2, $3, $4, $5, $6);
+ my ($nb, $func, $in, $out, $modname, $sysname) = ($1, $2, $3, $4, $5, $6);
# Split argument lists on comma.
my @in = parseparamlist($in);
my @out = parseparamlist($out);
- # Dll file name.
+ # So file name.
if($modname eq "") {
- $modname = "kernel32";
+ $modname = "libc";
}
my $modvname = "mod$modname";
if($modnames !~ /$modname/) {
$modnames .= ".$modname";
- $mods .= "\t$modvname = ${syscalldot}NewLazyDLL(\"$modname.dll\")\n";
+ $mods .= "\t$modvname = ${syscalldot}newLazySO(\"$modname.so\")\n";
}
# System call name.
@@ -112,16 +107,11 @@ while(<>) {
# System call pointer variable name.
my $sysvarname = "proc$sysname";
- # Returned value when failed
- if($failcond eq "") {
- $failcond = "== 0";
- }
-
- # Decide which version of api is used: ascii or unicode.
- my $strconvfunc = $sysname !~ /W$/ ? "BytePtrFromString" : "UTF16PtrFromString";
- my $strconvtype = $sysname !~ /W$/ ? "*byte" : "*uint16";
+ my $strconvfunc = "BytePtrFromString";
+ my $strconvtype = "*byte";
- # Winapi proc address variable.
+ # Library proc address variable.
+ $sysname =~ y/A-Z/a-z/; # All libc functions are lowercase.
$vars .= "\t$sysvarname = $modvname.NewProc(\"$sysname\")\n";
# Go function header.
@@ -191,31 +181,14 @@ while(<>) {
my $nargs = @args;
# Determine which form to use; pad args with zeros.
- my $asm = "${syscalldot}Syscall";
- if(@args <= 3) {
- while(@args < 3) {
- push @args, "0";
- }
- } elsif(@args <= 6) {
- $asm = "${syscalldot}Syscall6";
+ my $asm = "${syscalldot}sysvicall6";
+ if ($nonblock) {
+ $asm = "${syscalldot}rawSysvicall6";
+ }
+ if(@args <= 6) {
while(@args < 6) {
push @args, "0";
}
- } elsif(@args <= 9) {
- $asm = "${syscalldot}Syscall9";
- while(@args < 9) {
- push @args, "0";
- }
- } elsif(@args <= 12) {
- $asm = "${syscalldot}Syscall12";
- while(@args < 12) {
- push @args, "0";
- }
- } elsif(@args <= 15) {
- $asm = "${syscalldot}Syscall15";
- while(@args < 15) {
- push @args, "0";
- }
} else {
print STDERR "$ARGV:$.: too many arguments to system call\n";
}
@@ -229,6 +202,7 @@ while(<>) {
my $failexpr = "";
my @ret = ("_", "_", "_");
my @pout= ();
+ my $do_errno = 0;
for(my $i=0; $i<@out; $i++) {
my $p = $out[$i];
my ($name, $type) = parseparam($p);
@@ -236,6 +210,7 @@ while(<>) {
if($name eq "err") {
$reg = "e1";
$ret[2] = $reg;
+ $do_errno = 1;
} else {
$reg = sprintf("r%d", $i);
$ret[$i] = $reg;
@@ -256,40 +231,9 @@ while(<>) {
$ret[$i] = sprintf("r%d", $i);
$ret[$i+1] = sprintf("r%d", $i+1);
}
- my $rettype = $type;
- if($type =~ /^\*/) {
- $reg = "unsafe.Pointer($reg)";
- $rettype = "($rettype)";
- }
- if($i == 0) {
- if($type eq "bool") {
- $failexpr = "!$name";
- } elsif($name eq "err") {
- $ret[$i] = "r1";
- $failexpr = "r1 $failcond";
- } else {
- $failexpr = "$name $failcond";
- }
- }
- $failexpr =~ s/(=)([0-9A-Za-z\-+])/$1 $2/; # gofmt compatible
- if($name eq "err") {
- # Set err to "last error" only if returned value indicate failure
- $body .= "\tif $failexpr {\n";
- $body .= "\t\tif $reg != 0 {\n";
- $body .= "\t\t\t$name = $type($reg)\n";
- $body .= "\t\t} else {\n";
- $body .= "\t\t\t$name = ${syscalldot}EINVAL\n";
- $body .= "\t\t}\n";
- $body .= "\t}\n";
- } elsif($rettype eq "error") {
- # Set $reg to "error" only if returned value indicate failure
- $body .= "\tif $reg != 0 {\n";
- $body .= "\t\t$name = ${syscalldot}Errno($reg)\n";
- $body .= "\t}\n";
- } else {
- $body .= "\t$name = $rettype($reg)\n";
+ if($reg ne "e1") {
+ $body .= "\t$name = $type($reg)\n";
}
- push @pout, sprintf "\"%s=\", %s, ", $name, $name;
}
if ($ret[0] eq "_" && $ret[1] eq "_" && $ret[2] eq "_") {
$text .= "\t$call\n";
@@ -297,10 +241,12 @@ while(<>) {
$text .= "\t$ret[0], $ret[1], $ret[2] := $call\n";
}
$text .= $body;
- if(0) {
- $text .= sprintf 'print("SYSCALL: %s(", %s") (", %s")\n")%s', $func, join('", ", ', @pin), join('", ", ', @pout), "\n";
- }
+ if ($do_errno) {
+ $text .= "\tif e1 != 0 {\n";
+ $text .= "\t\terr = e1\n";
+ $text .= "\t}\n";
+ }
$text .= "\treturn\n";
$text .= "}\n";
}
diff --git a/src/pkg/syscall/mksyscall_windows.go b/src/pkg/syscall/mksyscall_windows.go
new file mode 100644
index 000000000..4225588de
--- /dev/null
+++ b/src/pkg/syscall/mksyscall_windows.go
@@ -0,0 +1,662 @@
+// 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
+
+/*
+mksyscall_windows generates windows system call bodies
+
+It parses all files specified on command line containing function
+prototypes (like syscall_windows.go) and prints system call bodies
+to standard output.
+
+The prototypes are marked by lines beginning with "//sys" and read
+like func declarations if //sys is replaced by func, but:
+
+* The parameter lists must give a name for each argument. This
+ includes return parameters.
+
+* The parameter lists must give a type for each argument:
+ the (x, y, z int) shorthand is not allowed.
+
+* If the return parameter is an error number, it must be named err.
+
+* If go func name needs to be different from it's winapi dll name,
+ the winapi name could be specified at the end, after "=" sign, like
+ //sys LoadLibrary(libname string) (handle uint32, err error) = LoadLibraryA
+
+* Each function that returns err needs to supply a condition, that
+ return value of winapi will be tested against to detect failure.
+ This would set err to windows "last-error", otherwise it will be nil.
+ The value can be provided at end of //sys declaration, like
+ //sys LoadLibrary(libname string) (handle uint32, err error) [failretval==-1] = LoadLibraryA
+ and is [failretval==0] by default.
+
+Usage:
+ mksyscall_windows [flags] [path ...]
+
+The flags are:
+ -trace
+ Generate print statement after every syscall.
+*/
+package main
+
+import (
+ "bufio"
+ "errors"
+ "flag"
+ "fmt"
+ "io"
+ "log"
+ "os"
+ "strconv"
+ "strings"
+ "text/template"
+)
+
+var PrintTraceFlag = flag.Bool("trace", false, "generate print statement after every syscall")
+
+func trim(s string) string {
+ return strings.Trim(s, " \t")
+}
+
+// Param is function parameter
+type Param struct {
+ Name string
+ Type string
+ fn *Fn
+ tmpVarIdx int
+}
+
+// tmpVar returns temp variable name that will be used to represent p during syscall.
+func (p *Param) tmpVar() string {
+ if p.tmpVarIdx < 0 {
+ p.tmpVarIdx = p.fn.curTmpVarIdx
+ p.fn.curTmpVarIdx++
+ }
+ return fmt.Sprintf("_p%d", p.tmpVarIdx)
+}
+
+// BoolTmpVarCode returns source code for bool temp variable.
+func (p *Param) BoolTmpVarCode() string {
+ const code = `var %s uint32
+ if %s {
+ %s = 1
+ } else {
+ %s = 0
+ }`
+ tmp := p.tmpVar()
+ return fmt.Sprintf(code, tmp, p.Name, tmp, tmp)
+}
+
+// SliceTmpVarCode returns source code for slice temp variable.
+func (p *Param) SliceTmpVarCode() string {
+ const code = `var %s *%s
+ if len(%s) > 0 {
+ %s = &%s[0]
+ }`
+ tmp := p.tmpVar()
+ return fmt.Sprintf(code, tmp, p.Type[2:], p.Name, tmp, p.Name)
+}
+
+// StringTmpVarCode returns source code for string temp variable.
+func (p *Param) StringTmpVarCode() string {
+ errvar := p.fn.Rets.ErrorVarName()
+ if errvar == "" {
+ errvar = "_"
+ }
+ tmp := p.tmpVar()
+ const code = `var %s %s
+ %s, %s = %s(%s)`
+ s := fmt.Sprintf(code, tmp, p.fn.StrconvType(), tmp, errvar, p.fn.StrconvFunc(), p.Name)
+ if errvar == "-" {
+ return s
+ }
+ const morecode = `
+ if %s != nil {
+ return
+ }`
+ return s + fmt.Sprintf(morecode, errvar)
+}
+
+// TmpVarCode returns source code for temp variable.
+func (p *Param) TmpVarCode() string {
+ switch {
+ case p.Type == "string":
+ return p.StringTmpVarCode()
+ case p.Type == "bool":
+ return p.BoolTmpVarCode()
+ case strings.HasPrefix(p.Type, "[]"):
+ return p.SliceTmpVarCode()
+ default:
+ return ""
+ }
+}
+
+// SyscallArgList returns source code fragments representing p parameter
+// in syscall. Slices are translated into 2 syscall parameters: pointer to
+// the first element and length.
+func (p *Param) SyscallArgList() []string {
+ var s string
+ switch {
+ case p.Type[0] == '*':
+ s = fmt.Sprintf("unsafe.Pointer(%s)", p.Name)
+ case p.Type == "string":
+ s = fmt.Sprintf("unsafe.Pointer(%s)", p.tmpVar())
+ case p.Type == "bool":
+ s = p.tmpVar()
+ case strings.HasPrefix(p.Type, "[]"):
+ return []string{
+ fmt.Sprintf("uintptr(unsafe.Pointer(%s))", p.tmpVar()),
+ fmt.Sprintf("uintptr(len(%s))", p.Name),
+ }
+ default:
+ s = p.Name
+ }
+ return []string{fmt.Sprintf("uintptr(%s)", s)}
+}
+
+// IsError determines if p parameter is used to return error.
+func (p *Param) IsError() bool {
+ return p.Name == "err" && p.Type == "error"
+}
+
+// join concatenates parameters ps into a string with sep separator.
+// Each parameter is converted into string by applying fn to it
+// before conversion.
+func join(ps []*Param, fn func(*Param) string, sep string) string {
+ if len(ps) == 0 {
+ return ""
+ }
+ a := make([]string, 0)
+ for _, p := range ps {
+ a = append(a, fn(p))
+ }
+ return strings.Join(a, sep)
+}
+
+// Rets describes function return parameters.
+type Rets struct {
+ Name string
+ Type string
+ ReturnsError bool
+ FailCond string
+}
+
+// ErrorVarName returns error variable name for r.
+func (r *Rets) ErrorVarName() string {
+ if r.ReturnsError {
+ return "err"
+ }
+ if r.Type == "error" {
+ return r.Name
+ }
+ return ""
+}
+
+// ToParams converts r into slice of *Param.
+func (r *Rets) ToParams() []*Param {
+ ps := make([]*Param, 0)
+ if len(r.Name) > 0 {
+ ps = append(ps, &Param{Name: r.Name, Type: r.Type})
+ }
+ if r.ReturnsError {
+ ps = append(ps, &Param{Name: "err", Type: "error"})
+ }
+ return ps
+}
+
+// List returns source code of syscall return parameters.
+func (r *Rets) List() string {
+ s := join(r.ToParams(), func(p *Param) string { return p.Name + " " + p.Type }, ", ")
+ if len(s) > 0 {
+ s = "(" + s + ")"
+ }
+ return s
+}
+
+// PrintList returns source code of trace printing part correspondent
+// to syscall return values.
+func (r *Rets) PrintList() string {
+ return join(r.ToParams(), func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `)
+}
+
+// SetReturnValuesCode returns source code that accepts syscall return values.
+func (r *Rets) SetReturnValuesCode() string {
+ if r.Name == "" && !r.ReturnsError {
+ return ""
+ }
+ retvar := "r0"
+ if r.Name == "" {
+ retvar = "r1"
+ }
+ errvar := "_"
+ if r.ReturnsError {
+ errvar = "e1"
+ }
+ return fmt.Sprintf("%s, _, %s := ", retvar, errvar)
+}
+
+func (r *Rets) useLongHandleErrorCode(retvar string) string {
+ const code = `if %s {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }`
+ cond := retvar + " == 0"
+ if r.FailCond != "" {
+ cond = strings.Replace(r.FailCond, "failretval", retvar, 1)
+ }
+ return fmt.Sprintf(code, cond)
+}
+
+// SetErrorCode returns source code that sets return parameters.
+func (r *Rets) SetErrorCode() string {
+ const code = `if r0 != 0 {
+ %s = Errno(r0)
+ }`
+ if r.Name == "" && !r.ReturnsError {
+ return ""
+ }
+ if r.Name == "" {
+ return r.useLongHandleErrorCode("r1")
+ }
+ if r.Type == "error" {
+ return fmt.Sprintf(code, r.Name)
+ }
+ s := ""
+ if r.Type[0] == '*' {
+ s = fmt.Sprintf("%s = (%s)(unsafe.Pointer(r0))", r.Name, r.Type)
+ } else {
+ s = fmt.Sprintf("%s = %s(r0)", r.Name, r.Type)
+ }
+ if !r.ReturnsError {
+ return s
+ }
+ return s + "\n\t" + r.useLongHandleErrorCode(r.Name)
+}
+
+// Fn describes syscall function.
+type Fn struct {
+ Name string
+ Params []*Param
+ Rets *Rets
+ PrintTrace bool
+ dllname string
+ dllfuncname string
+ src string
+ // TODO: get rid of this field and just use parameter index instead
+ curTmpVarIdx int // insure tmp variables have uniq names
+}
+
+// extractParams parses s to extract function parameters.
+func extractParams(s string, f *Fn) ([]*Param, error) {
+ s = trim(s)
+ if s == "" {
+ return nil, nil
+ }
+ a := strings.Split(s, ",")
+ ps := make([]*Param, len(a))
+ for i := range ps {
+ s2 := trim(a[i])
+ b := strings.Split(s2, " ")
+ if len(b) != 2 {
+ b = strings.Split(s2, "\t")
+ if len(b) != 2 {
+ return nil, errors.New("Could not extract function parameter from \"" + s2 + "\"")
+ }
+ }
+ ps[i] = &Param{
+ Name: trim(b[0]),
+ Type: trim(b[1]),
+ fn: f,
+ tmpVarIdx: -1,
+ }
+ }
+ return ps, nil
+}
+
+// extractSection extracts text out of string s starting after start
+// and ending just before end. found return value will indicate success,
+// and prefix, body and suffix will contain correspondent parts of string s.
+func extractSection(s string, start, end rune) (prefix, body, suffix string, found bool) {
+ s = trim(s)
+ if strings.HasPrefix(s, string(start)) {
+ // no prefix
+ body = s[1:]
+ } else {
+ a := strings.SplitN(s, string(start), 2)
+ if len(a) != 2 {
+ return "", "", s, false
+ }
+ prefix = a[0]
+ body = a[1]
+ }
+ a := strings.SplitN(body, string(end), 2)
+ if len(a) != 2 {
+ return "", "", "", false
+ }
+ return prefix, a[0], a[1], true
+}
+
+// newFn parses string s and return created function Fn.
+func newFn(s string) (*Fn, error) {
+ s = trim(s)
+ f := &Fn{
+ Rets: &Rets{},
+ src: s,
+ PrintTrace: *PrintTraceFlag,
+ }
+ // function name and args
+ prefix, body, s, found := extractSection(s, '(', ')')
+ if !found || prefix == "" {
+ return nil, errors.New("Could not extract function name and parameters from \"" + f.src + "\"")
+ }
+ f.Name = prefix
+ var err error
+ f.Params, err = extractParams(body, f)
+ if err != nil {
+ return nil, err
+ }
+ // return values
+ _, body, s, found = extractSection(s, '(', ')')
+ if found {
+ r, err := extractParams(body, f)
+ if err != nil {
+ return nil, err
+ }
+ switch len(r) {
+ case 0:
+ case 1:
+ if r[0].IsError() {
+ f.Rets.ReturnsError = true
+ } else {
+ f.Rets.Name = r[0].Name
+ f.Rets.Type = r[0].Type
+ }
+ case 2:
+ if !r[1].IsError() {
+ return nil, errors.New("Only last windows error is allowed as second return value in \"" + f.src + "\"")
+ }
+ f.Rets.ReturnsError = true
+ f.Rets.Name = r[0].Name
+ f.Rets.Type = r[0].Type
+ default:
+ return nil, errors.New("Too many return values in \"" + f.src + "\"")
+ }
+ }
+ // fail condition
+ _, body, s, found = extractSection(s, '[', ']')
+ if found {
+ f.Rets.FailCond = body
+ }
+ // dll and dll function names
+ s = trim(s)
+ if s == "" {
+ return f, nil
+ }
+ if !strings.HasPrefix(s, "=") {
+ return nil, errors.New("Could not extract dll name from \"" + f.src + "\"")
+ }
+ s = trim(s[1:])
+ a := strings.Split(s, ".")
+ switch len(a) {
+ case 1:
+ f.dllfuncname = a[0]
+ case 2:
+ f.dllname = a[0]
+ f.dllfuncname = a[1]
+ default:
+ return nil, errors.New("Could not extract dll name from \"" + f.src + "\"")
+ }
+ return f, nil
+}
+
+// DLLName returns DLL name for function f.
+func (f *Fn) DLLName() string {
+ if f.dllname == "" {
+ return "kernel32"
+ }
+ return f.dllname
+}
+
+// DLLName returns DLL function name for function f.
+func (f *Fn) DLLFuncName() string {
+ if f.dllfuncname == "" {
+ return f.Name
+ }
+ return f.dllfuncname
+}
+
+// ParamList returns source code for function f parameters.
+func (f *Fn) ParamList() string {
+ return join(f.Params, func(p *Param) string { return p.Name + " " + p.Type }, ", ")
+}
+
+// ParamPrintList returns source code of trace printing part correspondent
+// to syscall input parameters.
+func (f *Fn) ParamPrintList() string {
+ return join(f.Params, func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `)
+}
+
+// ParamCount return number of syscall parameters for function f.
+func (f *Fn) ParamCount() int {
+ n := 0
+ for _, p := range f.Params {
+ n += len(p.SyscallArgList())
+ }
+ return n
+}
+
+// SyscallParamCount determines which version of Syscall/Syscall6/Syscall9/...
+// to use. It returns parameter count for correspondent SyscallX function.
+func (f *Fn) SyscallParamCount() int {
+ n := f.ParamCount()
+ switch {
+ case n <= 3:
+ return 3
+ case n <= 6:
+ return 6
+ case n <= 9:
+ return 9
+ case n <= 12:
+ return 12
+ case n <= 15:
+ return 15
+ default:
+ panic("too many arguments to system call")
+ }
+}
+
+// Syscall determines which SyscallX function to use for function f.
+func (f *Fn) Syscall() string {
+ c := f.SyscallParamCount()
+ if c == 3 {
+ return "Syscall"
+ }
+ return "Syscall" + strconv.Itoa(c)
+}
+
+// SyscallParamList returns source code for SyscallX parameters for function f.
+func (f *Fn) SyscallParamList() string {
+ a := make([]string, 0)
+ for _, p := range f.Params {
+ a = append(a, p.SyscallArgList()...)
+ }
+ for len(a) < f.SyscallParamCount() {
+ a = append(a, "0")
+ }
+ return strings.Join(a, ", ")
+}
+
+// IsUTF16 is true, if f is W (utf16) function. It is false
+// for all A (ascii) functions.
+func (f *Fn) IsUTF16() bool {
+ s := f.DLLFuncName()
+ return s[len(s)-1] == 'W'
+}
+
+// StrconvFunc returns name of Go string to OS string function for f.
+func (f *Fn) StrconvFunc() string {
+ if f.IsUTF16() {
+ return "UTF16PtrFromString"
+ }
+ return "BytePtrFromString"
+}
+
+// StrconvType returns Go type name used for OS string for f.
+func (f *Fn) StrconvType() string {
+ if f.IsUTF16() {
+ return "*uint16"
+ }
+ return "*byte"
+}
+
+// Source files and functions.
+type Source struct {
+ Funcs []*Fn
+ Files []string
+}
+
+// ParseFiles parses files listed in fs and extracts all syscall
+// functions listed in sys comments. It returns source files
+// and functions collection *Source if successful.
+func ParseFiles(fs []string) (*Source, error) {
+ src := &Source{
+ Funcs: make([]*Fn, 0),
+ Files: make([]string, 0),
+ }
+ for _, file := range fs {
+ if err := src.ParseFile(file); err != nil {
+ return nil, err
+ }
+ }
+ return src, nil
+}
+
+// DLLs return dll names for a source set src.
+func (src *Source) DLLs() []string {
+ uniq := make(map[string]bool)
+ r := make([]string, 0)
+ for _, f := range src.Funcs {
+ name := f.DLLName()
+ if _, found := uniq[name]; !found {
+ uniq[name] = true
+ r = append(r, name)
+ }
+ }
+ return r
+}
+
+// ParseFile adds adition file path to a source set src.
+func (src *Source) ParseFile(path string) error {
+ file, err := os.Open(path)
+ if err != nil {
+ return err
+ }
+ defer file.Close()
+
+ s := bufio.NewScanner(file)
+ for s.Scan() {
+ t := trim(s.Text())
+ if len(t) < 7 {
+ continue
+ }
+ if !strings.HasPrefix(t, "//sys") {
+ continue
+ }
+ t = t[5:]
+ if !(t[0] == ' ' || t[0] == '\t') {
+ continue
+ }
+ f, err := newFn(t[1:])
+ if err != nil {
+ return err
+ }
+ src.Funcs = append(src.Funcs, f)
+ }
+ if err := s.Err(); err != nil {
+ return err
+ }
+ src.Files = append(src.Files, path)
+ return nil
+}
+
+// Generate output source file from a source set src.
+func (src *Source) Generate(w io.Writer) error {
+ t := template.Must(template.New("main").Parse(srcTemplate))
+ err := t.Execute(w, src)
+ if err != nil {
+ return errors.New("Failed to execute template: " + err.Error())
+ }
+ return nil
+}
+
+func usage() {
+ fmt.Fprintf(os.Stderr, "usage: mksyscall_windows [flags] [path ...]\n")
+ flag.PrintDefaults()
+ os.Exit(1)
+}
+
+func main() {
+ flag.Usage = usage
+ flag.Parse()
+ if len(os.Args) <= 1 {
+ fmt.Fprintf(os.Stderr, "no files to parse provided\n")
+ usage()
+ }
+ src, err := ParseFiles(os.Args[1:])
+ if err != nil {
+ log.Fatal(err)
+ }
+ if err := src.Generate(os.Stdout); err != nil {
+ log.Fatal(err)
+ }
+}
+
+// TODO: use println instead to print in the following template
+const srcTemplate = `
+
+{{define "main"}}// go build mksyscall_windows.go && ./mksyscall_windows{{range .Files}} {{.}}{{end}}
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+var (
+{{template "dlls" .}}
+{{template "funcnames" .}})
+{{range .Funcs}}{{template "funcbody" .}}{{end}}
+{{end}}
+
+{{/* help functions */}}
+
+{{define "dlls"}}{{range .DLLs}} mod{{.}} = NewLazyDLL("{{.}}.dll")
+{{end}}{{end}}
+
+{{define "funcnames"}}{{range .Funcs}} proc{{.DLLFuncName}} = mod{{.DLLName}}.NewProc("{{.DLLFuncName}}")
+{{end}}{{end}}
+
+{{define "funcbody"}}
+func {{.Name}}({{.ParamList}}) {{if .Rets.List}}{{.Rets.List}} {{end}}{
+{{template "tmpvars" .}} {{template "syscall" .}}
+{{template "seterror" .}}{{template "printtrace" .}} return
+}
+{{end}}
+
+{{define "tmpvars"}}{{range .Params}}{{if .TmpVarCode}} {{.TmpVarCode}}
+{{end}}{{end}}{{end}}
+
+{{define "syscall"}}{{.Rets.SetReturnValuesCode}}{{.Syscall}}(proc{{.DLLFuncName}}.Addr(), {{.ParamCount}}, {{.SyscallParamList}}){{end}}
+
+{{define "seterror"}}{{if .Rets.SetErrorCode}} {{.Rets.SetErrorCode}}
+{{end}}{{end}}
+
+{{define "printtrace"}}{{if .PrintTrace}} print("SYSCALL: {{.Name}}(", {{.ParamPrintList}}") (", {{.Rets.PrintList}}")\n")
+{{end}}{{end}}
+
+`
diff --git a/src/pkg/syscall/mksysnum_dragonfly.pl b/src/pkg/syscall/mksysnum_dragonfly.pl
index 769c29ea7..3eba3ab3d 100755
--- a/src/pkg/syscall/mksysnum_dragonfly.pl
+++ b/src/pkg/syscall/mksysnum_dragonfly.pl
@@ -20,7 +20,7 @@ const (
EOF
while(<>){
- if(/^([0-9]+)\s+STD\s+\S+\s+({ \S+\s+(\w+).*)$/){
+ if(/^([0-9]+)\s+STD\s+({ \S+\s+(\w+).*)$/){
my $num = $1;
my $proto = $2;
my $name = "SYS_$3";
diff --git a/src/pkg/syscall/mksysnum_freebsd.pl b/src/pkg/syscall/mksysnum_freebsd.pl
index 5c156338e..cd675780b 100755
--- a/src/pkg/syscall/mksysnum_freebsd.pl
+++ b/src/pkg/syscall/mksysnum_freebsd.pl
@@ -33,8 +33,21 @@ while(<>){
if($name eq 'SYS_SYS_EXIT'){
$name = 'SYS_EXIT';
}
+ if($name =~ /^SYS_CAP_+/ || $name =~ /^SYS___CAP_+/){
+ next
+ }
print " $name = $num; // $proto\n";
+
+ # We keep Capsicum syscall numbers for FreeBSD
+ # 9-STABLE here because we are not sure whether they
+ # are mature and stable.
+ if($num == 513){
+ print " SYS_CAP_NEW = 514 // { int cap_new(int fd, uint64_t rights); }\n";
+ print " SYS_CAP_GETRIGHTS = 515 // { int cap_getrights(int fd, \\\n";
+ print " SYS_CAP_ENTER = 516 // { int cap_enter(void); }\n";
+ print " SYS_CAP_GETMODE = 517 // { int cap_getmode(u_int *modep); }\n";
+ }
}
}
diff --git a/src/pkg/syscall/mmap_unix_test.go b/src/pkg/syscall/mmap_unix_test.go
new file mode 100644
index 000000000..01f778302
--- /dev/null
+++ b/src/pkg/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/src/pkg/syscall/net_nacl.go b/src/pkg/syscall/net_nacl.go
new file mode 100644
index 000000000..b9488f48d
--- /dev/null
+++ b/src/pkg/syscall/net_nacl.go
@@ -0,0 +1,912 @@
+// 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.
+
+// A simulated network for use within NaCl.
+// The simulation is not particularly tied to NaCl,
+// but other systems have real networks.
+
+package syscall
+
+import (
+ "sync"
+ "sync/atomic"
+)
+
+// Interface to timers implemented in package runtime.
+// Must be in sync with ../runtime/runtime.h:/^struct.Timer$
+// Really for use by package time, but we cannot import time here.
+
+type runtimeTimer struct {
+ i int32
+ when int64
+ period int64
+ f func(int64, interface{}) // NOTE: must not be closure
+ arg interface{}
+}
+
+func startTimer(*runtimeTimer)
+func stopTimer(*runtimeTimer) bool
+
+type timer struct {
+ expired bool
+ q *queue
+ r runtimeTimer
+}
+
+func (t *timer) start(q *queue, deadline int64) {
+ if deadline == 0 {
+ return
+ }
+ t.q = q
+ t.r.when = deadline
+ t.r.f = timerExpired
+ t.r.arg = t
+ startTimer(&t.r)
+}
+
+func (t *timer) stop() {
+ stopTimer(&t.r)
+}
+
+func timerExpired(now int64, i interface{}) {
+ t := i.(*timer)
+ go func() {
+ t.q.Lock()
+ defer t.q.Unlock()
+ t.expired = true
+ t.q.canRead.Broadcast()
+ t.q.canWrite.Broadcast()
+ }()
+}
+
+// Network constants and data structures. These match the traditional values.
+
+const (
+ AF_UNSPEC = iota
+ AF_UNIX
+ AF_INET
+ AF_INET6
+)
+
+const (
+ SHUT_RD = iota
+ SHUT_WR
+ SHUT_RDWR
+)
+
+const (
+ SOCK_STREAM = 1 + iota
+ SOCK_DGRAM
+ SOCK_RAW
+ SOCK_SEQPACKET
+)
+
+const (
+ IPPROTO_IP = 0
+ IPPROTO_IPV4 = 4
+ IPPROTO_IPV6 = 0x29
+ IPPROTO_TCP = 6
+ IPPROTO_UDP = 0x11
+)
+
+// Misc constants expected by package net but not supported.
+const (
+ _ = iota
+ SOL_SOCKET
+ SO_TYPE
+ NET_RT_IFLIST
+ IFNAMSIZ
+ IFF_UP
+ IFF_BROADCAST
+ IFF_LOOPBACK
+ IFF_POINTOPOINT
+ IFF_MULTICAST
+ IPV6_V6ONLY
+ SOMAXCONN
+ F_DUPFD_CLOEXEC
+ SO_BROADCAST
+ SO_REUSEADDR
+ SO_REUSEPORT
+ SO_RCVBUF
+ SO_SNDBUF
+ SO_KEEPALIVE
+ SO_LINGER
+ SO_ERROR
+ IP_PORTRANGE
+ IP_PORTRANGE_DEFAULT
+ IP_PORTRANGE_LOW
+ IP_PORTRANGE_HIGH
+ IP_MULTICAST_IF
+ IP_MULTICAST_LOOP
+ IP_ADD_MEMBERSHIP
+ IPV6_PORTRANGE
+ IPV6_PORTRANGE_DEFAULT
+ IPV6_PORTRANGE_LOW
+ IPV6_PORTRANGE_HIGH
+ IPV6_MULTICAST_IF
+ IPV6_MULTICAST_LOOP
+ IPV6_JOIN_GROUP
+ TCP_NODELAY
+ TCP_KEEPINTVL
+ TCP_KEEPIDLE
+
+ SYS_FCNTL = 500 // unsupported
+)
+
+var SocketDisableIPv6 bool
+
+// A Sockaddr is one of the SockaddrXxx structs.
+type Sockaddr interface {
+ // copy returns a copy of the underlying data.
+ copy() Sockaddr
+
+ // key returns the value of the underlying data,
+ // for comparison as a map key.
+ key() interface{}
+}
+
+type SockaddrInet4 struct {
+ Port int
+ Addr [4]byte
+}
+
+func (sa *SockaddrInet4) copy() Sockaddr {
+ sa1 := *sa
+ return &sa1
+}
+
+func (sa *SockaddrInet4) key() interface{} { return *sa }
+
+type SockaddrInet6 struct {
+ Port int
+ ZoneId uint32
+ Addr [16]byte
+}
+
+func (sa *SockaddrInet6) copy() Sockaddr {
+ sa1 := *sa
+ return &sa1
+}
+
+func (sa *SockaddrInet6) key() interface{} { return *sa }
+
+type SockaddrUnix struct {
+ Name string
+}
+
+func (sa *SockaddrUnix) copy() Sockaddr {
+ sa1 := *sa
+ return &sa1
+}
+
+func (sa *SockaddrUnix) key() interface{} { return *sa }
+
+type SockaddrDatalink struct {
+ Len uint8
+ Family uint8
+ Index uint16
+ Type uint8
+ Nlen uint8
+ Alen uint8
+ Slen uint8
+ Data [12]int8
+}
+
+func (sa *SockaddrDatalink) copy() Sockaddr {
+ sa1 := *sa
+ return &sa1
+}
+
+func (sa *SockaddrDatalink) key() interface{} { return *sa }
+
+// RoutingMessage represents a routing message.
+type RoutingMessage interface {
+ unimplemented()
+}
+
+type IPMreq struct {
+ Multiaddr [4]byte /* in_addr */
+ Interface [4]byte /* in_addr */
+}
+
+type IPv6Mreq struct {
+ Multiaddr [16]byte /* in6_addr */
+ Interface uint32
+}
+
+type Linger struct {
+ Onoff int32
+ Linger int32
+}
+
+type ICMPv6Filter struct {
+ Filt [8]uint32
+}
+
+// A queue is the bookkeeping for a synchronized buffered queue.
+// We do not use channels because we need to be able to handle
+// writes after and during close, and because a chan byte would
+// require too many send and receive operations in real use.
+type queue struct {
+ sync.Mutex
+ canRead sync.Cond
+ canWrite sync.Cond
+ r int // total read index
+ w int // total write index
+ m int // index mask
+ closed bool
+}
+
+func (q *queue) init(size int) {
+ if size&(size-1) != 0 {
+ panic("invalid queue size - must be power of two")
+ }
+ q.canRead.L = &q.Mutex
+ q.canWrite.L = &q.Mutex
+ q.m = size - 1
+}
+
+func past(deadline int64) bool {
+ sec, nsec := now()
+ return deadline > 0 && deadline < sec*1e9+int64(nsec)
+}
+
+func (q *queue) waitRead(n int, deadline int64) (int, error) {
+ if past(deadline) {
+ return 0, EAGAIN
+ }
+ var t timer
+ t.start(q, deadline)
+ for q.w-q.r == 0 && !q.closed && !t.expired {
+ q.canRead.Wait()
+ }
+ t.stop()
+ m := q.w - q.r
+ if m == 0 && t.expired {
+ return 0, EAGAIN
+ }
+ if m > n {
+ m = n
+ q.canRead.Signal() // wake up next reader too
+ }
+ q.canWrite.Signal()
+ return m, nil
+}
+
+func (q *queue) waitWrite(n int, deadline int64) (int, error) {
+ if past(deadline) {
+ return 0, EAGAIN
+ }
+ var t timer
+ t.start(q, deadline)
+ for q.w-q.r > q.m && !q.closed && !t.expired {
+ q.canWrite.Wait()
+ }
+ t.stop()
+ m := q.m + 1 - (q.w - q.r)
+ if m == 0 && t.expired {
+ return 0, EAGAIN
+ }
+ if m == 0 {
+ return 0, EAGAIN
+ }
+ if m > n {
+ m = n
+ q.canWrite.Signal() // wake up next writer too
+ }
+ q.canRead.Signal()
+ return m, nil
+}
+
+func (q *queue) close() {
+ q.Lock()
+ defer q.Unlock()
+ q.closed = true
+ q.canRead.Broadcast()
+ q.canWrite.Broadcast()
+}
+
+// A byteq is a byte queue.
+type byteq struct {
+ queue
+ data []byte
+}
+
+func newByteq() *byteq {
+ q := &byteq{
+ data: make([]byte, 4096),
+ }
+ q.init(len(q.data))
+ return q
+}
+
+func (q *byteq) read(b []byte, deadline int64) (int, error) {
+ q.Lock()
+ defer q.Unlock()
+ n, err := q.waitRead(len(b), deadline)
+ if err != nil {
+ return 0, err
+ }
+ b = b[:n]
+ for len(b) > 0 {
+ m := copy(b, q.data[q.r&q.m:])
+ q.r += m
+ b = b[m:]
+ }
+ return n, nil
+}
+
+func (q *byteq) write(b []byte, deadline int64) (n int, err error) {
+ q.Lock()
+ defer q.Unlock()
+ for n < len(b) {
+ nn, err := q.waitWrite(len(b[n:]), deadline)
+ if err != nil {
+ return n, err
+ }
+ bb := b[n : n+nn]
+ n += nn
+ for len(bb) > 0 {
+ m := copy(q.data[q.w&q.m:], bb)
+ q.w += m
+ bb = bb[m:]
+ }
+ }
+ return n, nil
+}
+
+// A msgq is a queue of messages.
+type msgq struct {
+ queue
+ data []interface{}
+}
+
+func newMsgq() *msgq {
+ q := &msgq{
+ data: make([]interface{}, 32),
+ }
+ q.init(len(q.data))
+ return q
+}
+
+func (q *msgq) read(deadline int64) (interface{}, error) {
+ q.Lock()
+ defer q.Unlock()
+ n, err := q.waitRead(1, deadline)
+ if err != nil {
+ return nil, err
+ }
+ if n == 0 {
+ return nil, nil
+ }
+ m := q.data[q.r&q.m]
+ q.r++
+ return m, nil
+}
+
+func (q *msgq) write(m interface{}, deadline int64) error {
+ q.Lock()
+ defer q.Unlock()
+ _, err := q.waitWrite(1, deadline)
+ if err != nil {
+ return err
+ }
+ q.data[q.w&q.m] = m
+ q.w++
+ return nil
+}
+
+// An addr is a sequence of bytes uniquely identifying a network address.
+// It is not human-readable.
+type addr string
+
+// A conn is one side of a stream-based network connection.
+// That is, a stream-based network connection is a pair of cross-connected conns.
+type conn struct {
+ rd *byteq
+ wr *byteq
+ local addr
+ remote addr
+}
+
+// A pktconn is one side of a packet-based network connection.
+// That is, a packet-based network connection is a pair of cross-connected pktconns.
+type pktconn struct {
+ rd *msgq
+ wr *msgq
+ local addr
+ remote addr
+}
+
+// A listener accepts incoming stream-based network connections.
+type listener struct {
+ rd *msgq
+ local addr
+}
+
+// A netFile is an open network file.
+type netFile struct {
+ defaultFileImpl
+ proto *netproto
+ sotype int
+ listener *msgq
+ packet *msgq
+ rd *byteq
+ wr *byteq
+ rddeadline int64
+ wrdeadline int64
+ addr Sockaddr
+ raddr Sockaddr
+}
+
+// A netAddr is a network address in the global listener map.
+// All the fields must have defined == operations.
+type netAddr struct {
+ proto *netproto
+ sotype int
+ addr interface{}
+}
+
+// net records the state of the network.
+// It maps a network address to the listener on that address.
+var net = struct {
+ sync.Mutex
+ listener map[netAddr]*netFile
+}{
+ listener: make(map[netAddr]*netFile),
+}
+
+// TODO(rsc): Some day, do a better job with port allocation.
+// For playground programs, incrementing is fine.
+var nextport = 2
+
+// A netproto contains protocol-specific functionality
+// (one for AF_INET, one for AF_INET6 and so on).
+// It is a struct instead of an interface because the
+// implementation needs no state, and I expect to
+// add some data fields at some point.
+type netproto struct {
+ bind func(*netFile, Sockaddr) error
+}
+
+var netprotoAF_INET = &netproto{
+ bind: func(f *netFile, sa Sockaddr) error {
+ if sa == nil {
+ f.addr = &SockaddrInet4{
+ Port: nextport,
+ Addr: [4]byte{127, 0, 0, 1},
+ }
+ nextport++
+ return nil
+ }
+ addr, ok := sa.(*SockaddrInet4)
+ if !ok {
+ return EINVAL
+ }
+ addr = addr.copy().(*SockaddrInet4)
+ if addr.Port == 0 {
+ addr.Port = nextport
+ nextport++
+ }
+ f.addr = addr
+ return nil
+ },
+}
+
+var netprotos = map[int]*netproto{
+ AF_INET: netprotoAF_INET,
+}
+
+// These functions implement the usual BSD socket operations.
+
+func (f *netFile) bind(sa Sockaddr) error {
+ if f.addr != nil {
+ return EISCONN
+ }
+ if err := f.proto.bind(f, sa); err != nil {
+ return err
+ }
+ if f.sotype == SOCK_DGRAM {
+ _, ok := net.listener[netAddr{f.proto, f.sotype, f.addr.key()}]
+ if ok {
+ f.addr = nil
+ return EADDRINUSE
+ }
+ net.listener[netAddr{f.proto, f.sotype, f.addr.key()}] = f
+ f.packet = newMsgq()
+ }
+ return nil
+}
+
+func (f *netFile) listen(backlog int) error {
+ net.Lock()
+ defer net.Unlock()
+ if f.listener != nil {
+ return EINVAL
+ }
+ _, ok := net.listener[netAddr{f.proto, f.sotype, f.addr.key()}]
+ if ok {
+ return EADDRINUSE
+ }
+ net.listener[netAddr{f.proto, f.sotype, f.addr.key()}] = f
+ f.listener = newMsgq()
+ return nil
+}
+
+func (f *netFile) accept() (fd int, sa Sockaddr, err error) {
+ msg, err := f.listener.read(f.readDeadline())
+ if err != nil {
+ return -1, nil, err
+ }
+ newf, ok := msg.(*netFile)
+ if !ok {
+ // must be eof
+ return -1, nil, EAGAIN
+ }
+ return newFD(newf), newf.raddr.copy(), nil
+}
+
+func (f *netFile) connect(sa Sockaddr) error {
+ if past(f.writeDeadline()) {
+ return EAGAIN
+ }
+ if f.addr == nil {
+ if err := f.bind(nil); err != nil {
+ return err
+ }
+ }
+ net.Lock()
+ if sa == nil {
+ net.Unlock()
+ return EINVAL
+ }
+ sa = sa.copy()
+ if f.raddr != nil {
+ net.Unlock()
+ return EISCONN
+ }
+ if f.sotype == SOCK_DGRAM {
+ net.Unlock()
+ f.raddr = sa
+ return nil
+ }
+ if f.listener != nil {
+ net.Unlock()
+ return EISCONN
+ }
+ l, ok := net.listener[netAddr{f.proto, f.sotype, sa.key()}]
+ if !ok {
+ net.Unlock()
+ return ECONNREFUSED
+ }
+ f.raddr = sa
+ f.rd = newByteq()
+ f.wr = newByteq()
+ newf := &netFile{
+ proto: f.proto,
+ sotype: f.sotype,
+ addr: f.raddr,
+ raddr: f.addr,
+ rd: f.wr,
+ wr: f.rd,
+ }
+ net.Unlock()
+ l.listener.write(newf, f.writeDeadline())
+ return nil
+}
+
+func (f *netFile) read(b []byte) (int, error) {
+ if f.rd == nil {
+ if f.raddr != nil {
+ n, _, err := f.recvfrom(b, 0)
+ return n, err
+ }
+ return 0, ENOTCONN
+ }
+ return f.rd.read(b, f.readDeadline())
+}
+
+func (f *netFile) write(b []byte) (int, error) {
+ if f.wr == nil {
+ if f.raddr != nil {
+ err := f.sendto(b, 0, f.raddr)
+ var n int
+ if err == nil {
+ n = len(b)
+ }
+ return n, err
+ }
+ return 0, ENOTCONN
+ }
+ return f.wr.write(b, f.writeDeadline())
+}
+
+type pktmsg struct {
+ buf []byte
+ addr Sockaddr
+}
+
+func (f *netFile) recvfrom(p []byte, flags int) (n int, from Sockaddr, err error) {
+ if f.sotype != SOCK_DGRAM {
+ return 0, nil, EINVAL
+ }
+ if f.packet == nil {
+ return 0, nil, ENOTCONN
+ }
+ msg1, err := f.packet.read(f.readDeadline())
+ if err != nil {
+ return 0, nil, err
+ }
+ msg, ok := msg1.(*pktmsg)
+ if !ok {
+ return 0, nil, EAGAIN
+ }
+ return copy(p, msg.buf), msg.addr, nil
+}
+
+func (f *netFile) sendto(p []byte, flags int, to Sockaddr) error {
+ if f.sotype != SOCK_DGRAM {
+ return EINVAL
+ }
+ if f.packet == nil {
+ if err := f.bind(nil); err != nil {
+ return err
+ }
+ }
+ net.Lock()
+ if to == nil {
+ net.Unlock()
+ return EINVAL
+ }
+ to = to.copy()
+ l, ok := net.listener[netAddr{f.proto, f.sotype, to.key()}]
+ if !ok || l.packet == nil {
+ net.Unlock()
+ return ECONNREFUSED
+ }
+ net.Unlock()
+ msg := &pktmsg{
+ buf: make([]byte, len(p)),
+ addr: f.addr,
+ }
+ copy(msg.buf, p)
+ l.packet.write(msg, f.writeDeadline())
+ return nil
+}
+
+func (f *netFile) close() error {
+ if f.listener != nil {
+ f.listener.close()
+ }
+ if f.packet != nil {
+ f.packet.close()
+ }
+ if f.rd != nil {
+ f.rd.close()
+ }
+ if f.wr != nil {
+ f.wr.close()
+ }
+ return nil
+}
+
+func fdToNetFile(fd int) (*netFile, error) {
+ f, err := fdToFile(fd)
+ if err != nil {
+ return nil, err
+ }
+ impl := f.impl
+ netf, ok := impl.(*netFile)
+ if !ok {
+ return nil, EINVAL
+ }
+ return netf, nil
+}
+
+func Socket(proto, sotype, unused int) (fd int, err error) {
+ p := netprotos[proto]
+ if p == nil {
+ return -1, EPROTONOSUPPORT
+ }
+ if sotype != SOCK_STREAM && sotype != SOCK_DGRAM {
+ return -1, ESOCKTNOSUPPORT
+ }
+ f := &netFile{
+ proto: p,
+ sotype: sotype,
+ }
+ return newFD(f), nil
+}
+
+func Bind(fd int, sa Sockaddr) error {
+ f, err := fdToNetFile(fd)
+ if err != nil {
+ return err
+ }
+ return f.bind(sa)
+}
+
+func StopIO(fd int) error {
+ f, err := fdToNetFile(fd)
+ if err != nil {
+ return err
+ }
+ f.close()
+ return nil
+}
+
+func Listen(fd int, backlog int) error {
+ f, err := fdToNetFile(fd)
+ if err != nil {
+ return err
+ }
+ return f.listen(backlog)
+}
+
+func Accept(fd int) (newfd int, sa Sockaddr, err error) {
+ f, err := fdToNetFile(fd)
+ if err != nil {
+ return 0, nil, err
+ }
+ return f.accept()
+}
+
+func Getsockname(fd int) (sa Sockaddr, err error) {
+ f, err := fdToNetFile(fd)
+ if err != nil {
+ return nil, err
+ }
+ if f.addr == nil {
+ return nil, ENOTCONN
+ }
+ return f.addr.copy(), nil
+}
+
+func Getpeername(fd int) (sa Sockaddr, err error) {
+ f, err := fdToNetFile(fd)
+ if err != nil {
+ return nil, err
+ }
+ if f.raddr == nil {
+ return nil, ENOTCONN
+ }
+ return f.raddr.copy(), nil
+}
+
+func Connect(fd int, sa Sockaddr) error {
+ f, err := fdToNetFile(fd)
+ if err != nil {
+ return err
+ }
+ return f.connect(sa)
+}
+
+func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) {
+ f, err := fdToNetFile(fd)
+ if err != nil {
+ return 0, nil, err
+ }
+ return f.recvfrom(p, flags)
+}
+
+func Sendto(fd int, p []byte, flags int, to Sockaddr) error {
+ f, err := fdToNetFile(fd)
+ if err != nil {
+ return err
+ }
+ return f.sendto(p, flags, to)
+}
+
+func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn, recvflags int, from Sockaddr, err error) {
+ f, err := fdToNetFile(fd)
+ if err != nil {
+ return
+ }
+ n, from, err = f.recvfrom(p, flags)
+ return
+}
+
+func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) error {
+ _, err := SendmsgN(fd, p, oob, to, flags)
+ return err
+}
+
+func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
+ f, err := fdToNetFile(fd)
+ if err != nil {
+ return 0, err
+ }
+ switch f.sotype {
+ case SOCK_STREAM:
+ n, err = f.write(p)
+ case SOCK_DGRAM:
+ n = len(p)
+ err = f.sendto(p, flags, to)
+ }
+ if err != nil {
+ return 0, err
+ }
+ return n, nil
+}
+
+func GetsockoptInt(fd, level, opt int) (value int, err error) {
+ f, err := fdToNetFile(fd)
+ if err != nil {
+ return 0, err
+ }
+ switch {
+ case level == SOL_SOCKET && opt == SO_TYPE:
+ return f.sotype, nil
+ }
+ return 0, ENOTSUP
+}
+
+func SetsockoptInt(fd, level, opt int, value int) error {
+ return nil
+}
+
+func SetsockoptByte(fd, level, opt int, value byte) error {
+ _, err := fdToNetFile(fd)
+ if err != nil {
+ return err
+ }
+ return ENOTSUP
+}
+
+func SetsockoptLinger(fd, level, opt int, l *Linger) error {
+ return nil
+}
+
+func SetReadDeadline(fd int, t int64) error {
+ f, err := fdToNetFile(fd)
+ if err != nil {
+ return err
+ }
+ atomic.StoreInt64(&f.rddeadline, t)
+ return nil
+}
+
+func (f *netFile) readDeadline() int64 {
+ return atomic.LoadInt64(&f.rddeadline)
+}
+
+func SetWriteDeadline(fd int, t int64) error {
+ f, err := fdToNetFile(fd)
+ if err != nil {
+ return err
+ }
+ atomic.StoreInt64(&f.wrdeadline, t)
+ return nil
+}
+
+func (f *netFile) writeDeadline() int64 {
+ return atomic.LoadInt64(&f.wrdeadline)
+}
+
+func Shutdown(fd int, how int) error {
+ f, err := fdToNetFile(fd)
+ if err != nil {
+ return err
+ }
+ switch how {
+ case SHUT_RD:
+ f.rd.close()
+ case SHUT_WR:
+ f.wr.close()
+ case SHUT_RDWR:
+ f.rd.close()
+ f.wr.close()
+ }
+ return nil
+}
+
+func SetsockoptICMPv6Filter(fd, level, opt int, filter *ICMPv6Filter) error { panic("SetsockoptICMPv") }
+func SetsockoptIPMreq(fd, level, opt int, mreq *IPMreq) error { panic("SetsockoptIPMreq") }
+func SetsockoptIPv6Mreq(fd, level, opt int, mreq *IPv6Mreq) error { panic("SetsockoptIPv") }
+func SetsockoptInet4Addr(fd, level, opt int, value [4]byte) error { panic("SetsockoptInet") }
+func SetsockoptString(fd, level, opt int, s string) error { panic("SetsockoptString") }
+func SetsockoptTimeval(fd, level, opt int, tv *Timeval) error { panic("SetsockoptTimeval") }
+func Socketpair(domain, typ, proto int) (fd [2]int, err error) { panic("Socketpair") }
+
+func SetNonblock(fd int, nonblocking bool) error { return nil }
diff --git a/src/pkg/syscall/rlimit_linux_test.go b/src/pkg/syscall/rlimit_linux_test.go
deleted file mode 100644
index 4ec720e93..000000000
--- a/src/pkg/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/src/pkg/syscall/route_bsd.go b/src/pkg/syscall/route_bsd.go
index 638073592..48af58745 100644
--- a/src/pkg/syscall/route_bsd.go
+++ b/src/pkg/syscall/route_bsd.go
@@ -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/src/pkg/syscall/route_dragonfly.go b/src/pkg/syscall/route_dragonfly.go
index acad7a2be..79190d2b0 100644
--- a/src/pkg/syscall/route_dragonfly.go
+++ b/src/pkg/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/src/pkg/syscall/route_freebsd.go b/src/pkg/syscall/route_freebsd.go
index d8f80316b..15897b1ac 100644
--- a/src/pkg/syscall/route_freebsd.go
+++ b/src/pkg/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/src/pkg/syscall/route_freebsd_32bit.go b/src/pkg/syscall/route_freebsd_32bit.go
new file mode 100644
index 000000000..93efdddb3
--- /dev/null
+++ b/src/pkg/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/src/pkg/syscall/route_freebsd_64bit.go b/src/pkg/syscall/route_freebsd_64bit.go
new file mode 100644
index 000000000..9377f2fed
--- /dev/null
+++ b/src/pkg/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/src/pkg/syscall/route_netbsd.go b/src/pkg/syscall/route_netbsd.go
index a6baa02f8..9883aebaf 100644
--- a/src/pkg/syscall/route_netbsd.go
+++ b/src/pkg/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/src/pkg/syscall/route_openbsd.go b/src/pkg/syscall/route_openbsd.go
index 223c15779..19f902db7 100644
--- a/src/pkg/syscall/route_openbsd.go
+++ b/src/pkg/syscall/route_openbsd.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/src/pkg/syscall/so_solaris.go b/src/pkg/syscall/so_solaris.go
new file mode 100644
index 000000000..659cd67c1
--- /dev/null
+++ b/src/pkg/syscall/so_solaris.go
@@ -0,0 +1,260 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+import (
+ "sync"
+ "sync/atomic"
+ "unsafe"
+)
+
+// soError describes reasons for shared library load failures.
+type soError struct {
+ Err error
+ ObjName string
+ Msg string
+}
+
+func (e *soError) Error() string { return e.Msg }
+
+// Implemented in ../runtime/syscall_solaris.goc.
+func rawSysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
+func sysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
+func dlclose(handle uintptr) (err Errno)
+func dlopen(name *uint8, mode uintptr) (handle uintptr, err Errno)
+func dlsym(handle uintptr, name *uint8) (proc uintptr, err Errno)
+
+// A so implements access to a single shared library object.
+type so struct {
+ Name string
+ Handle uintptr
+}
+
+// loadSO loads shared library file into memory.
+func loadSO(name string) (*so, error) {
+ namep, err := BytePtrFromString(name)
+ if err != nil {
+ return nil, err
+ }
+ h, e := dlopen(namep, 1) // RTLD_LAZY
+ if e != 0 {
+ return nil, &soError{
+ Err: e,
+ ObjName: name,
+ Msg: "Failed to load " + name + ": " + e.Error(),
+ }
+ }
+ d := &so{
+ Name: name,
+ Handle: uintptr(h),
+ }
+ return d, nil
+}
+
+// mustLoadSO is like loadSO but panics if load operation fails.
+func mustLoadSO(name string) *so {
+ d, e := loadSO(name)
+ if e != nil {
+ panic(e)
+ }
+ return d
+}
+
+// FindProc searches shared library d for procedure named name and returns
+// *proc if found. It returns an error if the search fails.
+func (d *so) FindProc(name string) (*proc, error) {
+ namep, err := BytePtrFromString(name)
+ if err != nil {
+ return nil, err
+ }
+ a, _ := dlsym(uintptr(d.Handle), namep)
+ if a == 0 {
+ return nil, &soError{
+ Err: ENOSYS,
+ ObjName: name,
+ Msg: "Failed to find " + name + " procedure in " + d.Name,
+ }
+ }
+ p := &proc{
+ SO: d,
+ Name: name,
+ addr: a,
+ }
+ return p, nil
+}
+
+// MustFindProc is like FindProc but panics if search fails.
+func (d *so) MustFindProc(name string) *proc {
+ p, e := d.FindProc(name)
+ if e != nil {
+ panic(e)
+ }
+ return p
+}
+
+// Release unloads shared library d from memory.
+func (d *so) Release() (err error) {
+ return dlclose(d.Handle)
+}
+
+// A proc implements access to a procedure inside a shared library.
+type proc struct {
+ SO *so
+ Name string
+ addr uintptr
+}
+
+// Addr returns the address of the procedure represented by p.
+// The return value can be passed to Syscall to run the procedure.
+func (p *proc) Addr() uintptr {
+ return p.addr
+}
+
+// Call executes procedure p with arguments a. It will panic, if more then
+// 6 arguments are supplied.
+//
+// The returned error is always non-nil, constructed from the result of
+// GetLastError. Callers must inspect the primary return value to decide
+// whether an error occurred (according to the semantics of the specific
+// function being called) before consulting the error. The error will be
+// guaranteed to contain syscall.Errno.
+func (p *proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
+ switch len(a) {
+ case 0:
+ return sysvicall6(p.Addr(), uintptr(len(a)), 0, 0, 0, 0, 0, 0)
+ case 1:
+ return sysvicall6(p.Addr(), uintptr(len(a)), a[0], 0, 0, 0, 0, 0)
+ case 2:
+ return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], 0, 0, 0, 0)
+ case 3:
+ return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], 0, 0, 0)
+ case 4:
+ return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
+ case 5:
+ return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
+ case 6:
+ return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
+ default:
+ panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
+ }
+ return
+}
+
+// A lazySO implements access to a single shared library. It will delay
+// the load of the shared library until the first call to its Handle method
+// or to one of its lazyProc's Addr method.
+type lazySO struct {
+ mu sync.Mutex
+ so *so // non nil once SO is loaded
+ Name string
+}
+
+// Load loads single shared file d.Name into memory. It returns an error if
+// fails. Load will not try to load SO, if it is already loaded into memory.
+func (d *lazySO) Load() error {
+ // Non-racy version of:
+ // if d.so == nil {
+ if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.so))) == nil {
+ d.mu.Lock()
+ defer d.mu.Unlock()
+ if d.so == nil {
+ so, e := loadSO(d.Name)
+ if e != nil {
+ return e
+ }
+ // Non-racy version of:
+ // d.so = so
+ atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.so)), unsafe.Pointer(so))
+ }
+ }
+ return nil
+}
+
+// mustLoad is like Load but panics if search fails.
+func (d *lazySO) mustLoad() {
+ e := d.Load()
+ if e != nil {
+ panic(e)
+ }
+}
+
+// Handle returns d's module handle.
+func (d *lazySO) Handle() uintptr {
+ d.mustLoad()
+ return uintptr(d.so.Handle)
+}
+
+// NewProc returns a lazyProc for accessing the named procedure in the SO d.
+func (d *lazySO) NewProc(name string) *lazyProc {
+ return &lazyProc{l: d, Name: name}
+}
+
+// newLazySO creates new lazySO associated with SO file.
+func newLazySO(name string) *lazySO {
+ return &lazySO{Name: name}
+}
+
+// A lazyProc implements access to a procedure inside a lazySO.
+// It delays the lookup until the Addr method is called.
+type lazyProc struct {
+ mu sync.Mutex
+ Name string
+ l *lazySO
+ proc *proc
+}
+
+// Find searches the shared library for procedure named p.Name. It returns an
+// error if search fails. Find will not search procedure, if it is already
+// found and loaded into memory.
+func (p *lazyProc) Find() error {
+ // Non-racy version of:
+ // if p.proc == nil {
+ if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil {
+ p.mu.Lock()
+ defer p.mu.Unlock()
+ if p.proc == nil {
+ e := p.l.Load()
+ if e != nil {
+ return e
+ }
+ proc, e := p.l.so.FindProc(p.Name)
+ if e != nil {
+ return e
+ }
+ // Non-racy version of:
+ // p.proc = proc
+ atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc))
+ }
+ }
+ return nil
+}
+
+// mustFind is like Find but panics if search fails.
+func (p *lazyProc) mustFind() {
+ e := p.Find()
+ if e != nil {
+ panic(e)
+ }
+}
+
+// Addr returns the address of the procedure represented by p.
+// The return value can be passed to Syscall to run the procedure.
+func (p *lazyProc) Addr() uintptr {
+ p.mustFind()
+ return p.proc.Addr()
+}
+
+// Call executes procedure p with arguments a. It will panic, if more then
+// 6 arguments are supplied.
+//
+// The returned error is always non-nil, constructed from the result of
+// GetLastError. Callers must inspect the primary return value to decide
+// whether an error occurred (according to the semantics of the specific
+// function being called) before consulting the error. The error will be
+// guaranteed to contain syscall.Errno.
+func (p *lazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
+ p.mustFind()
+ return p.proc.Call(a...)
+}
diff --git a/src/pkg/syscall/sockcmsg_unix.go b/src/pkg/syscall/sockcmsg_unix.go
index a2d234f21..045a012c0 100644
--- a/src/pkg/syscall/sockcmsg_unix.go
+++ b/src/pkg/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
@@ -13,9 +13,9 @@ import "unsafe"
// Round the length of a raw sockaddr up to align it properly.
func cmsgAlignOf(salen int) int {
salign := 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
}
return (salen + salign - 1) & ^(salign - 1)
diff --git a/src/pkg/syscall/srpc_nacl.go b/src/pkg/syscall/srpc_nacl.go
new file mode 100644
index 000000000..dd07373d1
--- /dev/null
+++ b/src/pkg/syscall/srpc_nacl.go
@@ -0,0 +1,822 @@
+// 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.
+
+// Native Client SRPC message passing.
+// This code is needed to invoke SecureRandom, the NaCl equivalent of /dev/random.
+
+package syscall
+
+import (
+ "errors"
+ "sync"
+ "unsafe"
+)
+
+// An srpcClient represents the client side of an SRPC connection.
+type srpcClient struct {
+ fd int // to server
+ r msgReceiver
+ s msgSender
+ service map[string]srpcService // services by name
+
+ outMu sync.Mutex // protects writing to connection
+
+ mu sync.Mutex // protects following fields
+ muxer bool // is someone reading and muxing responses
+ pending map[uint32]*srpc
+ idGen uint32 // generator for request IDs
+}
+
+// An srpcService is a single method that the server offers.
+type srpcService struct {
+ num uint32 // method number
+ fmt string // argument format; see "parsing of RPC messages" below
+}
+
+// An srpc represents a single srpc issued by a client.
+type srpc struct {
+ Ret []interface{}
+ Done chan *srpc
+ Err error
+ c *srpcClient
+ id uint32
+}
+
+// newClient allocates a new SRPC client using the file descriptor fd.
+func newClient(fd int) (*srpcClient, error) {
+ c := new(srpcClient)
+ c.fd = fd
+ c.r.fd = fd
+ c.s.fd = fd
+ c.service = make(map[string]srpcService)
+ c.pending = make(map[uint32]*srpc)
+
+ // service discovery request
+ m := &msg{
+ isRequest: 1,
+ template: []interface{}{[]byte(nil)},
+ size: []int{4000}, // max size to accept for returned byte slice
+ }
+ if err := m.pack(); err != nil {
+ return nil, errors.New("Native Client SRPC service_discovery: preparing request: " + err.Error())
+ }
+ c.s.send(m)
+ m, err := c.r.recv()
+ if err != nil {
+ return nil, err
+ }
+ m.unpack()
+ if m.status != uint32(srpcOK) {
+ return nil, errors.New("Native Client SRPC service_discovery: " + srpcErrno(m.status).Error())
+ }
+ list := m.value[0].([]byte)
+ var n uint32
+ for len(list) > 0 {
+ var line []byte
+ i := byteIndex(list, '\n')
+ if i < 0 {
+ line, list = list, nil
+ } else {
+ line, list = list[:i], list[i+1:]
+ }
+ i = byteIndex(line, ':')
+ if i >= 0 {
+ c.service[string(line)] = srpcService{n, string(line[i+1:])}
+ }
+ n++
+ }
+
+ return c, nil
+}
+
+func byteIndex(b []byte, c byte) int {
+ for i, bi := range b {
+ if bi == c {
+ return i
+ }
+ }
+ return -1
+}
+
+var yourTurn srpc
+
+func (c *srpcClient) wait(r *srpc) {
+ var rx *srpc
+ for rx = range r.Done {
+ if rx != &yourTurn {
+ break
+ }
+ c.input()
+ }
+ return
+}
+
+func (c *srpcClient) input() {
+ // read message
+ m, err := c.r.recv()
+ if err != nil {
+ println("Native Client SRPC receive error:", err.Error())
+ return
+ }
+ if m.unpack(); m.status != uint32(srpcOK) {
+ println("Native Client SRPC receive error: invalid message: ", srpcErrno(m.status).Error())
+ return
+ }
+
+ // deliver to intended recipient
+ c.mu.Lock()
+ rpc, ok := c.pending[m.id]
+ if ok {
+ delete(c.pending, m.id)
+ }
+
+ // wake a new muxer if there are more RPCs to read
+ c.muxer = false
+ for _, rpc := range c.pending {
+ c.muxer = true
+ rpc.Done <- &yourTurn
+ break
+ }
+ c.mu.Unlock()
+ if !ok {
+ println("Native Client: unexpected response for ID", m.id)
+ return
+ }
+ rpc.Ret = m.value
+ rpc.Done <- rpc
+}
+
+// Wait blocks until the RPC has finished.
+func (r *srpc) Wait() {
+ r.c.wait(r)
+}
+
+// Start issues an RPC request for method name with the given arguments.
+// The RPC r must not be in use for another pending request.
+// To wait for the RPC to finish, receive from r.Done and then
+// inspect r.Ret and r.Errno.
+func (r *srpc) Start(name string, arg []interface{}) {
+ r.Err = nil
+ r.c.mu.Lock()
+ srv, ok := r.c.service[name]
+ if !ok {
+ r.c.mu.Unlock()
+ r.Err = srpcErrBadRPCNumber
+ r.Done <- r
+ return
+ }
+ r.c.pending[r.id] = r
+ if !r.c.muxer {
+ r.c.muxer = true
+ r.Done <- &yourTurn
+ }
+ r.c.mu.Unlock()
+
+ var m msg
+ m.id = r.id
+ m.isRequest = 1
+ m.rpc = srv.num
+ m.value = arg
+
+ // Fill in the return values and sizes to generate
+ // the right type chars. We'll take most any size.
+
+ // Skip over input arguments.
+ // We could check them against arg, but the server
+ // will do that anyway.
+ i := 0
+ for srv.fmt[i] != ':' {
+ i++
+ }
+ format := srv.fmt[i+1:]
+
+ // Now the return prototypes.
+ m.template = make([]interface{}, len(format))
+ m.size = make([]int, len(format))
+ for i := 0; i < len(format); i++ {
+ switch format[i] {
+ default:
+ println("Native Client SRPC: unexpected service type " + string(format[i]))
+ r.Err = srpcErrBadRPCNumber
+ r.Done <- r
+ return
+ case 'b':
+ m.template[i] = false
+ case 'C':
+ m.template[i] = []byte(nil)
+ m.size[i] = 1 << 30
+ case 'd':
+ m.template[i] = float64(0)
+ case 'D':
+ m.template[i] = []float64(nil)
+ m.size[i] = 1 << 30
+ case 'h':
+ m.template[i] = int(-1)
+ case 'i':
+ m.template[i] = int32(0)
+ case 'I':
+ m.template[i] = []int32(nil)
+ m.size[i] = 1 << 30
+ case 's':
+ m.template[i] = ""
+ m.size[i] = 1 << 30
+ }
+ }
+
+ if err := m.pack(); err != nil {
+ r.Err = errors.New("Native Client RPC Start " + name + ": preparing request: " + err.Error())
+ r.Done <- r
+ return
+ }
+
+ r.c.outMu.Lock()
+ r.c.s.send(&m)
+ r.c.outMu.Unlock()
+}
+
+// Call is a convenience wrapper that starts the RPC request,
+// waits for it to finish, and then returns the results.
+// Its implementation is:
+//
+// r.Start(name, arg)
+// r.Wait()
+// return r.Ret, r.Errno
+//
+func (c *srpcClient) Call(name string, arg ...interface{}) (ret []interface{}, err error) {
+ r := c.NewRPC(nil)
+ r.Start(name, arg)
+ r.Wait()
+ return r.Ret, r.Err
+}
+
+// NewRPC creates a new RPC on the client connection.
+func (c *srpcClient) NewRPC(done chan *srpc) *srpc {
+ if done == nil {
+ done = make(chan *srpc, 1)
+ }
+ c.mu.Lock()
+ id := c.idGen
+ c.idGen++
+ c.mu.Unlock()
+ return &srpc{Done: done, c: c, id: id}
+}
+
+// The current protocol number.
+// Kind of useless, since there have been backwards-incompatible changes
+// to the wire protocol that did not update the protocol number.
+// At this point it's really just a sanity check.
+const protocol = 0xc0da0002
+
+// An srpcErrno is an SRPC status code.
+type srpcErrno uint32
+
+const (
+ srpcOK srpcErrno = 256 + iota
+ srpcErrBreak
+ srpcErrMessageTruncated
+ srpcErrNoMemory
+ srpcErrProtocolMismatch
+ srpcErrBadRPCNumber
+ srpcErrBadArgType
+ srpcErrTooFewArgs
+ srpcErrTooManyArgs
+ srpcErrInArgTypeMismatch
+ srpcErrOutArgTypeMismatch
+ srpcErrInternalError
+ srpcErrAppError
+)
+
+var srpcErrstr = [...]string{
+ srpcOK - srpcOK: "ok",
+ srpcErrBreak - srpcOK: "break",
+ srpcErrMessageTruncated - srpcOK: "message truncated",
+ srpcErrNoMemory - srpcOK: "out of memory",
+ srpcErrProtocolMismatch - srpcOK: "protocol mismatch",
+ srpcErrBadRPCNumber - srpcOK: "invalid RPC method number",
+ srpcErrBadArgType - srpcOK: "unexpected argument type",
+ srpcErrTooFewArgs - srpcOK: "too few arguments",
+ srpcErrTooManyArgs - srpcOK: "too many arguments",
+ srpcErrInArgTypeMismatch - srpcOK: "input argument type mismatch",
+ srpcErrOutArgTypeMismatch - srpcOK: "output argument type mismatch",
+ srpcErrInternalError - srpcOK: "internal error",
+ srpcErrAppError - srpcOK: "application error",
+}
+
+func (e srpcErrno) Error() string {
+ if e < srpcOK || int(e-srpcOK) >= len(srpcErrstr) {
+ return "srpcErrno(" + itoa(int(e)) + ")"
+ }
+ return srpcErrstr[e-srpcOK]
+}
+
+// A msgHdr is the data argument to the imc_recvmsg
+// and imc_sendmsg system calls.
+type msgHdr struct {
+ iov *iov
+ niov int32
+ desc *int32
+ ndesc int32
+ flags uint32
+}
+
+// A single region for I/O.
+type iov struct {
+ base *byte
+ len int32
+}
+
+const maxMsgSize = 1<<16 - 4*4
+
+// A msgReceiver receives messages from a file descriptor.
+type msgReceiver struct {
+ fd int
+ data [maxMsgSize]byte
+ desc [8]int32
+ hdr msgHdr
+ iov iov
+}
+
+func (r *msgReceiver) recv() (*msg, error) {
+ // Init pointers to buffers where syscall recvmsg can write.
+ r.iov.base = &r.data[0]
+ r.iov.len = int32(len(r.data))
+ r.hdr.iov = &r.iov
+ r.hdr.niov = 1
+ r.hdr.desc = &r.desc[0]
+ r.hdr.ndesc = int32(len(r.desc))
+ n, _, e := Syscall(sys_imc_recvmsg, uintptr(r.fd), uintptr(unsafe.Pointer(&r.hdr)), 0)
+ if e != 0 {
+ println("Native Client imc_recvmsg: ", e.Error())
+ return nil, e
+ }
+
+ // Make a copy of the data so that the next recvmsg doesn't
+ // smash it. The system call did not update r.iov.len. Instead it
+ // returned the total byte count as n.
+ m := new(msg)
+ m.data = make([]byte, n)
+ copy(m.data, r.data[0:])
+
+ // Make a copy of the desc too.
+ // The system call *did* update r.hdr.ndesc.
+ if r.hdr.ndesc > 0 {
+ m.desc = make([]int32, r.hdr.ndesc)
+ copy(m.desc, r.desc[:])
+ }
+
+ return m, nil
+}
+
+// A msgSender sends messages on a file descriptor.
+type msgSender struct {
+ fd int
+ hdr msgHdr
+ iov iov
+}
+
+func (s *msgSender) send(m *msg) error {
+ if len(m.data) > 0 {
+ s.iov.base = &m.data[0]
+ }
+ s.iov.len = int32(len(m.data))
+ s.hdr.iov = &s.iov
+ s.hdr.niov = 1
+ s.hdr.desc = nil
+ s.hdr.ndesc = 0
+ _, _, e := Syscall(sys_imc_sendmsg, uintptr(s.fd), uintptr(unsafe.Pointer(&s.hdr)), 0)
+ if e != 0 {
+ println("Native Client imc_sendmsg: ", e.Error())
+ return e
+ }
+ return nil
+}
+
+// A msg is the Go representation of an SRPC message.
+type msg struct {
+ data []byte // message data
+ desc []int32 // message file descriptors
+
+ // parsed version of message
+ id uint32
+ isRequest uint32
+ rpc uint32
+ status uint32
+ value []interface{}
+ template []interface{}
+ size []int
+ format string
+ broken bool
+}
+
+// reading from a msg
+
+func (m *msg) uint32() uint32 {
+ if m.broken {
+ return 0
+ }
+ if len(m.data) < 4 {
+ m.broken = true
+ return 0
+ }
+ b := m.data[:4]
+ x := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+ m.data = m.data[4:]
+ return x
+}
+
+func (m *msg) uint64() uint64 {
+ x := uint64(m.uint32()) | uint64(m.uint32())<<32
+ if m.broken {
+ return 0
+ }
+ return x
+}
+
+func (m *msg) bytes(n int) []byte {
+ if m.broken {
+ return nil
+ }
+ if len(m.data) < n {
+ m.broken = true
+ return nil
+ }
+ x := m.data[0:n]
+ m.data = m.data[n:]
+ return x
+}
+
+// writing to a msg
+
+func (m *msg) wuint32(x uint32) {
+ m.data = append(m.data, byte(x), byte(x>>8), byte(x>>16), byte(x>>24))
+}
+
+func (m *msg) wuint64(x uint64) {
+ lo := uint32(x)
+ hi := uint32(x >> 32)
+ m.data = append(m.data, byte(lo), byte(lo>>8), byte(lo>>16), byte(lo>>24), byte(hi), byte(hi>>8), byte(hi>>16), byte(hi>>24))
+}
+
+func (m *msg) wbytes(p []byte) {
+ m.data = append(m.data, p...)
+}
+
+func (m *msg) wstring(s string) {
+ m.data = append(m.data, s...)
+}
+
+// Parsing of RPC messages.
+//
+// Each message begins with
+// total_size uint32
+// total_descs uint32
+// fragment_size uint32
+// fragment_descs uint32
+//
+// If fragment_size < total_size or fragment_descs < total_descs, the actual
+// message is broken up in multiple messages; follow-up messages omit
+// the "total" fields and begin with the "fragment" fields.
+// We do not support putting fragmented messages back together.
+// To do this we would need to change the message receiver.
+//
+// After that size information, the message header follows:
+// protocol uint32
+// requestID uint32
+// isRequest uint32
+// rpcNumber uint32
+// status uint32
+// numValue uint32
+// numTemplate uint32
+//
+// After the header come numTemplate fixed-size arguments,
+// numValue fixed-size arguments, and then the variable-sized
+// part of the values. The templates describe the expected results
+// and have no associated variable sized data in the request.
+//
+// Each fixed-size argument has the form:
+// tag uint32 // really a char, like 'b' or 'C'
+// pad uint32 // unused
+// val1 uint32
+// val2 uint32
+//
+// The tags are:
+// 'b': bool; val1 == 0 or 1
+// 'C': []byte; val1 == len, data in variable-sized section
+// 'd': float64; (val1, val2) is data
+// 'D': []float64; val1 == len, data in variable-sized section
+// 'h': int; val1 == file descriptor
+// 'i': int32; descriptor in next entry in m.desc
+// 'I': []int; val1 == len, data in variable-sized section
+// 's': string; val1 == len, data in variable-sized section
+//
+
+func (m *msg) pack() error {
+ m.data = m.data[:0]
+ m.desc = m.desc[:0]
+
+ // sizes, to fill in later
+ m.wuint32(0)
+ m.wuint32(0)
+ m.wuint32(0)
+ m.wuint32(0)
+
+ // message header
+ m.wuint32(protocol)
+ m.wuint32(m.id)
+ m.wuint32(m.isRequest)
+ m.wuint32(m.rpc)
+ m.wuint32(m.status)
+ m.wuint32(uint32(len(m.value)))
+ m.wuint32(uint32(len(m.template)))
+
+ // fixed-size templates
+ for i, x := range m.template {
+ var tag, val1, val2 uint32
+ switch x.(type) {
+ default:
+ return errors.New("unexpected template type")
+ case bool:
+ tag = 'b'
+ case []byte:
+ tag = 'C'
+ val1 = uint32(m.size[i])
+ case float64:
+ tag = 'd'
+ case []float64:
+ tag = 'D'
+ val1 = uint32(m.size[i])
+ case int:
+ tag = 'h'
+ case int32:
+ tag = 'i'
+ case []int32:
+ tag = 'I'
+ val1 = uint32(m.size[i])
+ case string:
+ tag = 's'
+ val1 = uint32(m.size[i])
+ }
+ m.wuint32(tag)
+ m.wuint32(0)
+ m.wuint32(val1)
+ m.wuint32(val2)
+ }
+
+ // fixed-size values
+ for _, x := range m.value {
+ var tag, val1, val2 uint32
+ switch x := x.(type) {
+ default:
+ return errors.New("unexpected value type")
+ case bool:
+ tag = 'b'
+ if x {
+ val1 = 1
+ }
+ case []byte:
+ tag = 'C'
+ val1 = uint32(len(x))
+ case float64:
+ tag = 'd'
+ v := float64bits(x)
+ val1 = uint32(v)
+ val2 = uint32(v >> 32)
+ case []float64:
+ tag = 'D'
+ val1 = uint32(len(x))
+ case int32:
+ tag = 'i'
+ m.desc = append(m.desc, x)
+ case []int32:
+ tag = 'I'
+ val1 = uint32(len(x))
+ case string:
+ tag = 's'
+ val1 = uint32(len(x) + 1)
+ }
+ m.wuint32(tag)
+ m.wuint32(0)
+ m.wuint32(val1)
+ m.wuint32(val2)
+ }
+
+ // variable-length data for values
+ for _, x := range m.value {
+ switch x := x.(type) {
+ case []byte:
+ m.wbytes(x)
+ case []float64:
+ for _, f := range x {
+ m.wuint64(float64bits(f))
+ }
+ case []int32:
+ for _, j := range x {
+ m.wuint32(uint32(j))
+ }
+ case string:
+ m.wstring(x)
+ m.wstring("\x00")
+ }
+ }
+
+ // fill in sizes
+ data := m.data
+ m.data = m.data[:0]
+ m.wuint32(uint32(len(data)))
+ m.wuint32(uint32(len(m.desc)))
+ m.wuint32(uint32(len(data)))
+ m.wuint32(uint32(len(m.desc)))
+ m.data = data
+
+ return nil
+}
+
+func (m *msg) unpack() error {
+ totalSize := m.uint32()
+ totalDesc := m.uint32()
+ fragSize := m.uint32()
+ fragDesc := m.uint32()
+ if totalSize != fragSize || totalDesc != fragDesc {
+ return errors.New("Native Client: fragmented RPC messages not supported")
+ }
+ if m.uint32() != protocol {
+ return errors.New("Native Client: RPC protocol mismatch")
+ }
+
+ // message header
+ m.id = m.uint32()
+ m.isRequest = m.uint32()
+ m.rpc = m.uint32()
+ m.status = m.uint32()
+ m.value = make([]interface{}, m.uint32())
+ m.template = make([]interface{}, m.uint32())
+ m.size = make([]int, len(m.template))
+ if m.broken {
+ return errors.New("Native Client: malformed message")
+ }
+
+ // fixed-size templates
+ for i := range m.template {
+ tag := m.uint32()
+ m.uint32() // padding
+ val1 := m.uint32()
+ m.uint32() // val2
+ switch tag {
+ default:
+ return errors.New("Native Client: unexpected template type " + string(rune(tag)))
+ case 'b':
+ m.template[i] = false
+ case 'C':
+ m.template[i] = []byte(nil)
+ m.size[i] = int(val1)
+ case 'd':
+ m.template[i] = float64(0)
+ case 'D':
+ m.template[i] = []float64(nil)
+ m.size[i] = int(val1)
+ case 'i':
+ m.template[i] = int32(0)
+ case 'I':
+ m.template[i] = []int32(nil)
+ m.size[i] = int(val1)
+ case 'h':
+ m.template[i] = int(0)
+ case 's':
+ m.template[i] = ""
+ m.size[i] = int(val1)
+ }
+ }
+
+ // fixed-size values
+ var (
+ strsize []uint32
+ d int
+ )
+ for i := range m.value {
+ tag := m.uint32()
+ m.uint32() // padding
+ val1 := m.uint32()
+ val2 := m.uint32()
+ switch tag {
+ default:
+ return errors.New("Native Client: unexpected value type " + string(rune(tag)))
+ case 'b':
+ m.value[i] = val1 > 0
+ case 'C':
+ m.value[i] = []byte(nil)
+ strsize = append(strsize, val1)
+ case 'd':
+ m.value[i] = float64frombits(uint64(val1) | uint64(val2)<<32)
+ case 'D':
+ m.value[i] = make([]float64, val1)
+ case 'i':
+ m.value[i] = int32(val1)
+ case 'I':
+ m.value[i] = make([]int32, val1)
+ case 'h':
+ m.value[i] = int(m.desc[d])
+ d++
+ case 's':
+ m.value[i] = ""
+ strsize = append(strsize, val1)
+ }
+ }
+
+ // variable-sized parts of values
+ for i, x := range m.value {
+ switch x := x.(type) {
+ case []byte:
+ m.value[i] = m.bytes(int(strsize[0]))
+ strsize = strsize[1:]
+ case []float64:
+ for i := range x {
+ x[i] = float64frombits(m.uint64())
+ }
+ case []int32:
+ for i := range x {
+ x[i] = int32(m.uint32())
+ }
+ case string:
+ m.value[i] = string(m.bytes(int(strsize[0])))
+ strsize = strsize[1:]
+ }
+ }
+
+ if len(m.data) > 0 {
+ return errors.New("Native Client: junk at end of message")
+ }
+ return nil
+}
+
+func float64bits(x float64) uint64 {
+ return *(*uint64)(unsafe.Pointer(&x))
+}
+
+func float64frombits(x uint64) float64 {
+ return *(*float64)(unsafe.Pointer(&x))
+}
+
+// At startup, connect to the name service.
+var nsClient = nsConnect()
+
+func nsConnect() *srpcClient {
+ var ns int32 = -1
+ _, _, errno := Syscall(sys_nameservice, uintptr(unsafe.Pointer(&ns)), 0, 0)
+ if errno != 0 {
+ println("Native Client nameservice:", errno.Error())
+ return nil
+ }
+
+ sock, _, errno := Syscall(sys_imc_connect, uintptr(ns), 0, 0)
+ if errno != 0 {
+ println("Native Client nameservice connect:", errno.Error())
+ return nil
+ }
+
+ c, err := newClient(int(sock))
+ if err != nil {
+ println("Native Client nameservice init:", err.Error())
+ return nil
+ }
+
+ return c
+}
+
+const (
+ nsSuccess = 0
+ nsNameNotFound = 1
+ nsDuplicateName = 2
+ nsInsufficientResources = 3
+ nsPermissionDenied = 4
+ nsInvalidArgument = 5
+)
+
+func openNamedService(name string, mode int32) (fd int, err error) {
+ if nsClient == nil {
+ return 0, errors.New("no name service")
+ }
+ ret, err := nsClient.Call("lookup:si:ih", name, int32(mode))
+ if err != nil {
+ return 0, err
+ }
+ status := ret[0].(int32)
+ fd = ret[1].(int)
+ switch status {
+ case nsSuccess:
+ // ok
+ case nsNameNotFound:
+ return -1, ENOENT
+ case nsDuplicateName:
+ return -1, EEXIST
+ case nsInsufficientResources:
+ return -1, EWOULDBLOCK
+ case nsPermissionDenied:
+ return -1, EPERM
+ case nsInvalidArgument:
+ return -1, EINVAL
+ default:
+ return -1, EINVAL
+ }
+ return fd, nil
+}
diff --git a/src/pkg/syscall/syscall_bsd.go b/src/pkg/syscall/syscall_bsd.go
index 76b1f41b4..b042841a5 100644
--- a/src/pkg/syscall/syscall_bsd.go
+++ b/src/pkg/syscall/syscall_bsd.go
@@ -64,8 +64,11 @@ func Setgroups(gids []int) (err error) {
func ReadDirent(fd int, buf []byte) (n int, err error) {
// Final argument is (basep *uintptr) and the syscall doesn't take nil.
+ // 64 bits should be enough. (32 bits isn't even on 386). Since the
+ // actual system call is getdirentries64, 64 is a good guess.
// TODO(rsc): Can we use a single global basep for all calls?
- return Getdirentries(fd, buf, new(uintptr))
+ var base = (*uintptr)(unsafe.Pointer(new(uint64)))
+ return Getdirentries(fd, buf, base)
}
// Wait status is 7 bits at bottom, either 0 (exited),
@@ -131,18 +134,18 @@ func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int,
}
//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
-//sys bind(s int, addr uintptr, addrlen _Socklen) (err error)
-//sys connect(s int, addr uintptr, addrlen _Socklen) (err error)
+//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
+//sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
//sysnb socket(domain int, typ int, proto int) (fd int, err error)
-//sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error)
-//sys setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error)
+//sys getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error)
+//sys setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error)
//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
//sysnb getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
//sys Shutdown(s int, how int) (err error)
-func (sa *SockaddrInet4) sockaddr() (uintptr, _Socklen, error) {
+func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) {
if sa.Port < 0 || sa.Port > 0xFFFF {
- return 0, 0, EINVAL
+ return nil, 0, EINVAL
}
sa.raw.Len = SizeofSockaddrInet4
sa.raw.Family = AF_INET
@@ -152,12 +155,12 @@ func (sa *SockaddrInet4) sockaddr() (uintptr, _Socklen, error) {
for i := 0; i < len(sa.Addr); i++ {
sa.raw.Addr[i] = sa.Addr[i]
}
- return uintptr(unsafe.Pointer(&sa.raw)), _Socklen(sa.raw.Len), nil
+ return unsafe.Pointer(&sa.raw), _Socklen(sa.raw.Len), nil
}
-func (sa *SockaddrInet6) sockaddr() (uintptr, _Socklen, error) {
+func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) {
if sa.Port < 0 || sa.Port > 0xFFFF {
- return 0, 0, EINVAL
+ return nil, 0, EINVAL
}
sa.raw.Len = SizeofSockaddrInet6
sa.raw.Family = AF_INET6
@@ -168,26 +171,26 @@ func (sa *SockaddrInet6) sockaddr() (uintptr, _Socklen, error) {
for i := 0; i < len(sa.Addr); i++ {
sa.raw.Addr[i] = sa.Addr[i]
}
- return uintptr(unsafe.Pointer(&sa.raw)), _Socklen(sa.raw.Len), nil
+ return unsafe.Pointer(&sa.raw), _Socklen(sa.raw.Len), nil
}
-func (sa *SockaddrUnix) sockaddr() (uintptr, _Socklen, error) {
+func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, _Socklen, error) {
name := sa.Name
n := len(name)
if n >= len(sa.raw.Path) || n == 0 {
- return 0, 0, EINVAL
+ return nil, 0, EINVAL
}
sa.raw.Len = byte(3 + n) // 2 for Family, Len; 1 for NUL
sa.raw.Family = AF_UNIX
for i := 0; i < n; i++ {
sa.raw.Path[i] = int8(name[i])
}
- return uintptr(unsafe.Pointer(&sa.raw)), _Socklen(sa.raw.Len), nil
+ return unsafe.Pointer(&sa.raw), _Socklen(sa.raw.Len), nil
}
-func (sa *SockaddrDatalink) sockaddr() (uintptr, _Socklen, error) {
+func (sa *SockaddrDatalink) sockaddr() (unsafe.Pointer, _Socklen, error) {
if sa.Index == 0 {
- return 0, 0, EINVAL
+ return nil, 0, EINVAL
}
sa.raw.Len = sa.Len
sa.raw.Family = AF_LINK
@@ -199,7 +202,7 @@ func (sa *SockaddrDatalink) sockaddr() (uintptr, _Socklen, error) {
for i := 0; i < len(sa.raw.Data); i++ {
sa.raw.Data[i] = sa.Data[i]
}
- return uintptr(unsafe.Pointer(&sa.raw)), SizeofSockaddrDatalink, nil
+ return unsafe.Pointer(&sa.raw), SizeofSockaddrDatalink, nil
}
func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
@@ -221,14 +224,20 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
case AF_UNIX:
pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa))
- if pp.Len < 3 || pp.Len > SizeofSockaddrUnix {
+ if pp.Len < 2 || pp.Len > SizeofSockaddrUnix {
return nil, EINVAL
}
sa := new(SockaddrUnix)
- n := int(pp.Len) - 3 // subtract leading Family, Len, terminating NUL
+
+ // Some BSDs include the trailing NUL in the length, whereas
+ // others do not. Work around this by subtracting the leading
+ // family and len. The path is then scanned to see if a NUL
+ // terminator still exists within the length.
+ n := int(pp.Len) - 2 // subtract leading Family, Len
for i := 0; i < n; i++ {
if pp.Path[i] == 0 {
- // found early NUL; assume Len is overestimating
+ // found early NUL; assume Len included the NUL
+ // or was overestimating.
n = i
break
}
@@ -290,10 +299,9 @@ func Getsockname(fd int) (sa Sockaddr, err error) {
if err = getsockname(fd, &rsa, &len); err != nil {
return
}
- // TODO(jsing): Remove after OpenBSD 5.4 is released (see issue 3349).
- // TODO(jsing): Apparently dragonfly has the same "bug", which should
- // be reported upstream.
- if (runtime.GOOS == "dragonfly" || runtime.GOOS == "openbsd") && rsa.Addr.Family == AF_UNSPEC && rsa.Addr.Len == 0 {
+ // TODO(jsing): DragonFly has a "bug" (see issue 3349), which should be
+ // reported upstream.
+ if runtime.GOOS == "dragonfly" && rsa.Addr.Family == AF_UNSPEC && rsa.Addr.Len == 0 {
rsa.Addr.Family = AF_UNIX
rsa.Addr.Len = SizeofSockaddrUnix
}
@@ -305,46 +313,46 @@ func Getsockname(fd int) (sa Sockaddr, err error) {
func GetsockoptByte(fd, level, opt int) (value byte, err error) {
var n byte
vallen := _Socklen(1)
- err = getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&n)), &vallen)
+ err = getsockopt(fd, level, opt, unsafe.Pointer(&n), &vallen)
return n, err
}
func GetsockoptInet4Addr(fd, level, opt int) (value [4]byte, err error) {
vallen := _Socklen(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(SizeofIPMreq)
- 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(SizeofIPv6Mreq)
- err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
return &value, err
}
func GetsockoptIPv6MTUInfo(fd, level, opt int) (*IPv6MTUInfo, error) {
var value IPv6MTUInfo
vallen := _Socklen(SizeofIPv6MTUInfo)
- err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
return &value, err
}
func GetsockoptICMPv6Filter(fd, level, opt int) (*ICMPv6Filter, error) {
var value ICMPv6Filter
vallen := _Socklen(SizeofICMPv6Filter)
- err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
return &value, err
}
//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error)
-//sys sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error)
+//sys sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error)
//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error)
func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) {
@@ -381,15 +389,20 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from
return
}
-//sys sendmsg(s int, msg *Msghdr, flags int) (err error)
+//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
- var ptr uintptr
+ _, 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 unsafe.Pointer
var salen _Socklen
if to != nil {
ptr, salen, err = to.sockaddr()
if err != nil {
- return
+ return 0, err
}
}
var msg Msghdr
@@ -412,21 +425,24 @@ 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 kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error)
+//sys kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error)
func Kevent(kq int, changes, events []Kevent_t, timeout *Timespec) (n int, err error) {
- var change, event uintptr
+ var change, event unsafe.Pointer
if len(changes) > 0 {
- change = uintptr(unsafe.Pointer(&changes[0]))
+ change = unsafe.Pointer(&changes[0])
}
if len(events) > 0 {
- event = uintptr(unsafe.Pointer(&events[0]))
+ event = unsafe.Pointer(&events[0])
}
return kevent(kq, change, len(changes), event, len(events), timeout)
}
diff --git a/src/pkg/syscall/syscall_bsd_test.go b/src/pkg/syscall/syscall_bsd_test.go
new file mode 100644
index 000000000..c2ea089d5
--- /dev/null
+++ b/src/pkg/syscall/syscall_bsd_test.go
@@ -0,0 +1,34 @@
+// 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 openbsd
+
+package syscall_test
+
+import (
+ "syscall"
+ "testing"
+)
+
+const MNT_WAIT = 1
+
+func TestGetfsstat(t *testing.T) {
+ n, err := syscall.Getfsstat(nil, MNT_WAIT)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ data := make([]syscall.Statfs_t, n)
+ n, err = syscall.Getfsstat(data, MNT_WAIT)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ empty := syscall.Statfs_t{}
+ for _, stat := range data {
+ if stat == empty {
+ t.Fatal("an empty Statfs_t struct was returned")
+ }
+ }
+}
diff --git a/src/pkg/syscall/syscall_darwin.go b/src/pkg/syscall/syscall_darwin.go
index bd929ff99..97414dcda 100644
--- a/src/pkg/syscall/syscall_darwin.go
+++ b/src/pkg/syscall/syscall_darwin.go
@@ -187,6 +187,21 @@ func Pipe(p []int) (err error) {
return
}
+func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
+ var _p0 unsafe.Pointer
+ var bufsize uintptr
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf))
+ }
+ r0, _, e1 := Syscall(SYS_GETFSSTAT64, uintptr(_p0), bufsize, uintptr(flags))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
/*
* Wrapped
*/
@@ -224,7 +239,6 @@ func Kill(pid int, signum Signal) (err error) { return kill(pid, int(signum), 1)
//sys Getdtablesize() (size int)
//sysnb Getegid() (egid int)
//sysnb Geteuid() (uid int)
-//sys Getfsstat(buf []Statfs_t, flags int) (n int, err error) = SYS_GETFSSTAT64
//sysnb Getgid() (gid int)
//sysnb Getpgid(pid int) (pgid int, err error)
//sysnb Getpgrp() (pgrp int)
@@ -244,6 +258,11 @@ func Kill(pid int, signum Signal) (err error) { return kill(pid, int(signum), 1)
//sys Mkdir(path string, mode uint32) (err error)
//sys Mkfifo(path string, mode uint32) (err error)
//sys Mknod(path string, mode uint32, dev int) (err error)
+//sys Mlock(b []byte) (err error)
+//sys Mlockall(flags int) (err error)
+//sys Mprotect(b []byte, prot int) (err error)
+//sys Munlock(b []byte) (err error)
+//sys Munlockall() (err error)
//sys Open(path string, mode int, perm uint32) (fd int, err error)
//sys Pathconf(path string, name int) (val int, err error)
//sys Pread(fd int, p []byte, offset int64) (n int, err error)
diff --git a/src/pkg/syscall/syscall_dragonfly.go b/src/pkg/syscall/syscall_dragonfly.go
index e19a9cee3..39c51df7e 100644
--- a/src/pkg/syscall/syscall_dragonfly.go
+++ b/src/pkg/syscall/syscall_dragonfly.go
@@ -101,6 +101,21 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
return extpwrite(fd, p, 0, offset)
}
+func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
+ var _p0 unsafe.Pointer
+ var bufsize uintptr
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf))
+ }
+ r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), bufsize, uintptr(flags))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
/*
* Exposed directly
*/
@@ -129,7 +144,6 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
//sys Getdtablesize() (size int)
//sysnb Getegid() (egid int)
//sysnb Geteuid() (uid int)
-//sys Getfsstat(buf []Statfs_t, flags int) (n int, err error)
//sysnb Getgid() (gid int)
//sysnb Getpgid(pid int) (pgid int, err error)
//sysnb Getpgrp() (pgrp int)
diff --git a/src/pkg/syscall/syscall_freebsd.go b/src/pkg/syscall/syscall_freebsd.go
index 9fbcc48c6..3d834f52b 100644
--- a/src/pkg/syscall/syscall_freebsd.go
+++ b/src/pkg/syscall/syscall_freebsd.go
@@ -95,12 +95,45 @@ func Pipe(p []int) (err error) {
func GetsockoptIPMreqn(fd, level, opt int) (*IPMreqn, error) {
var value IPMreqn
vallen := _Socklen(SizeofIPMreqn)
- errno := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+ errno := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
return &value, errno
}
func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) {
- return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(mreq)), unsafe.Sizeof(*mreq))
+ return setsockopt(fd, level, opt, unsafe.Pointer(mreq), unsafe.Sizeof(*mreq))
+}
+
+func Accept4(fd, flags int) (nfd int, sa Sockaddr, err error) {
+ var rsa RawSockaddrAny
+ var len _Socklen = SizeofSockaddrAny
+ nfd, err = accept4(fd, &rsa, &len, flags)
+ if err != nil {
+ return
+ }
+ if len > SizeofSockaddrAny {
+ panic("RawSockaddrAny too small")
+ }
+ sa, err = anyToSockaddr(&rsa)
+ if err != nil {
+ Close(nfd)
+ nfd = 0
+ }
+ return
+}
+
+func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
+ var _p0 unsafe.Pointer
+ var bufsize uintptr
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf))
+ }
+ r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), bufsize, uintptr(flags))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
}
/*
@@ -131,7 +164,6 @@ func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) {
//sys Getdtablesize() (size int)
//sysnb Getegid() (egid int)
//sysnb Geteuid() (uid int)
-//sys Getfsstat(buf []Statfs_t, flags int) (n int, err error)
//sysnb Getgid() (gid int)
//sysnb Getpgid(pid int) (pgid int, err error)
//sysnb Getpgrp() (pgrp int)
@@ -191,6 +223,7 @@ func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) {
//sys munmap(addr uintptr, length uintptr) (err error)
//sys readlen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_READ
//sys writelen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_WRITE
+//sys accept4(fd int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (nfd int, err error)
/*
* Unimplemented
diff --git a/src/pkg/syscall/syscall_linux.go b/src/pkg/syscall/syscall_linux.go
index 79c1fda68..fa0d7ea3c 100644
--- a/src/pkg/syscall/syscall_linux.go
+++ b/src/pkg/syscall/syscall_linux.go
@@ -230,9 +230,9 @@ func Mkfifo(path string, mode uint32) (err error) {
return Mknod(path, mode|S_IFIFO, 0)
}
-func (sa *SockaddrInet4) sockaddr() (uintptr, _Socklen, error) {
+func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) {
if sa.Port < 0 || sa.Port > 0xFFFF {
- return 0, 0, EINVAL
+ return nil, 0, EINVAL
}
sa.raw.Family = AF_INET
p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
@@ -241,12 +241,12 @@ func (sa *SockaddrInet4) sockaddr() (uintptr, _Socklen, error) {
for i := 0; i < len(sa.Addr); i++ {
sa.raw.Addr[i] = sa.Addr[i]
}
- return uintptr(unsafe.Pointer(&sa.raw)), SizeofSockaddrInet4, nil
+ return unsafe.Pointer(&sa.raw), SizeofSockaddrInet4, nil
}
-func (sa *SockaddrInet6) sockaddr() (uintptr, _Socklen, error) {
+func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) {
if sa.Port < 0 || sa.Port > 0xFFFF {
- return 0, 0, EINVAL
+ return nil, 0, EINVAL
}
sa.raw.Family = AF_INET6
p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
@@ -256,14 +256,14 @@ func (sa *SockaddrInet6) sockaddr() (uintptr, _Socklen, error) {
for i := 0; i < len(sa.Addr); i++ {
sa.raw.Addr[i] = sa.Addr[i]
}
- return uintptr(unsafe.Pointer(&sa.raw)), SizeofSockaddrInet6, nil
+ return unsafe.Pointer(&sa.raw), SizeofSockaddrInet6, nil
}
-func (sa *SockaddrUnix) sockaddr() (uintptr, _Socklen, error) {
+func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, _Socklen, error) {
name := sa.Name
n := len(name)
if n >= len(sa.raw.Path) {
- return 0, 0, EINVAL
+ return nil, 0, EINVAL
}
sa.raw.Family = AF_UNIX
for i := 0; i < n; i++ {
@@ -280,7 +280,7 @@ func (sa *SockaddrUnix) sockaddr() (uintptr, _Socklen, error) {
sl--
}
- return uintptr(unsafe.Pointer(&sa.raw)), sl, nil
+ return unsafe.Pointer(&sa.raw), sl, nil
}
type SockaddrLinklayer struct {
@@ -293,9 +293,9 @@ type SockaddrLinklayer struct {
raw RawSockaddrLinklayer
}
-func (sa *SockaddrLinklayer) sockaddr() (uintptr, _Socklen, error) {
+func (sa *SockaddrLinklayer) sockaddr() (unsafe.Pointer, _Socklen, error) {
if sa.Ifindex < 0 || sa.Ifindex > 0x7fffffff {
- return 0, 0, EINVAL
+ return nil, 0, EINVAL
}
sa.raw.Family = AF_PACKET
sa.raw.Protocol = sa.Protocol
@@ -306,7 +306,7 @@ func (sa *SockaddrLinklayer) sockaddr() (uintptr, _Socklen, error) {
for i := 0; i < len(sa.Addr); i++ {
sa.raw.Addr[i] = sa.Addr[i]
}
- return uintptr(unsafe.Pointer(&sa.raw)), SizeofSockaddrLinklayer, nil
+ return unsafe.Pointer(&sa.raw), SizeofSockaddrLinklayer, nil
}
type SockaddrNetlink struct {
@@ -317,12 +317,12 @@ type SockaddrNetlink struct {
raw RawSockaddrNetlink
}
-func (sa *SockaddrNetlink) sockaddr() (uintptr, _Socklen, error) {
+func (sa *SockaddrNetlink) sockaddr() (unsafe.Pointer, _Socklen, error) {
sa.raw.Family = AF_NETLINK
sa.raw.Pad = sa.Pad
sa.raw.Pid = sa.Pid
sa.raw.Groups = sa.Groups
- return uintptr(unsafe.Pointer(&sa.raw)), SizeofSockaddrNetlink, nil
+ return unsafe.Pointer(&sa.raw), SizeofSockaddrNetlink, nil
}
func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
@@ -420,6 +420,9 @@ func Accept4(fd int, flags int) (nfd int, sa Sockaddr, err error) {
if err != nil {
return
}
+ if len > SizeofSockaddrAny {
+ panic("RawSockaddrAny too small")
+ }
sa, err = anyToSockaddr(&rsa)
if err != nil {
Close(nfd)
@@ -439,54 +442,54 @@ func Getsockname(fd int) (sa Sockaddr, err error) {
func GetsockoptInet4Addr(fd, level, opt int) (value [4]byte, err error) {
vallen := _Socklen(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(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(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(SizeofIPv6Mreq)
- err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
return &value, err
}
func GetsockoptIPv6MTUInfo(fd, level, opt int) (*IPv6MTUInfo, error) {
var value IPv6MTUInfo
vallen := _Socklen(SizeofIPv6MTUInfo)
- err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
return &value, err
}
func GetsockoptICMPv6Filter(fd, level, opt int) (*ICMPv6Filter, error) {
var value ICMPv6Filter
vallen := _Socklen(SizeofICMPv6Filter)
- err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
return &value, err
}
func GetsockoptUcred(fd, level, opt int) (*Ucred, error) {
var value Ucred
vallen := _Socklen(SizeofUcred)
- err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
return &value, err
}
func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) {
- return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(mreq)), unsafe.Sizeof(*mreq))
+ return setsockopt(fd, level, opt, unsafe.Pointer(mreq), unsafe.Sizeof(*mreq))
}
func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) {
@@ -524,13 +527,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) {
- var ptr uintptr
+ _, 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 unsafe.Pointer
var salen _Socklen
if to != nil {
var err error
ptr, salen, err = to.sockaddr()
if err != nil {
- return err
+ return 0, err
}
}
var msg Msghdr
@@ -553,10 +561,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
}
// BindToDevice binds the socket associated with fd to device.
diff --git a/src/pkg/syscall/syscall_linux_386.go b/src/pkg/syscall/syscall_linux_386.go
index a61695676..c491a286c 100644
--- a/src/pkg/syscall/syscall_linux_386.go
+++ b/src/pkg/syscall/syscall_linux_386.go
@@ -2,6 +2,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"
@@ -132,7 +135,15 @@ func Setrlimit(resource int, rlim *Rlimit) (err error) {
// Underlying system call writes to newoffset via pointer.
// Implemented in assembly to avoid allocation.
-func Seek(fd int, offset int64, whence int) (newoffset int64, err error)
+func seek(fd int, offset int64, whence int) (newoffset int64, err Errno)
+
+func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
+ newoffset, errno := seek(fd, offset, whence)
+ if errno != 0 {
+ return 0, errno
+ }
+ return newoffset, nil
+}
// Vsyscalls on amd64.
//sysnb Gettimeofday(tv *Timeval) (err error)
@@ -212,7 +223,7 @@ func socketpair(domain int, typ int, flags int, fd *[2]int32) (err error) {
return
}
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, e := socketcall(_BIND, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
if e != 0 {
err = e
@@ -220,7 +231,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
return
}
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, e := socketcall(_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
if e != 0 {
err = e
@@ -236,7 +247,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
return
}
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, e := socketcall(_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e != 0 {
err = e
@@ -244,8 +255,8 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
return
}
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
- _, e := socketcall(_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), val, vallen, 0)
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
+ _, e := socketcall(_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), vallen, 0)
if e != 0 {
err = e
}
@@ -264,12 +275,12 @@ func recvfrom(s int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockle
return
}
-func sendto(s int, p []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, p []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var base uintptr
if len(p) > 0 {
base = uintptr(unsafe.Pointer(&p[0]))
}
- _, e := socketcall(_SENDTO, uintptr(s), base, uintptr(len(p)), uintptr(flags), to, uintptr(addrlen))
+ _, e := socketcall(_SENDTO, uintptr(s), base, uintptr(len(p)), uintptr(flags), uintptr(to), uintptr(addrlen))
if e != 0 {
err = e
}
@@ -284,8 +295,8 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
return
}
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
- _, e := socketcall(_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ n, e := socketcall(_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
if e != 0 {
err = e
}
diff --git a/src/pkg/syscall/syscall_linux_amd64.go b/src/pkg/syscall/syscall_linux_amd64.go
index f4b73b20e..8915ed83b 100644
--- a/src/pkg/syscall/syscall_linux_amd64.go
+++ b/src/pkg/syscall/syscall_linux_amd64.go
@@ -40,26 +40,46 @@ package syscall
//sys Truncate(path string, length int64) (err error)
//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
//sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error)
-//sys bind(s int, addr uintptr, addrlen _Socklen) (err error)
-//sys connect(s int, addr uintptr, addrlen _Socklen) (err error)
+//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
+//sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
//sysnb getgroups(n int, list *_Gid_t) (nn int, err error)
//sysnb setgroups(n int, list *_Gid_t) (err error)
-//sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error)
-//sys setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error)
+//sys getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error)
+//sys setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error)
//sysnb socket(domain int, typ int, proto int) (fd int, err error)
//sysnb socketpair(domain int, typ int, proto int, fd *[2]int32) (err error)
//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
//sysnb getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error)
-//sys sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error)
+//sys sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error)
//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error)
-//sys sendmsg(s int, msg *Msghdr, flags int) (err error)
+//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
//sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error)
func Getpagesize() int { return 4096 }
-func Gettimeofday(tv *Timeval) (err error)
-func Time(t *Time_t) (tt Time_t, err error)
+//go:noescape
+func gettimeofday(tv *Timeval) (err Errno)
+
+func Gettimeofday(tv *Timeval) (err error) {
+ errno := gettimeofday(tv)
+ if errno != 0 {
+ return errno
+ }
+ return nil
+}
+
+func Time(t *Time_t) (tt Time_t, err error) {
+ var tv Timeval
+ errno := gettimeofday(&tv)
+ if errno != 0 {
+ return 0, errno
+ }
+ if t != nil {
+ *t = Time_t(tv.Sec)
+ }
+ return Time_t(tv.Sec), nil
+}
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
diff --git a/src/pkg/syscall/syscall_linux_arm.go b/src/pkg/syscall/syscall_linux_arm.go
index 4aadf9e4c..9fe80232a 100644
--- a/src/pkg/syscall/syscall_linux_arm.go
+++ b/src/pkg/syscall/syscall_linux_arm.go
@@ -23,26 +23,34 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
return
}
-// Seek is defined in assembly.
-
-func Seek(fd int, offset int64, whence int) (newoffset int64, err error)
+// Underlying system call writes to newoffset via pointer.
+// Implemented in assembly to avoid allocation.
+func seek(fd int, offset int64, whence int) (newoffset int64, err Errno)
+
+func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
+ newoffset, errno := seek(fd, offset, whence)
+ if errno != 0 {
+ return 0, errno
+ }
+ return newoffset, nil
+}
//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
//sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error)
-//sys bind(s int, addr uintptr, addrlen _Socklen) (err error)
-//sys connect(s int, addr uintptr, addrlen _Socklen) (err error)
+//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
+//sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
//sysnb getgroups(n int, list *_Gid_t) (nn int, err error) = SYS_GETGROUPS32
//sysnb setgroups(n int, list *_Gid_t) (err error) = SYS_SETGROUPS32
-//sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error)
-//sys setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error)
+//sys getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error)
+//sys setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error)
//sysnb socket(domain int, typ int, proto int) (fd int, err error)
//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
//sysnb getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error)
-//sys sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error)
+//sys sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error)
//sysnb socketpair(domain int, typ int, flags int, fd *[2]int32) (err error)
//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error)
-//sys sendmsg(s int, msg *Msghdr, flags int) (err error)
+//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
// 64-bit file system and 32-bit uid calls
// (16-bit uid calls are not always supported in newer kernels)
diff --git a/src/pkg/syscall/syscall_nacl.go b/src/pkg/syscall/syscall_nacl.go
new file mode 100644
index 000000000..c2788b20a
--- /dev/null
+++ b/src/pkg/syscall/syscall_nacl.go
@@ -0,0 +1,311 @@
+// 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
+
+import (
+ "sync"
+ "unsafe"
+)
+
+//sys naclClose(fd int) (err error) = sys_close
+//sys Exit(code int) (err error)
+//sys naclFstat(fd int, stat *Stat_t) (err error) = sys_fstat
+//sys naclRead(fd int, b []byte) (n int, err error) = sys_read
+//sys naclSeek(fd int, off *int64, whence int) (err error) = sys_lseek
+
+const direntSize = 8 + 8 + 2 + 256
+
+// native_client/src/trusted/service_runtime/include/sys/dirent.h
+type Dirent struct {
+ Ino int64
+ Off int64
+ Reclen uint16
+ Name [256]byte
+}
+
+func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
+ origlen := len(buf)
+ count = 0
+ for max != 0 && len(buf) > 0 {
+ dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
+ buf = buf[dirent.Reclen:]
+ if dirent.Ino == 0 { // File absent in directory.
+ continue
+ }
+ bytes := (*[512 + PathMax]byte)(unsafe.Pointer(&dirent.Name[0]))
+ var name = string(bytes[0:clen(bytes[:])])
+ if name == "." || name == ".." { // Useless names
+ continue
+ }
+ max--
+ count++
+ names = append(names, name)
+ }
+ return origlen - len(buf), count, names
+}
+
+func clen(n []byte) int {
+ for i := 0; i < len(n); i++ {
+ if n[i] == 0 {
+ return i
+ }
+ }
+ return len(n)
+}
+
+const PathMax = 256
+
+// An Errno is an unsigned number describing an error condition.
+// It implements the error interface. The zero Errno is by convention
+// a non-error, so code to convert from Errno to error should use:
+// err = nil
+// if errno != 0 {
+// err = errno
+// }
+type Errno uintptr
+
+func (e Errno) Error() string {
+ if 0 <= int(e) && int(e) < len(errorstr) {
+ s := errorstr[e]
+ if s != "" {
+ return s
+ }
+ }
+ return "errno " + itoa(int(e))
+}
+
+func (e Errno) Temporary() bool {
+ return e == EINTR || e == EMFILE || e.Timeout()
+}
+
+func (e Errno) Timeout() bool {
+ return e == EAGAIN || e == EWOULDBLOCK || e == ETIMEDOUT
+}
+
+// A Signal is a number describing a process signal.
+// It implements the os.Signal interface.
+type Signal int
+
+const (
+ _ Signal = iota
+ SIGCHLD
+ SIGINT
+ SIGKILL
+ SIGTRAP
+ SIGQUIT
+)
+
+func (s Signal) Signal() {}
+
+func (s Signal) String() string {
+ if 0 <= s && int(s) < len(signals) {
+ str := signals[s]
+ if str != "" {
+ return str
+ }
+ }
+ return "signal " + itoa(int(s))
+}
+
+var signals = [...]string{}
+
+// File system
+
+const (
+ Stdin = 0
+ Stdout = 1
+ Stderr = 2
+)
+
+// native_client/src/trusted/service_runtime/include/sys/fcntl.h
+const (
+ O_RDONLY = 0
+ O_WRONLY = 1
+ O_RDWR = 2
+ O_ACCMODE = 3
+
+ O_CREAT = 0100
+ O_CREATE = O_CREAT // for ken
+ O_TRUNC = 01000
+ O_APPEND = 02000
+ O_EXCL = 0200
+ O_NONBLOCK = 04000
+ O_NDELAY = O_NONBLOCK
+ O_SYNC = 010000
+ O_FSYNC = O_SYNC
+ O_ASYNC = 020000
+
+ O_CLOEXEC = 0
+
+ FD_CLOEXEC = 1
+)
+
+// native_client/src/trusted/service_runtime/include/sys/fcntl.h
+const (
+ F_DUPFD = 0
+ F_GETFD = 1
+ F_SETFD = 2
+ F_GETFL = 3
+ F_SETFL = 4
+ F_GETOWN = 5
+ F_SETOWN = 6
+ F_GETLK = 7
+ F_SETLK = 8
+ F_SETLKW = 9
+ F_RGETLK = 10
+ F_RSETLK = 11
+ F_CNVT = 12
+ F_RSETLKW = 13
+
+ F_RDLCK = 1
+ F_WRLCK = 2
+ F_UNLCK = 3
+ F_UNLKSYS = 4
+)
+
+// native_client/src/trusted/service_runtime/include/bits/stat.h
+const (
+ S_IFMT = 0000370000
+ S_IFSHM_SYSV = 0000300000
+ S_IFSEMA = 0000270000
+ S_IFCOND = 0000260000
+ S_IFMUTEX = 0000250000
+ S_IFSHM = 0000240000
+ S_IFBOUNDSOCK = 0000230000
+ S_IFSOCKADDR = 0000220000
+ S_IFDSOCK = 0000210000
+
+ S_IFSOCK = 0000140000
+ S_IFLNK = 0000120000
+ S_IFREG = 0000100000
+ S_IFBLK = 0000060000
+ S_IFDIR = 0000040000
+ S_IFCHR = 0000020000
+ S_IFIFO = 0000010000
+
+ S_UNSUP = 0000370000
+
+ S_ISUID = 0004000
+ S_ISGID = 0002000
+ S_ISVTX = 0001000
+
+ S_IREAD = 0400
+ S_IWRITE = 0200
+ S_IEXEC = 0100
+
+ S_IRWXU = 0700
+ S_IRUSR = 0400
+ S_IWUSR = 0200
+ S_IXUSR = 0100
+
+ S_IRWXG = 070
+ S_IRGRP = 040
+ S_IWGRP = 020
+ S_IXGRP = 010
+
+ S_IRWXO = 07
+ S_IROTH = 04
+ S_IWOTH = 02
+ S_IXOTH = 01
+)
+
+// native_client/src/trusted/service_runtime/include/sys/stat.h
+// native_client/src/trusted/service_runtime/include/machine/_types.h
+type Stat_t struct {
+ Dev int64
+ Ino uint64
+ Mode uint32
+ Nlink uint32
+ Uid uint32
+ Gid uint32
+ Rdev int64
+ Size int64
+ Blksize int32
+ Blocks int32
+ Atime int64
+ AtimeNsec int64
+ Mtime int64
+ MtimeNsec int64
+ Ctime int64
+ CtimeNsec int64
+}
+
+// Processes
+// Not supported on NaCl - just enough for package os.
+
+var ForkLock sync.RWMutex
+
+type WaitStatus uint32
+
+func (w WaitStatus) Exited() bool { return false }
+func (w WaitStatus) ExitStatus() int { return 0 }
+func (w WaitStatus) Signaled() bool { return false }
+func (w WaitStatus) Signal() Signal { return 0 }
+func (w WaitStatus) CoreDump() bool { return false }
+func (w WaitStatus) Stopped() bool { return false }
+func (w WaitStatus) Continued() bool { return false }
+func (w WaitStatus) StopSignal() Signal { return 0 }
+func (w WaitStatus) TrapCause() int { return 0 }
+
+// XXX made up
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+}
+
+// XXX made up
+type ProcAttr struct {
+ Dir string
+ Env []string
+ Files []uintptr
+ Sys *SysProcAttr
+}
+
+type SysProcAttr struct {
+}
+
+// System
+
+func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
+func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) { return 0, 0, ENOSYS }
+func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) { return 0, 0, ENOSYS }
+func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) {
+ return 0, 0, ENOSYS
+}
+
+func Sysctl(key string) (string, error) {
+ if key == "kern.hostname" {
+ return "naclbox", nil
+ }
+ return "", ENOSYS
+}
+
+// Unimplemented Unix midden heap.
+
+const ImplementsGetwd = false
+
+func Getwd() (wd string, err error) { return "", ENOSYS }
+func Getegid() int { return 1 }
+func Geteuid() int { return 1 }
+func Getgid() int { return 1 }
+func Getgroups() ([]int, error) { return []int{1}, nil }
+func Getpagesize() int { return 65536 }
+func Getppid() int { return 2 }
+func Getpid() int { return 3 }
+func Getuid() int { return 1 }
+func Kill(pid int, signum Signal) error { return ENOSYS }
+func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+ return 0, ENOSYS
+}
+func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {
+ return 0, 0, ENOSYS
+}
+func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) {
+ return 0, ENOSYS
+}
+func RouteRIB(facility, param int) ([]byte, error) { return nil, ENOSYS }
+func ParseRoutingMessage(b []byte) ([]RoutingMessage, error) { return nil, ENOSYS }
+func ParseRoutingSockaddr(msg RoutingMessage) ([]Sockaddr, error) { return nil, ENOSYS }
+func SysctlUint32(name string) (value uint32, err error) { return 0, ENOSYS }
diff --git a/src/pkg/syscall/syscall_nacl_386.go b/src/pkg/syscall/syscall_nacl_386.go
new file mode 100644
index 000000000..d12f8e2d6
--- /dev/null
+++ b/src/pkg/syscall/syscall_nacl_386.go
@@ -0,0 +1,32 @@
+// 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
+
+type Timespec struct {
+ Sec int64
+ Nsec int32
+}
+
+type Timeval struct {
+ Sec int64
+ Usec int32
+}
+
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+func NsecToTimespec(nsec int64) (ts Timespec) {
+ ts.Sec = int64(nsec / 1e9)
+ ts.Nsec = int32(nsec % 1e9)
+ return
+}
+
+func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+ nsec += 999 // round up to microsecond
+ tv.Usec = int32(nsec % 1e9 / 1e3)
+ tv.Sec = int64(nsec / 1e9)
+ return
+}
diff --git a/src/pkg/syscall/syscall_nacl_amd64p32.go b/src/pkg/syscall/syscall_nacl_amd64p32.go
new file mode 100644
index 000000000..d12f8e2d6
--- /dev/null
+++ b/src/pkg/syscall/syscall_nacl_amd64p32.go
@@ -0,0 +1,32 @@
+// 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
+
+type Timespec struct {
+ Sec int64
+ Nsec int32
+}
+
+type Timeval struct {
+ Sec int64
+ Usec int32
+}
+
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+func NsecToTimespec(nsec int64) (ts Timespec) {
+ ts.Sec = int64(nsec / 1e9)
+ ts.Nsec = int32(nsec % 1e9)
+ return
+}
+
+func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+ nsec += 999 // round up to microsecond
+ tv.Usec = int32(nsec % 1e9 / 1e3)
+ tv.Sec = int64(nsec / 1e9)
+ return
+}
diff --git a/src/pkg/syscall/syscall_openbsd.go b/src/pkg/syscall/syscall_openbsd.go
index 89c73215a..8d3f825f8 100644
--- a/src/pkg/syscall/syscall_openbsd.go
+++ b/src/pkg/syscall/syscall_openbsd.go
@@ -90,11 +90,31 @@ func Pipe(p []int) (err error) {
return
}
+//sys getdents(fd int, buf []byte) (n int, err error)
+func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
+ return getdents(fd, buf)
+}
+
// TODO
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
return -1, ENOSYS
}
+func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
+ var _p0 unsafe.Pointer
+ var bufsize uintptr
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf))
+ }
+ r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), bufsize, uintptr(flags))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
/*
* Exposed directly
*/
@@ -119,10 +139,8 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
//sys Fstatfs(fd int, stat *Statfs_t) (err error)
//sys Fsync(fd int) (err error)
//sys Ftruncate(fd int, length int64) (err error)
-//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error)
//sysnb Getegid() (egid int)
//sysnb Geteuid() (uid int)
-//sys Getfsstat(buf []Statfs_t, flags int) (n int, err error)
//sysnb Getgid() (gid int)
//sysnb Getpgid(pid int) (pgid int, err error)
//sysnb Getpgrp() (pgrp int)
diff --git a/src/pkg/syscall/syscall_openbsd_386.go b/src/pkg/syscall/syscall_openbsd_386.go
index 3c4c693c9..ad5ae14bf 100644
--- a/src/pkg/syscall/syscall_openbsd_386.go
+++ b/src/pkg/syscall/syscall_openbsd_386.go
@@ -9,7 +9,7 @@ func Getpagesize() int { return 4096 }
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = int32(nsec / 1e9)
+ ts.Sec = int64(nsec / 1e9)
ts.Nsec = int32(nsec % 1e9)
return
}
@@ -19,7 +19,7 @@ func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)
func NsecToTimeval(nsec int64) (tv Timeval) {
nsec += 999 // round up to microsecond
tv.Usec = int32(nsec % 1e9 / 1e3)
- tv.Sec = int32(nsec / 1e9)
+ tv.Sec = int64(nsec / 1e9)
return
}
diff --git a/src/pkg/syscall/syscall_openbsd_amd64.go b/src/pkg/syscall/syscall_openbsd_amd64.go
index c356ad4fa..6181344cd 100644
--- a/src/pkg/syscall/syscall_openbsd_amd64.go
+++ b/src/pkg/syscall/syscall_openbsd_amd64.go
@@ -9,7 +9,7 @@ func Getpagesize() int { return 4096 }
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = int32(nsec / 1e9)
+ ts.Sec = nsec / 1e9
ts.Nsec = nsec % 1e9
return
}
@@ -19,12 +19,12 @@ func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)
func NsecToTimeval(nsec int64) (tv Timeval) {
nsec += 999 // round up to microsecond
tv.Usec = nsec % 1e9 / 1e3
- tv.Sec = int64(nsec / 1e9)
+ tv.Sec = nsec / 1e9
return
}
func SetKevent(k *Kevent_t, fd, mode, flags int) {
- k.Ident = uint32(fd)
+ k.Ident = uint64(fd)
k.Filter = int16(mode)
k.Flags = uint16(flags)
}
diff --git a/src/pkg/syscall/syscall_plan9.go b/src/pkg/syscall/syscall_plan9.go
index 2e1c064c4..a8c340541 100644
--- a/src/pkg/syscall/syscall_plan9.go
+++ b/src/pkg/syscall/syscall_plan9.go
@@ -83,7 +83,7 @@ func errstr() string {
}
// Implemented in assembly to import from runtime.
-func exit(int)
+func exit(code int)
func Exit(code int) { exit(code) }
diff --git a/src/pkg/syscall/syscall_solaris.go b/src/pkg/syscall/syscall_solaris.go
new file mode 100644
index 000000000..adc52b1f7
--- /dev/null
+++ b/src/pkg/syscall/syscall_solaris.go
@@ -0,0 +1,523 @@
+// 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.
+
+// Solaris system calls.
+// This file is compiled as ordinary Go code,
+// but it is also input to mksyscall,
+// which parses the //sys lines and generates system call stubs.
+// Note that sometimes we use a lowercase //sys name and wrap
+// it in our own nicer implementation, either here or in
+// syscall_solaris.go or syscall_unix.go.
+
+package syscall
+
+import "unsafe"
+
+type SockaddrDatalink struct {
+ Family uint16
+ Index uint16
+ Type uint8
+ Nlen uint8
+ Alen uint8
+ Slen uint8
+ Data [244]int8
+ raw RawSockaddrDatalink
+}
+
+func clen(n []byte) int {
+ for i := 0; i < len(n); i++ {
+ if n[i] == 0 {
+ return i
+ }
+ }
+ return len(n)
+}
+
+// ParseDirent parses up to max directory entries in buf,
+// appending the names to names. It returns the number
+// bytes consumed from buf, the number of entries added
+// to names, and the new names slice.
+func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
+ origlen := len(buf)
+ for max != 0 && len(buf) > 0 {
+ dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
+ if dirent.Reclen == 0 {
+ buf = nil
+ break
+ }
+ buf = buf[dirent.Reclen:]
+ if dirent.Ino == 0 { // File absent in directory.
+ continue
+ }
+ bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
+ var name = string(bytes[0:clen(bytes[:])])
+ if name == "." || name == ".." { // Useless names
+ continue
+ }
+ max--
+ count++
+ names = append(names, name)
+ }
+ return origlen - len(buf), count, names
+}
+
+func pipe() (r uintptr, w uintptr, err uintptr)
+
+func Pipe(p []int) (err error) {
+ if len(p) != 2 {
+ return EINVAL
+ }
+ r0, w0, e1 := pipe()
+ if e1 != 0 {
+ err = Errno(e1)
+ }
+ p[0], p[1] = int(r0), int(w0)
+ return
+}
+
+func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) {
+ if sa.Port < 0 || sa.Port > 0xFFFF {
+ return nil, 0, EINVAL
+ }
+ sa.raw.Family = AF_INET
+ p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
+ p[0] = byte(sa.Port >> 8)
+ p[1] = byte(sa.Port)
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.raw.Addr[i] = sa.Addr[i]
+ }
+ return unsafe.Pointer(&sa.raw), SizeofSockaddrInet4, nil
+}
+
+func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) {
+ if sa.Port < 0 || sa.Port > 0xFFFF {
+ return nil, 0, EINVAL
+ }
+ sa.raw.Family = AF_INET6
+ p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
+ p[0] = byte(sa.Port >> 8)
+ p[1] = byte(sa.Port)
+ sa.raw.Scope_id = sa.ZoneId
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.raw.Addr[i] = sa.Addr[i]
+ }
+ return unsafe.Pointer(&sa.raw), SizeofSockaddrInet6, nil
+}
+
+func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, _Socklen, error) {
+ name := sa.Name
+ n := len(name)
+ if n >= len(sa.raw.Path) {
+ return nil, 0, EINVAL
+ }
+ sa.raw.Family = AF_UNIX
+ for i := 0; i < n; i++ {
+ sa.raw.Path[i] = int8(name[i])
+ }
+ // length is family (uint16), name, NUL.
+ sl := _Socklen(2)
+ if n > 0 {
+ sl += _Socklen(n) + 1
+ }
+ if sa.raw.Path[0] == '@' {
+ sa.raw.Path[0] = 0
+ // Don't count trailing NUL for abstract address.
+ sl--
+ }
+
+ return unsafe.Pointer(&sa.raw), sl, nil
+}
+
+func Getsockname(fd int) (sa Sockaddr, err error) {
+ var rsa RawSockaddrAny
+ var len _Socklen = SizeofSockaddrAny
+ if err = getsockname(fd, &rsa, &len); err != nil {
+ return
+ }
+ return anyToSockaddr(&rsa)
+}
+
+// The const provides a compile-time constant so clients
+// can adjust to whether there is a working Getwd and avoid
+// even linking this function into the binary. See ../os/getwd.go.
+const ImplementsGetwd = false
+
+func Getwd() (string, error) { return "", ENOTSUP }
+
+/*
+ * Wrapped
+ */
+
+//sysnb getgroups(ngid int, gid *_Gid_t) (n int, err error)
+//sysnb setgroups(ngid int, gid *_Gid_t) (err error)
+
+func Getgroups() (gids []int, err error) {
+ n, err := getgroups(0, nil)
+ if err != nil {
+ return nil, err
+ }
+ if n == 0 {
+ return nil, nil
+ }
+
+ // Sanity check group count. Max is 16 on BSD.
+ if n < 0 || n > 1000 {
+ return nil, EINVAL
+ }
+
+ a := make([]_Gid_t, n)
+ n, err = getgroups(n, &a[0])
+ if err != nil {
+ return nil, err
+ }
+ gids = make([]int, n)
+ for i, v := range a[0:n] {
+ gids[i] = int(v)
+ }
+ return
+}
+
+func Setgroups(gids []int) (err error) {
+ if len(gids) == 0 {
+ return setgroups(0, nil)
+ }
+
+ a := make([]_Gid_t, len(gids))
+ for i, v := range gids {
+ a[i] = _Gid_t(v)
+ }
+ return setgroups(len(a), &a[0])
+}
+
+func ReadDirent(fd int, buf []byte) (n int, err error) {
+ // Final argument is (basep *uintptr) and the syscall doesn't take nil.
+ // TODO(rsc): Can we use a single global basep for all calls?
+ return Getdents(fd, buf, new(uintptr))
+}
+
+// Wait status is 7 bits at bottom, either 0 (exited),
+// 0x7F (stopped), or a signal number that caused an exit.
+// The 0x80 bit is whether there was a core dump.
+// An extra number (exit code, signal causing a stop)
+// is in the high bits.
+
+type WaitStatus uint32
+
+const (
+ mask = 0x7F
+ core = 0x80
+ shift = 8
+
+ exited = 0
+ stopped = 0x7F
+)
+
+func (w WaitStatus) Exited() bool { return w&mask == exited }
+
+func (w WaitStatus) ExitStatus() int {
+ if w&mask != exited {
+ return -1
+ }
+ return int(w >> shift)
+}
+
+func (w WaitStatus) Signaled() bool { return w&mask != stopped && w&mask != 0 }
+
+func (w WaitStatus) Signal() Signal {
+ sig := Signal(w & mask)
+ if sig == stopped || sig == 0 {
+ return -1
+ }
+ return sig
+}
+
+func (w WaitStatus) CoreDump() bool { return w.Signaled() && w&core != 0 }
+
+func (w WaitStatus) Stopped() bool { return w&mask == stopped && Signal(w>>shift) != SIGSTOP }
+
+func (w WaitStatus) Continued() bool { return w&mask == stopped && Signal(w>>shift) == SIGSTOP }
+
+func (w WaitStatus) StopSignal() Signal {
+ if !w.Stopped() {
+ return -1
+ }
+ return Signal(w>>shift) & 0xFF
+}
+
+func (w WaitStatus) TrapCause() int { return -1 }
+
+func wait4(pid uintptr, wstatus *WaitStatus, options uintptr, rusage *Rusage) (wpid uintptr, err uintptr)
+
+func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) {
+ r0, e1 := wait4(uintptr(pid), wstatus, uintptr(options), rusage)
+ if e1 != 0 {
+ err = Errno(e1)
+ }
+ return int(r0), err
+}
+
+func gethostname() (name string, err uintptr)
+
+func Gethostname() (name string, err error) {
+ name, e1 := gethostname()
+ if e1 != 0 {
+ err = Errno(e1)
+ }
+ return name, err
+}
+
+func UtimesNano(path string, ts []Timespec) (err error) {
+ if len(ts) != 2 {
+ return EINVAL
+ }
+ var tv [2]Timeval
+ for i := 0; i < 2; i++ {
+ tv[i].Sec = ts[i].Sec
+ tv[i].Usec = ts[i].Nsec / 1000
+ }
+ return Utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
+}
+
+//sys fcntl(fd int, cmd int, arg int) (val int, err error)
+
+// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
+func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error {
+ _, _, e1 := sysvicall6(procfcntl.Addr(), 3, uintptr(fd), uintptr(cmd), uintptr(unsafe.Pointer(lk)), 0, 0, 0)
+ if e1 != 0 {
+ return e1
+ }
+ return nil
+}
+
+func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
+ switch rsa.Addr.Family {
+ case AF_UNIX:
+ pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa))
+ sa := new(SockaddrUnix)
+ // Assume path ends at NUL.
+ // This is not technically the Solaris semantics for
+ // abstract Unix domain sockets -- they are supposed
+ // to be uninterpreted fixed-size binary blobs -- but
+ // everyone uses this convention.
+ n := 0
+ for n < len(pp.Path) && pp.Path[n] != 0 {
+ n++
+ }
+ bytes := (*[10000]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
+ sa.Name = string(bytes)
+ return sa, nil
+
+ case AF_INET:
+ pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa))
+ sa := new(SockaddrInet4)
+ p := (*[2]byte)(unsafe.Pointer(&pp.Port))
+ sa.Port = int(p[0])<<8 + int(p[1])
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.Addr[i] = pp.Addr[i]
+ }
+ return sa, nil
+
+ case AF_INET6:
+ pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa))
+ sa := new(SockaddrInet6)
+ p := (*[2]byte)(unsafe.Pointer(&pp.Port))
+ sa.Port = int(p[0])<<8 + int(p[1])
+ sa.ZoneId = pp.Scope_id
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.Addr[i] = pp.Addr[i]
+ }
+ return sa, nil
+ }
+ return nil, EAFNOSUPPORT
+}
+
+//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) = libsocket.accept
+
+func Accept(fd int) (nfd int, sa Sockaddr, err error) {
+ var rsa RawSockaddrAny
+ var len _Socklen = SizeofSockaddrAny
+ nfd, err = accept(fd, &rsa, &len)
+ if err != nil {
+ return
+ }
+ sa, err = anyToSockaddr(&rsa)
+ if err != nil {
+ Close(nfd)
+ nfd = 0
+ }
+ return
+}
+
+func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) {
+ var msg Msghdr
+ var rsa RawSockaddrAny
+ msg.Name = (*byte)(unsafe.Pointer(&rsa))
+ msg.Namelen = uint32(SizeofSockaddrAny)
+ var iov Iovec
+ if len(p) > 0 {
+ iov.Base = (*int8)(unsafe.Pointer(&p[0]))
+ iov.SetLen(len(p))
+ }
+ var dummy int8
+ if len(oob) > 0 {
+ // receive at least one normal byte
+ if len(p) == 0 {
+ iov.Base = &dummy
+ iov.SetLen(1)
+ }
+ msg.Accrights = (*int8)(unsafe.Pointer(&oob[0]))
+ }
+ msg.Iov = &iov
+ msg.Iovlen = 1
+ if n, err = recvmsg(fd, &msg, flags); err != nil {
+ return
+ }
+ oobn = int(msg.Accrightslen)
+ // source address is only specified if the socket is unconnected
+ if rsa.Addr.Family != AF_UNSPEC {
+ from, err = anyToSockaddr(&rsa)
+ }
+ return
+}
+
+func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
+ _, err = SendmsgN(fd, p, oob, to, flags)
+ return
+}
+
+//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error) = libsocket.sendmsg
+
+func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
+ var ptr unsafe.Pointer
+ var salen _Socklen
+ if to != nil {
+ ptr, salen, err = to.sockaddr()
+ if err != nil {
+ return 0, err
+ }
+ }
+ var msg Msghdr
+ msg.Name = (*byte)(unsafe.Pointer(ptr))
+ msg.Namelen = uint32(salen)
+ var iov Iovec
+ if len(p) > 0 {
+ iov.Base = (*int8)(unsafe.Pointer(&p[0]))
+ iov.SetLen(len(p))
+ }
+ var dummy int8
+ if len(oob) > 0 {
+ // send at least one normal byte
+ if len(p) == 0 {
+ iov.Base = &dummy
+ iov.SetLen(1)
+ }
+ msg.Accrights = (*int8)(unsafe.Pointer(&oob[0]))
+ }
+ msg.Iov = &iov
+ msg.Iovlen = 1
+ if n, err = sendmsg(fd, &msg, flags); err != nil {
+ return 0, err
+ }
+ if len(oob) > 0 && len(p) == 0 {
+ n = 0
+ }
+ return n, nil
+}
+
+/*
+ * Exposed directly
+ */
+//sys Access(path string, mode uint32) (err error)
+//sys Adjtime(delta *Timeval, olddelta *Timeval) (err error)
+//sys Chdir(path string) (err error)
+//sys Chmod(path string, mode uint32) (err error)
+//sys Chown(path string, uid int, gid int) (err error)
+//sys Chroot(path string) (err error)
+//sys Close(fd int) (err error)
+//sys Dup(fd int) (nfd int, err error)
+//sys Exit(code int)
+//sys Fchdir(fd int) (err error)
+//sys Fchmod(fd int, mode uint32) (err error)
+//sys Fchown(fd int, uid int, gid int) (err error)
+//sys Fpathconf(fd int, name int) (val int, err error)
+//sys Fstat(fd int, stat *Stat_t) (err error)
+//sys Getdents(fd int, buf []byte, basep *uintptr) (n int, err error)
+//sysnb Getgid() (gid int)
+//sysnb Getpid() (pid int)
+//sys Geteuid() (euid int)
+//sys Getegid() (egid int)
+//sys Getppid() (ppid int)
+//sys Getpriority(which int, who int) (n int, err error)
+//sysnb Getrlimit(which int, lim *Rlimit) (err error)
+//sysnb Gettimeofday(tv *Timeval) (err error)
+//sysnb Getuid() (uid int)
+//sys Kill(pid int, signum Signal) (err error)
+//sys Lchown(path string, uid int, gid int) (err error)
+//sys Link(path string, link string) (err error)
+//sys Listen(s int, backlog int) (err error) = libsocket.listen
+//sys Lstat(path string, stat *Stat_t) (err error)
+//sys Mkdir(path string, mode uint32) (err error)
+//sys Mknod(path string, mode uint32, dev int) (err error)
+//sys Nanosleep(time *Timespec, leftover *Timespec) (err error)
+//sys Open(path string, mode int, perm uint32) (fd int, err error)
+//sys Pathconf(path string, name int) (val int, err error)
+//sys Pread(fd int, p []byte, offset int64) (n int, err error)
+//sys Pwrite(fd int, p []byte, offset int64) (n int, err error)
+//sys read(fd int, p []byte) (n int, err error)
+//sys Readlink(path string, buf []byte) (n int, err error)
+//sys Rename(from string, to string) (err error)
+//sys Rmdir(path string) (err error)
+//sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = lseek
+//sysnb Setegid(egid int) (err error)
+//sysnb Seteuid(euid int) (err error)
+//sysnb Setgid(gid int) (err error)
+//sysnb Setpgid(pid int, pgid int) (err error)
+//sys Setpriority(which int, who int, prio int) (err error)
+//sysnb Setregid(rgid int, egid int) (err error)
+//sysnb Setreuid(ruid int, euid int) (err error)
+//sysnb Setrlimit(which int, lim *Rlimit) (err error)
+//sysnb Setsid() (pid int, err error)
+//sysnb Setuid(uid int) (err error)
+//sys Shutdown(s int, how int) (err error) = libsocket.shutdown
+//sys Stat(path string, stat *Stat_t) (err error)
+//sys Symlink(path string, link string) (err error)
+//sys Sync() (err error)
+//sys Truncate(path string, length int64) (err error)
+//sys Fsync(fd int) (err error)
+//sys Ftruncate(fd int, length int64) (err error)
+//sys Umask(newmask int) (oldmask int)
+//sys Unlink(path string) (err error)
+//sys Utimes(path string, times *[2]Timeval) (err error)
+//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) = libsocket.bind
+//sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) = libsocket.connect
+//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error)
+//sys munmap(addr uintptr, length uintptr) (err error)
+//sys sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) = libsocket.sendto
+//sys socket(domain int, typ int, proto int) (fd int, err error) = libsocket.socket
+//sysnb socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) = libsocket.socketpair
+//sys write(fd int, p []byte) (n int, err error)
+//sys getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) = libsocket.getsockopt
+//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) = libsocket.getpeername
+//sys getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) = libsocket.getsockname
+//sys setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) = libsocket.setsockopt
+//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) = libsocket.recvfrom
+//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error) = libsocket.recvmsg
+
+func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
+ r0, _, e1 := sysvicall6(procread.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf), 0, 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
+ r0, _, e1 := sysvicall6(procwrite.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf), 0, 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
diff --git a/src/pkg/syscall/syscall_solaris_amd64.go b/src/pkg/syscall/syscall_solaris_amd64.go
new file mode 100644
index 000000000..37cf06d70
--- /dev/null
+++ b/src/pkg/syscall/syscall_solaris_amd64.go
@@ -0,0 +1,37 @@
+// 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 syscall
+
+func Getpagesize() int { return 4096 }
+
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+func NsecToTimespec(nsec int64) (ts Timespec) {
+ ts.Sec = nsec / 1e9
+ ts.Nsec = nsec % 1e9
+ return
+}
+
+func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+ nsec += 999 // round up to microsecond
+ tv.Usec = nsec % 1e9 / 1e3
+ tv.Sec = int64(nsec / 1e9)
+ return
+}
+
+func (iov *Iovec) SetLen(length int) {
+ iov.Len = uint64(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+ cmsg.Len = uint32(length)
+}
+
+func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+ // TODO(aram): implement this, see issue 5847.
+ panic("unimplemented")
+}
diff --git a/src/pkg/syscall/syscall_unix.go b/src/pkg/syscall/syscall_unix.go
index 6455dc29c..b28891568 100644
--- a/src/pkg/syscall/syscall_unix.go
+++ b/src/pkg/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
@@ -19,8 +19,9 @@ var (
)
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
)
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
@@ -55,7 +56,7 @@ func (m *mmapper) Mmap(fd int, offset int64, length int, prot int, flags int) (d
cap int
}{addr, length, length}
- // Use unsafe to turn sl into a []byte.
+ // Use unsafeto turn sl into a []byte.
b := *(*[]byte)(unsafe.Pointer(&sl))
// Register mapping in m and return it.
@@ -160,7 +161,7 @@ func Write(fd int, p []byte) (n int, err error) {
var SocketDisableIPv6 bool
type Sockaddr interface {
- sockaddr() (ptr uintptr, len _Socklen, err error) // lowercase; only we can define Sockaddrs
+ sockaddr() (ptr unsafe.Pointer, len _Socklen, err error) // lowercase; only we can define Sockaddrs
}
type SockaddrInet4 struct {
@@ -209,7 +210,7 @@ func Getpeername(fd int) (sa Sockaddr, err error) {
func GetsockoptInt(fd, level, opt int) (value int, err error) {
var n int32
vallen := _Socklen(4)
- err = getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&n)), &vallen)
+ err = getsockopt(fd, level, opt, unsafe.Pointer(&n), &vallen)
return int(n), err
}
@@ -234,40 +235,40 @@ func Sendto(fd int, p []byte, flags int, to Sockaddr) (err error) {
}
func SetsockoptByte(fd, level, opt int, value byte) (err error) {
- return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), 1)
+ return setsockopt(fd, level, opt, unsafe.Pointer(&value), 1)
}
func SetsockoptInt(fd, level, opt int, value int) (err error) {
var n = int32(value)
- return setsockopt(fd, level, opt, uintptr(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, uintptr(unsafe.Pointer(&value[0])), 4)
+ return setsockopt(fd, level, opt, unsafe.Pointer(&value[0]), 4)
}
func SetsockoptIPMreq(fd, level, opt int, mreq *IPMreq) (err error) {
- return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(mreq)), SizeofIPMreq)
+ return setsockopt(fd, level, opt, unsafe.Pointer(mreq), SizeofIPMreq)
}
func SetsockoptIPv6Mreq(fd, level, opt int, mreq *IPv6Mreq) (err error) {
- return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(mreq)), SizeofIPv6Mreq)
+ return setsockopt(fd, level, opt, unsafe.Pointer(mreq), SizeofIPv6Mreq)
}
func SetsockoptICMPv6Filter(fd, level, opt int, filter *ICMPv6Filter) error {
- return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(filter)), SizeofICMPv6Filter)
+ return setsockopt(fd, level, opt, unsafe.Pointer(filter), SizeofICMPv6Filter)
}
func SetsockoptLinger(fd, level, opt int, l *Linger) (err error) {
- return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(l)), SizeofLinger)
+ return setsockopt(fd, level, opt, unsafe.Pointer(l), SizeofLinger)
}
func SetsockoptString(fd, level, opt int, s string) (err error) {
- return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&[]byte(s)[0])), uintptr(len(s)))
+ return setsockopt(fd, level, opt, unsafe.Pointer(&[]byte(s)[0]), uintptr(len(s)))
}
func SetsockoptTimeval(fd, level, opt int, tv *Timeval) (err error) {
- return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(tv)), unsafe.Sizeof(*tv))
+ return setsockopt(fd, level, opt, unsafe.Pointer(tv), unsafe.Sizeof(*tv))
}
func Socket(domain, typ, proto int) (fd int, err error) {
diff --git a/src/pkg/syscall/passfd_test.go b/src/pkg/syscall/syscall_unix_test.go
index 53c7a1ffa..a0afb91fc 100644
--- a/src/pkg/syscall/passfd_test.go
+++ b/src/pkg/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()
@@ -200,3 +262,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/src/pkg/syscall/syscall_windows.go b/src/pkg/syscall/syscall_windows.go
index 3d78b6823..f9733f6ce 100644
--- a/src/pkg/syscall/syscall_windows.go
+++ b/src/pkg/syscall/syscall_windows.go
@@ -106,10 +106,11 @@ func (e Errno) Timeout() bool {
}
// Converts a Go function to a function pointer conforming
-// to the stdcall calling convention. This is useful when
+// to the stdcall or cdecl calling convention. This is useful when
// interoperating with Windows code requiring callbacks.
// Implemented in ../runtime/syscall_windows.goc
func NewCallback(fn interface{}) uintptr
+func NewCallbackCDecl(fn interface{}) uintptr
// windows api calls
@@ -522,8 +523,8 @@ const socket_error = uintptr(^uint32(0))
//sys socket(af int32, typ int32, protocol int32) (handle Handle, err error) [failretval==InvalidHandle] = ws2_32.socket
//sys Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (err error) [failretval==socket_error] = ws2_32.setsockopt
//sys Getsockopt(s Handle, level int32, optname int32, optval *byte, optlen *int32) (err error) [failretval==socket_error] = ws2_32.getsockopt
-//sys bind(s Handle, name uintptr, namelen int32) (err error) [failretval==socket_error] = ws2_32.bind
-//sys connect(s Handle, name uintptr, namelen int32) (err error) [failretval==socket_error] = ws2_32.connect
+//sys bind(s Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socket_error] = ws2_32.bind
+//sys connect(s Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socket_error] = ws2_32.connect
//sys getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) [failretval==socket_error] = ws2_32.getsockname
//sys getpeername(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) [failretval==socket_error] = ws2_32.getpeername
//sys listen(s Handle, backlog int32) (err error) [failretval==socket_error] = ws2_32.listen
@@ -578,7 +579,7 @@ type RawSockaddrAny struct {
}
type Sockaddr interface {
- sockaddr() (ptr uintptr, len int32, err error) // lowercase; only we can define Sockaddrs
+ sockaddr() (ptr unsafe.Pointer, len int32, err error) // lowercase; only we can define Sockaddrs
}
type SockaddrInet4 struct {
@@ -587,9 +588,9 @@ type SockaddrInet4 struct {
raw RawSockaddrInet4
}
-func (sa *SockaddrInet4) sockaddr() (uintptr, int32, error) {
+func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, int32, error) {
if sa.Port < 0 || sa.Port > 0xFFFF {
- return 0, 0, EINVAL
+ return nil, 0, EINVAL
}
sa.raw.Family = AF_INET
p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
@@ -598,7 +599,7 @@ func (sa *SockaddrInet4) sockaddr() (uintptr, int32, error) {
for i := 0; i < len(sa.Addr); i++ {
sa.raw.Addr[i] = sa.Addr[i]
}
- return uintptr(unsafe.Pointer(&sa.raw)), int32(unsafe.Sizeof(sa.raw)), nil
+ return unsafe.Pointer(&sa.raw), int32(unsafe.Sizeof(sa.raw)), nil
}
type SockaddrInet6 struct {
@@ -608,9 +609,9 @@ type SockaddrInet6 struct {
raw RawSockaddrInet6
}
-func (sa *SockaddrInet6) sockaddr() (uintptr, int32, error) {
+func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, int32, error) {
if sa.Port < 0 || sa.Port > 0xFFFF {
- return 0, 0, EINVAL
+ return nil, 0, EINVAL
}
sa.raw.Family = AF_INET6
p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
@@ -620,16 +621,16 @@ func (sa *SockaddrInet6) sockaddr() (uintptr, int32, error) {
for i := 0; i < len(sa.Addr); i++ {
sa.raw.Addr[i] = sa.Addr[i]
}
- return uintptr(unsafe.Pointer(&sa.raw)), int32(unsafe.Sizeof(sa.raw)), nil
+ return unsafe.Pointer(&sa.raw), int32(unsafe.Sizeof(sa.raw)), nil
}
type SockaddrUnix struct {
Name string
}
-func (sa *SockaddrUnix) sockaddr() (uintptr, int32, error) {
+func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, int32, error) {
// TODO(brainman): implement SockaddrUnix.sockaddr()
- return 0, 0, EWINDOWS
+ return nil, 0, EWINDOWS
}
func (rsa *RawSockaddrAny) Sockaddr() (Sockaddr, error) {
@@ -753,7 +754,7 @@ func LoadConnectEx() error {
return connectExFunc.err
}
-func connectEx(s Handle, name uintptr, namelen int32, sendBuf *byte, sendDataLen uint32, bytesSent *uint32, overlapped *Overlapped) (err error) {
+func connectEx(s Handle, name unsafe.Pointer, namelen int32, sendBuf *byte, sendDataLen uint32, bytesSent *uint32, overlapped *Overlapped) (err error) {
r1, _, e1 := Syscall9(connectExFunc.addr, 7, uintptr(s), uintptr(name), uintptr(namelen), uintptr(unsafe.Pointer(sendBuf)), uintptr(sendDataLen), uintptr(unsafe.Pointer(bytesSent)), uintptr(unsafe.Pointer(overlapped)), 0, 0)
if r1 == 0 {
if e1 != 0 {
diff --git a/src/pkg/syscall/tables_nacl.go b/src/pkg/syscall/tables_nacl.go
new file mode 100644
index 000000000..08f4ced53
--- /dev/null
+++ b/src/pkg/syscall/tables_nacl.go
@@ -0,0 +1,324 @@
+// 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
+
+// TODO: generate with runtime/mknacl.sh, allow override with IRT.
+const (
+ sys_null = 1
+ sys_nameservice = 2
+ sys_dup = 8
+ sys_dup2 = 9
+ sys_open = 10
+ sys_close = 11
+ sys_read = 12
+ sys_write = 13
+ sys_lseek = 14
+ sys_ioctl = 15
+ sys_stat = 16
+ sys_fstat = 17
+ sys_chmod = 18
+ sys_brk = 20
+ sys_mmap = 21
+ sys_munmap = 22
+ sys_getdents = 23
+ sys_mprotect = 24
+ sys_list_mappings = 25
+ sys_exit = 30
+ sys_getpid = 31
+ sys_sched_yield = 32
+ sys_sysconf = 33
+ sys_gettimeofday = 40
+ sys_clock = 41
+ sys_nanosleep = 42
+ sys_clock_getres = 43
+ sys_clock_gettime = 44
+ sys_mkdir = 45
+ sys_rmdir = 46
+ sys_chdir = 47
+ sys_getcwd = 48
+ sys_unlink = 49
+ sys_imc_makeboundsock = 60
+ sys_imc_accept = 61
+ sys_imc_connect = 62
+ sys_imc_sendmsg = 63
+ sys_imc_recvmsg = 64
+ sys_imc_mem_obj_create = 65
+ sys_imc_socketpair = 66
+ sys_mutex_create = 70
+ sys_mutex_lock = 71
+ sys_mutex_trylock = 72
+ sys_mutex_unlock = 73
+ sys_cond_create = 74
+ sys_cond_wait = 75
+ sys_cond_signal = 76
+ sys_cond_broadcast = 77
+ sys_cond_timed_wait_abs = 79
+ sys_thread_create = 80
+ sys_thread_exit = 81
+ sys_tls_init = 82
+ sys_thread_nice = 83
+ sys_tls_get = 84
+ sys_second_tls_set = 85
+ sys_second_tls_get = 86
+ sys_exception_handler = 87
+ sys_exception_stack = 88
+ sys_exception_clear_flag = 89
+ sys_sem_create = 100
+ sys_sem_wait = 101
+ sys_sem_post = 102
+ sys_sem_get_value = 103
+ sys_dyncode_create = 104
+ sys_dyncode_modify = 105
+ sys_dyncode_delete = 106
+ sys_test_infoleak = 109
+ sys_test_crash = 110
+ sys_test_syscall_1 = 111
+ sys_test_syscall_2 = 112
+)
+
+// TODO: Auto-generate some day. (Hard-coded in binaries so not likely to change.)
+const (
+ // native_client/src/trusted/service_runtime/include/sys/errno.h
+ // The errors are mainly copied from Linux.
+ EPERM Errno = 1 /* Operation not permitted */
+ ENOENT Errno = 2 /* No such file or directory */
+ ESRCH Errno = 3 /* No such process */
+ EINTR Errno = 4 /* Interrupted system call */
+ EIO Errno = 5 /* I/O error */
+ ENXIO Errno = 6 /* No such device or address */
+ E2BIG Errno = 7 /* Argument list too long */
+ ENOEXEC Errno = 8 /* Exec format error */
+ EBADF Errno = 9 /* Bad file number */
+ ECHILD Errno = 10 /* No child processes */
+ EAGAIN Errno = 11 /* Try again */
+ ENOMEM Errno = 12 /* Out of memory */
+ EACCES Errno = 13 /* Permission denied */
+ EFAULT Errno = 14 /* Bad address */
+ EBUSY Errno = 16 /* Device or resource busy */
+ EEXIST Errno = 17 /* File exists */
+ EXDEV Errno = 18 /* Cross-device link */
+ ENODEV Errno = 19 /* No such device */
+ ENOTDIR Errno = 20 /* Not a directory */
+ EISDIR Errno = 21 /* Is a directory */
+ EINVAL Errno = 22 /* Invalid argument */
+ ENFILE Errno = 23 /* File table overflow */
+ EMFILE Errno = 24 /* Too many open files */
+ ENOTTY Errno = 25 /* Not a typewriter */
+ EFBIG Errno = 27 /* File too large */
+ ENOSPC Errno = 28 /* No space left on device */
+ ESPIPE Errno = 29 /* Illegal seek */
+ EROFS Errno = 30 /* Read-only file system */
+ EMLINK Errno = 31 /* Too many links */
+ EPIPE Errno = 32 /* Broken pipe */
+ ENAMETOOLONG Errno = 36 /* File name too long */
+ ENOSYS Errno = 38 /* Function not implemented */
+ EDQUOT Errno = 122 /* Quota exceeded */
+ EDOM Errno = 33 /* Math arg out of domain of func */
+ ERANGE Errno = 34 /* Math result not representable */
+ EDEADLK Errno = 35 /* Deadlock condition */
+ ENOLCK Errno = 37 /* No record locks available */
+ ENOTEMPTY Errno = 39 /* Directory not empty */
+ ELOOP Errno = 40 /* Too many symbolic links */
+ ENOMSG Errno = 42 /* No message of desired type */
+ EIDRM Errno = 43 /* Identifier removed */
+ ECHRNG Errno = 44 /* Channel number out of range */
+ EL2NSYNC Errno = 45 /* Level 2 not synchronized */
+ EL3HLT Errno = 46 /* Level 3 halted */
+ EL3RST Errno = 47 /* Level 3 reset */
+ ELNRNG Errno = 48 /* Link number out of range */
+ EUNATCH Errno = 49 /* Protocol driver not attached */
+ ENOCSI Errno = 50 /* No CSI structure available */
+ EL2HLT Errno = 51 /* Level 2 halted */
+ EBADE Errno = 52 /* Invalid exchange */
+ EBADR Errno = 53 /* Invalid request descriptor */
+ EXFULL Errno = 54 /* Exchange full */
+ ENOANO Errno = 55 /* No anode */
+ EBADRQC Errno = 56 /* Invalid request code */
+ EBADSLT Errno = 57 /* Invalid slot */
+ EDEADLOCK Errno = EDEADLK /* File locking deadlock error */
+ EBFONT Errno = 59 /* Bad font file fmt */
+ ENOSTR Errno = 60 /* Device not a stream */
+ ENODATA Errno = 61 /* No data (for no delay io) */
+ ETIME Errno = 62 /* Timer expired */
+ ENOSR Errno = 63 /* Out of streams resources */
+ ENONET Errno = 64 /* Machine is not on the network */
+ ENOPKG Errno = 65 /* Package not installed */
+ EREMOTE Errno = 66 /* The object is remote */
+ ENOLINK Errno = 67 /* The link has been severed */
+ EADV Errno = 68 /* Advertise error */
+ ESRMNT Errno = 69 /* Srmount error */
+ ECOMM Errno = 70 /* Communication error on send */
+ EPROTO Errno = 71 /* Protocol error */
+ EMULTIHOP Errno = 72 /* Multihop attempted */
+ EDOTDOT Errno = 73 /* Cross mount point (not really error) */
+ EBADMSG Errno = 74 /* Trying to read unreadable message */
+ EOVERFLOW Errno = 75 /* Value too large for defined data type */
+ ENOTUNIQ Errno = 76 /* Given log. name not unique */
+ EBADFD Errno = 77 /* f.d. invalid for this operation */
+ EREMCHG Errno = 78 /* Remote address changed */
+ ELIBACC Errno = 79 /* Can't access a needed shared lib */
+ ELIBBAD Errno = 80 /* Accessing a corrupted shared lib */
+ ELIBSCN Errno = 81 /* .lib section in a.out corrupted */
+ ELIBMAX Errno = 82 /* Attempting to link in too many libs */
+ ELIBEXEC Errno = 83 /* Attempting to exec a shared library */
+ EILSEQ Errno = 84
+ EUSERS Errno = 87
+ ENOTSOCK Errno = 88 /* Socket operation on non-socket */
+ EDESTADDRREQ Errno = 89 /* Destination address required */
+ EMSGSIZE Errno = 90 /* Message too long */
+ EPROTOTYPE Errno = 91 /* Protocol wrong type for socket */
+ ENOPROTOOPT Errno = 92 /* Protocol not available */
+ EPROTONOSUPPORT Errno = 93 /* Unknown protocol */
+ ESOCKTNOSUPPORT Errno = 94 /* Socket type not supported */
+ EOPNOTSUPP Errno = 95 /* Operation not supported on transport endpoint */
+ EPFNOSUPPORT Errno = 96 /* Protocol family not supported */
+ EAFNOSUPPORT Errno = 97 /* Address family not supported by protocol family */
+ EADDRINUSE Errno = 98 /* Address already in use */
+ EADDRNOTAVAIL Errno = 99 /* Address not available */
+ ENETDOWN Errno = 100 /* Network interface is not configured */
+ ENETUNREACH Errno = 101 /* Network is unreachable */
+ ENETRESET Errno = 102
+ ECONNABORTED Errno = 103 /* Connection aborted */
+ ECONNRESET Errno = 104 /* Connection reset by peer */
+ ENOBUFS Errno = 105 /* No buffer space available */
+ EISCONN Errno = 106 /* Socket is already connected */
+ ENOTCONN Errno = 107 /* Socket is not connected */
+ ESHUTDOWN Errno = 108 /* Can't send after socket shutdown */
+ ETOOMANYREFS Errno = 109
+ ETIMEDOUT Errno = 110 /* Connection timed out */
+ ECONNREFUSED Errno = 111 /* Connection refused */
+ EHOSTDOWN Errno = 112 /* Host is down */
+ EHOSTUNREACH Errno = 113 /* Host is unreachable */
+ EALREADY Errno = 114 /* Socket already connected */
+ EINPROGRESS Errno = 115 /* Connection already in progress */
+ ESTALE Errno = 116
+ ENOTSUP Errno = EOPNOTSUPP /* Not supported */
+ ENOMEDIUM Errno = 123 /* No medium (in tape drive) */
+ ECANCELED Errno = 125 /* Operation canceled. */
+ ELBIN Errno = 2048 /* Inode is remote (not really error) */
+ EFTYPE Errno = 2049 /* Inappropriate file type or format */
+ ENMFILE Errno = 2050 /* No more files */
+ EPROCLIM Errno = 2051
+ ENOSHARE Errno = 2052 /* No such host or network path */
+ ECASECLASH Errno = 2053 /* Filename exists with different case */
+ EWOULDBLOCK Errno = EAGAIN /* Operation would block */
+)
+
+// TODO: Auto-generate some day. (Hard-coded in binaries so not likely to change.)
+var errorstr = [...]string{
+ EPERM: "Operation not permitted",
+ ENOENT: "No such file or directory",
+ ESRCH: "No such process",
+ EINTR: "Interrupted system call",
+ EIO: "I/O error",
+ ENXIO: "No such device or address",
+ E2BIG: "Argument list too long",
+ ENOEXEC: "Exec format error",
+ EBADF: "Bad file number",
+ ECHILD: "No child processes",
+ EAGAIN: "Try again",
+ ENOMEM: "Out of memory",
+ EACCES: "Permission denied",
+ EFAULT: "Bad address",
+ EBUSY: "Device or resource busy",
+ EEXIST: "File exists",
+ EXDEV: "Cross-device link",
+ ENODEV: "No such device",
+ ENOTDIR: "Not a directory",
+ EISDIR: "Is a directory",
+ EINVAL: "Invalid argument",
+ ENFILE: "File table overflow",
+ EMFILE: "Too many open files",
+ ENOTTY: "Not a typewriter",
+ EFBIG: "File too large",
+ ENOSPC: "No space left on device",
+ ESPIPE: "Illegal seek",
+ EROFS: "Read-only file system",
+ EMLINK: "Too many links",
+ EPIPE: "Broken pipe",
+ ENAMETOOLONG: "File name too long",
+ ENOSYS: "not implemented on Native Client",
+ EDQUOT: "Quota exceeded",
+ EDOM: "Math arg out of domain of func",
+ ERANGE: "Math result not representable",
+ EDEADLK: "Deadlock condition",
+ ENOLCK: "No record locks available",
+ ENOTEMPTY: "Directory not empty",
+ ELOOP: "Too many symbolic links",
+ ENOMSG: "No message of desired type",
+ EIDRM: "Identifier removed",
+ ECHRNG: "Channel number out of range",
+ EL2NSYNC: "Level 2 not synchronized",
+ EL3HLT: "Level 3 halted",
+ EL3RST: "Level 3 reset",
+ ELNRNG: "Link number out of range",
+ EUNATCH: "Protocol driver not attached",
+ ENOCSI: "No CSI structure available",
+ EL2HLT: "Level 2 halted",
+ EBADE: "Invalid exchange",
+ EBADR: "Invalid request descriptor",
+ EXFULL: "Exchange full",
+ ENOANO: "No anode",
+ EBADRQC: "Invalid request code",
+ EBADSLT: "Invalid slot",
+ EBFONT: "Bad font file fmt",
+ ENOSTR: "Device not a stream",
+ ENODATA: "No data (for no delay io)",
+ ETIME: "Timer expired",
+ ENOSR: "Out of streams resources",
+ ENONET: "Machine is not on the network",
+ ENOPKG: "Package not installed",
+ EREMOTE: "The object is remote",
+ ENOLINK: "The link has been severed",
+ EADV: "Advertise error",
+ ESRMNT: "Srmount error",
+ ECOMM: "Communication error on send",
+ EPROTO: "Protocol error",
+ EMULTIHOP: "Multihop attempted",
+ EDOTDOT: "Cross mount point (not really error)",
+ EBADMSG: "Trying to read unreadable message",
+ EOVERFLOW: "Value too large for defined data type",
+ ENOTUNIQ: "Given log. name not unique",
+ EBADFD: "f.d. invalid for this operation",
+ EREMCHG: "Remote address changed",
+ ELIBACC: "Can't access a needed shared lib",
+ ELIBBAD: "Accessing a corrupted shared lib",
+ ELIBSCN: ".lib section in a.out corrupted",
+ ELIBMAX: "Attempting to link in too many libs",
+ ELIBEXEC: "Attempting to exec a shared library",
+ ENOTSOCK: "Socket operation on non-socket",
+ EDESTADDRREQ: "Destination address required",
+ EMSGSIZE: "Message too long",
+ EPROTOTYPE: "Protocol wrong type for socket",
+ ENOPROTOOPT: "Protocol not available",
+ EPROTONOSUPPORT: "Unknown protocol",
+ ESOCKTNOSUPPORT: "Socket type not supported",
+ EOPNOTSUPP: "Operation not supported on transport endpoint",
+ EPFNOSUPPORT: "Protocol family not supported",
+ EAFNOSUPPORT: "Address family not supported by protocol family",
+ EADDRINUSE: "Address already in use",
+ EADDRNOTAVAIL: "Address not available",
+ ENETDOWN: "Network interface is not configured",
+ ENETUNREACH: "Network is unreachable",
+ ECONNABORTED: "Connection aborted",
+ ECONNRESET: "Connection reset by peer",
+ ENOBUFS: "No buffer space available",
+ EISCONN: "Socket is already connected",
+ ENOTCONN: "Socket is not connected",
+ ESHUTDOWN: "Can't send after socket shutdown",
+ ETIMEDOUT: "Connection timed out",
+ ECONNREFUSED: "Connection refused",
+ EHOSTDOWN: "Host is down",
+ EHOSTUNREACH: "Host is unreachable",
+ EALREADY: "Socket already connected",
+ EINPROGRESS: "Connection already in progress",
+ ENOMEDIUM: "No medium (in tape drive)",
+ ECANCELED: "Operation canceled.",
+ ELBIN: "Inode is remote (not really error)",
+ EFTYPE: "Inappropriate file type or format",
+ ENMFILE: "No more files",
+ ENOSHARE: "No such host or network path",
+ ECASECLASH: "Filename exists with different case",
+}
diff --git a/src/pkg/syscall/time_nacl_386.s b/src/pkg/syscall/time_nacl_386.s
new file mode 100644
index 000000000..b5a22d31b
--- /dev/null
+++ b/src/pkg/syscall/time_nacl_386.s
@@ -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.
+
+#include "../../cmd/ld/textflag.h"
+
+TEXT ·startTimer(SB),NOSPLIT,$0
+ JMP time·startTimer(SB)
+
+TEXT ·stopTimer(SB),NOSPLIT,$0
+ JMP time·stopTimer(SB)
diff --git a/src/pkg/syscall/time_nacl_amd64p32.s b/src/pkg/syscall/time_nacl_amd64p32.s
new file mode 100644
index 000000000..b5a22d31b
--- /dev/null
+++ b/src/pkg/syscall/time_nacl_amd64p32.s
@@ -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.
+
+#include "../../cmd/ld/textflag.h"
+
+TEXT ·startTimer(SB),NOSPLIT,$0
+ JMP time·startTimer(SB)
+
+TEXT ·stopTimer(SB),NOSPLIT,$0
+ JMP time·stopTimer(SB)
diff --git a/src/pkg/syscall/types_dragonfly.go b/src/pkg/syscall/types_dragonfly.go
index 009b8f045..fb7fd1bb4 100644
--- a/src/pkg/syscall/types_dragonfly.go
+++ b/src/pkg/syscall/types_dragonfly.go
@@ -18,6 +18,7 @@ package syscall
#include <dirent.h>
#include <fcntl.h>
#include <signal.h>
+#include <termios.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/event.h>
@@ -97,10 +98,6 @@ type _Gid_t C.gid_t
// Files
-const (
- F_DUPFD_CLOEXEC = 0 // not supported
-)
-
const ( // Directory mode bits
S_IFMT = C.S_IFMT
S_IFIFO = C.S_IFIFO
@@ -239,3 +236,7 @@ type BpfProgram C.struct_bpf_program
type BpfInsn C.struct_bpf_insn
type BpfHdr C.struct_bpf_hdr
+
+// Terminal handling
+
+type Termios C.struct_termios
diff --git a/src/pkg/syscall/types_freebsd.go b/src/pkg/syscall/types_freebsd.go
index ccf53d0ad..68a69312b 100644
--- a/src/pkg/syscall/types_freebsd.go
+++ b/src/pkg/syscall/types_freebsd.go
@@ -18,6 +18,7 @@ package syscall
#include <dirent.h>
#include <fcntl.h>
#include <signal.h>
+#include <termios.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/event.h>
@@ -59,6 +60,91 @@ struct sockaddr_any {
char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)];
};
+// This structure is a duplicate of stat on FreeBSD 8-STABLE.
+// See /usr/include/sys/stat.h.
+struct stat8 {
+#undef st_atimespec st_atim
+#undef st_mtimespec st_mtim
+#undef st_ctimespec st_ctim
+#undef st_birthtimespec st_birthtim
+ __dev_t st_dev;
+ ino_t st_ino;
+ mode_t st_mode;
+ nlink_t st_nlink;
+ uid_t st_uid;
+ gid_t st_gid;
+ __dev_t st_rdev;
+#if __BSD_VISIBLE
+ struct timespec st_atimespec;
+ struct timespec st_mtimespec;
+ struct timespec st_ctimespec;
+#else
+ time_t st_atime;
+ long __st_atimensec;
+ time_t st_mtime;
+ long __st_mtimensec;
+ time_t st_ctime;
+ long __st_ctimensec;
+#endif
+ off_t st_size;
+ blkcnt_t st_blocks;
+ blksize_t st_blksize;
+ fflags_t st_flags;
+ __uint32_t st_gen;
+ __int32_t st_lspare;
+#if __BSD_VISIBLE
+ struct timespec st_birthtimespec;
+ unsigned int :(8 / 2) * (16 - (int)sizeof(struct timespec));
+ unsigned int :(8 / 2) * (16 - (int)sizeof(struct timespec));
+#else
+ time_t st_birthtime;
+ long st_birthtimensec;
+ unsigned int :(8 / 2) * (16 - (int)sizeof(struct __timespec));
+ unsigned int :(8 / 2) * (16 - (int)sizeof(struct __timespec));
+#endif
+};
+
+// This structure is a duplicate of if_data on FreeBSD 8-STABLE.
+// See /usr/include/net/if.h.
+struct if_data8 {
+ u_char ifi_type;
+ u_char ifi_physical;
+ u_char ifi_addrlen;
+ u_char ifi_hdrlen;
+ u_char ifi_link_state;
+ u_char ifi_spare_char1;
+ u_char ifi_spare_char2;
+ u_char ifi_datalen;
+ u_long ifi_mtu;
+ u_long ifi_metric;
+ u_long ifi_baudrate;
+ u_long ifi_ipackets;
+ u_long ifi_ierrors;
+ u_long ifi_opackets;
+ u_long ifi_oerrors;
+ u_long ifi_collisions;
+ u_long ifi_ibytes;
+ u_long ifi_obytes;
+ u_long ifi_imcasts;
+ u_long ifi_omcasts;
+ u_long ifi_iqdrops;
+ u_long ifi_noproto;
+ u_long ifi_hwassist;
+ time_t ifi_epoch;
+ struct timeval ifi_lastchange;
+};
+
+// This structure is a duplicate of if_msghdr on FreeBSD 8-STABLE.
+// See /usr/include/net/if.h.
+struct if_msghdr8 {
+ u_short ifm_msglen;
+ u_char ifm_version;
+ u_char ifm_type;
+ int ifm_addrs;
+ int ifm_flags;
+ u_short ifm_index;
+ struct if_data8 ifm_data;
+};
*/
import "C"
@@ -97,10 +183,6 @@ type _Gid_t C.gid_t
// Files
-const (
- O_CLOEXEC = 0 // not supported
-)
-
const ( // Directory mode bits
S_IFMT = C.S_IFMT
S_IFIFO = C.S_IFIFO
@@ -118,7 +200,7 @@ const ( // Directory mode bits
S_IXUSR = C.S_IXUSR
)
-type Stat_t C.struct_stat
+type Stat_t C.struct_stat8
type Statfs_t C.struct_statfs
@@ -200,8 +282,10 @@ type FdSet C.fd_set
// Routing and interface messages
const (
- SizeofIfMsghdr = C.sizeof_struct_if_msghdr
- SizeofIfData = C.sizeof_struct_if_data
+ sizeofIfMsghdr = C.sizeof_struct_if_msghdr
+ SizeofIfMsghdr = C.sizeof_struct_if_msghdr8
+ sizeofIfData = C.sizeof_struct_if_data
+ SizeofIfData = C.sizeof_struct_if_data8
SizeofIfaMsghdr = C.sizeof_struct_ifa_msghdr
SizeofIfmaMsghdr = C.sizeof_struct_ifma_msghdr
SizeofIfAnnounceMsghdr = C.sizeof_struct_if_announcemsghdr
@@ -209,9 +293,13 @@ const (
SizeofRtMetrics = C.sizeof_struct_rt_metrics
)
-type IfMsghdr C.struct_if_msghdr
+type ifMsghdr C.struct_if_msghdr
+
+type IfMsghdr C.struct_if_msghdr8
-type IfData C.struct_if_data
+type ifData C.struct_if_data
+
+type IfData C.struct_if_data8
type IfaMsghdr C.struct_ifa_msghdr
@@ -248,3 +336,7 @@ type BpfInsn C.struct_bpf_insn
type BpfHdr C.struct_bpf_hdr
type BpfZbufHeader C.struct_bpf_zbuf_header
+
+// Terminal handling
+
+type Termios C.struct_termios
diff --git a/src/pkg/syscall/types_linux.go b/src/pkg/syscall/types_linux.go
index fea09d1d7..e8396a41f 100644
--- a/src/pkg/syscall/types_linux.go
+++ b/src/pkg/syscall/types_linux.go
@@ -158,6 +158,8 @@ type Dirent C.struct_dirent
type Fsid C.fsid_t
+type Flock_t C.struct_flock
+
// Sockets
type RawSockaddrInet4 C.struct_sockaddr_in
diff --git a/src/pkg/syscall/types_netbsd.go b/src/pkg/syscall/types_netbsd.go
index badaa1049..04354a32a 100644
--- a/src/pkg/syscall/types_netbsd.go
+++ b/src/pkg/syscall/types_netbsd.go
@@ -18,6 +18,7 @@ package syscall
#include <dirent.h>
#include <fcntl.h>
#include <signal.h>
+#include <termios.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/param.h>
@@ -222,6 +223,10 @@ type BpfHdr C.struct_bpf_hdr
type BpfTimeval C.struct_bpf_timeval
+// Terminal handling
+
+type Termios C.struct_termios
+
// Sysctl
type Sysctlnode C.struct_sysctlnode
diff --git a/src/pkg/syscall/types_openbsd.go b/src/pkg/syscall/types_openbsd.go
index 6fe2af6e0..e6d1ea704 100644
--- a/src/pkg/syscall/types_openbsd.go
+++ b/src/pkg/syscall/types_openbsd.go
@@ -18,6 +18,7 @@ package syscall
#include <dirent.h>
#include <fcntl.h>
#include <signal.h>
+#include <termios.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/param.h>
@@ -237,3 +238,7 @@ type BpfInsn C.struct_bpf_insn
type BpfHdr C.struct_bpf_hdr
type BpfTimeval C.struct_bpf_timeval
+
+// Terminal handling
+
+type Termios C.struct_termios
diff --git a/src/pkg/syscall/types_solaris.go b/src/pkg/syscall/types_solaris.go
new file mode 100644
index 000000000..53fa35068
--- /dev/null
+++ b/src/pkg/syscall/types_solaris.go
@@ -0,0 +1,222 @@
+// 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
+
+/*
+Input to cgo -godefs. See also mkerrors.sh and mkall.sh
+*/
+
+// +godefs map struct_in_addr [4]byte /* in_addr */
+// +godefs map struct_in6_addr [16]byte /* in6_addr */
+
+package syscall
+
+/*
+#define KERNEL
+#include <dirent.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <termios.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <sys/select.h>
+#include <sys/signal.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/icmp6.h>
+#include <netinet/tcp.h>
+
+enum {
+ sizeofPtr = sizeof(void*),
+};
+
+union sockaddr_all {
+ struct sockaddr s1; // this one gets used for fields
+ struct sockaddr_in s2; // these pad it out
+ struct sockaddr_in6 s3;
+ struct sockaddr_un s4;
+ struct sockaddr_dl s5;
+};
+
+struct sockaddr_any {
+ struct sockaddr addr;
+ char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)];
+};
+
+*/
+import "C"
+
+// Machine characteristics; for internal use.
+
+const (
+ sizeofPtr = C.sizeofPtr
+ sizeofShort = C.sizeof_short
+ sizeofInt = C.sizeof_int
+ sizeofLong = C.sizeof_long
+ sizeofLongLong = C.sizeof_longlong
+)
+
+// Basic types
+
+type (
+ _C_short C.short
+ _C_int C.int
+ _C_long C.long
+ _C_long_long C.longlong
+)
+
+// Time
+
+type Timespec C.struct_timespec
+
+type Timeval C.struct_timeval
+
+type Timeval32 C.struct_timeval32
+
+// Processes
+
+type Rusage C.struct_rusage
+
+type Rlimit C.struct_rlimit
+
+type _Gid_t C.gid_t
+
+// Files
+
+const ( // Directory mode bits
+ S_IFMT = C.S_IFMT
+ S_IFIFO = C.S_IFIFO
+ S_IFCHR = C.S_IFCHR
+ S_IFDIR = C.S_IFDIR
+ S_IFBLK = C.S_IFBLK
+ S_IFREG = C.S_IFREG
+ S_IFLNK = C.S_IFLNK
+ S_IFSOCK = C.S_IFSOCK
+ S_ISUID = C.S_ISUID
+ S_ISGID = C.S_ISGID
+ S_ISVTX = C.S_ISVTX
+ S_IRUSR = C.S_IRUSR
+ S_IWUSR = C.S_IWUSR
+ S_IXUSR = C.S_IXUSR
+)
+
+type Stat_t C.struct_stat
+
+type Flock_t C.struct_flock
+
+type Dirent C.struct_dirent
+
+// Sockets
+
+type RawSockaddrInet4 C.struct_sockaddr_in
+
+type RawSockaddrInet6 C.struct_sockaddr_in6
+
+type RawSockaddrUnix C.struct_sockaddr_un
+
+type RawSockaddrDatalink C.struct_sockaddr_dl
+
+type RawSockaddr C.struct_sockaddr
+
+type RawSockaddrAny C.struct_sockaddr_any
+
+type _Socklen C.socklen_t
+
+type Linger C.struct_linger
+
+type Iovec C.struct_iovec
+
+type IPMreq C.struct_ip_mreq
+
+type IPv6Mreq C.struct_ipv6_mreq
+
+type Msghdr C.struct_msghdr
+
+type Cmsghdr C.struct_cmsghdr
+
+type Inet6Pktinfo C.struct_in6_pktinfo
+
+type IPv6MTUInfo C.struct_ip6_mtuinfo
+
+type ICMPv6Filter C.struct_icmp6_filter
+
+const (
+ SizeofSockaddrInet4 = C.sizeof_struct_sockaddr_in
+ SizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
+ SizeofSockaddrAny = C.sizeof_struct_sockaddr_any
+ SizeofSockaddrUnix = C.sizeof_struct_sockaddr_un
+ SizeofSockaddrDatalink = C.sizeof_struct_sockaddr_dl
+ SizeofLinger = C.sizeof_struct_linger
+ SizeofIPMreq = C.sizeof_struct_ip_mreq
+ SizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq
+ SizeofMsghdr = C.sizeof_struct_msghdr
+ SizeofCmsghdr = C.sizeof_struct_cmsghdr
+ SizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo
+ SizeofIPv6MTUInfo = C.sizeof_struct_ip6_mtuinfo
+ SizeofICMPv6Filter = C.sizeof_struct_icmp6_filter
+)
+
+// Select
+
+type FdSet C.fd_set
+
+// Routing and interface messages
+
+const (
+ SizeofIfMsghdr = C.sizeof_struct_if_msghdr
+ SizeofIfData = C.sizeof_struct_if_data
+ SizeofIfaMsghdr = C.sizeof_struct_ifa_msghdr
+ SizeofRtMsghdr = C.sizeof_struct_rt_msghdr
+ SizeofRtMetrics = C.sizeof_struct_rt_metrics
+)
+
+type IfMsghdr C.struct_if_msghdr
+
+type IfData C.struct_if_data
+
+type IfaMsghdr C.struct_ifa_msghdr
+
+type RtMsghdr C.struct_rt_msghdr
+
+type RtMetrics C.struct_rt_metrics
+
+// Berkeley packet filter
+
+const (
+ SizeofBpfVersion = C.sizeof_struct_bpf_version
+ SizeofBpfStat = C.sizeof_struct_bpf_stat
+ SizeofBpfProgram = C.sizeof_struct_bpf_program
+ SizeofBpfInsn = C.sizeof_struct_bpf_insn
+ SizeofBpfHdr = C.sizeof_struct_bpf_hdr
+)
+
+type BpfVersion C.struct_bpf_version
+
+type BpfStat C.struct_bpf_stat
+
+type BpfProgram C.struct_bpf_program
+
+type BpfInsn C.struct_bpf_insn
+
+type BpfTimeval C.struct_bpf_timeval
+
+type BpfHdr C.struct_bpf_hdr
+
+// Terminal handling
+
+type Termios C.struct_termios
diff --git a/src/pkg/syscall/unzip_nacl.go b/src/pkg/syscall/unzip_nacl.go
new file mode 100644
index 000000000..5845e44f0
--- /dev/null
+++ b/src/pkg/syscall/unzip_nacl.go
@@ -0,0 +1,685 @@
+// 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.
+
+// Small in-memory unzip implementation.
+// A simplified copy of the pre-Go 1 compress/flate/inflate.go
+// and a modified copy of the zip reader in package time.
+// (The one in package time does not support decompression; this one does.)
+
+package syscall
+
+const (
+ maxCodeLen = 16 // max length of Huffman code
+ maxHist = 32768 // max history required
+ maxLit = 286
+ maxDist = 32
+ numCodes = 19 // number of codes in Huffman meta-code
+)
+
+type decompressor struct {
+ in string // compressed input
+ out []byte // uncompressed output
+ b uint32 // input bits, at top of b
+ nb uint
+ err bool // invalid input
+ eof bool // reached EOF
+
+ h1, h2 huffmanDecoder // decoders for literal/length, distance
+ bits [maxLit + maxDist]int // lengths defining Huffman codes
+ codebits [numCodes]int
+}
+
+func (f *decompressor) nextBlock() {
+ for f.nb < 1+2 {
+ if f.moreBits(); f.err {
+ return
+ }
+ }
+ f.eof = f.b&1 == 1
+ f.b >>= 1
+ typ := f.b & 3
+ f.b >>= 2
+ f.nb -= 1 + 2
+ switch typ {
+ case 0:
+ f.dataBlock()
+ case 1:
+ // compressed, fixed Huffman tables
+ f.huffmanBlock(&fixedHuffmanDecoder, nil)
+ case 2:
+ // compressed, dynamic Huffman tables
+ if f.readHuffman(); f.err {
+ break
+ }
+ f.huffmanBlock(&f.h1, &f.h2)
+ default:
+ // 3 is reserved.
+ f.err = true
+ }
+}
+
+// RFC 1951 section 3.2.7.
+// Compression with dynamic Huffman codes
+
+var codeOrder = [...]int{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}
+
+func (f *decompressor) readHuffman() {
+ // HLIT[5], HDIST[5], HCLEN[4].
+ for f.nb < 5+5+4 {
+ if f.moreBits(); f.err {
+ return
+ }
+ }
+ nlit := int(f.b&0x1F) + 257
+ f.b >>= 5
+ ndist := int(f.b&0x1F) + 1
+ f.b >>= 5
+ nclen := int(f.b&0xF) + 4
+ f.b >>= 4
+ f.nb -= 5 + 5 + 4
+
+ // (HCLEN+4)*3 bits: code lengths in the magic codeOrder order.
+ for i := 0; i < nclen; i++ {
+ for f.nb < 3 {
+ if f.moreBits(); f.err {
+ return
+ }
+ }
+ f.codebits[codeOrder[i]] = int(f.b & 0x7)
+ f.b >>= 3
+ f.nb -= 3
+ }
+ for i := nclen; i < len(codeOrder); i++ {
+ f.codebits[codeOrder[i]] = 0
+ }
+ if !f.h1.init(f.codebits[0:]) {
+ f.err = true
+ return
+ }
+
+ // HLIT + 257 code lengths, HDIST + 1 code lengths,
+ // using the code length Huffman code.
+ for i, n := 0, nlit+ndist; i < n; {
+ x := f.huffSym(&f.h1)
+ if f.err {
+ return
+ }
+ if x < 16 {
+ // Actual length.
+ f.bits[i] = x
+ i++
+ continue
+ }
+ // Repeat previous length or zero.
+ var rep int
+ var nb uint
+ var b int
+ switch x {
+ default:
+ f.err = true
+ return
+ case 16:
+ rep = 3
+ nb = 2
+ if i == 0 {
+ f.err = true
+ return
+ }
+ b = f.bits[i-1]
+ case 17:
+ rep = 3
+ nb = 3
+ b = 0
+ case 18:
+ rep = 11
+ nb = 7
+ b = 0
+ }
+ for f.nb < nb {
+ if f.moreBits(); f.err {
+ return
+ }
+ }
+ rep += int(f.b & uint32(1<<nb-1))
+ f.b >>= nb
+ f.nb -= nb
+ if i+rep > n {
+ f.err = true
+ return
+ }
+ for j := 0; j < rep; j++ {
+ f.bits[i] = b
+ i++
+ }
+ }
+
+ if !f.h1.init(f.bits[0:nlit]) || !f.h2.init(f.bits[nlit:nlit+ndist]) {
+ f.err = true
+ return
+ }
+}
+
+// Decode a single Huffman block from f.
+// hl and hd are the Huffman states for the lit/length values
+// and the distance values, respectively. If hd == nil, using the
+// fixed distance encoding associated with fixed Huffman blocks.
+func (f *decompressor) huffmanBlock(hl, hd *huffmanDecoder) {
+ for {
+ v := f.huffSym(hl)
+ if f.err {
+ return
+ }
+ var n uint // number of bits extra
+ var length int
+ switch {
+ case v < 256:
+ f.out = append(f.out, byte(v))
+ continue
+ case v == 256:
+ // Done with huffman block; read next block.
+ return
+ // otherwise, reference to older data
+ case v < 265:
+ length = v - (257 - 3)
+ n = 0
+ case v < 269:
+ length = v*2 - (265*2 - 11)
+ n = 1
+ case v < 273:
+ length = v*4 - (269*4 - 19)
+ n = 2
+ case v < 277:
+ length = v*8 - (273*8 - 35)
+ n = 3
+ case v < 281:
+ length = v*16 - (277*16 - 67)
+ n = 4
+ case v < 285:
+ length = v*32 - (281*32 - 131)
+ n = 5
+ default:
+ length = 258
+ n = 0
+ }
+ if n > 0 {
+ for f.nb < n {
+ if f.moreBits(); f.err {
+ return
+ }
+ }
+ length += int(f.b & uint32(1<<n-1))
+ f.b >>= n
+ f.nb -= n
+ }
+
+ var dist int
+ if hd == nil {
+ for f.nb < 5 {
+ if f.moreBits(); f.err {
+ return
+ }
+ }
+ dist = int(reverseByte[(f.b&0x1F)<<3])
+ f.b >>= 5
+ f.nb -= 5
+ } else {
+ if dist = f.huffSym(hd); f.err {
+ return
+ }
+ }
+
+ switch {
+ case dist < 4:
+ dist++
+ case dist >= 30:
+ f.err = true
+ return
+ default:
+ nb := uint(dist-2) >> 1
+ // have 1 bit in bottom of dist, need nb more.
+ extra := (dist & 1) << nb
+ for f.nb < nb {
+ if f.moreBits(); f.err {
+ return
+ }
+ }
+ extra |= int(f.b & uint32(1<<nb-1))
+ f.b >>= nb
+ f.nb -= nb
+ dist = 1<<(nb+1) + 1 + extra
+ }
+
+ // Copy [-dist:-dist+length] into output.
+ // Encoding can be prescient, so no check on length.
+ if dist > len(f.out) {
+ f.err = true
+ return
+ }
+
+ p := len(f.out) - dist
+ for i := 0; i < length; i++ {
+ f.out = append(f.out, f.out[p])
+ p++
+ }
+ }
+}
+
+// Copy a single uncompressed data block from input to output.
+func (f *decompressor) dataBlock() {
+ // Uncompressed.
+ // Discard current half-byte.
+ f.nb = 0
+ f.b = 0
+
+ if len(f.in) < 4 {
+ f.err = true
+ return
+ }
+
+ buf := f.in[:4]
+ f.in = f.in[4:]
+ n := int(buf[0]) | int(buf[1])<<8
+ nn := int(buf[2]) | int(buf[3])<<8
+ if uint16(nn) != uint16(^n) {
+ f.err = true
+ return
+ }
+
+ if len(f.in) < n {
+ f.err = true
+ return
+ }
+ f.out = append(f.out, f.in[:n]...)
+ f.in = f.in[n:]
+}
+
+func (f *decompressor) moreBits() {
+ if len(f.in) == 0 {
+ f.err = true
+ return
+ }
+ c := f.in[0]
+ f.in = f.in[1:]
+ f.b |= uint32(c) << f.nb
+ f.nb += 8
+}
+
+// Read the next Huffman-encoded symbol from f according to h.
+func (f *decompressor) huffSym(h *huffmanDecoder) int {
+ for n := uint(h.min); n <= uint(h.max); n++ {
+ lim := h.limit[n]
+ if lim == -1 {
+ continue
+ }
+ for f.nb < n {
+ if f.moreBits(); f.err {
+ return 0
+ }
+ }
+ v := int(f.b & uint32(1<<n-1))
+ v <<= 16 - n
+ v = int(reverseByte[v>>8]) | int(reverseByte[v&0xFF])<<8 // reverse bits
+ if v <= lim {
+ f.b >>= n
+ f.nb -= n
+ return h.codes[v-h.base[n]]
+ }
+ }
+ f.err = true
+ return 0
+}
+
+var reverseByte = [256]byte{
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
+}
+
+// Hard-coded Huffman tables for DEFLATE algorithm.
+// See RFC 1951, section 3.2.6.
+var fixedHuffmanDecoder = huffmanDecoder{
+ 7, 9,
+ [maxCodeLen + 1]int{7: 23, 199, 511},
+ [maxCodeLen + 1]int{7: 0, 24, 224},
+ []int{
+ // length 7: 256-279
+ 256, 257, 258, 259, 260, 261, 262,
+ 263, 264, 265, 266, 267, 268, 269,
+ 270, 271, 272, 273, 274, 275, 276,
+ 277, 278, 279,
+
+ // length 8: 0-143
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
+ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
+ 92, 93, 94, 95, 96, 97, 98, 99, 100,
+ 101, 102, 103, 104, 105, 106, 107, 108,
+ 109, 110, 111, 112, 113, 114, 115, 116,
+ 117, 118, 119, 120, 121, 122, 123, 124,
+ 125, 126, 127, 128, 129, 130, 131, 132,
+ 133, 134, 135, 136, 137, 138, 139, 140,
+ 141, 142, 143,
+
+ // length 8: 280-287
+ 280, 281, 282, 283, 284, 285, 286, 287,
+
+ // length 9: 144-255
+ 144, 145, 146, 147, 148, 149, 150, 151,
+ 152, 153, 154, 155, 156, 157, 158, 159,
+ 160, 161, 162, 163, 164, 165, 166, 167,
+ 168, 169, 170, 171, 172, 173, 174, 175,
+ 176, 177, 178, 179, 180, 181, 182, 183,
+ 184, 185, 186, 187, 188, 189, 190, 191,
+ 192, 193, 194, 195, 196, 197, 198, 199,
+ 200, 201, 202, 203, 204, 205, 206, 207,
+ 208, 209, 210, 211, 212, 213, 214, 215,
+ 216, 217, 218, 219, 220, 221, 222, 223,
+ 224, 225, 226, 227, 228, 229, 230, 231,
+ 232, 233, 234, 235, 236, 237, 238, 239,
+ 240, 241, 242, 243, 244, 245, 246, 247,
+ 248, 249, 250, 251, 252, 253, 254, 255,
+ },
+}
+
+// Huffman decoder is based on
+// J. Brian Connell, ``A Huffman-Shannon-Fano Code,''
+// Proceedings of the IEEE, 61(7) (July 1973), pp 1046-1047.
+type huffmanDecoder struct {
+ // min, max code length
+ min, max int
+
+ // limit[i] = largest code word of length i
+ // Given code v of length n,
+ // need more bits if v > limit[n].
+ limit [maxCodeLen + 1]int
+
+ // base[i] = smallest code word of length i - seq number
+ base [maxCodeLen + 1]int
+
+ // codes[seq number] = output code.
+ // Given code v of length n, value is
+ // codes[v - base[n]].
+ codes []int
+}
+
+// Initialize Huffman decoding tables from array of code lengths.
+func (h *huffmanDecoder) init(bits []int) bool {
+ // Count number of codes of each length,
+ // compute min and max length.
+ var count [maxCodeLen + 1]int
+ var min, max int
+ for _, n := range bits {
+ if n == 0 {
+ continue
+ }
+ if min == 0 || n < min {
+ min = n
+ }
+ if n > max {
+ max = n
+ }
+ count[n]++
+ }
+ if max == 0 {
+ return false
+ }
+
+ h.min = min
+ h.max = max
+
+ // For each code range, compute
+ // nextcode (first code of that length),
+ // limit (last code of that length), and
+ // base (offset from first code to sequence number).
+ code := 0
+ seq := 0
+ var nextcode [maxCodeLen]int
+ for i := min; i <= max; i++ {
+ n := count[i]
+ nextcode[i] = code
+ h.base[i] = code - seq
+ code += n
+ seq += n
+ h.limit[i] = code - 1
+ code <<= 1
+ }
+
+ // Make array mapping sequence numbers to codes.
+ if len(h.codes) < len(bits) {
+ h.codes = make([]int, len(bits))
+ }
+ for i, n := range bits {
+ if n == 0 {
+ continue
+ }
+ code := nextcode[n]
+ nextcode[n]++
+ seq := code - h.base[n]
+ h.codes[seq] = i
+ }
+ return true
+}
+
+func inflate(in string) (out []byte) {
+ var d decompressor
+ d.in = in
+ for !d.err && !d.eof {
+ d.nextBlock()
+ }
+ if len(d.in) != 0 {
+ println("fs unzip: junk at end of compressed data")
+ return nil
+ }
+ return d.out
+}
+
+// get4 returns the little-endian 32-bit value in b.
+func zget4(b string) int {
+ if len(b) < 4 {
+ return 0
+ }
+ return int(b[0]) | int(b[1])<<8 | int(b[2])<<16 | int(b[3])<<24
+}
+
+// get2 returns the little-endian 16-bit value in b.
+func zget2(b string) int {
+ if len(b) < 2 {
+ return 0
+ }
+ return int(b[0]) | int(b[1])<<8
+}
+
+func unzip(data string) {
+ const (
+ zecheader = 0x06054b50
+ zcheader = 0x02014b50
+ ztailsize = 22
+ zheadersize = 30
+ zheader = 0x04034b50
+ )
+
+ buf := data[len(data)-ztailsize:]
+ n := zget2(buf[10:])
+ size := zget4(buf[12:])
+ off := zget4(buf[16:])
+
+ hdr := data[off : off+size]
+ for i := 0; i < n; i++ {
+ // zip entry layout:
+ // 0 magic[4]
+ // 4 madevers[1]
+ // 5 madeos[1]
+ // 6 extvers[1]
+ // 7 extos[1]
+ // 8 flags[2]
+ // 10 meth[2]
+ // 12 modtime[2]
+ // 14 moddate[2]
+ // 16 crc[4]
+ // 20 csize[4]
+ // 24 uncsize[4]
+ // 28 namelen[2]
+ // 30 xlen[2]
+ // 32 fclen[2]
+ // 34 disknum[2]
+ // 36 iattr[2]
+ // 38 eattr[4]
+ // 42 off[4]
+ // 46 name[namelen]
+ // 46+namelen+xlen+fclen - next header
+ //
+ if zget4(hdr) != zcheader {
+ println("fs unzip: bad magic")
+ break
+ }
+ meth := zget2(hdr[10:])
+ mtime := zget2(hdr[12:])
+ mdate := zget2(hdr[14:])
+ csize := zget4(hdr[20:])
+ size := zget4(hdr[24:])
+ namelen := zget2(hdr[28:])
+ xlen := zget2(hdr[30:])
+ fclen := zget2(hdr[32:])
+ xattr := uint32(zget4(hdr[38:])) >> 16
+ off := zget4(hdr[42:])
+ name := hdr[46 : 46+namelen]
+ hdr = hdr[46+namelen+xlen+fclen:]
+
+ // zip per-file header layout:
+ // 0 magic[4]
+ // 4 extvers[1]
+ // 5 extos[1]
+ // 6 flags[2]
+ // 8 meth[2]
+ // 10 modtime[2]
+ // 12 moddate[2]
+ // 14 crc[4]
+ // 18 csize[4]
+ // 22 uncsize[4]
+ // 26 namelen[2]
+ // 28 xlen[2]
+ // 30 name[namelen]
+ // 30+namelen+xlen - file data
+ //
+ buf := data[off : off+zheadersize+namelen]
+ if zget4(buf) != zheader ||
+ zget2(buf[8:]) != meth ||
+ zget2(buf[26:]) != namelen ||
+ buf[30:30+namelen] != name {
+ println("fs unzip: inconsistent zip file")
+ return
+ }
+ xlen = zget2(buf[28:])
+
+ off += zheadersize + namelen + xlen
+
+ var fdata []byte
+ switch meth {
+ case 0:
+ // buf is uncompressed
+ buf = data[off : off+size]
+ fdata = []byte(buf)
+ case 8:
+ // buf is deflate-compressed
+ buf = data[off : off+csize]
+ fdata = inflate(buf)
+ if len(fdata) != size {
+ println("fs unzip: inconsistent size in zip file")
+ return
+ }
+ }
+
+ if xattr&S_IFMT == 0 {
+ if xattr&0777 == 0 {
+ xattr |= 0666
+ }
+ if len(name) > 0 && name[len(name)-1] == '/' {
+ xattr |= S_IFDIR
+ xattr |= 0111
+ } else {
+ xattr |= S_IFREG
+ }
+ }
+
+ if err := create(name, xattr, zipToTime(mdate, mtime), fdata); err != nil {
+ print("fs unzip: create ", name, ": ", err.Error(), "\n")
+ }
+ }
+
+ chdirEnv()
+}
+
+func zipToTime(date, time int) int64 {
+ dd := date & 0x1f
+ mm := date >> 5 & 0xf
+ yy := date >> 9 // since 1980
+
+ sec := int64(315532800) // jan 1 1980
+ sec += int64(yy) * 365 * 86400
+ sec += int64(yy) / 4 * 86400
+ if yy%4 > 0 || mm >= 3 {
+ sec += 86400
+ }
+ sec += int64(daysBeforeMonth[mm]) * 86400
+ sec += int64(dd-1) * 86400
+
+ h := time >> 11
+ m := time >> 5 & 0x3F
+ s := time & 0x1f * 2
+ sec += int64(h*3600 + m*60 + s)
+
+ return sec
+}
+
+var daysBeforeMonth = [...]int32{
+ 0,
+ 0,
+ 31,
+ 31 + 28,
+ 31 + 28 + 31,
+ 31 + 28 + 31 + 30,
+ 31 + 28 + 31 + 30 + 31,
+ 31 + 28 + 31 + 30 + 31 + 30,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31,
+}
diff --git a/src/pkg/syscall/zerrors_dragonfly_386.go b/src/pkg/syscall/zerrors_dragonfly_386.go
index a2eb926ee..701a1c381 100644
--- a/src/pkg/syscall/zerrors_dragonfly_386.go
+++ b/src/pkg/syscall/zerrors_dragonfly_386.go
@@ -311,7 +311,10 @@ const (
FD_CLOEXEC = 0x1
FD_SETSIZE = 0x400
FLUSHO = 0x800000
+ F_DUP2FD = 0xa
+ F_DUP2FD_CLOEXEC = 0x12
F_DUPFD = 0x0
+ F_DUPFD_CLOEXEC = 0x11
F_GETFD = 0x1
F_GETFL = 0x3
F_GETLK = 0x7
@@ -1475,7 +1478,7 @@ var errors = [...]string{
90: "multihop attempted",
91: "link has been severed",
92: "protocol error",
- 93: "unknown error: 93",
+ 93: "no medium found",
94: "unknown error: 94",
95: "unknown error: 95",
96: "unknown error: 96",
diff --git a/src/pkg/syscall/zerrors_dragonfly_amd64.go b/src/pkg/syscall/zerrors_dragonfly_amd64.go
index d2fe97c68..59bff751c 100644
--- a/src/pkg/syscall/zerrors_dragonfly_amd64.go
+++ b/src/pkg/syscall/zerrors_dragonfly_amd64.go
@@ -311,7 +311,10 @@ const (
FD_CLOEXEC = 0x1
FD_SETSIZE = 0x400
FLUSHO = 0x800000
+ F_DUP2FD = 0xa
+ F_DUP2FD_CLOEXEC = 0x12
F_DUPFD = 0x0
+ F_DUPFD_CLOEXEC = 0x11
F_GETFD = 0x1
F_GETFL = 0x3
F_GETLK = 0x7
@@ -1475,7 +1478,7 @@ var errors = [...]string{
90: "multihop attempted",
91: "link has been severed",
92: "protocol error",
- 93: "unknown error: 93",
+ 93: "no medium found",
94: "unknown error: 94",
95: "unknown error: 95",
96: "unknown error: 96",
diff --git a/src/pkg/syscall/zerrors_freebsd_386.go b/src/pkg/syscall/zerrors_freebsd_386.go
index 43d7c5969..cd3aa80a9 100644
--- a/src/pkg/syscall/zerrors_freebsd_386.go
+++ b/src/pkg/syscall/zerrors_freebsd_386.go
@@ -25,13 +25,15 @@ const (
AF_IMPLINK = 0x3
AF_INET = 0x2
AF_INET6 = 0x1c
+ AF_INET6_SDP = 0x2a
+ AF_INET_SDP = 0x28
AF_IPX = 0x17
AF_ISDN = 0x1a
AF_ISO = 0x7
AF_LAT = 0xe
AF_LINK = 0x12
AF_LOCAL = 0x1
- AF_MAX = 0x26
+ AF_MAX = 0x2a
AF_NATM = 0x1d
AF_NETBIOS = 0x6
AF_NETGRAPH = 0x20
@@ -332,10 +334,11 @@ const (
DLT_LINUX_SLL = 0x71
DLT_LOOP = 0x6c
DLT_LTALK = 0x72
- DLT_MATCHING_MAX = 0xf2
+ DLT_MATCHING_MAX = 0xf6
DLT_MATCHING_MIN = 0x68
DLT_MFR = 0xb6
DLT_MOST = 0xd3
+ DLT_MPEG_2_TS = 0xf3
DLT_MPLS = 0xdb
DLT_MTP2 = 0x8c
DLT_MTP2_WITH_PHDR = 0x8b
@@ -343,7 +346,9 @@ const (
DLT_MUX27010 = 0xec
DLT_NETANALYZER = 0xf0
DLT_NETANALYZER_TRANSPARENT = 0xf1
+ DLT_NFC_LLCP = 0xf5
DLT_NFLOG = 0xef
+ DLT_NG40 = 0xf4
DLT_NULL = 0x0
DLT_PCI_EXP = 0x7d
DLT_PFLOG = 0x75
@@ -423,6 +428,7 @@ const (
EV_DELETE = 0x2
EV_DISABLE = 0x8
EV_DISPATCH = 0x80
+ EV_DROP = 0x1000
EV_ENABLE = 0x4
EV_EOF = 0x8000
EV_ERROR = 0x4000
@@ -789,6 +795,7 @@ const (
IPPROTO_MHRP = 0x30
IPPROTO_MICP = 0x5f
IPPROTO_MOBILE = 0x37
+ IPPROTO_MPLS = 0x89
IPPROTO_MTP = 0x5c
IPPROTO_MUX = 0x12
IPPROTO_ND = 0x4d
@@ -996,6 +1003,9 @@ const (
MADV_RANDOM = 0x1
MADV_SEQUENTIAL = 0x2
MADV_WILLNEED = 0x3
+ MAP_ALIGNED_SUPER = 0x1000000
+ MAP_ALIGNMENT_MASK = -0x1000000
+ MAP_ALIGNMENT_SHIFT = 0x18
MAP_ANON = 0x1000
MAP_ANONYMOUS = 0x1000
MAP_COPY = 0x2
@@ -1014,6 +1024,7 @@ const (
MAP_STACK = 0x400
MCL_CURRENT = 0x1
MCL_FUTURE = 0x2
+ MSG_CMSG_CLOEXEC = 0x40000
MSG_COMPAT = 0x8000
MSG_CTRUNC = 0x20
MSG_DONTROUTE = 0x4
@@ -1030,6 +1041,7 @@ const (
MS_ASYNC = 0x1
MS_INVALIDATE = 0x2
MS_SYNC = 0x0
+ NAME_MAX = 0xff
NET_RT_DUMP = 0x1
NET_RT_FLAGS = 0x2
NET_RT_IFLIST = 0x3
@@ -1069,6 +1081,7 @@ const (
O_ACCMODE = 0x3
O_APPEND = 0x8
O_ASYNC = 0x40
+ O_CLOEXEC = 0x100000
O_CREAT = 0x200
O_DIRECT = 0x10000
O_DIRECTORY = 0x20000
@@ -1129,6 +1142,7 @@ const (
RTF_DYNAMIC = 0x10
RTF_FMASK = 0x1004d808
RTF_GATEWAY = 0x2
+ RTF_GWFLAG_COMPAT = 0x80000000
RTF_HOST = 0x4
RTF_LLDATA = 0x400
RTF_LLINFO = 0x400
@@ -1177,6 +1191,7 @@ const (
RTV_WEIGHT = 0x100
RT_CACHING_CONTEXT = 0x1
RT_DEFAULT_FIB = 0x0
+ RT_NORTREF = 0x2
RUSAGE_CHILDREN = -0x1
RUSAGE_SELF = 0x0
RUSAGE_THREAD = 0x1
@@ -1258,8 +1273,10 @@ const (
SIOCSLIFPHYADDR = 0x8118694a
SIOCSLOWAT = 0x80047302
SIOCSPGRP = 0x80047308
+ SOCK_CLOEXEC = 0x10000000
SOCK_DGRAM = 0x2
SOCK_MAXADDRLEN = 0xff
+ SOCK_NONBLOCK = 0x20000000
SOCK_RAW = 0x3
SOCK_RDM = 0x4
SOCK_SEQPACKET = 0x5
@@ -1299,6 +1316,7 @@ const (
SO_TYPE = 0x1008
SO_USELOOPBACK = 0x40
SO_USER_COOKIE = 0x1015
+ SO_VENDOR = 0x80000000
TCIFLUSH = 0x1
TCIOFLUSH = 0x3
TCOFLUSH = 0x2
@@ -1322,6 +1340,7 @@ const (
TCP_NODELAY = 0x1
TCP_NOOPT = 0x8
TCP_NOPUSH = 0x4
+ TCP_VENDOR = 0x80000000
TCSAFLUSH = 0x2
TIOCCBRK = 0x2000747a
TIOCCDTR = 0x20007478
@@ -1407,10 +1426,12 @@ const (
VWERASE = 0x4
WCONTINUED = 0x4
WCOREFLAG = 0x80
+ WEXITED = 0x10
WLINUXCLONE = 0x80000000
WNOHANG = 0x1
WNOWAIT = 0x8
WSTOPPED = 0x2
+ WTRAPPED = 0x20
WUNTRACED = 0x2
)
@@ -1453,7 +1474,7 @@ const (
EIO = Errno(0x5)
EISCONN = Errno(0x38)
EISDIR = Errno(0x15)
- ELAST = Errno(0x5e)
+ ELAST = Errno(0x60)
ELOOP = Errno(0x3e)
EMFILE = Errno(0x18)
EMLINK = Errno(0x1f)
@@ -1482,12 +1503,14 @@ const (
ENOTCONN = Errno(0x39)
ENOTDIR = Errno(0x14)
ENOTEMPTY = Errno(0x42)
+ ENOTRECOVERABLE = Errno(0x5f)
ENOTSOCK = Errno(0x26)
ENOTSUP = Errno(0x2d)
ENOTTY = Errno(0x19)
ENXIO = Errno(0x6)
EOPNOTSUPP = Errno(0x2d)
EOVERFLOW = Errno(0x54)
+ EOWNERDEAD = Errno(0x60)
EPERM = Errno(0x1)
EPFNOSUPPORT = Errno(0x2e)
EPIPE = Errno(0x20)
@@ -1531,6 +1554,7 @@ const (
SIGIO = Signal(0x17)
SIGIOT = Signal(0x6)
SIGKILL = Signal(0x9)
+ SIGLIBRT = Signal(0x21)
SIGLWP = Signal(0x20)
SIGPIPE = Signal(0xd)
SIGPROF = Signal(0x1b)
@@ -1649,6 +1673,8 @@ var errors = [...]string{
92: "protocol error",
93: "capabilities insufficient",
94: "not permitted in capability mode",
+ 95: "state not recoverable",
+ 96: "previous owner died",
}
// Signal table
@@ -1685,4 +1711,5 @@ var signals = [...]string{
30: "user defined signal 1",
31: "user defined signal 2",
32: "unknown signal",
+ 33: "unknown signal",
}
diff --git a/src/pkg/syscall/zerrors_freebsd_amd64.go b/src/pkg/syscall/zerrors_freebsd_amd64.go
index 8e03f45e2..9edce6e2f 100644
--- a/src/pkg/syscall/zerrors_freebsd_amd64.go
+++ b/src/pkg/syscall/zerrors_freebsd_amd64.go
@@ -25,13 +25,15 @@ const (
AF_IMPLINK = 0x3
AF_INET = 0x2
AF_INET6 = 0x1c
+ AF_INET6_SDP = 0x2a
+ AF_INET_SDP = 0x28
AF_IPX = 0x17
AF_ISDN = 0x1a
AF_ISO = 0x7
AF_LAT = 0xe
AF_LINK = 0x12
AF_LOCAL = 0x1
- AF_MAX = 0x26
+ AF_MAX = 0x2a
AF_NATM = 0x1d
AF_NETBIOS = 0x6
AF_NETGRAPH = 0x20
@@ -332,10 +334,11 @@ const (
DLT_LINUX_SLL = 0x71
DLT_LOOP = 0x6c
DLT_LTALK = 0x72
- DLT_MATCHING_MAX = 0xf2
+ DLT_MATCHING_MAX = 0xf6
DLT_MATCHING_MIN = 0x68
DLT_MFR = 0xb6
DLT_MOST = 0xd3
+ DLT_MPEG_2_TS = 0xf3
DLT_MPLS = 0xdb
DLT_MTP2 = 0x8c
DLT_MTP2_WITH_PHDR = 0x8b
@@ -343,7 +346,9 @@ const (
DLT_MUX27010 = 0xec
DLT_NETANALYZER = 0xf0
DLT_NETANALYZER_TRANSPARENT = 0xf1
+ DLT_NFC_LLCP = 0xf5
DLT_NFLOG = 0xef
+ DLT_NG40 = 0xf4
DLT_NULL = 0x0
DLT_PCI_EXP = 0x7d
DLT_PFLOG = 0x75
@@ -423,6 +428,7 @@ const (
EV_DELETE = 0x2
EV_DISABLE = 0x8
EV_DISPATCH = 0x80
+ EV_DROP = 0x1000
EV_ENABLE = 0x4
EV_EOF = 0x8000
EV_ERROR = 0x4000
@@ -789,6 +795,7 @@ const (
IPPROTO_MHRP = 0x30
IPPROTO_MICP = 0x5f
IPPROTO_MOBILE = 0x37
+ IPPROTO_MPLS = 0x89
IPPROTO_MTP = 0x5c
IPPROTO_MUX = 0x12
IPPROTO_ND = 0x4d
@@ -996,6 +1003,10 @@ const (
MADV_RANDOM = 0x1
MADV_SEQUENTIAL = 0x2
MADV_WILLNEED = 0x3
+ MAP_32BIT = 0x80000
+ MAP_ALIGNED_SUPER = 0x1000000
+ MAP_ALIGNMENT_MASK = -0x1000000
+ MAP_ALIGNMENT_SHIFT = 0x18
MAP_ANON = 0x1000
MAP_ANONYMOUS = 0x1000
MAP_COPY = 0x2
@@ -1014,6 +1025,7 @@ const (
MAP_STACK = 0x400
MCL_CURRENT = 0x1
MCL_FUTURE = 0x2
+ MSG_CMSG_CLOEXEC = 0x40000
MSG_COMPAT = 0x8000
MSG_CTRUNC = 0x20
MSG_DONTROUTE = 0x4
@@ -1030,6 +1042,7 @@ const (
MS_ASYNC = 0x1
MS_INVALIDATE = 0x2
MS_SYNC = 0x0
+ NAME_MAX = 0xff
NET_RT_DUMP = 0x1
NET_RT_FLAGS = 0x2
NET_RT_IFLIST = 0x3
@@ -1069,6 +1082,7 @@ const (
O_ACCMODE = 0x3
O_APPEND = 0x8
O_ASYNC = 0x40
+ O_CLOEXEC = 0x100000
O_CREAT = 0x200
O_DIRECT = 0x10000
O_DIRECTORY = 0x20000
@@ -1129,6 +1143,7 @@ const (
RTF_DYNAMIC = 0x10
RTF_FMASK = 0x1004d808
RTF_GATEWAY = 0x2
+ RTF_GWFLAG_COMPAT = 0x80000000
RTF_HOST = 0x4
RTF_LLDATA = 0x400
RTF_LLINFO = 0x400
@@ -1177,6 +1192,7 @@ const (
RTV_WEIGHT = 0x100
RT_CACHING_CONTEXT = 0x1
RT_DEFAULT_FIB = 0x0
+ RT_NORTREF = 0x2
RUSAGE_CHILDREN = -0x1
RUSAGE_SELF = 0x0
RUSAGE_THREAD = 0x1
@@ -1258,8 +1274,10 @@ const (
SIOCSLIFPHYADDR = 0x8118694a
SIOCSLOWAT = 0x80047302
SIOCSPGRP = 0x80047308
+ SOCK_CLOEXEC = 0x10000000
SOCK_DGRAM = 0x2
SOCK_MAXADDRLEN = 0xff
+ SOCK_NONBLOCK = 0x20000000
SOCK_RAW = 0x3
SOCK_RDM = 0x4
SOCK_SEQPACKET = 0x5
@@ -1299,6 +1317,7 @@ const (
SO_TYPE = 0x1008
SO_USELOOPBACK = 0x40
SO_USER_COOKIE = 0x1015
+ SO_VENDOR = 0x80000000
TCIFLUSH = 0x1
TCIOFLUSH = 0x3
TCOFLUSH = 0x2
@@ -1322,6 +1341,7 @@ const (
TCP_NODELAY = 0x1
TCP_NOOPT = 0x8
TCP_NOPUSH = 0x4
+ TCP_VENDOR = 0x80000000
TCSAFLUSH = 0x2
TIOCCBRK = 0x2000747a
TIOCCDTR = 0x20007478
@@ -1407,10 +1427,12 @@ const (
VWERASE = 0x4
WCONTINUED = 0x4
WCOREFLAG = 0x80
+ WEXITED = 0x10
WLINUXCLONE = 0x80000000
WNOHANG = 0x1
WNOWAIT = 0x8
WSTOPPED = 0x2
+ WTRAPPED = 0x20
WUNTRACED = 0x2
)
@@ -1453,7 +1475,7 @@ const (
EIO = Errno(0x5)
EISCONN = Errno(0x38)
EISDIR = Errno(0x15)
- ELAST = Errno(0x5e)
+ ELAST = Errno(0x60)
ELOOP = Errno(0x3e)
EMFILE = Errno(0x18)
EMLINK = Errno(0x1f)
@@ -1482,12 +1504,14 @@ const (
ENOTCONN = Errno(0x39)
ENOTDIR = Errno(0x14)
ENOTEMPTY = Errno(0x42)
+ ENOTRECOVERABLE = Errno(0x5f)
ENOTSOCK = Errno(0x26)
ENOTSUP = Errno(0x2d)
ENOTTY = Errno(0x19)
ENXIO = Errno(0x6)
EOPNOTSUPP = Errno(0x2d)
EOVERFLOW = Errno(0x54)
+ EOWNERDEAD = Errno(0x60)
EPERM = Errno(0x1)
EPFNOSUPPORT = Errno(0x2e)
EPIPE = Errno(0x20)
@@ -1531,6 +1555,7 @@ const (
SIGIO = Signal(0x17)
SIGIOT = Signal(0x6)
SIGKILL = Signal(0x9)
+ SIGLIBRT = Signal(0x21)
SIGLWP = Signal(0x20)
SIGPIPE = Signal(0xd)
SIGPROF = Signal(0x1b)
@@ -1649,6 +1674,8 @@ var errors = [...]string{
92: "protocol error",
93: "capabilities insufficient",
94: "not permitted in capability mode",
+ 95: "state not recoverable",
+ 96: "previous owner died",
}
// Signal table
@@ -1685,4 +1712,5 @@ var signals = [...]string{
30: "user defined signal 1",
31: "user defined signal 2",
32: "unknown signal",
+ 33: "unknown signal",
}
diff --git a/src/pkg/syscall/zerrors_freebsd_arm.go b/src/pkg/syscall/zerrors_freebsd_arm.go
index 269f179b3..f29dd057b 100644
--- a/src/pkg/syscall/zerrors_freebsd_arm.go
+++ b/src/pkg/syscall/zerrors_freebsd_arm.go
@@ -25,13 +25,15 @@ const (
AF_IMPLINK = 0x3
AF_INET = 0x2
AF_INET6 = 0x1c
+ AF_INET6_SDP = 0x2a
+ AF_INET_SDP = 0x28
AF_IPX = 0x17
AF_ISDN = 0x1a
AF_ISO = 0x7
AF_LAT = 0xe
AF_LINK = 0x12
AF_LOCAL = 0x1
- AF_MAX = 0x26
+ AF_MAX = 0x2a
AF_NATM = 0x1d
AF_NETBIOS = 0x6
AF_NETGRAPH = 0x20
@@ -128,7 +130,7 @@ const (
BIOCGETZMAX = 0x4004427f
BIOCGHDRCMPLT = 0x40044274
BIOCGRSIG = 0x40044272
- BIOCGRTIMEOUT = 0x400c426e
+ BIOCGRTIMEOUT = 0x4010426e
BIOCGSEESENT = 0x40044276
BIOCGSTATS = 0x4008426f
BIOCGTSTAMP = 0x40044283
@@ -147,7 +149,7 @@ const (
BIOCSETZBUF = 0x800c4281
BIOCSHDRCMPLT = 0x80044275
BIOCSRSIG = 0x80044273
- BIOCSRTIMEOUT = 0x800c426d
+ BIOCSRTIMEOUT = 0x8010426d
BIOCSSEESENT = 0x80044277
BIOCSTSTAMP = 0x80044284
BIOCVERSION = 0x40044271
@@ -426,6 +428,7 @@ const (
EV_DELETE = 0x2
EV_DISABLE = 0x8
EV_DISPATCH = 0x80
+ EV_DROP = 0x1000
EV_ENABLE = 0x4
EV_EOF = 0x8000
EV_ERROR = 0x4000
@@ -521,6 +524,7 @@ const (
IFT_BGPPOLICYACCOUNTING = 0xa2
IFT_BRIDGE = 0xd1
IFT_BSC = 0x53
+ IFT_CARP = 0xf8
IFT_CCTEMUL = 0x3d
IFT_CEPT = 0x13
IFT_CES = 0x85
@@ -999,6 +1003,9 @@ const (
MADV_RANDOM = 0x1
MADV_SEQUENTIAL = 0x2
MADV_WILLNEED = 0x3
+ MAP_ALIGNED_SUPER = 0x1000000
+ MAP_ALIGNMENT_MASK = -0x1000000
+ MAP_ALIGNMENT_SHIFT = 0x18
MAP_ANON = 0x1000
MAP_ANONYMOUS = 0x1000
MAP_COPY = 0x2
@@ -1017,6 +1024,7 @@ const (
MAP_STACK = 0x400
MCL_CURRENT = 0x1
MCL_FUTURE = 0x2
+ MSG_CMSG_CLOEXEC = 0x40000
MSG_COMPAT = 0x8000
MSG_CTRUNC = 0x20
MSG_DONTROUTE = 0x4
@@ -1033,6 +1041,7 @@ const (
MS_ASYNC = 0x1
MS_INVALIDATE = 0x2
MS_SYNC = 0x0
+ NAME_MAX = 0xff
NET_RT_DUMP = 0x1
NET_RT_FLAGS = 0x2
NET_RT_IFLIST = 0x3
@@ -1072,6 +1081,7 @@ const (
O_ACCMODE = 0x3
O_APPEND = 0x8
O_ASYNC = 0x40
+ O_CLOEXEC = 0x100000
O_CREAT = 0x200
O_DIRECT = 0x10000
O_DIRECTORY = 0x20000
@@ -1132,6 +1142,7 @@ const (
RTF_DYNAMIC = 0x10
RTF_FMASK = 0x1004d808
RTF_GATEWAY = 0x2
+ RTF_GWFLAG_COMPAT = 0x80000000
RTF_HOST = 0x4
RTF_LLDATA = 0x400
RTF_LLINFO = 0x400
@@ -1193,7 +1204,7 @@ const (
SHUT_WR = 0x1
SIOCADDMULTI = 0x80206931
SIOCADDRT = 0x8030720a
- SIOCAIFADDR = 0x8044692b
+ SIOCAIFADDR = 0x8040691a
SIOCAIFGROUP = 0x80246987
SIOCALIFADDR = 0x8118691b
SIOCATMARK = 0x40047307
@@ -1227,7 +1238,7 @@ const (
SIOCGIFPDSTADDR = 0xc0206948
SIOCGIFPHYS = 0xc0206935
SIOCGIFPSRCADDR = 0xc0206947
- SIOCGIFSTATUS = 0xc334693b
+ SIOCGIFSTATUS = 0xc331693b
SIOCGLIFADDR = 0xc118691c
SIOCGLIFPHYADDR = 0xc118694b
SIOCGLOWAT = 0x40047303
@@ -1255,15 +1266,17 @@ const (
SIOCSIFMTU = 0x80206934
SIOCSIFNAME = 0x80206928
SIOCSIFNETMASK = 0x80206916
- SIOCSIFPHYADDR = 0x80446946
+ SIOCSIFPHYADDR = 0x80406946
SIOCSIFPHYS = 0x80206936
SIOCSIFRVNET = 0xc020695b
SIOCSIFVNET = 0xc020695a
SIOCSLIFPHYADDR = 0x8118694a
SIOCSLOWAT = 0x80047302
SIOCSPGRP = 0x80047308
+ SOCK_CLOEXEC = 0x10000000
SOCK_DGRAM = 0x2
SOCK_MAXADDRLEN = 0xff
+ SOCK_NONBLOCK = 0x20000000
SOCK_RAW = 0x3
SOCK_RDM = 0x4
SOCK_SEQPACKET = 0x5
@@ -1303,6 +1316,7 @@ const (
SO_TYPE = 0x1008
SO_USELOOPBACK = 0x40
SO_USER_COOKIE = 0x1015
+ SO_VENDOR = 0x80000000
TCIFLUSH = 0x1
TCIOFLUSH = 0x3
TCOFLUSH = 0x2
@@ -1326,6 +1340,7 @@ const (
TCP_NODELAY = 0x1
TCP_NOOPT = 0x8
TCP_NOPUSH = 0x4
+ TCP_VENDOR = 0x80000000
TCSAFLUSH = 0x2
TIOCCBRK = 0x2000747a
TIOCCDTR = 0x20007478
@@ -1387,7 +1402,7 @@ const (
TIOCSTI = 0x80017472
TIOCSTOP = 0x2000746f
TIOCSWINSZ = 0x80087467
- TIOCTIMESTAMP = 0x400c7459
+ TIOCTIMESTAMP = 0x40107459
TIOCUCNTL = 0x80047466
TOSTOP = 0x400000
VDISCARD = 0xf
@@ -1459,7 +1474,7 @@ const (
EIO = Errno(0x5)
EISCONN = Errno(0x38)
EISDIR = Errno(0x15)
- ELAST = Errno(0x5e)
+ ELAST = Errno(0x60)
ELOOP = Errno(0x3e)
EMFILE = Errno(0x18)
EMLINK = Errno(0x1f)
@@ -1488,12 +1503,14 @@ const (
ENOTCONN = Errno(0x39)
ENOTDIR = Errno(0x14)
ENOTEMPTY = Errno(0x42)
+ ENOTRECOVERABLE = Errno(0x5f)
ENOTSOCK = Errno(0x26)
ENOTSUP = Errno(0x2d)
ENOTTY = Errno(0x19)
ENXIO = Errno(0x6)
EOPNOTSUPP = Errno(0x2d)
EOVERFLOW = Errno(0x54)
+ EOWNERDEAD = Errno(0x60)
EPERM = Errno(0x1)
EPFNOSUPPORT = Errno(0x2e)
EPIPE = Errno(0x20)
@@ -1656,6 +1673,8 @@ var errors = [...]string{
92: "protocol error",
93: "capabilities insufficient",
94: "not permitted in capability mode",
+ 95: "state not recoverable",
+ 96: "previous owner died",
}
// Signal table
diff --git a/src/pkg/syscall/zerrors_netbsd_386.go b/src/pkg/syscall/zerrors_netbsd_386.go
index 9b93f5a15..1e3dff7fa 100644
--- a/src/pkg/syscall/zerrors_netbsd_386.go
+++ b/src/pkg/syscall/zerrors_netbsd_386.go
@@ -146,6 +146,14 @@ const (
BRKINT = 0x2
CFLUSH = 0xf
CLOCAL = 0x8000
+ CLONE_CSIGNAL = 0xff
+ CLONE_FILES = 0x400
+ CLONE_FS = 0x200
+ CLONE_PID = 0x1000
+ CLONE_PTRACE = 0x2000
+ CLONE_SIGHAND = 0x800
+ CLONE_VFORK = 0x4000
+ CLONE_VM = 0x100
CREAD = 0x800
CS5 = 0x0
CS6 = 0x100
@@ -962,6 +970,40 @@ const (
LOCK_NB = 0x4
LOCK_SH = 0x1
LOCK_UN = 0x8
+ MADV_DONTNEED = 0x4
+ MADV_FREE = 0x6
+ MADV_NORMAL = 0x0
+ MADV_RANDOM = 0x1
+ MADV_SEQUENTIAL = 0x2
+ MADV_SPACEAVAIL = 0x5
+ MADV_WILLNEED = 0x3
+ MAP_ALIGNMENT_16MB = 0x18000000
+ MAP_ALIGNMENT_1TB = 0x28000000
+ MAP_ALIGNMENT_256TB = 0x30000000
+ MAP_ALIGNMENT_4GB = 0x20000000
+ MAP_ALIGNMENT_64KB = 0x10000000
+ MAP_ALIGNMENT_64PB = 0x38000000
+ MAP_ALIGNMENT_MASK = -0x1000000
+ MAP_ALIGNMENT_SHIFT = 0x18
+ MAP_ANON = 0x1000
+ MAP_FILE = 0x0
+ MAP_FIXED = 0x10
+ MAP_HASSEMAPHORE = 0x200
+ MAP_INHERIT = 0x80
+ MAP_INHERIT_COPY = 0x1
+ MAP_INHERIT_DEFAULT = 0x1
+ MAP_INHERIT_DONATE_COPY = 0x3
+ MAP_INHERIT_NONE = 0x2
+ MAP_INHERIT_SHARE = 0x0
+ MAP_NORESERVE = 0x40
+ MAP_PRIVATE = 0x2
+ MAP_RENAME = 0x20
+ MAP_SHARED = 0x1
+ MAP_STACK = 0x2000
+ MAP_TRYFIXED = 0x400
+ MAP_WIRED = 0x800
+ MCL_CURRENT = 0x1
+ MCL_FUTURE = 0x2
MSG_BCAST = 0x100
MSG_CMSG_CLOEXEC = 0x800
MSG_CONTROLMBUF = 0x2000000
@@ -980,6 +1022,9 @@ const (
MSG_TRUNC = 0x10
MSG_USERFLAGS = 0xffffff
MSG_WAITALL = 0x40
+ MS_ASYNC = 0x1
+ MS_INVALIDATE = 0x2
+ MS_SYNC = 0x4
NAME_MAX = 0x1ff
NET_RT_DUMP = 0x1
NET_RT_FLAGS = 0x2
@@ -1039,10 +1084,14 @@ const (
PARMRK = 0x8
PARODD = 0x2000
PENDIN = 0x20000000
- PRI_IOFLUSH = 0x7c
PRIO_PGRP = 0x1
PRIO_PROCESS = 0x0
PRIO_USER = 0x2
+ PRI_IOFLUSH = 0x7c
+ PROT_EXEC = 0x4
+ PROT_NONE = 0x0
+ PROT_READ = 0x1
+ PROT_WRITE = 0x2
RLIMIT_AS = 0xa
RLIMIT_CORE = 0x4
RLIMIT_CPU = 0x0
diff --git a/src/pkg/syscall/zerrors_netbsd_amd64.go b/src/pkg/syscall/zerrors_netbsd_amd64.go
index 4db30fa5c..1469d00b7 100644
--- a/src/pkg/syscall/zerrors_netbsd_amd64.go
+++ b/src/pkg/syscall/zerrors_netbsd_amd64.go
@@ -146,6 +146,14 @@ const (
BRKINT = 0x2
CFLUSH = 0xf
CLOCAL = 0x8000
+ CLONE_CSIGNAL = 0xff
+ CLONE_FILES = 0x400
+ CLONE_FS = 0x200
+ CLONE_PID = 0x1000
+ CLONE_PTRACE = 0x2000
+ CLONE_SIGHAND = 0x800
+ CLONE_VFORK = 0x4000
+ CLONE_VM = 0x100
CREAD = 0x800
CS5 = 0x0
CS6 = 0x100
@@ -952,6 +960,40 @@ const (
LOCK_NB = 0x4
LOCK_SH = 0x1
LOCK_UN = 0x8
+ MADV_DONTNEED = 0x4
+ MADV_FREE = 0x6
+ MADV_NORMAL = 0x0
+ MADV_RANDOM = 0x1
+ MADV_SEQUENTIAL = 0x2
+ MADV_SPACEAVAIL = 0x5
+ MADV_WILLNEED = 0x3
+ MAP_ALIGNMENT_16MB = 0x18000000
+ MAP_ALIGNMENT_1TB = 0x28000000
+ MAP_ALIGNMENT_256TB = 0x30000000
+ MAP_ALIGNMENT_4GB = 0x20000000
+ MAP_ALIGNMENT_64KB = 0x10000000
+ MAP_ALIGNMENT_64PB = 0x38000000
+ MAP_ALIGNMENT_MASK = -0x1000000
+ MAP_ALIGNMENT_SHIFT = 0x18
+ MAP_ANON = 0x1000
+ MAP_FILE = 0x0
+ MAP_FIXED = 0x10
+ MAP_HASSEMAPHORE = 0x200
+ MAP_INHERIT = 0x80
+ MAP_INHERIT_COPY = 0x1
+ MAP_INHERIT_DEFAULT = 0x1
+ MAP_INHERIT_DONATE_COPY = 0x3
+ MAP_INHERIT_NONE = 0x2
+ MAP_INHERIT_SHARE = 0x0
+ MAP_NORESERVE = 0x40
+ MAP_PRIVATE = 0x2
+ MAP_RENAME = 0x20
+ MAP_SHARED = 0x1
+ MAP_STACK = 0x2000
+ MAP_TRYFIXED = 0x400
+ MAP_WIRED = 0x800
+ MCL_CURRENT = 0x1
+ MCL_FUTURE = 0x2
MSG_BCAST = 0x100
MSG_CMSG_CLOEXEC = 0x800
MSG_CONTROLMBUF = 0x2000000
@@ -970,6 +1012,9 @@ const (
MSG_TRUNC = 0x10
MSG_USERFLAGS = 0xffffff
MSG_WAITALL = 0x40
+ MS_ASYNC = 0x1
+ MS_INVALIDATE = 0x2
+ MS_SYNC = 0x4
NAME_MAX = 0x1ff
NET_RT_DUMP = 0x1
NET_RT_FLAGS = 0x2
@@ -1029,10 +1074,14 @@ const (
PARMRK = 0x8
PARODD = 0x2000
PENDIN = 0x20000000
- PRI_IOFLUSH = 0x7c
PRIO_PGRP = 0x1
PRIO_PROCESS = 0x0
PRIO_USER = 0x2
+ PRI_IOFLUSH = 0x7c
+ PROT_EXEC = 0x4
+ PROT_NONE = 0x0
+ PROT_READ = 0x1
+ PROT_WRITE = 0x2
RLIMIT_AS = 0xa
RLIMIT_CORE = 0x4
RLIMIT_CPU = 0x0
diff --git a/src/pkg/syscall/zerrors_netbsd_arm.go b/src/pkg/syscall/zerrors_netbsd_arm.go
index 9262d5afb..1a88c0d22 100644
--- a/src/pkg/syscall/zerrors_netbsd_arm.go
+++ b/src/pkg/syscall/zerrors_netbsd_arm.go
@@ -952,6 +952,38 @@ const (
LOCK_NB = 0x4
LOCK_SH = 0x1
LOCK_UN = 0x8
+ MADV_DONTNEED = 0x4
+ MADV_FREE = 0x6
+ MADV_NORMAL = 0x0
+ MADV_RANDOM = 0x1
+ MADV_SEQUENTIAL = 0x2
+ MADV_SPACEAVAIL = 0x5
+ MADV_WILLNEED = 0x3
+ MAP_ALIGNMENT_16MB = 0x18000000
+ MAP_ALIGNMENT_1TB = 0x28000000
+ MAP_ALIGNMENT_256TB = 0x30000000
+ MAP_ALIGNMENT_4GB = 0x20000000
+ MAP_ALIGNMENT_64KB = 0x10000000
+ MAP_ALIGNMENT_64PB = 0x38000000
+ MAP_ALIGNMENT_MASK = -0x1000000
+ MAP_ALIGNMENT_SHIFT = 0x18
+ MAP_ANON = 0x1000
+ MAP_FILE = 0x0
+ MAP_FIXED = 0x10
+ MAP_HASSEMAPHORE = 0x200
+ MAP_INHERIT = 0x80
+ MAP_INHERIT_COPY = 0x1
+ MAP_INHERIT_DEFAULT = 0x1
+ MAP_INHERIT_DONATE_COPY = 0x3
+ MAP_INHERIT_NONE = 0x2
+ MAP_INHERIT_SHARE = 0x0
+ MAP_NORESERVE = 0x40
+ MAP_PRIVATE = 0x2
+ MAP_RENAME = 0x20
+ MAP_SHARED = 0x1
+ MAP_STACK = 0x2000
+ MAP_TRYFIXED = 0x400
+ MAP_WIRED = 0x800
MSG_BCAST = 0x100
MSG_CMSG_CLOEXEC = 0x800
MSG_CONTROLMBUF = 0x2000000
@@ -1029,6 +1061,10 @@ const (
PARMRK = 0x8
PARODD = 0x2000
PENDIN = 0x20000000
+ PROT_EXEC = 0x4
+ PROT_NONE = 0x0
+ PROT_READ = 0x1
+ PROT_WRITE = 0x2
PRI_IOFLUSH = 0x7c
PRIO_PGRP = 0x1
PRIO_PROCESS = 0x0
diff --git a/src/pkg/syscall/zerrors_openbsd_386.go b/src/pkg/syscall/zerrors_openbsd_386.go
index e546243b0..082983494 100644
--- a/src/pkg/syscall/zerrors_openbsd_386.go
+++ b/src/pkg/syscall/zerrors_openbsd_386.go
@@ -77,7 +77,7 @@ const (
BIOCGFILDROP = 0x40044278
BIOCGHDRCMPLT = 0x40044274
BIOCGRSIG = 0x40044273
- BIOCGRTIMEOUT = 0x4008426e
+ BIOCGRTIMEOUT = 0x400c426e
BIOCGSTATS = 0x4008426f
BIOCIMMEDIATE = 0x80044270
BIOCLOCK = 0x20004276
@@ -91,7 +91,7 @@ const (
BIOCSFILDROP = 0x80044279
BIOCSHDRCMPLT = 0x80044275
BIOCSRSIG = 0x80044272
- BIOCSRTIMEOUT = 0x8008426d
+ BIOCSRTIMEOUT = 0x800c426d
BIOCVERSION = 0x40044271
BPF_A = 0x10
BPF_ABS = 0x20
@@ -713,6 +713,8 @@ const (
IPPROTO_AH = 0x33
IPPROTO_CARP = 0x70
IPPROTO_DIVERT = 0x102
+ IPPROTO_DIVERT_INIT = 0x2
+ IPPROTO_DIVERT_RESP = 0x1
IPPROTO_DONE = 0x101
IPPROTO_DSTOPTS = 0x3c
IPPROTO_EGP = 0x8
@@ -783,6 +785,7 @@ const (
IPV6_PORTRANGE_HIGH = 0x1
IPV6_PORTRANGE_LOW = 0x2
IPV6_RECVDSTOPTS = 0x28
+ IPV6_RECVDSTPORT = 0x40
IPV6_RECVHOPLIMIT = 0x25
IPV6_RECVHOPOPTS = 0x27
IPV6_RECVPATHMTU = 0x2b
@@ -807,6 +810,7 @@ const (
IP_DEFAULT_MULTICAST_LOOP = 0x1
IP_DEFAULT_MULTICAST_TTL = 0x1
IP_DF = 0x4000
+ IP_DIVERTFL = 0x1022
IP_DROP_MEMBERSHIP = 0xd
IP_ESP_NETWORK_LEVEL = 0x16
IP_ESP_TRANS_LEVEL = 0x15
@@ -857,6 +861,32 @@ const (
LOCK_NB = 0x4
LOCK_SH = 0x1
LOCK_UN = 0x8
+ MADV_DONTNEED = 0x4
+ MADV_FREE = 0x6
+ MADV_NORMAL = 0x0
+ MADV_RANDOM = 0x1
+ MADV_SEQUENTIAL = 0x2
+ MADV_SPACEAVAIL = 0x5
+ MADV_WILLNEED = 0x3
+ MAP_ANON = 0x1000
+ MAP_COPY = 0x4
+ MAP_FILE = 0x0
+ MAP_FIXED = 0x10
+ MAP_FLAGMASK = 0x1ff7
+ MAP_HASSEMAPHORE = 0x200
+ MAP_INHERIT = 0x80
+ MAP_INHERIT_COPY = 0x1
+ MAP_INHERIT_DONATE_COPY = 0x3
+ MAP_INHERIT_NONE = 0x2
+ MAP_INHERIT_SHARE = 0x0
+ MAP_NOEXTEND = 0x100
+ MAP_NORESERVE = 0x40
+ MAP_PRIVATE = 0x2
+ MAP_RENAME = 0x20
+ MAP_SHARED = 0x1
+ MAP_TRYFIXED = 0x400
+ MCL_CURRENT = 0x1
+ MCL_FUTURE = 0x2
MSG_BCAST = 0x100
MSG_CTRUNC = 0x20
MSG_DONTROUTE = 0x4
@@ -868,6 +898,9 @@ const (
MSG_PEEK = 0x2
MSG_TRUNC = 0x10
MSG_WAITALL = 0x40
+ MS_ASYNC = 0x1
+ MS_INVALIDATE = 0x4
+ MS_SYNC = 0x2
NAME_MAX = 0xff
NET_RT_DUMP = 0x1
NET_RT_FLAGS = 0x2
@@ -926,10 +959,14 @@ const (
PARODD = 0x2000
PENDIN = 0x20000000
PF_FLUSH = 0x1
- PT_MASK = 0x3ff000
PRIO_PGRP = 0x1
PRIO_PROCESS = 0x0
PRIO_USER = 0x2
+ PROT_EXEC = 0x4
+ PROT_NONE = 0x0
+ PROT_READ = 0x1
+ PROT_WRITE = 0x2
+ PT_MASK = 0x3ff000
RLIMIT_CORE = 0x4
RLIMIT_CPU = 0x0
RLIMIT_DATA = 0x2
@@ -966,7 +1003,7 @@ const (
RTF_CLONING = 0x100
RTF_DONE = 0x40
RTF_DYNAMIC = 0x10
- RTF_FMASK = 0xf808
+ RTF_FMASK = 0x10f808
RTF_GATEWAY = 0x2
RTF_HOST = 0x4
RTF_LLINFO = 0x400
@@ -1001,7 +1038,7 @@ const (
RTM_REDIRECT = 0x6
RTM_RESOLVE = 0xb
RTM_RTTUNIT = 0xf4240
- RTM_VERSION = 0x4
+ RTM_VERSION = 0x5
RTV_EXPIRE = 0x4
RTV_HOPCOUNT = 0x2
RTV_MTU = 0x1
@@ -1027,7 +1064,7 @@ const (
SIOCBRDGADD = 0x8054693c
SIOCBRDGADDS = 0x80546941
SIOCBRDGARL = 0x806e694d
- SIOCBRDGDADDR = 0x80286947
+ SIOCBRDGDADDR = 0x81286947
SIOCBRDGDEL = 0x8054693d
SIOCBRDGDELS = 0x80546942
SIOCBRDGFLUSH = 0x80546948
@@ -1037,14 +1074,14 @@ const (
SIOCBRDGGHT = 0xc0146951
SIOCBRDGGIFFLGS = 0xc054693e
SIOCBRDGGMA = 0xc0146953
- SIOCBRDGGPARAM = 0xc0386958
+ SIOCBRDGGPARAM = 0xc03c6958
SIOCBRDGGPRI = 0xc0146950
SIOCBRDGGRL = 0xc028694f
SIOCBRDGGSIFS = 0xc054693c
SIOCBRDGGTO = 0xc0146946
SIOCBRDGIFS = 0xc0546942
SIOCBRDGRTS = 0xc0186943
- SIOCBRDGSADDR = 0xc0286944
+ SIOCBRDGSADDR = 0xc1286944
SIOCBRDGSCACHE = 0x80146940
SIOCBRDGSFD = 0x80146952
SIOCBRDGSHT = 0x80146951
@@ -1067,6 +1104,7 @@ const (
SIOCGETPFSYNC = 0xc02069f8
SIOCGETSGCNT = 0xc0147534
SIOCGETVIFCNT = 0xc0147533
+ SIOCGETVLAN = 0xc0206990
SIOCGHIWAT = 0x40047301
SIOCGIFADDR = 0xc0206921
SIOCGIFASYNCMAP = 0xc020697c
@@ -1080,6 +1118,7 @@ const (
SIOCGIFGENERIC = 0xc020693a
SIOCGIFGMEMB = 0xc024698a
SIOCGIFGROUP = 0xc0246988
+ SIOCGIFHARDMTU = 0xc02069a5
SIOCGIFMEDIA = 0xc0286936
SIOCGIFMETRIC = 0xc0206917
SIOCGIFMTU = 0xc020697e
@@ -1094,9 +1133,12 @@ const (
SIOCGLIFADDR = 0xc218691d
SIOCGLIFPHYADDR = 0xc218694b
SIOCGLIFPHYRTABLE = 0xc02069a2
+ SIOCGLIFPHYTTL = 0xc02069a9
SIOCGLOWAT = 0x40047303
SIOCGPGRP = 0x40047309
+ SIOCGSPPPPARAMS = 0xc0206994
SIOCGVH = 0xc02069f6
+ SIOCGVNETID = 0xc02069a7
SIOCIFCREATE = 0x8020697a
SIOCIFDESTROY = 0x80206979
SIOCIFGCLONERS = 0xc00c6978
@@ -1104,6 +1146,7 @@ const (
SIOCSETLABEL = 0x80206999
SIOCSETPFLOW = 0x802069fd
SIOCSETPFSYNC = 0x802069f7
+ SIOCSETVLAN = 0x8020698f
SIOCSHIWAT = 0x80047300
SIOCSIFADDR = 0x8020690c
SIOCSIFASYNCMAP = 0x8020697d
@@ -1126,9 +1169,12 @@ const (
SIOCSIFXFLAGS = 0x8020699d
SIOCSLIFPHYADDR = 0x8218694a
SIOCSLIFPHYRTABLE = 0x802069a1
+ SIOCSLIFPHYTTL = 0x802069a8
SIOCSLOWAT = 0x80047302
SIOCSPGRP = 0x80047308
+ SIOCSSPPPPARAMS = 0x80206993
SIOCSVH = 0xc02069f5
+ SIOCSVNETID = 0x802069a6
SOCK_DGRAM = 0x2
SOCK_RAW = 0x3
SOCK_RDM = 0x4
@@ -1171,6 +1217,7 @@ const (
TCP_MD5SIG = 0x4
TCP_MSS = 0x200
TCP_NODELAY = 0x1
+ TCP_NOPUSH = 0x10
TCP_NSTATES = 0xb
TCP_SACK_ENABLE = 0x8
TCSAFLUSH = 0x2
@@ -1190,7 +1237,8 @@ const (
TIOCGETD = 0x4004741a
TIOCGFLAGS = 0x4004745d
TIOCGPGRP = 0x40047477
- TIOCGTSTAMP = 0x4008745b
+ TIOCGSID = 0x40047463
+ TIOCGTSTAMP = 0x400c745b
TIOCGWINSZ = 0x40087468
TIOCMBIC = 0x8004746b
TIOCMBIS = 0x8004746c
diff --git a/src/pkg/syscall/zerrors_openbsd_amd64.go b/src/pkg/syscall/zerrors_openbsd_amd64.go
index 411b51a68..e9fa37cde 100644
--- a/src/pkg/syscall/zerrors_openbsd_amd64.go
+++ b/src/pkg/syscall/zerrors_openbsd_amd64.go
@@ -140,10 +140,8 @@ const (
BPF_W = 0x0
BPF_X = 0x8
BRKINT = 0x2
- CCR0_FLUSH = 0x10
CFLUSH = 0xf
CLOCAL = 0x8000
- CPUID_CFLUSH = 0x80000
CREAD = 0x800
CS5 = 0x0
CS6 = 0x100
@@ -198,10 +196,6 @@ const (
ECHOKE = 0x1
ECHONL = 0x10
ECHOPRT = 0x20
- EFER_LMA = 0x400
- EFER_LME = 0x100
- EFER_NXE = 0x800
- EFER_SCE = 0x1
EMT_TAGOVF = 0x1
EMUL_ENABLED = 0x1
EMUL_NATIVE = 0x2
@@ -719,6 +713,8 @@ const (
IPPROTO_AH = 0x33
IPPROTO_CARP = 0x70
IPPROTO_DIVERT = 0x102
+ IPPROTO_DIVERT_INIT = 0x2
+ IPPROTO_DIVERT_RESP = 0x1
IPPROTO_DONE = 0x101
IPPROTO_DSTOPTS = 0x3c
IPPROTO_EGP = 0x8
@@ -789,6 +785,7 @@ const (
IPV6_PORTRANGE_HIGH = 0x1
IPV6_PORTRANGE_LOW = 0x2
IPV6_RECVDSTOPTS = 0x28
+ IPV6_RECVDSTPORT = 0x40
IPV6_RECVHOPLIMIT = 0x25
IPV6_RECVHOPOPTS = 0x27
IPV6_RECVPATHMTU = 0x2b
@@ -813,6 +810,7 @@ const (
IP_DEFAULT_MULTICAST_LOOP = 0x1
IP_DEFAULT_MULTICAST_TTL = 0x1
IP_DF = 0x4000
+ IP_DIVERTFL = 0x1022
IP_DROP_MEMBERSHIP = 0xd
IP_ESP_NETWORK_LEVEL = 0x16
IP_ESP_TRANS_LEVEL = 0x15
@@ -863,6 +861,32 @@ const (
LOCK_NB = 0x4
LOCK_SH = 0x1
LOCK_UN = 0x8
+ MADV_DONTNEED = 0x4
+ MADV_FREE = 0x6
+ MADV_NORMAL = 0x0
+ MADV_RANDOM = 0x1
+ MADV_SEQUENTIAL = 0x2
+ MADV_SPACEAVAIL = 0x5
+ MADV_WILLNEED = 0x3
+ MAP_ANON = 0x1000
+ MAP_COPY = 0x4
+ MAP_FILE = 0x0
+ MAP_FIXED = 0x10
+ MAP_FLAGMASK = 0x1ff7
+ MAP_HASSEMAPHORE = 0x200
+ MAP_INHERIT = 0x80
+ MAP_INHERIT_COPY = 0x1
+ MAP_INHERIT_DONATE_COPY = 0x3
+ MAP_INHERIT_NONE = 0x2
+ MAP_INHERIT_SHARE = 0x0
+ MAP_NOEXTEND = 0x100
+ MAP_NORESERVE = 0x40
+ MAP_PRIVATE = 0x2
+ MAP_RENAME = 0x20
+ MAP_SHARED = 0x1
+ MAP_TRYFIXED = 0x400
+ MCL_CURRENT = 0x1
+ MCL_FUTURE = 0x2
MSG_BCAST = 0x100
MSG_CTRUNC = 0x20
MSG_DONTROUTE = 0x4
@@ -874,6 +898,9 @@ const (
MSG_PEEK = 0x2
MSG_TRUNC = 0x10
MSG_WAITALL = 0x40
+ MS_ASYNC = 0x1
+ MS_INVALIDATE = 0x4
+ MS_SYNC = 0x2
NAME_MAX = 0xff
NET_RT_DUMP = 0x1
NET_RT_FLAGS = 0x2
@@ -932,10 +959,13 @@ const (
PARODD = 0x2000
PENDIN = 0x20000000
PF_FLUSH = 0x1
- PMC5_PIPELINE_FLUSH = 0x15
PRIO_PGRP = 0x1
PRIO_PROCESS = 0x0
PRIO_USER = 0x2
+ PROT_EXEC = 0x4
+ PROT_NONE = 0x0
+ PROT_READ = 0x1
+ PROT_WRITE = 0x2
RLIMIT_CORE = 0x4
RLIMIT_CPU = 0x0
RLIMIT_DATA = 0x2
@@ -972,7 +1002,7 @@ const (
RTF_CLONING = 0x100
RTF_DONE = 0x40
RTF_DYNAMIC = 0x10
- RTF_FMASK = 0xf808
+ RTF_FMASK = 0x10f808
RTF_GATEWAY = 0x2
RTF_HOST = 0x4
RTF_LLINFO = 0x400
@@ -1007,7 +1037,7 @@ const (
RTM_REDIRECT = 0x6
RTM_RESOLVE = 0xb
RTM_RTTUNIT = 0xf4240
- RTM_VERSION = 0x4
+ RTM_VERSION = 0x5
RTV_EXPIRE = 0x4
RTV_HOPCOUNT = 0x2
RTV_MTU = 0x1
@@ -1033,7 +1063,7 @@ const (
SIOCBRDGADD = 0x8058693c
SIOCBRDGADDS = 0x80586941
SIOCBRDGARL = 0x806e694d
- SIOCBRDGDADDR = 0x80286947
+ SIOCBRDGDADDR = 0x81286947
SIOCBRDGDEL = 0x8058693d
SIOCBRDGDELS = 0x80586942
SIOCBRDGFLUSH = 0x80586948
@@ -1050,7 +1080,7 @@ const (
SIOCBRDGGTO = 0xc0146946
SIOCBRDGIFS = 0xc0586942
SIOCBRDGRTS = 0xc0206943
- SIOCBRDGSADDR = 0xc0286944
+ SIOCBRDGSADDR = 0xc1286944
SIOCBRDGSCACHE = 0x80146940
SIOCBRDGSFD = 0x80146952
SIOCBRDGSHT = 0x80146951
@@ -1073,6 +1103,7 @@ const (
SIOCGETPFSYNC = 0xc02069f8
SIOCGETSGCNT = 0xc0207534
SIOCGETVIFCNT = 0xc0287533
+ SIOCGETVLAN = 0xc0206990
SIOCGHIWAT = 0x40047301
SIOCGIFADDR = 0xc0206921
SIOCGIFASYNCMAP = 0xc020697c
@@ -1086,6 +1117,7 @@ const (
SIOCGIFGENERIC = 0xc020693a
SIOCGIFGMEMB = 0xc028698a
SIOCGIFGROUP = 0xc0286988
+ SIOCGIFHARDMTU = 0xc02069a5
SIOCGIFMEDIA = 0xc0306936
SIOCGIFMETRIC = 0xc0206917
SIOCGIFMTU = 0xc020697e
@@ -1100,9 +1132,12 @@ const (
SIOCGLIFADDR = 0xc218691d
SIOCGLIFPHYADDR = 0xc218694b
SIOCGLIFPHYRTABLE = 0xc02069a2
+ SIOCGLIFPHYTTL = 0xc02069a9
SIOCGLOWAT = 0x40047303
SIOCGPGRP = 0x40047309
+ SIOCGSPPPPARAMS = 0xc0206994
SIOCGVH = 0xc02069f6
+ SIOCGVNETID = 0xc02069a7
SIOCIFCREATE = 0x8020697a
SIOCIFDESTROY = 0x80206979
SIOCIFGCLONERS = 0xc0106978
@@ -1110,6 +1145,7 @@ const (
SIOCSETLABEL = 0x80206999
SIOCSETPFLOW = 0x802069fd
SIOCSETPFSYNC = 0x802069f7
+ SIOCSETVLAN = 0x8020698f
SIOCSHIWAT = 0x80047300
SIOCSIFADDR = 0x8020690c
SIOCSIFASYNCMAP = 0x8020697d
@@ -1132,9 +1168,12 @@ const (
SIOCSIFXFLAGS = 0x8020699d
SIOCSLIFPHYADDR = 0x8218694a
SIOCSLIFPHYRTABLE = 0x802069a1
+ SIOCSLIFPHYTTL = 0x802069a8
SIOCSLOWAT = 0x80047302
SIOCSPGRP = 0x80047308
+ SIOCSSPPPPARAMS = 0x80206993
SIOCSVH = 0xc02069f5
+ SIOCSVNETID = 0x802069a6
SOCK_DGRAM = 0x2
SOCK_RAW = 0x3
SOCK_RDM = 0x4
@@ -1177,6 +1216,7 @@ const (
TCP_MD5SIG = 0x4
TCP_MSS = 0x200
TCP_NODELAY = 0x1
+ TCP_NOPUSH = 0x10
TCP_NSTATES = 0xb
TCP_SACK_ENABLE = 0x8
TCSAFLUSH = 0x2
@@ -1196,6 +1236,7 @@ const (
TIOCGETD = 0x4004741a
TIOCGFLAGS = 0x4004745d
TIOCGPGRP = 0x40047477
+ TIOCGSID = 0x40047463
TIOCGTSTAMP = 0x4010745b
TIOCGWINSZ = 0x40087468
TIOCMBIC = 0x8004746b
diff --git a/src/pkg/syscall/zerrors_solaris_amd64.go b/src/pkg/syscall/zerrors_solaris_amd64.go
new file mode 100644
index 000000000..3f4cbfd98
--- /dev/null
+++ b/src/pkg/syscall/zerrors_solaris_amd64.go
@@ -0,0 +1,1414 @@
+// mkerrors.sh -m64
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- -m64 _const.go
+
+package syscall
+
+const (
+ AF_802 = 0x12
+ AF_APPLETALK = 0x10
+ AF_CCITT = 0xa
+ AF_CHAOS = 0x5
+ AF_DATAKIT = 0x9
+ AF_DECnet = 0xc
+ AF_DLI = 0xd
+ AF_ECMA = 0x8
+ AF_FILE = 0x1
+ AF_GOSIP = 0x16
+ AF_HYLINK = 0xf
+ AF_IMPLINK = 0x3
+ AF_INET = 0x2
+ AF_INET6 = 0x1a
+ AF_INET_OFFLOAD = 0x1e
+ AF_IPX = 0x17
+ AF_KEY = 0x1b
+ AF_LAT = 0xe
+ AF_LINK = 0x19
+ AF_LOCAL = 0x1
+ AF_MAX = 0x20
+ AF_NBS = 0x7
+ AF_NCA = 0x1c
+ AF_NIT = 0x11
+ AF_NS = 0x6
+ AF_OSI = 0x13
+ AF_OSINET = 0x15
+ AF_PACKET = 0x20
+ AF_POLICY = 0x1d
+ AF_PUP = 0x4
+ AF_ROUTE = 0x18
+ AF_SNA = 0xb
+ AF_TRILL = 0x1f
+ AF_UNIX = 0x1
+ AF_UNSPEC = 0x0
+ AF_X25 = 0x14
+ ARPHRD_ARCNET = 0x7
+ ARPHRD_ATM = 0x10
+ ARPHRD_AX25 = 0x3
+ ARPHRD_CHAOS = 0x5
+ ARPHRD_EETHER = 0x2
+ ARPHRD_ETHER = 0x1
+ ARPHRD_FC = 0x12
+ ARPHRD_FRAME = 0xf
+ ARPHRD_HDLC = 0x11
+ ARPHRD_IB = 0x20
+ ARPHRD_IEEE802 = 0x6
+ ARPHRD_IPATM = 0x13
+ ARPHRD_METRICOM = 0x17
+ ARPHRD_TUNNEL = 0x1f
+ B0 = 0x0
+ B110 = 0x3
+ B115200 = 0x12
+ B1200 = 0x9
+ B134 = 0x4
+ B150 = 0x5
+ B153600 = 0x13
+ B1800 = 0xa
+ B19200 = 0xe
+ B200 = 0x6
+ B230400 = 0x14
+ B2400 = 0xb
+ B300 = 0x7
+ B307200 = 0x15
+ B38400 = 0xf
+ B460800 = 0x16
+ B4800 = 0xc
+ B50 = 0x1
+ B57600 = 0x10
+ B600 = 0x8
+ B75 = 0x2
+ B76800 = 0x11
+ B921600 = 0x17
+ B9600 = 0xd
+ BIOCFLUSH = 0x20004268
+ BIOCGBLEN = 0x40044266
+ BIOCGDLT = 0x4004426a
+ BIOCGDLTLIST = -0x3fefbd89
+ BIOCGDLTLIST32 = -0x3ff7bd89
+ BIOCGETIF = 0x4020426b
+ BIOCGETLIF = 0x4078426b
+ BIOCGHDRCMPLT = 0x40044274
+ BIOCGRTIMEOUT = 0x4010427b
+ BIOCGRTIMEOUT32 = 0x4008427b
+ BIOCGSEESENT = 0x40044278
+ BIOCGSTATS = 0x4080426f
+ BIOCGSTATSOLD = 0x4008426f
+ BIOCIMMEDIATE = -0x7ffbbd90
+ BIOCPROMISC = 0x20004269
+ BIOCSBLEN = -0x3ffbbd9a
+ BIOCSDLT = -0x7ffbbd8a
+ BIOCSETF = -0x7fefbd99
+ BIOCSETF32 = -0x7ff7bd99
+ BIOCSETIF = -0x7fdfbd94
+ BIOCSETLIF = -0x7f87bd94
+ BIOCSHDRCMPLT = -0x7ffbbd8b
+ BIOCSRTIMEOUT = -0x7fefbd86
+ BIOCSRTIMEOUT32 = -0x7ff7bd86
+ BIOCSSEESENT = -0x7ffbbd87
+ BIOCSTCPF = -0x7fefbd8e
+ BIOCSUDPF = -0x7fefbd8d
+ BIOCVERSION = 0x40044271
+ BPF_A = 0x10
+ BPF_ABS = 0x20
+ BPF_ADD = 0x0
+ BPF_ALIGNMENT = 0x4
+ BPF_ALU = 0x4
+ BPF_AND = 0x50
+ BPF_B = 0x10
+ BPF_DFLTBUFSIZE = 0x100000
+ BPF_DIV = 0x30
+ BPF_H = 0x8
+ BPF_IMM = 0x0
+ BPF_IND = 0x40
+ BPF_JA = 0x0
+ BPF_JEQ = 0x10
+ BPF_JGE = 0x30
+ BPF_JGT = 0x20
+ BPF_JMP = 0x5
+ BPF_JSET = 0x40
+ BPF_K = 0x0
+ BPF_LD = 0x0
+ BPF_LDX = 0x1
+ BPF_LEN = 0x80
+ BPF_LSH = 0x60
+ BPF_MAJOR_VERSION = 0x1
+ BPF_MAXBUFSIZE = 0x1000000
+ BPF_MAXINSNS = 0x200
+ BPF_MEM = 0x60
+ BPF_MEMWORDS = 0x10
+ BPF_MINBUFSIZE = 0x20
+ BPF_MINOR_VERSION = 0x1
+ BPF_MISC = 0x7
+ BPF_MSH = 0xa0
+ BPF_MUL = 0x20
+ BPF_NEG = 0x80
+ BPF_OR = 0x40
+ BPF_RELEASE = 0x30bb6
+ BPF_RET = 0x6
+ BPF_RSH = 0x70
+ BPF_ST = 0x2
+ BPF_STX = 0x3
+ BPF_SUB = 0x10
+ BPF_TAX = 0x0
+ BPF_TXA = 0x80
+ BPF_W = 0x0
+ BPF_X = 0x8
+ BRKINT = 0x2
+ CFLUSH = 0xf
+ CLOCAL = 0x800
+ CREAD = 0x80
+ CS5 = 0x0
+ CS6 = 0x10
+ CS7 = 0x20
+ CS8 = 0x30
+ CSIZE = 0x30
+ CSTART = 0x11
+ CSTOP = 0x13
+ CSTOPB = 0x40
+ CSUSP = 0x1a
+ CSWTCH = 0x1a
+ DLT_AIRONET_HEADER = 0x78
+ DLT_APPLE_IP_OVER_IEEE1394 = 0x8a
+ DLT_ARCNET = 0x7
+ DLT_ARCNET_LINUX = 0x81
+ DLT_ATM_CLIP = 0x13
+ DLT_ATM_RFC1483 = 0xb
+ DLT_AURORA = 0x7e
+ DLT_AX25 = 0x3
+ DLT_BACNET_MS_TP = 0xa5
+ DLT_CHAOS = 0x5
+ DLT_CISCO_IOS = 0x76
+ DLT_C_HDLC = 0x68
+ DLT_DOCSIS = 0x8f
+ DLT_ECONET = 0x73
+ DLT_EN10MB = 0x1
+ DLT_EN3MB = 0x2
+ DLT_ENC = 0x6d
+ DLT_ERF_ETH = 0xaf
+ DLT_ERF_POS = 0xb0
+ DLT_FDDI = 0xa
+ DLT_FRELAY = 0x6b
+ DLT_GCOM_SERIAL = 0xad
+ DLT_GCOM_T1E1 = 0xac
+ DLT_GPF_F = 0xab
+ DLT_GPF_T = 0xaa
+ DLT_GPRS_LLC = 0xa9
+ DLT_HDLC = 0x10
+ DLT_HHDLC = 0x79
+ DLT_HIPPI = 0xf
+ DLT_IBM_SN = 0x92
+ DLT_IBM_SP = 0x91
+ DLT_IEEE802 = 0x6
+ DLT_IEEE802_11 = 0x69
+ DLT_IEEE802_11_RADIO = 0x7f
+ DLT_IEEE802_11_RADIO_AVS = 0xa3
+ DLT_IPNET = 0xe2
+ DLT_IPOIB = 0xa2
+ DLT_IP_OVER_FC = 0x7a
+ DLT_JUNIPER_ATM1 = 0x89
+ DLT_JUNIPER_ATM2 = 0x87
+ DLT_JUNIPER_CHDLC = 0xb5
+ DLT_JUNIPER_ES = 0x84
+ DLT_JUNIPER_ETHER = 0xb2
+ DLT_JUNIPER_FRELAY = 0xb4
+ DLT_JUNIPER_GGSN = 0x85
+ DLT_JUNIPER_MFR = 0x86
+ DLT_JUNIPER_MLFR = 0x83
+ DLT_JUNIPER_MLPPP = 0x82
+ DLT_JUNIPER_MONITOR = 0xa4
+ DLT_JUNIPER_PIC_PEER = 0xae
+ DLT_JUNIPER_PPP = 0xb3
+ DLT_JUNIPER_PPPOE = 0xa7
+ DLT_JUNIPER_PPPOE_ATM = 0xa8
+ DLT_JUNIPER_SERVICES = 0x88
+ DLT_LINUX_IRDA = 0x90
+ DLT_LINUX_LAPD = 0xb1
+ DLT_LINUX_SLL = 0x71
+ DLT_LOOP = 0x6c
+ DLT_LTALK = 0x72
+ DLT_MTP2 = 0x8c
+ DLT_MTP2_WITH_PHDR = 0x8b
+ DLT_MTP3 = 0x8d
+ DLT_NULL = 0x0
+ DLT_PCI_EXP = 0x7d
+ DLT_PFLOG = 0x75
+ DLT_PFSYNC = 0x12
+ DLT_PPP = 0x9
+ DLT_PPP_BSDOS = 0xe
+ DLT_PPP_PPPD = 0xa6
+ DLT_PRISM_HEADER = 0x77
+ DLT_PRONET = 0x4
+ DLT_RAW = 0xc
+ DLT_RAWAF_MASK = 0x2240000
+ DLT_RIO = 0x7c
+ DLT_SCCP = 0x8e
+ DLT_SLIP = 0x8
+ DLT_SLIP_BSDOS = 0xd
+ DLT_SUNATM = 0x7b
+ DLT_SYMANTEC_FIREWALL = 0x63
+ DLT_TZSP = 0x80
+ ECHO = 0x8
+ ECHOCTL = 0x200
+ ECHOE = 0x10
+ ECHOK = 0x20
+ ECHOKE = 0x800
+ ECHONL = 0x40
+ ECHOPRT = 0x400
+ EMPTY_SET = 0x0
+ EMT_CPCOVF = 0x1
+ EQUALITY_CHECK = 0x0
+ EXTA = 0xe
+ EXTB = 0xf
+ FD_CLOEXEC = 0x1
+ FD_NFDBITS = 0x40
+ FD_SETSIZE = 0x10000
+ FLUSHALL = 0x1
+ FLUSHDATA = 0x0
+ FLUSHO = 0x2000
+ F_ALLOCSP = 0xa
+ F_ALLOCSP64 = 0xa
+ F_BADFD = 0x2e
+ F_BLKSIZE = 0x13
+ F_BLOCKS = 0x12
+ F_CHKFL = 0x8
+ F_COMPAT = 0x8
+ F_DUP2FD = 0x9
+ F_DUP2FD_CLOEXEC = 0x24
+ F_DUPFD = 0x0
+ F_DUPFD_CLOEXEC = 0x25
+ F_FREESP = 0xb
+ F_FREESP64 = 0xb
+ F_GETFD = 0x1
+ F_GETFL = 0x3
+ F_GETLK = 0xe
+ F_GETLK64 = 0xe
+ F_GETOWN = 0x17
+ F_GETXFL = 0x2d
+ F_HASREMOTELOCKS = 0x1a
+ F_ISSTREAM = 0xd
+ F_MANDDNY = 0x10
+ F_MDACC = 0x20
+ F_NODNY = 0x0
+ F_NPRIV = 0x10
+ F_PRIV = 0xf
+ F_QUOTACTL = 0x11
+ F_RDACC = 0x1
+ F_RDDNY = 0x1
+ F_RDLCK = 0x1
+ F_REVOKE = 0x19
+ F_RMACC = 0x4
+ F_RMDNY = 0x4
+ F_RWACC = 0x3
+ F_RWDNY = 0x3
+ F_SETFD = 0x2
+ F_SETFL = 0x4
+ F_SETLK = 0x6
+ F_SETLK64 = 0x6
+ F_SETLK64_NBMAND = 0x2a
+ F_SETLKW = 0x7
+ F_SETLKW64 = 0x7
+ F_SETLK_NBMAND = 0x2a
+ F_SETOWN = 0x18
+ F_SHARE = 0x28
+ F_SHARE_NBMAND = 0x2b
+ F_UNLCK = 0x3
+ F_UNLKSYS = 0x4
+ F_UNSHARE = 0x29
+ F_WRACC = 0x2
+ F_WRDNY = 0x2
+ F_WRLCK = 0x2
+ HUPCL = 0x400
+ ICANON = 0x2
+ ICRNL = 0x100
+ IEXTEN = 0x8000
+ IFF_ADDRCONF = 0x80000
+ IFF_ALLMULTI = 0x200
+ IFF_ANYCAST = 0x400000
+ IFF_BROADCAST = 0x2
+ IFF_CANTCHANGE = 0x7f203003b5a
+ IFF_COS_ENABLED = 0x200000000
+ IFF_DEBUG = 0x4
+ IFF_DEPRECATED = 0x40000
+ IFF_DHCPRUNNING = 0x4000
+ IFF_DUPLICATE = 0x4000000000
+ IFF_FAILED = 0x10000000
+ IFF_FIXEDMTU = 0x1000000000
+ IFF_INACTIVE = 0x40000000
+ IFF_INTELLIGENT = 0x400
+ IFF_IPMP = 0x8000000000
+ IFF_IPMP_CANTCHANGE = 0x10000000
+ IFF_IPMP_INVALID = 0x1ec200080
+ IFF_IPV4 = 0x1000000
+ IFF_IPV6 = 0x2000000
+ IFF_L3PROTECT = 0x40000000000
+ IFF_LOOPBACK = 0x8
+ IFF_MULTICAST = 0x800
+ IFF_MULTI_BCAST = 0x1000
+ IFF_NOACCEPT = 0x4000000
+ IFF_NOARP = 0x80
+ IFF_NOFAILOVER = 0x8000000
+ IFF_NOLINKLOCAL = 0x20000000000
+ IFF_NOLOCAL = 0x20000
+ IFF_NONUD = 0x200000
+ IFF_NORTEXCH = 0x800000
+ IFF_NOTRAILERS = 0x20
+ IFF_NOXMIT = 0x10000
+ IFF_OFFLINE = 0x80000000
+ IFF_POINTOPOINT = 0x10
+ IFF_PREFERRED = 0x400000000
+ IFF_PRIVATE = 0x8000
+ IFF_PROMISC = 0x100
+ IFF_ROUTER = 0x100000
+ IFF_RUNNING = 0x40
+ IFF_STANDBY = 0x20000000
+ IFF_TEMPORARY = 0x800000000
+ IFF_UNNUMBERED = 0x2000
+ IFF_UP = 0x1
+ IFF_VIRTUAL = 0x2000000000
+ IFF_VRRP = 0x10000000000
+ IFF_XRESOLV = 0x100000000
+ IFNAMSIZ = 0x10
+ IFT_1822 = 0x2
+ IFT_6TO4 = 0xca
+ IFT_AAL5 = 0x31
+ IFT_ARCNET = 0x23
+ IFT_ARCNETPLUS = 0x24
+ IFT_ATM = 0x25
+ IFT_CEPT = 0x13
+ IFT_DS3 = 0x1e
+ IFT_EON = 0x19
+ IFT_ETHER = 0x6
+ IFT_FDDI = 0xf
+ IFT_FRELAY = 0x20
+ IFT_FRELAYDCE = 0x2c
+ IFT_HDH1822 = 0x3
+ IFT_HIPPI = 0x2f
+ IFT_HSSI = 0x2e
+ IFT_HY = 0xe
+ IFT_IB = 0xc7
+ IFT_IPV4 = 0xc8
+ IFT_IPV6 = 0xc9
+ IFT_ISDNBASIC = 0x14
+ IFT_ISDNPRIMARY = 0x15
+ IFT_ISO88022LLC = 0x29
+ IFT_ISO88023 = 0x7
+ IFT_ISO88024 = 0x8
+ IFT_ISO88025 = 0x9
+ IFT_ISO88026 = 0xa
+ IFT_LAPB = 0x10
+ IFT_LOCALTALK = 0x2a
+ IFT_LOOP = 0x18
+ IFT_MIOX25 = 0x26
+ IFT_MODEM = 0x30
+ IFT_NSIP = 0x1b
+ IFT_OTHER = 0x1
+ IFT_P10 = 0xc
+ IFT_P80 = 0xd
+ IFT_PARA = 0x22
+ IFT_PPP = 0x17
+ IFT_PROPMUX = 0x36
+ IFT_PROPVIRTUAL = 0x35
+ IFT_PTPSERIAL = 0x16
+ IFT_RS232 = 0x21
+ IFT_SDLC = 0x11
+ IFT_SIP = 0x1f
+ IFT_SLIP = 0x1c
+ IFT_SMDSDXI = 0x2b
+ IFT_SMDSICIP = 0x34
+ IFT_SONET = 0x27
+ IFT_SONETPATH = 0x32
+ IFT_SONETVT = 0x33
+ IFT_STARLAN = 0xb
+ IFT_T1 = 0x12
+ IFT_ULTRA = 0x1d
+ IFT_V35 = 0x2d
+ IFT_X25 = 0x5
+ IFT_X25DDN = 0x4
+ IFT_X25PLE = 0x28
+ IFT_XETHER = 0x1a
+ IGNBRK = 0x1
+ IGNCR = 0x80
+ IGNPAR = 0x4
+ IMAXBEL = 0x2000
+ INLCR = 0x40
+ INPCK = 0x10
+ IN_AUTOCONF_MASK = 0xffff0000
+ IN_AUTOCONF_NET = 0xa9fe0000
+ IN_CLASSA_HOST = 0xffffff
+ IN_CLASSA_MAX = 0x80
+ IN_CLASSA_NET = 0xff000000
+ IN_CLASSA_NSHIFT = 0x18
+ IN_CLASSB_HOST = 0xffff
+ IN_CLASSB_MAX = 0x10000
+ IN_CLASSB_NET = 0xffff0000
+ IN_CLASSB_NSHIFT = 0x10
+ IN_CLASSC_HOST = 0xff
+ IN_CLASSC_NET = 0xffffff00
+ IN_CLASSC_NSHIFT = 0x8
+ IN_CLASSD_HOST = 0xfffffff
+ IN_CLASSD_NET = 0xf0000000
+ IN_CLASSD_NSHIFT = 0x1c
+ IN_CLASSE_NET = 0xffffffff
+ IN_LOOPBACKNET = 0x7f
+ IN_PRIVATE12_MASK = 0xfff00000
+ IN_PRIVATE12_NET = 0xac100000
+ IN_PRIVATE16_MASK = 0xffff0000
+ IN_PRIVATE16_NET = 0xc0a80000
+ IN_PRIVATE8_MASK = 0xff000000
+ IN_PRIVATE8_NET = 0xa000000
+ IPPROTO_AH = 0x33
+ IPPROTO_DSTOPTS = 0x3c
+ IPPROTO_EGP = 0x8
+ IPPROTO_ENCAP = 0x4
+ IPPROTO_EON = 0x50
+ IPPROTO_ESP = 0x32
+ IPPROTO_FRAGMENT = 0x2c
+ IPPROTO_GGP = 0x3
+ IPPROTO_HELLO = 0x3f
+ IPPROTO_HOPOPTS = 0x0
+ IPPROTO_ICMP = 0x1
+ IPPROTO_ICMPV6 = 0x3a
+ IPPROTO_IDP = 0x16
+ IPPROTO_IGMP = 0x2
+ IPPROTO_IP = 0x0
+ IPPROTO_IPV6 = 0x29
+ IPPROTO_MAX = 0x100
+ IPPROTO_ND = 0x4d
+ IPPROTO_NONE = 0x3b
+ IPPROTO_OSPF = 0x59
+ IPPROTO_PIM = 0x67
+ IPPROTO_PUP = 0xc
+ IPPROTO_RAW = 0xff
+ IPPROTO_ROUTING = 0x2b
+ IPPROTO_RSVP = 0x2e
+ IPPROTO_SCTP = 0x84
+ IPPROTO_TCP = 0x6
+ IPPROTO_UDP = 0x11
+ IPV6_ADD_MEMBERSHIP = 0x9
+ IPV6_BOUND_IF = 0x41
+ IPV6_CHECKSUM = 0x18
+ IPV6_DONTFRAG = 0x21
+ IPV6_DROP_MEMBERSHIP = 0xa
+ IPV6_DSTOPTS = 0xf
+ IPV6_FLOWINFO_FLOWLABEL = 0xffff0f00
+ IPV6_FLOWINFO_TCLASS = 0xf00f
+ IPV6_HOPLIMIT = 0xc
+ IPV6_HOPOPTS = 0xe
+ IPV6_JOIN_GROUP = 0x9
+ IPV6_LEAVE_GROUP = 0xa
+ IPV6_MULTICAST_HOPS = 0x7
+ IPV6_MULTICAST_IF = 0x6
+ IPV6_MULTICAST_LOOP = 0x8
+ IPV6_NEXTHOP = 0xd
+ IPV6_PAD1_OPT = 0x0
+ IPV6_PATHMTU = 0x25
+ IPV6_PKTINFO = 0xb
+ IPV6_PREFER_SRC_CGA = 0x20
+ IPV6_PREFER_SRC_CGADEFAULT = 0x10
+ IPV6_PREFER_SRC_CGAMASK = 0x30
+ IPV6_PREFER_SRC_COA = 0x2
+ IPV6_PREFER_SRC_DEFAULT = 0x15
+ IPV6_PREFER_SRC_HOME = 0x1
+ IPV6_PREFER_SRC_MASK = 0x3f
+ IPV6_PREFER_SRC_MIPDEFAULT = 0x1
+ IPV6_PREFER_SRC_MIPMASK = 0x3
+ IPV6_PREFER_SRC_NONCGA = 0x10
+ IPV6_PREFER_SRC_PUBLIC = 0x4
+ IPV6_PREFER_SRC_TMP = 0x8
+ IPV6_PREFER_SRC_TMPDEFAULT = 0x4
+ IPV6_PREFER_SRC_TMPMASK = 0xc
+ IPV6_RECVDSTOPTS = 0x28
+ IPV6_RECVHOPLIMIT = 0x13
+ IPV6_RECVHOPOPTS = 0x14
+ IPV6_RECVPATHMTU = 0x24
+ IPV6_RECVPKTINFO = 0x12
+ IPV6_RECVRTHDR = 0x16
+ IPV6_RECVRTHDRDSTOPTS = 0x17
+ IPV6_RECVTCLASS = 0x19
+ IPV6_RTHDR = 0x10
+ IPV6_RTHDRDSTOPTS = 0x11
+ IPV6_RTHDR_TYPE_0 = 0x0
+ IPV6_SEC_OPT = 0x22
+ IPV6_SRC_PREFERENCES = 0x23
+ IPV6_TCLASS = 0x26
+ IPV6_UNICAST_HOPS = 0x5
+ IPV6_UNSPEC_SRC = 0x42
+ IPV6_USE_MIN_MTU = 0x20
+ IPV6_V6ONLY = 0x27
+ IP_ADD_MEMBERSHIP = 0x13
+ IP_ADD_SOURCE_MEMBERSHIP = 0x17
+ IP_BLOCK_SOURCE = 0x15
+ IP_BOUND_IF = 0x41
+ IP_BROADCAST = 0x106
+ IP_BROADCAST_TTL = 0x43
+ IP_DEFAULT_MULTICAST_LOOP = 0x1
+ IP_DEFAULT_MULTICAST_TTL = 0x1
+ IP_DF = 0x4000
+ IP_DHCPINIT_IF = 0x45
+ IP_DONTFRAG = 0x1b
+ IP_DONTROUTE = 0x105
+ IP_DROP_MEMBERSHIP = 0x14
+ IP_DROP_SOURCE_MEMBERSHIP = 0x18
+ IP_HDRINCL = 0x2
+ IP_MAXPACKET = 0xffff
+ IP_MF = 0x2000
+ IP_MSS = 0x240
+ IP_MULTICAST_IF = 0x10
+ IP_MULTICAST_LOOP = 0x12
+ IP_MULTICAST_TTL = 0x11
+ IP_NEXTHOP = 0x19
+ IP_OPTIONS = 0x1
+ IP_PKTINFO = 0x1a
+ IP_RECVDSTADDR = 0x7
+ IP_RECVIF = 0x9
+ IP_RECVOPTS = 0x5
+ IP_RECVPKTINFO = 0x1a
+ IP_RECVRETOPTS = 0x6
+ IP_RECVSLLA = 0xa
+ IP_RECVTTL = 0xb
+ IP_RETOPTS = 0x8
+ IP_REUSEADDR = 0x104
+ IP_SEC_OPT = 0x22
+ IP_TOS = 0x3
+ IP_TTL = 0x4
+ IP_UNBLOCK_SOURCE = 0x16
+ IP_UNSPEC_SRC = 0x42
+ ISIG = 0x1
+ ISTRIP = 0x20
+ IXANY = 0x800
+ IXOFF = 0x1000
+ IXON = 0x400
+ MADV_ACCESS_DEFAULT = 0x6
+ MADV_ACCESS_LWP = 0x7
+ MADV_ACCESS_MANY = 0x8
+ MADV_DONTNEED = 0x4
+ MADV_FREE = 0x5
+ MADV_NORMAL = 0x0
+ MADV_RANDOM = 0x1
+ MADV_SEQUENTIAL = 0x2
+ MADV_WILLNEED = 0x3
+ MAP_32BIT = 0x80
+ MAP_ALIGN = 0x200
+ MAP_ANON = 0x100
+ MAP_ANONYMOUS = 0x100
+ MAP_FIXED = 0x10
+ MAP_INITDATA = 0x800
+ MAP_NORESERVE = 0x40
+ MAP_PRIVATE = 0x2
+ MAP_RENAME = 0x20
+ MAP_SHARED = 0x1
+ MAP_TEXT = 0x400
+ MAP_TYPE = 0xf
+ MCL_CURRENT = 0x1
+ MCL_FUTURE = 0x2
+ MSG_CTRUNC = 0x10
+ MSG_DONTROUTE = 0x4
+ MSG_DONTWAIT = 0x80
+ MSG_DUPCTRL = 0x800
+ MSG_EOR = 0x8
+ MSG_MAXIOVLEN = 0x10
+ MSG_NOTIFICATION = 0x100
+ MSG_OOB = 0x1
+ MSG_PEEK = 0x2
+ MSG_TRUNC = 0x20
+ MSG_WAITALL = 0x40
+ MSG_XPG4_2 = 0x8000
+ MS_ASYNC = 0x1
+ MS_INVALIDATE = 0x2
+ MS_OLDSYNC = 0x0
+ MS_SYNC = 0x4
+ M_FLUSH = 0x86
+ NOFLSH = 0x80
+ OCRNL = 0x8
+ OFDEL = 0x80
+ OFILL = 0x40
+ ONLCR = 0x4
+ ONLRET = 0x20
+ ONOCR = 0x10
+ OPENFAIL = -0x1
+ OPOST = 0x1
+ O_ACCMODE = 0x600003
+ O_APPEND = 0x8
+ O_CLOEXEC = 0x800000
+ O_CREAT = 0x100
+ O_DSYNC = 0x40
+ O_EXCL = 0x400
+ O_EXEC = 0x400000
+ O_LARGEFILE = 0x2000
+ O_NDELAY = 0x4
+ O_NOCTTY = 0x800
+ O_NOFOLLOW = 0x20000
+ O_NOLINKS = 0x40000
+ O_NONBLOCK = 0x80
+ O_RDONLY = 0x0
+ O_RDWR = 0x2
+ O_RSYNC = 0x8000
+ O_SEARCH = 0x200000
+ O_SIOCGIFCONF = -0x3ff796ec
+ O_SIOCGLIFCONF = -0x3fef9688
+ O_SYNC = 0x10
+ O_TRUNC = 0x200
+ O_WRONLY = 0x1
+ O_XATTR = 0x4000
+ PARENB = 0x100
+ PAREXT = 0x100000
+ PARMRK = 0x8
+ PARODD = 0x200
+ PENDIN = 0x4000
+ PRIO_PGRP = 0x1
+ PRIO_PROCESS = 0x0
+ PRIO_USER = 0x2
+ PROT_EXEC = 0x4
+ PROT_NONE = 0x0
+ PROT_READ = 0x1
+ PROT_WRITE = 0x2
+ RLIMIT_AS = 0x6
+ RLIMIT_CORE = 0x4
+ RLIMIT_CPU = 0x0
+ RLIMIT_DATA = 0x2
+ RLIMIT_FSIZE = 0x1
+ RLIMIT_NOFILE = 0x5
+ RLIMIT_STACK = 0x3
+ RLIM_INFINITY = -0x3
+ RTAX_AUTHOR = 0x6
+ RTAX_BRD = 0x7
+ RTAX_DST = 0x0
+ RTAX_GATEWAY = 0x1
+ RTAX_GENMASK = 0x3
+ RTAX_IFA = 0x5
+ RTAX_IFP = 0x4
+ RTAX_MAX = 0x9
+ RTAX_NETMASK = 0x2
+ RTAX_SRC = 0x8
+ RTA_AUTHOR = 0x40
+ RTA_BRD = 0x80
+ RTA_DST = 0x1
+ RTA_GATEWAY = 0x2
+ RTA_GENMASK = 0x8
+ RTA_IFA = 0x20
+ RTA_IFP = 0x10
+ RTA_NETMASK = 0x4
+ RTA_NUMBITS = 0x9
+ RTA_SRC = 0x100
+ RTF_BLACKHOLE = 0x1000
+ RTF_CLONING = 0x100
+ RTF_DONE = 0x40
+ RTF_DYNAMIC = 0x10
+ RTF_GATEWAY = 0x2
+ RTF_HOST = 0x4
+ RTF_INDIRECT = 0x40000
+ RTF_KERNEL = 0x80000
+ RTF_LLINFO = 0x400
+ RTF_MASK = 0x80
+ RTF_MODIFIED = 0x20
+ RTF_MULTIRT = 0x10000
+ RTF_PRIVATE = 0x2000
+ RTF_PROTO1 = 0x8000
+ RTF_PROTO2 = 0x4000
+ RTF_REJECT = 0x8
+ RTF_SETSRC = 0x20000
+ RTF_STATIC = 0x800
+ RTF_UP = 0x1
+ RTF_XRESOLVE = 0x200
+ RTF_ZONE = 0x100000
+ RTM_ADD = 0x1
+ RTM_CHANGE = 0x3
+ RTM_CHGADDR = 0xf
+ RTM_DELADDR = 0xd
+ RTM_DELETE = 0x2
+ RTM_FREEADDR = 0x10
+ RTM_GET = 0x4
+ RTM_IFINFO = 0xe
+ RTM_LOCK = 0x8
+ RTM_LOSING = 0x5
+ RTM_MISS = 0x7
+ RTM_NEWADDR = 0xc
+ RTM_OLDADD = 0x9
+ RTM_OLDDEL = 0xa
+ RTM_REDIRECT = 0x6
+ RTM_RESOLVE = 0xb
+ RTM_VERSION = 0x3
+ RTV_EXPIRE = 0x4
+ RTV_HOPCOUNT = 0x2
+ RTV_MTU = 0x1
+ RTV_RPIPE = 0x8
+ RTV_RTT = 0x40
+ RTV_RTTVAR = 0x80
+ RTV_SPIPE = 0x10
+ RTV_SSTHRESH = 0x20
+ RT_AWARE = 0x1
+ RUSAGE_CHILDREN = -0x1
+ RUSAGE_SELF = 0x0
+ SCM_RIGHTS = 0x1010
+ SCM_TIMESTAMP = 0x1013
+ SCM_UCRED = 0x1012
+ SHUT_RD = 0x0
+ SHUT_RDWR = 0x2
+ SHUT_WR = 0x1
+ SIG2STR_MAX = 0x20
+ SIOCADDMULTI = -0x7fdf96cf
+ SIOCADDRT = -0x7fcf8df6
+ SIOCATMARK = 0x40047307
+ SIOCDARP = -0x7fdb96e0
+ SIOCDELMULTI = -0x7fdf96ce
+ SIOCDELRT = -0x7fcf8df5
+ SIOCDIPSECONFIG = -0x7ffb9669
+ SIOCDXARP = -0x7fff9658
+ SIOCFIPSECONFIG = -0x7ffb966b
+ SIOCGARP = -0x3fdb96e1
+ SIOCGDSTINFO = -0x3fff965c
+ SIOCGENADDR = -0x3fdf96ab
+ SIOCGENPSTATS = -0x3fdf96c7
+ SIOCGETLSGCNT = -0x3fef8deb
+ SIOCGETNAME = 0x40107334
+ SIOCGETPEER = 0x40107335
+ SIOCGETPROP = -0x3fff8f44
+ SIOCGETSGCNT = -0x3feb8deb
+ SIOCGETSYNC = -0x3fdf96d3
+ SIOCGETVIFCNT = -0x3feb8dec
+ SIOCGHIWAT = 0x40047301
+ SIOCGIFADDR = -0x3fdf96f3
+ SIOCGIFBRDADDR = -0x3fdf96e9
+ SIOCGIFCONF = -0x3ff796a4
+ SIOCGIFDSTADDR = -0x3fdf96f1
+ SIOCGIFFLAGS = -0x3fdf96ef
+ SIOCGIFHWADDR = -0x3fdf9647
+ SIOCGIFINDEX = -0x3fdf96a6
+ SIOCGIFMEM = -0x3fdf96ed
+ SIOCGIFMETRIC = -0x3fdf96e5
+ SIOCGIFMTU = -0x3fdf96ea
+ SIOCGIFMUXID = -0x3fdf96a8
+ SIOCGIFNETMASK = -0x3fdf96e7
+ SIOCGIFNUM = 0x40046957
+ SIOCGIP6ADDRPOLICY = -0x3fff965e
+ SIOCGIPMSFILTER = -0x3ffb964c
+ SIOCGLIFADDR = -0x3f87968f
+ SIOCGLIFBINDING = -0x3f879666
+ SIOCGLIFBRDADDR = -0x3f879685
+ SIOCGLIFCONF = -0x3fef965b
+ SIOCGLIFDADSTATE = -0x3f879642
+ SIOCGLIFDSTADDR = -0x3f87968d
+ SIOCGLIFFLAGS = -0x3f87968b
+ SIOCGLIFGROUPINFO = -0x3f4b9663
+ SIOCGLIFGROUPNAME = -0x3f879664
+ SIOCGLIFHWADDR = -0x3f879640
+ SIOCGLIFINDEX = -0x3f87967b
+ SIOCGLIFLNKINFO = -0x3f879674
+ SIOCGLIFMETRIC = -0x3f879681
+ SIOCGLIFMTU = -0x3f879686
+ SIOCGLIFMUXID = -0x3f87967d
+ SIOCGLIFNETMASK = -0x3f879683
+ SIOCGLIFNUM = -0x3ff3967e
+ SIOCGLIFSRCOF = -0x3fef964f
+ SIOCGLIFSUBNET = -0x3f879676
+ SIOCGLIFTOKEN = -0x3f879678
+ SIOCGLIFUSESRC = -0x3f879651
+ SIOCGLIFZONE = -0x3f879656
+ SIOCGLOWAT = 0x40047303
+ SIOCGMSFILTER = -0x3ffb964e
+ SIOCGPGRP = 0x40047309
+ SIOCGSTAMP = -0x3fef9646
+ SIOCGXARP = -0x3fff9659
+ SIOCIFDETACH = -0x7fdf96c8
+ SIOCILB = -0x3ffb9645
+ SIOCLIFADDIF = -0x3f879691
+ SIOCLIFDELND = -0x7f879673
+ SIOCLIFGETND = -0x3f879672
+ SIOCLIFREMOVEIF = -0x7f879692
+ SIOCLIFSETND = -0x7f879671
+ SIOCLIPSECONFIG = -0x7ffb9668
+ SIOCLOWER = -0x7fdf96d7
+ SIOCSARP = -0x7fdb96e2
+ SIOCSCTPGOPT = -0x3fef9653
+ SIOCSCTPPEELOFF = -0x3ffb9652
+ SIOCSCTPSOPT = -0x7fef9654
+ SIOCSENABLESDP = -0x3ffb9649
+ SIOCSETPROP = -0x7ffb8f43
+ SIOCSETSYNC = -0x7fdf96d4
+ SIOCSHIWAT = -0x7ffb8d00
+ SIOCSIFADDR = -0x7fdf96f4
+ SIOCSIFBRDADDR = -0x7fdf96e8
+ SIOCSIFDSTADDR = -0x7fdf96f2
+ SIOCSIFFLAGS = -0x7fdf96f0
+ SIOCSIFINDEX = -0x7fdf96a5
+ SIOCSIFMEM = -0x7fdf96ee
+ SIOCSIFMETRIC = -0x7fdf96e4
+ SIOCSIFMTU = -0x7fdf96eb
+ SIOCSIFMUXID = -0x7fdf96a7
+ SIOCSIFNAME = -0x7fdf96b7
+ SIOCSIFNETMASK = -0x7fdf96e6
+ SIOCSIP6ADDRPOLICY = -0x7fff965d
+ SIOCSIPMSFILTER = -0x7ffb964b
+ SIOCSIPSECONFIG = -0x7ffb966a
+ SIOCSLGETREQ = -0x3fdf96b9
+ SIOCSLIFADDR = -0x7f879690
+ SIOCSLIFBRDADDR = -0x7f879684
+ SIOCSLIFDSTADDR = -0x7f87968e
+ SIOCSLIFFLAGS = -0x7f87968c
+ SIOCSLIFGROUPNAME = -0x7f879665
+ SIOCSLIFINDEX = -0x7f87967a
+ SIOCSLIFLNKINFO = -0x7f879675
+ SIOCSLIFMETRIC = -0x7f879680
+ SIOCSLIFMTU = -0x7f879687
+ SIOCSLIFMUXID = -0x7f87967c
+ SIOCSLIFNAME = -0x3f87967f
+ SIOCSLIFNETMASK = -0x7f879682
+ SIOCSLIFPREFIX = -0x3f879641
+ SIOCSLIFSUBNET = -0x7f879677
+ SIOCSLIFTOKEN = -0x7f879679
+ SIOCSLIFUSESRC = -0x7f879650
+ SIOCSLIFZONE = -0x7f879655
+ SIOCSLOWAT = -0x7ffb8cfe
+ SIOCSLSTAT = -0x7fdf96b8
+ SIOCSMSFILTER = -0x7ffb964d
+ SIOCSPGRP = -0x7ffb8cf8
+ SIOCSPROMISC = -0x7ffb96d0
+ SIOCSQPTR = -0x3ffb9648
+ SIOCSSDSTATS = -0x3fdf96d2
+ SIOCSSESTATS = -0x3fdf96d1
+ SIOCSXARP = -0x7fff965a
+ SIOCTMYADDR = -0x3ff79670
+ SIOCTMYSITE = -0x3ff7966e
+ SIOCTONLINK = -0x3ff7966f
+ SIOCUPPER = -0x7fdf96d8
+ SIOCX25RCV = -0x3fdf96c4
+ SIOCX25TBL = -0x3fdf96c3
+ SIOCX25XMT = -0x3fdf96c5
+ SIOCXPROTO = 0x20007337
+ SOCK_CLOEXEC = 0x80000
+ SOCK_DGRAM = 0x1
+ SOCK_NDELAY = 0x200000
+ SOCK_NONBLOCK = 0x100000
+ SOCK_RAW = 0x4
+ SOCK_RDM = 0x5
+ SOCK_SEQPACKET = 0x6
+ SOCK_STREAM = 0x2
+ SOCK_TYPE_MASK = 0xffff
+ SOL_FILTER = 0xfffc
+ SOL_PACKET = 0xfffd
+ SOL_ROUTE = 0xfffe
+ SOL_SOCKET = 0xffff
+ SOMAXCONN = 0x80
+ SO_ACCEPTCONN = 0x2
+ SO_ALL = 0x3f
+ SO_ALLZONES = 0x1014
+ SO_ANON_MLP = 0x100a
+ SO_ATTACH_FILTER = 0x40000001
+ SO_BAND = 0x4000
+ SO_BROADCAST = 0x20
+ SO_COPYOPT = 0x80000
+ SO_DEBUG = 0x1
+ SO_DELIM = 0x8000
+ SO_DETACH_FILTER = 0x40000002
+ SO_DGRAM_ERRIND = 0x200
+ SO_DOMAIN = 0x100c
+ SO_DONTLINGER = -0x81
+ SO_DONTROUTE = 0x10
+ SO_ERROPT = 0x40000
+ SO_ERROR = 0x1007
+ SO_EXCLBIND = 0x1015
+ SO_HIWAT = 0x10
+ SO_ISNTTY = 0x800
+ SO_ISTTY = 0x400
+ SO_KEEPALIVE = 0x8
+ SO_LINGER = 0x80
+ SO_LOWAT = 0x20
+ SO_MAC_EXEMPT = 0x100b
+ SO_MAC_IMPLICIT = 0x1016
+ SO_MAXBLK = 0x100000
+ SO_MAXPSZ = 0x8
+ SO_MINPSZ = 0x4
+ SO_MREADOFF = 0x80
+ SO_MREADON = 0x40
+ SO_NDELOFF = 0x200
+ SO_NDELON = 0x100
+ SO_NODELIM = 0x10000
+ SO_OOBINLINE = 0x100
+ SO_PROTOTYPE = 0x1009
+ SO_RCVBUF = 0x1002
+ SO_RCVLOWAT = 0x1004
+ SO_RCVPSH = 0x100d
+ SO_RCVTIMEO = 0x1006
+ SO_READOPT = 0x1
+ SO_RECVUCRED = 0x400
+ SO_REUSEADDR = 0x4
+ SO_SECATTR = 0x1011
+ SO_SNDBUF = 0x1001
+ SO_SNDLOWAT = 0x1003
+ SO_SNDTIMEO = 0x1005
+ SO_STRHOLD = 0x20000
+ SO_TAIL = 0x200000
+ SO_TIMESTAMP = 0x1013
+ SO_TONSTOP = 0x2000
+ SO_TOSTOP = 0x1000
+ SO_TYPE = 0x1008
+ SO_USELOOPBACK = 0x40
+ SO_VRRP = 0x1017
+ SO_WROFF = 0x2
+ TCFLSH = 0x5407
+ TCIFLUSH = 0x0
+ TCIOFLUSH = 0x2
+ TCOFLUSH = 0x1
+ TCP_ABORT_THRESHOLD = 0x11
+ TCP_ANONPRIVBIND = 0x20
+ TCP_CONN_ABORT_THRESHOLD = 0x13
+ TCP_CONN_NOTIFY_THRESHOLD = 0x12
+ TCP_CORK = 0x18
+ TCP_EXCLBIND = 0x21
+ TCP_INIT_CWND = 0x15
+ TCP_KEEPALIVE = 0x8
+ TCP_KEEPALIVE_ABORT_THRESHOLD = 0x17
+ TCP_KEEPALIVE_THRESHOLD = 0x16
+ TCP_KEEPCNT = 0x23
+ TCP_KEEPIDLE = 0x22
+ TCP_KEEPINTVL = 0x24
+ TCP_LINGER2 = 0x1c
+ TCP_MAXSEG = 0x2
+ TCP_MSS = 0x218
+ TCP_NODELAY = 0x1
+ TCP_NOTIFY_THRESHOLD = 0x10
+ TCP_RECVDSTADDR = 0x14
+ TCP_RTO_INITIAL = 0x19
+ TCP_RTO_MAX = 0x1b
+ TCP_RTO_MIN = 0x1a
+ TCSAFLUSH = 0x5410
+ TIOC = 0x5400
+ TIOCCBRK = 0x747a
+ TIOCCDTR = 0x7478
+ TIOCCILOOP = 0x746c
+ TIOCEXCL = 0x740d
+ TIOCFLUSH = 0x7410
+ TIOCGETC = 0x7412
+ TIOCGETD = 0x7400
+ TIOCGETP = 0x7408
+ TIOCGLTC = 0x7474
+ TIOCGPGRP = 0x7414
+ TIOCGPPS = 0x547d
+ TIOCGPPSEV = 0x547f
+ TIOCGSID = 0x7416
+ TIOCGSOFTCAR = 0x5469
+ TIOCGWINSZ = 0x5468
+ TIOCHPCL = 0x7402
+ TIOCKBOF = 0x5409
+ TIOCKBON = 0x5408
+ TIOCLBIC = 0x747e
+ TIOCLBIS = 0x747f
+ TIOCLGET = 0x747c
+ TIOCLSET = 0x747d
+ TIOCMBIC = 0x741c
+ TIOCMBIS = 0x741b
+ TIOCMGET = 0x741d
+ TIOCMSET = 0x741a
+ TIOCM_CAR = 0x40
+ TIOCM_CD = 0x40
+ TIOCM_CTS = 0x20
+ TIOCM_DSR = 0x100
+ TIOCM_DTR = 0x2
+ TIOCM_LE = 0x1
+ TIOCM_RI = 0x80
+ TIOCM_RNG = 0x80
+ TIOCM_RTS = 0x4
+ TIOCM_SR = 0x10
+ TIOCM_ST = 0x8
+ TIOCNOTTY = 0x7471
+ TIOCNXCL = 0x740e
+ TIOCOUTQ = 0x7473
+ TIOCREMOTE = 0x741e
+ TIOCSBRK = 0x747b
+ TIOCSCTTY = 0x7484
+ TIOCSDTR = 0x7479
+ TIOCSETC = 0x7411
+ TIOCSETD = 0x7401
+ TIOCSETN = 0x740a
+ TIOCSETP = 0x7409
+ TIOCSIGNAL = 0x741f
+ TIOCSILOOP = 0x746d
+ TIOCSLTC = 0x7475
+ TIOCSPGRP = 0x7415
+ TIOCSPPS = 0x547e
+ TIOCSSOFTCAR = 0x546a
+ TIOCSTART = 0x746e
+ TIOCSTI = 0x7417
+ TIOCSTOP = 0x746f
+ TIOCSWINSZ = 0x5467
+ TOSTOP = 0x100
+ VCEOF = 0x8
+ VCEOL = 0x9
+ VDISCARD = 0xd
+ VDSUSP = 0xb
+ VEOF = 0x4
+ VEOL = 0x5
+ VEOL2 = 0x6
+ VERASE = 0x2
+ VINTR = 0x0
+ VKILL = 0x3
+ VLNEXT = 0xf
+ VMIN = 0x4
+ VQUIT = 0x1
+ VREPRINT = 0xc
+ VSTART = 0x8
+ VSTOP = 0x9
+ VSUSP = 0xa
+ VSWTCH = 0x7
+ VT0 = 0x0
+ VT1 = 0x4000
+ VTDLY = 0x4000
+ VTIME = 0x5
+ VWERASE = 0xe
+ WCONTFLG = 0xffff
+ WCONTINUED = 0x8
+ WCOREFLG = 0x80
+ WEXITED = 0x1
+ WNOHANG = 0x40
+ WNOWAIT = 0x80
+ WOPTMASK = 0xcf
+ WRAP = 0x20000
+ WSIGMASK = 0x7f
+ WSTOPFLG = 0x7f
+ WSTOPPED = 0x4
+ WTRAPPED = 0x2
+ WUNTRACED = 0x4
+)
+
+// Errors
+const (
+ E2BIG = Errno(0x7)
+ EACCES = Errno(0xd)
+ EADDRINUSE = Errno(0x7d)
+ EADDRNOTAVAIL = Errno(0x7e)
+ EADV = Errno(0x44)
+ EAFNOSUPPORT = Errno(0x7c)
+ EAGAIN = Errno(0xb)
+ EALREADY = Errno(0x95)
+ EBADE = Errno(0x32)
+ EBADF = Errno(0x9)
+ EBADFD = Errno(0x51)
+ EBADMSG = Errno(0x4d)
+ EBADR = Errno(0x33)
+ EBADRQC = Errno(0x36)
+ EBADSLT = Errno(0x37)
+ EBFONT = Errno(0x39)
+ EBUSY = Errno(0x10)
+ ECANCELED = Errno(0x2f)
+ ECHILD = Errno(0xa)
+ ECHRNG = Errno(0x25)
+ ECOMM = Errno(0x46)
+ ECONNABORTED = Errno(0x82)
+ ECONNREFUSED = Errno(0x92)
+ ECONNRESET = Errno(0x83)
+ EDEADLK = Errno(0x2d)
+ EDEADLOCK = Errno(0x38)
+ EDESTADDRREQ = Errno(0x60)
+ EDOM = Errno(0x21)
+ EDQUOT = Errno(0x31)
+ EEXIST = Errno(0x11)
+ EFAULT = Errno(0xe)
+ EFBIG = Errno(0x1b)
+ EHOSTDOWN = Errno(0x93)
+ EHOSTUNREACH = Errno(0x94)
+ EIDRM = Errno(0x24)
+ EILSEQ = Errno(0x58)
+ EINPROGRESS = Errno(0x96)
+ EINTR = Errno(0x4)
+ EINVAL = Errno(0x16)
+ EIO = Errno(0x5)
+ EISCONN = Errno(0x85)
+ EISDIR = Errno(0x15)
+ EL2HLT = Errno(0x2c)
+ EL2NSYNC = Errno(0x26)
+ EL3HLT = Errno(0x27)
+ EL3RST = Errno(0x28)
+ ELIBACC = Errno(0x53)
+ ELIBBAD = Errno(0x54)
+ ELIBEXEC = Errno(0x57)
+ ELIBMAX = Errno(0x56)
+ ELIBSCN = Errno(0x55)
+ ELNRNG = Errno(0x29)
+ ELOCKUNMAPPED = Errno(0x48)
+ ELOOP = Errno(0x5a)
+ EMFILE = Errno(0x18)
+ EMLINK = Errno(0x1f)
+ EMSGSIZE = Errno(0x61)
+ EMULTIHOP = Errno(0x4a)
+ ENAMETOOLONG = Errno(0x4e)
+ ENETDOWN = Errno(0x7f)
+ ENETRESET = Errno(0x81)
+ ENETUNREACH = Errno(0x80)
+ ENFILE = Errno(0x17)
+ ENOANO = Errno(0x35)
+ ENOBUFS = Errno(0x84)
+ ENOCSI = Errno(0x2b)
+ ENODATA = Errno(0x3d)
+ ENODEV = Errno(0x13)
+ ENOENT = Errno(0x2)
+ ENOEXEC = Errno(0x8)
+ ENOLCK = Errno(0x2e)
+ ENOLINK = Errno(0x43)
+ ENOMEM = Errno(0xc)
+ ENOMSG = Errno(0x23)
+ ENONET = Errno(0x40)
+ ENOPKG = Errno(0x41)
+ ENOPROTOOPT = Errno(0x63)
+ ENOSPC = Errno(0x1c)
+ ENOSR = Errno(0x3f)
+ ENOSTR = Errno(0x3c)
+ ENOSYS = Errno(0x59)
+ ENOTACTIVE = Errno(0x49)
+ ENOTBLK = Errno(0xf)
+ ENOTCONN = Errno(0x86)
+ ENOTDIR = Errno(0x14)
+ ENOTEMPTY = Errno(0x5d)
+ ENOTRECOVERABLE = Errno(0x3b)
+ ENOTSOCK = Errno(0x5f)
+ ENOTSUP = Errno(0x30)
+ ENOTTY = Errno(0x19)
+ ENOTUNIQ = Errno(0x50)
+ ENXIO = Errno(0x6)
+ EOPNOTSUPP = Errno(0x7a)
+ EOVERFLOW = Errno(0x4f)
+ EOWNERDEAD = Errno(0x3a)
+ EPERM = Errno(0x1)
+ EPFNOSUPPORT = Errno(0x7b)
+ EPIPE = Errno(0x20)
+ EPROTO = Errno(0x47)
+ EPROTONOSUPPORT = Errno(0x78)
+ EPROTOTYPE = Errno(0x62)
+ ERANGE = Errno(0x22)
+ EREMCHG = Errno(0x52)
+ EREMOTE = Errno(0x42)
+ ERESTART = Errno(0x5b)
+ EROFS = Errno(0x1e)
+ ESHUTDOWN = Errno(0x8f)
+ ESOCKTNOSUPPORT = Errno(0x79)
+ ESPIPE = Errno(0x1d)
+ ESRCH = Errno(0x3)
+ ESRMNT = Errno(0x45)
+ ESTALE = Errno(0x97)
+ ESTRPIPE = Errno(0x5c)
+ ETIME = Errno(0x3e)
+ ETIMEDOUT = Errno(0x91)
+ ETOOMANYREFS = Errno(0x90)
+ ETXTBSY = Errno(0x1a)
+ EUNATCH = Errno(0x2a)
+ EUSERS = Errno(0x5e)
+ EWOULDBLOCK = Errno(0xb)
+ EXDEV = Errno(0x12)
+ EXFULL = Errno(0x34)
+)
+
+// Signals
+const (
+ SIGABRT = Signal(0x6)
+ SIGALRM = Signal(0xe)
+ SIGBUS = Signal(0xa)
+ SIGCANCEL = Signal(0x24)
+ SIGCHLD = Signal(0x12)
+ SIGCLD = Signal(0x12)
+ SIGCONT = Signal(0x19)
+ SIGEMT = Signal(0x7)
+ SIGFPE = Signal(0x8)
+ SIGFREEZE = Signal(0x22)
+ SIGHUP = Signal(0x1)
+ SIGILL = Signal(0x4)
+ SIGINT = Signal(0x2)
+ SIGIO = Signal(0x16)
+ SIGIOT = Signal(0x6)
+ SIGJVM1 = Signal(0x27)
+ SIGJVM2 = Signal(0x28)
+ SIGKILL = Signal(0x9)
+ SIGLOST = Signal(0x25)
+ SIGLWP = Signal(0x21)
+ SIGPIPE = Signal(0xd)
+ SIGPOLL = Signal(0x16)
+ SIGPROF = Signal(0x1d)
+ SIGPWR = Signal(0x13)
+ SIGQUIT = Signal(0x3)
+ SIGSEGV = Signal(0xb)
+ SIGSTOP = Signal(0x17)
+ SIGSYS = Signal(0xc)
+ SIGTERM = Signal(0xf)
+ SIGTHAW = Signal(0x23)
+ SIGTRAP = Signal(0x5)
+ SIGTSTP = Signal(0x18)
+ SIGTTIN = Signal(0x1a)
+ SIGTTOU = Signal(0x1b)
+ SIGURG = Signal(0x15)
+ SIGUSR1 = Signal(0x10)
+ SIGUSR2 = Signal(0x11)
+ SIGVTALRM = Signal(0x1c)
+ SIGWAITING = Signal(0x20)
+ SIGWINCH = Signal(0x14)
+ SIGXCPU = Signal(0x1e)
+ SIGXFSZ = Signal(0x1f)
+ SIGXRES = Signal(0x26)
+)
+
+// Error table
+var errors = [...]string{
+ 1: "not owner",
+ 2: "no such file or directory",
+ 3: "no such process",
+ 4: "interrupted system call",
+ 5: "I/O error",
+ 6: "no such device or address",
+ 7: "arg list too long",
+ 8: "exec format error",
+ 9: "bad file number",
+ 10: "no child processes",
+ 11: "resource temporarily unavailable",
+ 12: "not enough space",
+ 13: "permission denied",
+ 14: "bad address",
+ 15: "block device required",
+ 16: "device busy",
+ 17: "file exists",
+ 18: "cross-device link",
+ 19: "no such device",
+ 20: "not a directory",
+ 21: "is a directory",
+ 22: "invalid argument",
+ 23: "file table overflow",
+ 24: "too many open files",
+ 25: "inappropriate ioctl for device",
+ 26: "text file busy",
+ 27: "file too large",
+ 28: "no space left on device",
+ 29: "illegal seek",
+ 30: "read-only file system",
+ 31: "too many links",
+ 32: "broken pipe",
+ 33: "argument out of domain",
+ 34: "result too large",
+ 35: "no message of desired type",
+ 36: "identifier removed",
+ 37: "channel number out of range",
+ 38: "level 2 not synchronized",
+ 39: "level 3 halted",
+ 40: "level 3 reset",
+ 41: "link number out of range",
+ 42: "protocol driver not attached",
+ 43: "no CSI structure available",
+ 44: "level 2 halted",
+ 45: "deadlock situation detected/avoided",
+ 46: "no record locks available",
+ 47: "operation canceled",
+ 48: "operation not supported",
+ 49: "disc quota exceeded",
+ 50: "bad exchange descriptor",
+ 51: "bad request descriptor",
+ 52: "message tables full",
+ 53: "anode table overflow",
+ 54: "bad request code",
+ 55: "invalid slot",
+ 56: "file locking deadlock",
+ 57: "bad font file format",
+ 58: "owner of the lock died",
+ 59: "lock is not recoverable",
+ 60: "not a stream device",
+ 61: "no data available",
+ 62: "timer expired",
+ 63: "out of stream resources",
+ 64: "machine is not on the network",
+ 65: "package not installed",
+ 66: "object is remote",
+ 67: "link has been severed",
+ 68: "advertise error",
+ 69: "srmount error",
+ 70: "communication error on send",
+ 71: "protocol error",
+ 72: "locked lock was unmapped ",
+ 73: "facility is not active",
+ 74: "multihop attempted",
+ 77: "not a data message",
+ 78: "file name too long",
+ 79: "value too large for defined data type",
+ 80: "name not unique on network",
+ 81: "file descriptor in bad state",
+ 82: "remote address changed",
+ 83: "can not access a needed shared library",
+ 84: "accessing a corrupted shared library",
+ 85: ".lib section in a.out corrupted",
+ 86: "attempting to link in more shared libraries than system limit",
+ 87: "can not exec a shared library directly",
+ 88: "illegal byte sequence",
+ 89: "operation not applicable",
+ 90: "number of symbolic links encountered during path name traversal exceeds MAXSYMLINKS",
+ 91: "error 91",
+ 92: "error 92",
+ 93: "directory not empty",
+ 94: "too many users",
+ 95: "socket operation on non-socket",
+ 96: "destination address required",
+ 97: "message too long",
+ 98: "protocol wrong type for socket",
+ 99: "option not supported by protocol",
+ 120: "protocol not supported",
+ 121: "socket type not supported",
+ 122: "operation not supported on transport endpoint",
+ 123: "protocol family not supported",
+ 124: "address family not supported by protocol family",
+ 125: "address already in use",
+ 126: "cannot assign requested address",
+ 127: "network is down",
+ 128: "network is unreachable",
+ 129: "network dropped connection because of reset",
+ 130: "software caused connection abort",
+ 131: "connection reset by peer",
+ 132: "no buffer space available",
+ 133: "transport endpoint is already connected",
+ 134: "transport endpoint is not connected",
+ 143: "cannot send after socket shutdown",
+ 144: "too many references: cannot splice",
+ 145: "connection timed out",
+ 146: "connection refused",
+ 147: "host is down",
+ 148: "no route to host",
+ 149: "operation already in progress",
+ 150: "operation now in progress",
+ 151: "stale NFS file handle",
+}
+
+// Signal table
+var signals = [...]string{
+ 1: "hangup",
+ 2: "interrupt",
+ 3: "quit",
+ 4: "illegal Instruction",
+ 5: "trace/Breakpoint Trap",
+ 6: "abort",
+ 7: "emulation Trap",
+ 8: "arithmetic Exception",
+ 9: "killed",
+ 10: "bus Error",
+ 11: "segmentation Fault",
+ 12: "bad System Call",
+ 13: "broken Pipe",
+ 14: "alarm Clock",
+ 15: "terminated",
+ 16: "user Signal 1",
+ 17: "user Signal 2",
+ 18: "child Status Changed",
+ 19: "power-Fail/Restart",
+ 20: "window Size Change",
+ 21: "urgent Socket Condition",
+ 22: "pollable Event",
+ 23: "stopped (signal)",
+ 24: "stopped (user)",
+ 25: "continued",
+ 26: "stopped (tty input)",
+ 27: "stopped (tty output)",
+ 28: "virtual Timer Expired",
+ 29: "profiling Timer Expired",
+ 30: "cpu Limit Exceeded",
+ 31: "file Size Limit Exceeded",
+ 32: "no runnable lwp",
+ 33: "inter-lwp signal",
+ 34: "checkpoint Freeze",
+ 35: "checkpoint Thaw",
+ 36: "thread Cancellation",
+ 37: "resource Lost",
+ 38: "resource Control Exceeded",
+ 39: "reserved for JVM 1",
+ 40: "reserved for JVM 2",
+}
diff --git a/src/pkg/syscall/zsyscall_darwin_386.go b/src/pkg/syscall/zsyscall_darwin_386.go
index 98500792d..a6a176b60 100644
--- a/src/pkg/syscall/zsyscall_darwin_386.go
+++ b/src/pkg/syscall/zsyscall_darwin_386.go
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
if e1 != 0 {
err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
- _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
if e1 != 0 {
err = e1
}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
if e1 != 0 {
@@ -590,23 +591,6 @@ func Geteuid() (uid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(buf) > 0 {
- _p0 = unsafe.Pointer(&buf[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall(SYS_GETFSSTAT64, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
- n = int(r0)
- if e1 != 0 {
- err = e1
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Getgid() (gid int) {
r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
gid = int(r0)
@@ -824,6 +808,74 @@ func Mknod(path string, mode uint32, dev int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func Mlock(b []byte) (err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mlockall(flags int) (err error) {
+ _, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mprotect(b []byte, prot int) (err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlock(b []byte) (err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlockall() (err error) {
+ _, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Open(path string, mode int, perm uint32) (fd int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
diff --git a/src/pkg/syscall/zsyscall_darwin_amd64.go b/src/pkg/syscall/zsyscall_darwin_amd64.go
index ee810e076..f5867c45d 100644
--- a/src/pkg/syscall/zsyscall_darwin_amd64.go
+++ b/src/pkg/syscall/zsyscall_darwin_amd64.go
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
if e1 != 0 {
err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
- _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
if e1 != 0 {
err = e1
}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
if e1 != 0 {
@@ -590,23 +591,6 @@ func Geteuid() (uid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(buf) > 0 {
- _p0 = unsafe.Pointer(&buf[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall(SYS_GETFSSTAT64, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
- n = int(r0)
- if e1 != 0 {
- err = e1
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Getgid() (gid int) {
r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
gid = int(r0)
@@ -824,6 +808,74 @@ func Mknod(path string, mode uint32, dev int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func Mlock(b []byte) (err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mlockall(flags int) (err error) {
+ _, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mprotect(b []byte, prot int) (err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlock(b []byte) (err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlockall() (err error) {
+ _, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Open(path string, mode int, perm uint32) (fd int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
diff --git a/src/pkg/syscall/zsyscall_dragonfly_386.go b/src/pkg/syscall/zsyscall_dragonfly_386.go
index 5c3fe0713..0ec813232 100644
--- a/src/pkg/syscall/zsyscall_dragonfly_386.go
+++ b/src/pkg/syscall/zsyscall_dragonfly_386.go
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
if e1 != 0 {
err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
- _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
if e1 != 0 {
err = e1
}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
if e1 != 0 {
@@ -584,23 +585,6 @@ func Geteuid() (uid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(buf) > 0 {
- _p0 = unsafe.Pointer(&buf[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
- n = int(r0)
- if e1 != 0 {
- err = e1
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Getgid() (gid int) {
r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
gid = int(r0)
diff --git a/src/pkg/syscall/zsyscall_dragonfly_amd64.go b/src/pkg/syscall/zsyscall_dragonfly_amd64.go
index c7766a8c3..8c7cce54e 100644
--- a/src/pkg/syscall/zsyscall_dragonfly_amd64.go
+++ b/src/pkg/syscall/zsyscall_dragonfly_amd64.go
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
if e1 != 0 {
err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
- _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
if e1 != 0 {
err = e1
}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
if e1 != 0 {
@@ -584,23 +585,6 @@ func Geteuid() (uid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(buf) > 0 {
- _p0 = unsafe.Pointer(&buf[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
- n = int(r0)
- if e1 != 0 {
- err = e1
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Getgid() (gid int) {
r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
gid = int(r0)
diff --git a/src/pkg/syscall/zsyscall_freebsd_386.go b/src/pkg/syscall/zsyscall_freebsd_386.go
index 631994fba..5befe83c6 100644
--- a/src/pkg/syscall/zsyscall_freebsd_386.go
+++ b/src/pkg/syscall/zsyscall_freebsd_386.go
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
if e1 != 0 {
err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
- _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
if e1 != 0 {
err = e1
}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
if e1 != 0 {
@@ -550,23 +551,6 @@ func Geteuid() (uid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(buf) > 0 {
- _p0 = unsafe.Pointer(&buf[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
- n = int(r0)
- if e1 != 0 {
- err = e1
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Getgid() (gid int) {
r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
gid = int(r0)
@@ -1301,3 +1285,14 @@ func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
}
return
}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func accept4(fd int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (nfd int, err error) {
+ r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0)
+ nfd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
diff --git a/src/pkg/syscall/zsyscall_freebsd_amd64.go b/src/pkg/syscall/zsyscall_freebsd_amd64.go
index 1d5180853..ab2eb80c6 100644
--- a/src/pkg/syscall/zsyscall_freebsd_amd64.go
+++ b/src/pkg/syscall/zsyscall_freebsd_amd64.go
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
if e1 != 0 {
err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
- _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
if e1 != 0 {
err = e1
}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
if e1 != 0 {
@@ -550,23 +551,6 @@ func Geteuid() (uid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(buf) > 0 {
- _p0 = unsafe.Pointer(&buf[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
- n = int(r0)
- if e1 != 0 {
- err = e1
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Getgid() (gid int) {
r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
gid = int(r0)
@@ -1301,3 +1285,14 @@ func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
}
return
}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func accept4(fd int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (nfd int, err error) {
+ r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0)
+ nfd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
diff --git a/src/pkg/syscall/zsyscall_freebsd_arm.go b/src/pkg/syscall/zsyscall_freebsd_arm.go
index 925b83fbb..c1f0f907c 100644
--- a/src/pkg/syscall/zsyscall_freebsd_arm.go
+++ b/src/pkg/syscall/zsyscall_freebsd_arm.go
@@ -1,4 +1,4 @@
-// mksyscall.pl -l32 syscall_bsd.go syscall_freebsd.go syscall_freebsd_386.go
+// mksyscall.pl -l32 -arm syscall_bsd.go syscall_freebsd.go syscall_freebsd_arm.go
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package syscall
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
if e1 != 0 {
err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
- _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
if e1 != 0 {
err = e1
}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
if e1 != 0 {
@@ -418,13 +419,8 @@ func Fchdir(fd int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchflags(path string, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
+func Fchflags(fd int, flags int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
if e1 != 0 {
err = e1
}
@@ -505,7 +501,7 @@ func Fsync(fd int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Ftruncate(fd int, length int64) (err error) {
- _, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), uintptr(length>>32))
+ _, _, e1 := Syscall6(SYS_FTRUNCATE, uintptr(fd), 0, uintptr(length), uintptr(length>>32), 0, 0)
if e1 != 0 {
err = e1
}
@@ -555,23 +551,6 @@ func Geteuid() (uid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(buf) > 0 {
- _p0 = unsafe.Pointer(&buf[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
- n = int(r0)
- if e1 != 0 {
- err = e1
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Getgid() (gid int) {
r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
gid = int(r0)
@@ -858,7 +837,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
} else {
_p0 = unsafe.Pointer(&_zero)
}
- r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
+ r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
n = int(r0)
if e1 != 0 {
err = e1
@@ -875,7 +854,24 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
} else {
_p0 = unsafe.Pointer(&_zero)
}
- r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
+ r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func read(fd int, p []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
n = int(r0)
if e1 != 0 {
err = e1
@@ -958,7 +954,7 @@ func Rmdir(path string) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
- r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(offset>>32), uintptr(whence), 0, 0)
+ r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), 0, uintptr(offset), uintptr(offset>>32), uintptr(whence), 0)
newoffset = int64(int64(r1)<<32 | int64(r0))
if e1 != 0 {
err = e1
@@ -1170,7 +1166,7 @@ func Truncate(path string, length int64) (err error) {
if err != nil {
return
}
- _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), uintptr(length>>32))
+ _, _, e1 := Syscall6(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0)
if e1 != 0 {
err = e1
}
@@ -1232,9 +1228,15 @@ func Unmount(path string, flags int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) {
- r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos), uintptr(pos>>32), 0, 0)
- ret = uintptr(r0)
+func write(fd int, p []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
if e1 != 0 {
err = e1
}
@@ -1243,8 +1245,9 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func munmap(addr uintptr, length uintptr) (err error) {
- _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
+func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) {
+ r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), 0, uintptr(pos), uintptr(pos>>32), 0)
+ ret = uintptr(r0)
if e1 != 0 {
err = e1
}
@@ -1253,15 +1256,8 @@ func munmap(addr uintptr, length uintptr) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func read(fd int, p []byte) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(p) > 0 {
- _p0 = unsafe.Pointer(&p[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
- n = int(r0)
+func munmap(addr uintptr, length uintptr) (err error) {
+ _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
if e1 != 0 {
err = e1
}
@@ -1270,14 +1266,8 @@ func read(fd int, p []byte) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func write(fd int, p []byte) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(p) > 0 {
- _p0 = unsafe.Pointer(&p[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
n = int(r0)
if e1 != 0 {
err = e1
@@ -1287,8 +1277,8 @@ func write(fd int, p []byte) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
- r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
+func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
n = int(r0)
if e1 != 0 {
err = e1
@@ -1298,9 +1288,9 @@ func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
- r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
- n = int(r0)
+func accept4(fd int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (nfd int, err error) {
+ r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0)
+ nfd = int(r0)
if e1 != 0 {
err = e1
}
diff --git a/src/pkg/syscall/zsyscall_linux_amd64.go b/src/pkg/syscall/zsyscall_linux_amd64.go
index c1c3d4511..c65448e21 100644
--- a/src/pkg/syscall/zsyscall_linux_amd64.go
+++ b/src/pkg/syscall/zsyscall_linux_amd64.go
@@ -1763,7 +1763,7 @@ func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int,
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -1773,7 +1773,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -1804,7 +1804,7 @@ func setgroups(n int, list *_Gid_t) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
err = e1
@@ -1814,7 +1814,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
if e1 != 0 {
err = e1
@@ -1882,7 +1882,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -1909,8 +1909,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
- _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
if e1 != 0 {
err = e1
}
diff --git a/src/pkg/syscall/zsyscall_linux_arm.go b/src/pkg/syscall/zsyscall_linux_arm.go
index 3380714a6..a970ce6dc 100644
--- a/src/pkg/syscall/zsyscall_linux_arm.go
+++ b/src/pkg/syscall/zsyscall_linux_arm.go
@@ -1383,7 +1383,7 @@ func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int,
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -1393,7 +1393,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -1424,7 +1424,7 @@ func setgroups(n int, list *_Gid_t) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
err = e1
@@ -1434,7 +1434,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
if e1 != 0 {
err = e1
@@ -1492,7 +1492,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -1529,8 +1529,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
- _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
if e1 != 0 {
err = e1
}
diff --git a/src/pkg/syscall/zsyscall_nacl_386.go b/src/pkg/syscall/zsyscall_nacl_386.go
new file mode 100644
index 000000000..32eed339a
--- /dev/null
+++ b/src/pkg/syscall/zsyscall_nacl_386.go
@@ -0,0 +1,63 @@
+// mksyscall.pl -l32 -nacl syscall_nacl.go syscall_nacl_386.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclClose(fd int) (err error) {
+ _, _, e1 := Syscall(sys_close, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Exit(code int) (err error) {
+ _, _, e1 := Syscall(sys_exit, uintptr(code), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclFstat(fd int, stat *Stat_t) (err error) {
+ _, _, e1 := Syscall(sys_fstat, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclRead(fd int, b []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(sys_read, uintptr(fd), uintptr(_p0), uintptr(len(b)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclSeek(fd int, off *int64, whence int) (err error) {
+ _, _, e1 := Syscall(sys_lseek, uintptr(fd), uintptr(unsafe.Pointer(off)), uintptr(whence))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
diff --git a/src/pkg/syscall/zsyscall_nacl_amd64p32.go b/src/pkg/syscall/zsyscall_nacl_amd64p32.go
new file mode 100644
index 000000000..8bc81fac9
--- /dev/null
+++ b/src/pkg/syscall/zsyscall_nacl_amd64p32.go
@@ -0,0 +1,63 @@
+// mksyscall.pl -nacl syscall_nacl.go syscall_nacl_amd64p32.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclClose(fd int) (err error) {
+ _, _, e1 := Syscall(sys_close, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Exit(code int) (err error) {
+ _, _, e1 := Syscall(sys_exit, uintptr(code), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclFstat(fd int, stat *Stat_t) (err error) {
+ _, _, e1 := Syscall(sys_fstat, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclRead(fd int, b []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(sys_read, uintptr(fd), uintptr(_p0), uintptr(len(b)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclSeek(fd int, off *int64, whence int) (err error) {
+ _, _, e1 := Syscall(sys_lseek, uintptr(fd), uintptr(unsafe.Pointer(off)), uintptr(whence))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
diff --git a/src/pkg/syscall/zsyscall_netbsd_386.go b/src/pkg/syscall/zsyscall_netbsd_386.go
index 0ee19bee1..281208f41 100644
--- a/src/pkg/syscall/zsyscall_netbsd_386.go
+++ b/src/pkg/syscall/zsyscall_netbsd_386.go
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
if e1 != 0 {
err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
- _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
if e1 != 0 {
err = e1
}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
if e1 != 0 {
diff --git a/src/pkg/syscall/zsyscall_netbsd_amd64.go b/src/pkg/syscall/zsyscall_netbsd_amd64.go
index b9d272144..ed9a87df6 100644
--- a/src/pkg/syscall/zsyscall_netbsd_amd64.go
+++ b/src/pkg/syscall/zsyscall_netbsd_amd64.go
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
if e1 != 0 {
err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
- _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
if e1 != 0 {
err = e1
}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
if e1 != 0 {
diff --git a/src/pkg/syscall/zsyscall_netbsd_arm.go b/src/pkg/syscall/zsyscall_netbsd_arm.go
index 763a906e5..c5c9a9f2c 100644
--- a/src/pkg/syscall/zsyscall_netbsd_arm.go
+++ b/src/pkg/syscall/zsyscall_netbsd_arm.go
@@ -1,4 +1,4 @@
-// mksyscall.pl -l32 -netbsd syscall_bsd.go syscall_netbsd.go syscall_netbsd_arm.go
+// mksyscall.pl -l32 -arm syscall_bsd.go syscall_netbsd.go syscall_netbsd_arm.go
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package syscall
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
if e1 != 0 {
err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
- _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
if e1 != 0 {
err = e1
}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
if e1 != 0 {
@@ -435,13 +436,8 @@ func Fchdir(fd int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchflags(path string, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
+func Fchflags(fd int, flags int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
if e1 != 0 {
err = e1
}
diff --git a/src/pkg/syscall/zsyscall_openbsd_386.go b/src/pkg/syscall/zsyscall_openbsd_386.go
index 2c2a56732..785e7c3b8 100644
--- a/src/pkg/syscall/zsyscall_openbsd_386.go
+++ b/src/pkg/syscall/zsyscall_openbsd_386.go
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
if e1 != 0 {
err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
- _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
if e1 != 0 {
err = e1
}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
if e1 != 0 {
@@ -268,6 +269,23 @@ func pipe(p *[2]_C_int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func getdents(fd int, buf []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_GETDENTS, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Access(path string, mode uint32) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -507,23 +525,6 @@ func Ftruncate(fd int, length int64) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(buf) > 0 {
- _p0 = unsafe.Pointer(&buf[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_GETDIRENTRIES, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = e1
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Getegid() (egid int) {
r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0)
egid = int(r0)
@@ -540,23 +541,6 @@ func Geteuid() (uid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(buf) > 0 {
- _p0 = unsafe.Pointer(&buf[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
- n = int(r0)
- if e1 != 0 {
- err = e1
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Getgid() (gid int) {
r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
gid = int(r0)
diff --git a/src/pkg/syscall/zsyscall_openbsd_amd64.go b/src/pkg/syscall/zsyscall_openbsd_amd64.go
index 4e1470696..7a8d9b6f1 100644
--- a/src/pkg/syscall/zsyscall_openbsd_amd64.go
+++ b/src/pkg/syscall/zsyscall_openbsd_amd64.go
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
if e1 != 0 {
err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
- _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
if e1 != 0 {
err = e1
}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
if e1 != 0 {
@@ -268,6 +269,23 @@ func pipe(p *[2]_C_int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func getdents(fd int, buf []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_GETDENTS, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Access(path string, mode uint32) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -507,23 +525,6 @@ func Ftruncate(fd int, length int64) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(buf) > 0 {
- _p0 = unsafe.Pointer(&buf[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_GETDIRENTRIES, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = e1
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Getegid() (egid int) {
r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0)
egid = int(r0)
@@ -540,23 +541,6 @@ func Geteuid() (uid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(buf) > 0 {
- _p0 = unsafe.Pointer(&buf[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
- n = int(r0)
- if e1 != 0 {
- err = e1
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Getgid() (gid int) {
r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
gid = int(r0)
diff --git a/src/pkg/syscall/zsyscall_solaris_amd64.go b/src/pkg/syscall/zsyscall_solaris_amd64.go
new file mode 100644
index 000000000..8847cad01
--- /dev/null
+++ b/src/pkg/syscall/zsyscall_solaris_amd64.go
@@ -0,0 +1,883 @@
+// mksyscall_solaris.pl syscall_solaris.go syscall_solaris_amd64.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+var (
+ modlibc = newLazySO("libc.so")
+ modlibsocket = newLazySO("libsocket.so")
+
+ procgetgroups = modlibc.NewProc("getgroups")
+ procsetgroups = modlibc.NewProc("setgroups")
+ procfcntl = modlibc.NewProc("fcntl")
+ procaccept = modlibsocket.NewProc("accept")
+ procsendmsg = modlibsocket.NewProc("sendmsg")
+ procAccess = modlibc.NewProc("access")
+ procAdjtime = modlibc.NewProc("adjtime")
+ procChdir = modlibc.NewProc("chdir")
+ procChmod = modlibc.NewProc("chmod")
+ procChown = modlibc.NewProc("chown")
+ procChroot = modlibc.NewProc("chroot")
+ procClose = modlibc.NewProc("close")
+ procDup = modlibc.NewProc("dup")
+ procExit = modlibc.NewProc("exit")
+ procFchdir = modlibc.NewProc("fchdir")
+ procFchmod = modlibc.NewProc("fchmod")
+ procFchown = modlibc.NewProc("fchown")
+ procFpathconf = modlibc.NewProc("fpathconf")
+ procFstat = modlibc.NewProc("fstat")
+ procGetdents = modlibc.NewProc("getdents")
+ procGetgid = modlibc.NewProc("getgid")
+ procGetpid = modlibc.NewProc("getpid")
+ procGeteuid = modlibc.NewProc("geteuid")
+ procGetegid = modlibc.NewProc("getegid")
+ procGetppid = modlibc.NewProc("getppid")
+ procGetpriority = modlibc.NewProc("getpriority")
+ procGetrlimit = modlibc.NewProc("getrlimit")
+ procGettimeofday = modlibc.NewProc("gettimeofday")
+ procGetuid = modlibc.NewProc("getuid")
+ procKill = modlibc.NewProc("kill")
+ procLchown = modlibc.NewProc("lchown")
+ procLink = modlibc.NewProc("link")
+ proclisten = modlibsocket.NewProc("listen")
+ procLstat = modlibc.NewProc("lstat")
+ procMkdir = modlibc.NewProc("mkdir")
+ procMknod = modlibc.NewProc("mknod")
+ procNanosleep = modlibc.NewProc("nanosleep")
+ procOpen = modlibc.NewProc("open")
+ procPathconf = modlibc.NewProc("pathconf")
+ procPread = modlibc.NewProc("pread")
+ procPwrite = modlibc.NewProc("pwrite")
+ procread = modlibc.NewProc("read")
+ procReadlink = modlibc.NewProc("readlink")
+ procRename = modlibc.NewProc("rename")
+ procRmdir = modlibc.NewProc("rmdir")
+ proclseek = modlibc.NewProc("lseek")
+ procSetegid = modlibc.NewProc("setegid")
+ procSeteuid = modlibc.NewProc("seteuid")
+ procSetgid = modlibc.NewProc("setgid")
+ procSetpgid = modlibc.NewProc("setpgid")
+ procSetpriority = modlibc.NewProc("setpriority")
+ procSetregid = modlibc.NewProc("setregid")
+ procSetreuid = modlibc.NewProc("setreuid")
+ procSetrlimit = modlibc.NewProc("setrlimit")
+ procSetsid = modlibc.NewProc("setsid")
+ procSetuid = modlibc.NewProc("setuid")
+ procshutdown = modlibsocket.NewProc("shutdown")
+ procStat = modlibc.NewProc("stat")
+ procSymlink = modlibc.NewProc("symlink")
+ procSync = modlibc.NewProc("sync")
+ procTruncate = modlibc.NewProc("truncate")
+ procFsync = modlibc.NewProc("fsync")
+ procFtruncate = modlibc.NewProc("ftruncate")
+ procUmask = modlibc.NewProc("umask")
+ procUnlink = modlibc.NewProc("unlink")
+ procUtimes = modlibc.NewProc("utimes")
+ procbind = modlibsocket.NewProc("bind")
+ procconnect = modlibsocket.NewProc("connect")
+ procmmap = modlibc.NewProc("mmap")
+ procmunmap = modlibc.NewProc("munmap")
+ procsendto = modlibsocket.NewProc("sendto")
+ procsocket = modlibsocket.NewProc("socket")
+ procsocketpair = modlibsocket.NewProc("socketpair")
+ procwrite = modlibc.NewProc("write")
+ procgetsockopt = modlibsocket.NewProc("getsockopt")
+ procgetpeername = modlibsocket.NewProc("getpeername")
+ procgetsockname = modlibsocket.NewProc("getsockname")
+ procsetsockopt = modlibsocket.NewProc("setsockopt")
+ procrecvfrom = modlibsocket.NewProc("recvfrom")
+ procrecvmsg = modlibsocket.NewProc("recvmsg")
+)
+
+func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
+ r0, _, e1 := rawSysvicall6(procgetgroups.Addr(), 2, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0, 0, 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func setgroups(ngid int, gid *_Gid_t) (err error) {
+ _, _, e1 := rawSysvicall6(procsetgroups.Addr(), 2, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func fcntl(fd int, cmd int, arg int) (val int, err error) {
+ r0, _, e1 := sysvicall6(procfcntl.Addr(), 3, uintptr(fd), uintptr(cmd), uintptr(arg), 0, 0, 0)
+ val = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
+ r0, _, e1 := sysvicall6(procaccept.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := sysvicall6(procsendmsg.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Access(path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procAccess.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
+ _, _, e1 := sysvicall6(procAdjtime.Addr(), 2, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Chdir(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procChdir.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Chmod(path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procChmod.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Chown(path string, uid int, gid int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procChown.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Chroot(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procChroot.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Close(fd int) (err error) {
+ _, _, e1 := sysvicall6(procClose.Addr(), 1, uintptr(fd), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Dup(fd int) (nfd int, err error) {
+ r0, _, e1 := sysvicall6(procDup.Addr(), 1, uintptr(fd), 0, 0, 0, 0, 0)
+ nfd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Exit(code int) {
+ sysvicall6(procExit.Addr(), 1, uintptr(code), 0, 0, 0, 0, 0)
+ return
+}
+
+func Fchdir(fd int) (err error) {
+ _, _, e1 := sysvicall6(procFchdir.Addr(), 1, uintptr(fd), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Fchmod(fd int, mode uint32) (err error) {
+ _, _, e1 := sysvicall6(procFchmod.Addr(), 2, uintptr(fd), uintptr(mode), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Fchown(fd int, uid int, gid int) (err error) {
+ _, _, e1 := sysvicall6(procFchown.Addr(), 3, uintptr(fd), uintptr(uid), uintptr(gid), 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Fpathconf(fd int, name int) (val int, err error) {
+ r0, _, e1 := sysvicall6(procFpathconf.Addr(), 2, uintptr(fd), uintptr(name), 0, 0, 0, 0)
+ val = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Fstat(fd int, stat *Stat_t) (err error) {
+ _, _, e1 := sysvicall6(procFstat.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Getdents(fd int, buf []byte, basep *uintptr) (n int, err error) {
+ var _p0 *byte
+ if len(buf) > 0 {
+ _p0 = &buf[0]
+ }
+ r0, _, e1 := sysvicall6(procGetdents.Addr(), 4, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Getgid() (gid int) {
+ r0, _, _ := rawSysvicall6(procGetgid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+ gid = int(r0)
+ return
+}
+
+func Getpid() (pid int) {
+ r0, _, _ := rawSysvicall6(procGetpid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+ pid = int(r0)
+ return
+}
+
+func Geteuid() (euid int) {
+ r0, _, _ := sysvicall6(procGeteuid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+ euid = int(r0)
+ return
+}
+
+func Getegid() (egid int) {
+ r0, _, _ := sysvicall6(procGetegid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+ egid = int(r0)
+ return
+}
+
+func Getppid() (ppid int) {
+ r0, _, _ := sysvicall6(procGetppid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+ ppid = int(r0)
+ return
+}
+
+func Getpriority(which int, who int) (n int, err error) {
+ r0, _, e1 := sysvicall6(procGetpriority.Addr(), 2, uintptr(which), uintptr(who), 0, 0, 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Getrlimit(which int, lim *Rlimit) (err error) {
+ _, _, e1 := rawSysvicall6(procGetrlimit.Addr(), 2, uintptr(which), uintptr(unsafe.Pointer(lim)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Gettimeofday(tv *Timeval) (err error) {
+ _, _, e1 := rawSysvicall6(procGettimeofday.Addr(), 1, uintptr(unsafe.Pointer(tv)), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Getuid() (uid int) {
+ r0, _, _ := rawSysvicall6(procGetuid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+ uid = int(r0)
+ return
+}
+
+func Kill(pid int, signum Signal) (err error) {
+ _, _, e1 := sysvicall6(procKill.Addr(), 2, uintptr(pid), uintptr(signum), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Lchown(path string, uid int, gid int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procLchown.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Link(path string, link string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(link)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procLink.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Listen(s int, backlog int) (err error) {
+ _, _, e1 := sysvicall6(proclisten.Addr(), 2, uintptr(s), uintptr(backlog), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Lstat(path string, stat *Stat_t) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procLstat.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Mkdir(path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procMkdir.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Mknod(path string, mode uint32, dev int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procMknod.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
+ _, _, e1 := sysvicall6(procNanosleep.Addr(), 2, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Open(path string, mode int, perm uint32) (fd int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := sysvicall6(procOpen.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Pathconf(path string, name int) (val int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := sysvicall6(procPathconf.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0, 0, 0, 0)
+ val = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 *byte
+ if len(p) > 0 {
+ _p0 = &p[0]
+ }
+ r0, _, e1 := sysvicall6(procPread.Addr(), 4, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 *byte
+ if len(p) > 0 {
+ _p0 = &p[0]
+ }
+ r0, _, e1 := sysvicall6(procPwrite.Addr(), 4, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func read(fd int, p []byte) (n int, err error) {
+ var _p0 *byte
+ if len(p) > 0 {
+ _p0 = &p[0]
+ }
+ r0, _, e1 := sysvicall6(procread.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0, 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Readlink(path string, buf []byte) (n int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ if len(buf) > 0 {
+ _p1 = &buf[0]
+ }
+ r0, _, e1 := sysvicall6(procReadlink.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(len(buf)), 0, 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Rename(from string, to string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(from)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(to)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procRename.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Rmdir(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procRmdir.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
+ r0, _, e1 := sysvicall6(proclseek.Addr(), 3, uintptr(fd), uintptr(offset), uintptr(whence), 0, 0, 0)
+ newoffset = int64(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Setegid(egid int) (err error) {
+ _, _, e1 := rawSysvicall6(procSetegid.Addr(), 1, uintptr(egid), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Seteuid(euid int) (err error) {
+ _, _, e1 := rawSysvicall6(procSeteuid.Addr(), 1, uintptr(euid), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Setgid(gid int) (err error) {
+ _, _, e1 := rawSysvicall6(procSetgid.Addr(), 1, uintptr(gid), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Setpgid(pid int, pgid int) (err error) {
+ _, _, e1 := rawSysvicall6(procSetpgid.Addr(), 2, uintptr(pid), uintptr(pgid), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Setpriority(which int, who int, prio int) (err error) {
+ _, _, e1 := sysvicall6(procSetpriority.Addr(), 3, uintptr(which), uintptr(who), uintptr(prio), 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Setregid(rgid int, egid int) (err error) {
+ _, _, e1 := rawSysvicall6(procSetregid.Addr(), 2, uintptr(rgid), uintptr(egid), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Setreuid(ruid int, euid int) (err error) {
+ _, _, e1 := rawSysvicall6(procSetreuid.Addr(), 2, uintptr(ruid), uintptr(euid), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Setrlimit(which int, lim *Rlimit) (err error) {
+ _, _, e1 := rawSysvicall6(procSetrlimit.Addr(), 2, uintptr(which), uintptr(unsafe.Pointer(lim)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Setsid() (pid int, err error) {
+ r0, _, e1 := rawSysvicall6(procSetsid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+ pid = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Setuid(uid int) (err error) {
+ _, _, e1 := rawSysvicall6(procSetuid.Addr(), 1, uintptr(uid), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Shutdown(s int, how int) (err error) {
+ _, _, e1 := sysvicall6(procshutdown.Addr(), 2, uintptr(s), uintptr(how), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Stat(path string, stat *Stat_t) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procStat.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Symlink(path string, link string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(link)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procSymlink.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Sync() (err error) {
+ _, _, e1 := sysvicall6(procSync.Addr(), 0, 0, 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Truncate(path string, length int64) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procTruncate.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Fsync(fd int) (err error) {
+ _, _, e1 := sysvicall6(procFsync.Addr(), 1, uintptr(fd), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Ftruncate(fd int, length int64) (err error) {
+ _, _, e1 := sysvicall6(procFtruncate.Addr(), 2, uintptr(fd), uintptr(length), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Umask(newmask int) (oldmask int) {
+ r0, _, _ := sysvicall6(procUmask.Addr(), 1, uintptr(newmask), 0, 0, 0, 0, 0)
+ oldmask = int(r0)
+ return
+}
+
+func Unlink(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procUnlink.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Utimes(path string, times *[2]Timeval) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procUtimes.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
+ _, _, e1 := sysvicall6(procbind.Addr(), 3, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
+ _, _, e1 := sysvicall6(procconnect.Addr(), 3, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) {
+ r0, _, e1 := sysvicall6(procmmap.Addr(), 6, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos))
+ ret = uintptr(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func munmap(addr uintptr, length uintptr) (err error) {
+ _, _, e1 := sysvicall6(procmunmap.Addr(), 2, uintptr(addr), uintptr(length), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
+ var _p0 *byte
+ if len(buf) > 0 {
+ _p0 = &buf[0]
+ }
+ _, _, e1 := sysvicall6(procsendto.Addr(), 6, uintptr(s), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func socket(domain int, typ int, proto int) (fd int, err error) {
+ r0, _, e1 := sysvicall6(procsocket.Addr(), 3, uintptr(domain), uintptr(typ), uintptr(proto), 0, 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
+ _, _, e1 := rawSysvicall6(procsocketpair.Addr(), 4, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func write(fd int, p []byte) (n int, err error) {
+ var _p0 *byte
+ if len(p) > 0 {
+ _p0 = &p[0]
+ }
+ r0, _, e1 := sysvicall6(procwrite.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0, 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
+ _, _, e1 := sysvicall6(procgetsockopt.Addr(), 5, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+ _, _, e1 := rawSysvicall6(procgetpeername.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+ _, _, e1 := sysvicall6(procgetsockname.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
+ _, _, e1 := sysvicall6(procsetsockopt.Addr(), 5, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) {
+ var _p0 *byte
+ if len(p) > 0 {
+ _p0 = &p[0]
+ }
+ r0, _, e1 := sysvicall6(procrecvfrom.Addr(), 6, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := sysvicall6(procrecvmsg.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
diff --git a/src/pkg/syscall/zsyscall_windows_386.go b/src/pkg/syscall/zsyscall_windows_386.go
index 3cd12dd47..132adafef 100644
--- a/src/pkg/syscall/zsyscall_windows_386.go
+++ b/src/pkg/syscall/zsyscall_windows_386.go
@@ -1,4 +1,4 @@
-// mksyscall_windows.pl -l32 syscall_windows.go security_windows.go syscall_windows_386.go
+// go build mksyscall_windows.go && ./mksyscall_windows syscall_windows.go security_windows.go syscall_windows_386.go
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package syscall
@@ -1323,7 +1323,7 @@ func Getsockopt(s Handle, level int32, optname int32, optval *byte, optlen *int3
return
}
-func bind(s Handle, name uintptr, namelen int32) (err error) {
+func bind(s Handle, name unsafe.Pointer, namelen int32) (err error) {
r1, _, e1 := Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
if r1 == socket_error {
if e1 != 0 {
@@ -1335,7 +1335,7 @@ func bind(s Handle, name uintptr, namelen int32) (err error) {
return
}
-func connect(s Handle, name uintptr, namelen int32) (err error) {
+func connect(s Handle, name unsafe.Pointer, namelen int32) (err error) {
r1, _, e1 := Syscall(procconnect.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
if r1 == socket_error {
if e1 != 0 {
diff --git a/src/pkg/syscall/zsyscall_windows_amd64.go b/src/pkg/syscall/zsyscall_windows_amd64.go
index d23c2311a..353a6fd98 100644
--- a/src/pkg/syscall/zsyscall_windows_amd64.go
+++ b/src/pkg/syscall/zsyscall_windows_amd64.go
@@ -1,4 +1,4 @@
-// mksyscall_windows.pl syscall_windows.go security_windows.go syscall_windows_amd64.go
+// go build mksyscall_windows.go && ./mksyscall_windows syscall_windows.go security_windows.go syscall_windows_amd64.go
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package syscall
@@ -1323,7 +1323,7 @@ func Getsockopt(s Handle, level int32, optname int32, optval *byte, optlen *int3
return
}
-func bind(s Handle, name uintptr, namelen int32) (err error) {
+func bind(s Handle, name unsafe.Pointer, namelen int32) (err error) {
r1, _, e1 := Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
if r1 == socket_error {
if e1 != 0 {
@@ -1335,7 +1335,7 @@ func bind(s Handle, name uintptr, namelen int32) (err error) {
return
}
-func connect(s Handle, name uintptr, namelen int32) (err error) {
+func connect(s Handle, name unsafe.Pointer, namelen int32) (err error) {
r1, _, e1 := Syscall(procconnect.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
if r1 == socket_error {
if e1 != 0 {
diff --git a/src/pkg/syscall/zsysctl_openbsd.go b/src/pkg/syscall/zsysctl_openbsd.go
index a5914f3f0..923b2c29f 100644
--- a/src/pkg/syscall/zsysctl_openbsd.go
+++ b/src/pkg/syscall/zsysctl_openbsd.go
@@ -48,8 +48,7 @@ var sysctlMib = []mibentry{
{"kern.cp_time2", []_C_int{1, 71}},
{"kern.cryptodevallowsoft", []_C_int{1, 53}},
{"kern.domainname", []_C_int{1, 22}},
- {"kern.file", []_C_int{1, 15}},
- {"kern.file2", []_C_int{1, 73}},
+ {"kern.file", []_C_int{1, 73}},
{"kern.forkstat", []_C_int{1, 42}},
{"kern.fscale", []_C_int{1, 46}},
{"kern.fsync", []_C_int{1, 33}},
@@ -87,7 +86,6 @@ var sysctlMib = []mibentry{
{"kern.proc", []_C_int{1, 66}},
{"kern.random", []_C_int{1, 31}},
{"kern.rawpartition", []_C_int{1, 24}},
- {"kern.rthreads", []_C_int{1, 74}},
{"kern.saved_ids", []_C_int{1, 20}},
{"kern.securelevel", []_C_int{1, 9}},
{"kern.seminfo", []_C_int{1, 61}},
@@ -226,8 +224,6 @@ var sysctlMib = []mibentry{
{"net.inet6.ip6.forwsrcrt", []_C_int{4, 24, 17, 5}},
{"net.inet6.ip6.hdrnestlimit", []_C_int{4, 24, 17, 15}},
{"net.inet6.ip6.hlim", []_C_int{4, 24, 17, 3}},
- {"net.inet6.ip6.kame_version", []_C_int{4, 24, 17, 20}},
- {"net.inet6.ip6.keepfaith", []_C_int{4, 24, 17, 13}},
{"net.inet6.ip6.log_interval", []_C_int{4, 24, 17, 14}},
{"net.inet6.ip6.maxdynroutes", []_C_int{4, 24, 17, 48}},
{"net.inet6.ip6.maxfragpackets", []_C_int{4, 24, 17, 9}},
@@ -236,7 +232,7 @@ var sysctlMib = []mibentry{
{"net.inet6.ip6.maxifprefixes", []_C_int{4, 24, 17, 46}},
{"net.inet6.ip6.mforwarding", []_C_int{4, 24, 17, 42}},
{"net.inet6.ip6.mrtproto", []_C_int{4, 24, 17, 8}},
- {"net.inet6.ip6.mtu", []_C_int{4, 24, 17, 4}},
+ {"net.inet6.ip6.mtudisctimeout", []_C_int{4, 24, 17, 50}},
{"net.inet6.ip6.multicast_mtudisc", []_C_int{4, 24, 17, 44}},
{"net.inet6.ip6.multipath", []_C_int{4, 24, 17, 43}},
{"net.inet6.ip6.neighborgcthresh", []_C_int{4, 24, 17, 45}},
@@ -258,26 +254,6 @@ var sysctlMib = []mibentry{
{"net.mpls.ttl", []_C_int{4, 33, 2}},
{"net.pflow.stats", []_C_int{4, 34, 1}},
{"net.pipex.enable", []_C_int{4, 35, 1}},
- {"user.bc_base_max", []_C_int{8, 2}},
- {"user.bc_dim_max", []_C_int{8, 3}},
- {"user.bc_scale_max", []_C_int{8, 4}},
- {"user.bc_string_max", []_C_int{8, 5}},
- {"user.coll_weights_max", []_C_int{8, 6}},
- {"user.cs_path", []_C_int{8, 1}},
- {"user.expr_nest_max", []_C_int{8, 7}},
- {"user.line_max", []_C_int{8, 8}},
- {"user.posix2_c_bind", []_C_int{8, 11}},
- {"user.posix2_c_dev", []_C_int{8, 12}},
- {"user.posix2_char_term", []_C_int{8, 13}},
- {"user.posix2_fort_dev", []_C_int{8, 14}},
- {"user.posix2_fort_run", []_C_int{8, 15}},
- {"user.posix2_localedef", []_C_int{8, 16}},
- {"user.posix2_sw_dev", []_C_int{8, 17}},
- {"user.posix2_upe", []_C_int{8, 18}},
- {"user.posix2_version", []_C_int{8, 10}},
- {"user.re_dup_max", []_C_int{8, 9}},
- {"user.stream_max", []_C_int{8, 19}},
- {"user.tzname_max", []_C_int{8, 20}},
{"vm.anonmin", []_C_int{2, 7}},
{"vm.loadavg", []_C_int{2, 2}},
{"vm.maxslp", []_C_int{2, 10}},
diff --git a/src/pkg/syscall/zsysnum_dragonfly_386.go b/src/pkg/syscall/zsysnum_dragonfly_386.go
index 68eeb32ac..4b086b921 100644
--- a/src/pkg/syscall/zsysnum_dragonfly_386.go
+++ b/src/pkg/syscall/zsysnum_dragonfly_386.go
@@ -115,9 +115,6 @@ const (
SYS_UNAME = 164 // { int uname(struct utsname *name); }
SYS_SYSARCH = 165 // { int sysarch(int op, char *parms); }
SYS_RTPRIO = 166 // { int rtprio(int function, pid_t pid, \
- SYS_SEMSYS = 169 // { int semsys(int which, int a2, int a3, int a4, \
- SYS_MSGSYS = 170 // { int msgsys(int which, int a2, int a3, int a4, \
- SYS_SHMSYS = 171 // { int shmsys(int which, int a2, int a3, int a4); }
SYS_EXTPREAD = 173 // { ssize_t extpread(int fd, void *buf, \
SYS_EXTPWRITE = 174 // { ssize_t extpwrite(int fd, const void *buf, \
SYS_NTP_ADJTIME = 176 // { int ntp_adjtime(struct timex *tp); }
@@ -300,4 +297,6 @@ const (
SYS_LINKAT = 531 // { int linkat(int fd1, char *path1, int fd2, \
SYS_EACCESS = 532 // { int eaccess(char *path, int flags); }
SYS_LPATHCONF = 533 // { int lpathconf(char *path, int name); }
+ SYS_VMM_GUEST_CTL = 534 // { int vmm_guest_ctl(int op, struct vmm_guest_options *options); }
+ SYS_VMM_GUEST_SYNC_ADDR = 535 // { int vmm_guest_sync_addr(long *dstaddr, long *srcaddr); }
)
diff --git a/src/pkg/syscall/zsysnum_dragonfly_amd64.go b/src/pkg/syscall/zsysnum_dragonfly_amd64.go
index 68eeb32ac..4b086b921 100644
--- a/src/pkg/syscall/zsysnum_dragonfly_amd64.go
+++ b/src/pkg/syscall/zsysnum_dragonfly_amd64.go
@@ -115,9 +115,6 @@ const (
SYS_UNAME = 164 // { int uname(struct utsname *name); }
SYS_SYSARCH = 165 // { int sysarch(int op, char *parms); }
SYS_RTPRIO = 166 // { int rtprio(int function, pid_t pid, \
- SYS_SEMSYS = 169 // { int semsys(int which, int a2, int a3, int a4, \
- SYS_MSGSYS = 170 // { int msgsys(int which, int a2, int a3, int a4, \
- SYS_SHMSYS = 171 // { int shmsys(int which, int a2, int a3, int a4); }
SYS_EXTPREAD = 173 // { ssize_t extpread(int fd, void *buf, \
SYS_EXTPWRITE = 174 // { ssize_t extpwrite(int fd, const void *buf, \
SYS_NTP_ADJTIME = 176 // { int ntp_adjtime(struct timex *tp); }
@@ -300,4 +297,6 @@ const (
SYS_LINKAT = 531 // { int linkat(int fd1, char *path1, int fd2, \
SYS_EACCESS = 532 // { int eaccess(char *path, int flags); }
SYS_LPATHCONF = 533 // { int lpathconf(char *path, int name); }
+ SYS_VMM_GUEST_CTL = 534 // { int vmm_guest_ctl(int op, struct vmm_guest_options *options); }
+ SYS_VMM_GUEST_SYNC_ADDR = 535 // { int vmm_guest_sync_addr(long *dstaddr, long *srcaddr); }
)
diff --git a/src/pkg/syscall/zsysnum_freebsd_386.go b/src/pkg/syscall/zsysnum_freebsd_386.go
index 74400b6f6..dfca558bb 100644
--- a/src/pkg/syscall/zsysnum_freebsd_386.go
+++ b/src/pkg/syscall/zsysnum_freebsd_386.go
@@ -34,8 +34,8 @@ const (
SYS_GETPEERNAME = 31 // { int getpeername(int fdes, \
SYS_GETSOCKNAME = 32 // { int getsockname(int fdes, \
SYS_ACCESS = 33 // { int access(char *path, int amode); }
- SYS_CHFLAGS = 34 // { int chflags(char *path, int flags); }
- SYS_FCHFLAGS = 35 // { int fchflags(int fd, int flags); }
+ SYS_CHFLAGS = 34 // { int chflags(const char *path, u_long flags); }
+ SYS_FCHFLAGS = 35 // { int fchflags(int fd, u_long flags); }
SYS_SYNC = 36 // { int sync(void); }
SYS_KILL = 37 // { int kill(int pid, int signum); }
SYS_GETPPID = 39 // { pid_t getppid(void); }
@@ -208,14 +208,14 @@ const (
SYS___ACL_ACLCHECK_FILE = 353 // { int __acl_aclcheck_file(const char *path, \
SYS___ACL_ACLCHECK_FD = 354 // { int __acl_aclcheck_fd(int filedes, \
SYS_EXTATTRCTL = 355 // { int extattrctl(const char *path, int cmd, \
- SYS_EXTATTR_SET_FILE = 356 // { int extattr_set_file( \
+ SYS_EXTATTR_SET_FILE = 356 // { ssize_t extattr_set_file( \
SYS_EXTATTR_GET_FILE = 357 // { ssize_t extattr_get_file( \
SYS_EXTATTR_DELETE_FILE = 358 // { int extattr_delete_file(const char *path, \
SYS_GETRESUID = 360 // { int getresuid(uid_t *ruid, uid_t *euid, \
SYS_GETRESGID = 361 // { int getresgid(gid_t *rgid, gid_t *egid, \
SYS_KQUEUE = 362 // { int kqueue(void); }
SYS_KEVENT = 363 // { int kevent(int fd, \
- SYS_EXTATTR_SET_FD = 371 // { int extattr_set_fd(int fd, \
+ SYS_EXTATTR_SET_FD = 371 // { ssize_t extattr_set_fd(int fd, \
SYS_EXTATTR_GET_FD = 372 // { ssize_t extattr_get_fd(int fd, \
SYS_EXTATTR_DELETE_FD = 373 // { int extattr_delete_fd(int fd, \
SYS___SETUGID = 374 // { int __setugid(int flag); }
@@ -228,7 +228,7 @@ const (
SYS___MAC_SET_FD = 388 // { int __mac_set_fd(int fd, \
SYS___MAC_SET_FILE = 389 // { int __mac_set_file(const char *path_p, \
SYS_KENV = 390 // { int kenv(int what, const char *name, \
- SYS_LCHFLAGS = 391 // { int lchflags(const char *path, int flags); }
+ SYS_LCHFLAGS = 391 // { int lchflags(const char *path, \
SYS_UUIDGEN = 392 // { int uuidgen(struct uuid *store, \
SYS_SENDFILE = 393 // { int sendfile(int fd, int s, off_t offset, \
SYS_MAC_SYSCALL = 394 // { int mac_syscall(const char *policy, \
@@ -239,7 +239,7 @@ const (
SYS___MAC_GET_PID = 409 // { int __mac_get_pid(pid_t pid, \
SYS___MAC_GET_LINK = 410 // { int __mac_get_link(const char *path_p, \
SYS___MAC_SET_LINK = 411 // { int __mac_set_link(const char *path_p, \
- SYS_EXTATTR_SET_LINK = 412 // { int extattr_set_link( \
+ SYS_EXTATTR_SET_LINK = 412 // { ssize_t extattr_set_link( \
SYS_EXTATTR_GET_LINK = 413 // { ssize_t extattr_get_link( \
SYS_EXTATTR_DELETE_LINK = 414 // { int extattr_delete_link( \
SYS___MAC_EXECVE = 415 // { int __mac_execve(char *fname, char **argv, \
@@ -338,5 +338,11 @@ const (
SYS_RCTL_REMOVE_RULE = 529 // { int rctl_remove_rule(const void *inbufp, \
SYS_POSIX_FALLOCATE = 530 // { int posix_fallocate(int fd, \
SYS_POSIX_FADVISE = 531 // { int posix_fadvise(int fd, off_t offset, \
- SYS_WAIT6 = 532 // { int wait6(int idtype, int id, \
+ SYS_WAIT6 = 532 // { int wait6(idtype_t idtype, id_t id, \
+ SYS_BINDAT = 538 // { int bindat(int fd, int s, caddr_t name, \
+ SYS_CONNECTAT = 539 // { int connectat(int fd, int s, caddr_t name, \
+ SYS_CHFLAGSAT = 540 // { int chflagsat(int fd, const char *path, \
+ SYS_ACCEPT4 = 541 // { int accept4(int s, \
+ SYS_PIPE2 = 542 // { int pipe2(int *fildes, int flags); }
+ SYS_PROCCTL = 544 // { int procctl(idtype_t idtype, id_t id, \
)
diff --git a/src/pkg/syscall/zsysnum_freebsd_amd64.go b/src/pkg/syscall/zsysnum_freebsd_amd64.go
index 74400b6f6..dfca558bb 100644
--- a/src/pkg/syscall/zsysnum_freebsd_amd64.go
+++ b/src/pkg/syscall/zsysnum_freebsd_amd64.go
@@ -34,8 +34,8 @@ const (
SYS_GETPEERNAME = 31 // { int getpeername(int fdes, \
SYS_GETSOCKNAME = 32 // { int getsockname(int fdes, \
SYS_ACCESS = 33 // { int access(char *path, int amode); }
- SYS_CHFLAGS = 34 // { int chflags(char *path, int flags); }
- SYS_FCHFLAGS = 35 // { int fchflags(int fd, int flags); }
+ SYS_CHFLAGS = 34 // { int chflags(const char *path, u_long flags); }
+ SYS_FCHFLAGS = 35 // { int fchflags(int fd, u_long flags); }
SYS_SYNC = 36 // { int sync(void); }
SYS_KILL = 37 // { int kill(int pid, int signum); }
SYS_GETPPID = 39 // { pid_t getppid(void); }
@@ -208,14 +208,14 @@ const (
SYS___ACL_ACLCHECK_FILE = 353 // { int __acl_aclcheck_file(const char *path, \
SYS___ACL_ACLCHECK_FD = 354 // { int __acl_aclcheck_fd(int filedes, \
SYS_EXTATTRCTL = 355 // { int extattrctl(const char *path, int cmd, \
- SYS_EXTATTR_SET_FILE = 356 // { int extattr_set_file( \
+ SYS_EXTATTR_SET_FILE = 356 // { ssize_t extattr_set_file( \
SYS_EXTATTR_GET_FILE = 357 // { ssize_t extattr_get_file( \
SYS_EXTATTR_DELETE_FILE = 358 // { int extattr_delete_file(const char *path, \
SYS_GETRESUID = 360 // { int getresuid(uid_t *ruid, uid_t *euid, \
SYS_GETRESGID = 361 // { int getresgid(gid_t *rgid, gid_t *egid, \
SYS_KQUEUE = 362 // { int kqueue(void); }
SYS_KEVENT = 363 // { int kevent(int fd, \
- SYS_EXTATTR_SET_FD = 371 // { int extattr_set_fd(int fd, \
+ SYS_EXTATTR_SET_FD = 371 // { ssize_t extattr_set_fd(int fd, \
SYS_EXTATTR_GET_FD = 372 // { ssize_t extattr_get_fd(int fd, \
SYS_EXTATTR_DELETE_FD = 373 // { int extattr_delete_fd(int fd, \
SYS___SETUGID = 374 // { int __setugid(int flag); }
@@ -228,7 +228,7 @@ const (
SYS___MAC_SET_FD = 388 // { int __mac_set_fd(int fd, \
SYS___MAC_SET_FILE = 389 // { int __mac_set_file(const char *path_p, \
SYS_KENV = 390 // { int kenv(int what, const char *name, \
- SYS_LCHFLAGS = 391 // { int lchflags(const char *path, int flags); }
+ SYS_LCHFLAGS = 391 // { int lchflags(const char *path, \
SYS_UUIDGEN = 392 // { int uuidgen(struct uuid *store, \
SYS_SENDFILE = 393 // { int sendfile(int fd, int s, off_t offset, \
SYS_MAC_SYSCALL = 394 // { int mac_syscall(const char *policy, \
@@ -239,7 +239,7 @@ const (
SYS___MAC_GET_PID = 409 // { int __mac_get_pid(pid_t pid, \
SYS___MAC_GET_LINK = 410 // { int __mac_get_link(const char *path_p, \
SYS___MAC_SET_LINK = 411 // { int __mac_set_link(const char *path_p, \
- SYS_EXTATTR_SET_LINK = 412 // { int extattr_set_link( \
+ SYS_EXTATTR_SET_LINK = 412 // { ssize_t extattr_set_link( \
SYS_EXTATTR_GET_LINK = 413 // { ssize_t extattr_get_link( \
SYS_EXTATTR_DELETE_LINK = 414 // { int extattr_delete_link( \
SYS___MAC_EXECVE = 415 // { int __mac_execve(char *fname, char **argv, \
@@ -338,5 +338,11 @@ const (
SYS_RCTL_REMOVE_RULE = 529 // { int rctl_remove_rule(const void *inbufp, \
SYS_POSIX_FALLOCATE = 530 // { int posix_fallocate(int fd, \
SYS_POSIX_FADVISE = 531 // { int posix_fadvise(int fd, off_t offset, \
- SYS_WAIT6 = 532 // { int wait6(int idtype, int id, \
+ SYS_WAIT6 = 532 // { int wait6(idtype_t idtype, id_t id, \
+ SYS_BINDAT = 538 // { int bindat(int fd, int s, caddr_t name, \
+ SYS_CONNECTAT = 539 // { int connectat(int fd, int s, caddr_t name, \
+ SYS_CHFLAGSAT = 540 // { int chflagsat(int fd, const char *path, \
+ SYS_ACCEPT4 = 541 // { int accept4(int s, \
+ SYS_PIPE2 = 542 // { int pipe2(int *fildes, int flags); }
+ SYS_PROCCTL = 544 // { int procctl(idtype_t idtype, id_t id, \
)
diff --git a/src/pkg/syscall/zsysnum_freebsd_arm.go b/src/pkg/syscall/zsysnum_freebsd_arm.go
index 61a6a3295..dfca558bb 100644
--- a/src/pkg/syscall/zsysnum_freebsd_arm.go
+++ b/src/pkg/syscall/zsysnum_freebsd_arm.go
@@ -34,8 +34,8 @@ const (
SYS_GETPEERNAME = 31 // { int getpeername(int fdes, \
SYS_GETSOCKNAME = 32 // { int getsockname(int fdes, \
SYS_ACCESS = 33 // { int access(char *path, int amode); }
- SYS_CHFLAGS = 34 // { int chflags(char *path, int flags); }
- SYS_FCHFLAGS = 35 // { int fchflags(int fd, int flags); }
+ SYS_CHFLAGS = 34 // { int chflags(const char *path, u_long flags); }
+ SYS_FCHFLAGS = 35 // { int fchflags(int fd, u_long flags); }
SYS_SYNC = 36 // { int sync(void); }
SYS_KILL = 37 // { int kill(int pid, int signum); }
SYS_GETPPID = 39 // { pid_t getppid(void); }
@@ -208,14 +208,14 @@ const (
SYS___ACL_ACLCHECK_FILE = 353 // { int __acl_aclcheck_file(const char *path, \
SYS___ACL_ACLCHECK_FD = 354 // { int __acl_aclcheck_fd(int filedes, \
SYS_EXTATTRCTL = 355 // { int extattrctl(const char *path, int cmd, \
- SYS_EXTATTR_SET_FILE = 356 // { int extattr_set_file( \
+ SYS_EXTATTR_SET_FILE = 356 // { ssize_t extattr_set_file( \
SYS_EXTATTR_GET_FILE = 357 // { ssize_t extattr_get_file( \
SYS_EXTATTR_DELETE_FILE = 358 // { int extattr_delete_file(const char *path, \
SYS_GETRESUID = 360 // { int getresuid(uid_t *ruid, uid_t *euid, \
SYS_GETRESGID = 361 // { int getresgid(gid_t *rgid, gid_t *egid, \
SYS_KQUEUE = 362 // { int kqueue(void); }
SYS_KEVENT = 363 // { int kevent(int fd, \
- SYS_EXTATTR_SET_FD = 371 // { int extattr_set_fd(int fd, \
+ SYS_EXTATTR_SET_FD = 371 // { ssize_t extattr_set_fd(int fd, \
SYS_EXTATTR_GET_FD = 372 // { ssize_t extattr_get_fd(int fd, \
SYS_EXTATTR_DELETE_FD = 373 // { int extattr_delete_fd(int fd, \
SYS___SETUGID = 374 // { int __setugid(int flag); }
@@ -228,7 +228,7 @@ const (
SYS___MAC_SET_FD = 388 // { int __mac_set_fd(int fd, \
SYS___MAC_SET_FILE = 389 // { int __mac_set_file(const char *path_p, \
SYS_KENV = 390 // { int kenv(int what, const char *name, \
- SYS_LCHFLAGS = 391 // { int lchflags(const char *path, int flags); }
+ SYS_LCHFLAGS = 391 // { int lchflags(const char *path, \
SYS_UUIDGEN = 392 // { int uuidgen(struct uuid *store, \
SYS_SENDFILE = 393 // { int sendfile(int fd, int s, off_t offset, \
SYS_MAC_SYSCALL = 394 // { int mac_syscall(const char *policy, \
@@ -239,7 +239,7 @@ const (
SYS___MAC_GET_PID = 409 // { int __mac_get_pid(pid_t pid, \
SYS___MAC_GET_LINK = 410 // { int __mac_get_link(const char *path_p, \
SYS___MAC_SET_LINK = 411 // { int __mac_set_link(const char *path_p, \
- SYS_EXTATTR_SET_LINK = 412 // { int extattr_set_link( \
+ SYS_EXTATTR_SET_LINK = 412 // { ssize_t extattr_set_link( \
SYS_EXTATTR_GET_LINK = 413 // { ssize_t extattr_get_link( \
SYS_EXTATTR_DELETE_LINK = 414 // { int extattr_delete_link( \
SYS___MAC_EXECVE = 415 // { int __mac_execve(char *fname, char **argv, \
@@ -322,7 +322,7 @@ const (
SYS_CLOSEFROM = 509 // { int closefrom(int lowfd); }
SYS_LPATHCONF = 513 // { int lpathconf(char *path, int name); }
SYS_CAP_NEW = 514 // { int cap_new(int fd, uint64_t rights); }
- SYS_CAP_RIGHTS_GET = 515 // { int cap_rights_get(int fd, \
+ SYS_CAP_GETRIGHTS = 515 // { int cap_getrights(int fd, \
SYS_CAP_ENTER = 516 // { int cap_enter(void); }
SYS_CAP_GETMODE = 517 // { int cap_getmode(u_int *modep); }
SYS_PDFORK = 518 // { int pdfork(int *fdp, int flags); }
@@ -338,10 +338,11 @@ const (
SYS_RCTL_REMOVE_RULE = 529 // { int rctl_remove_rule(const void *inbufp, \
SYS_POSIX_FALLOCATE = 530 // { int posix_fallocate(int fd, \
SYS_POSIX_FADVISE = 531 // { int posix_fadvise(int fd, off_t offset, \
- SYS_WAIT6 = 532 // { int wait6(int idtype, int id, \
- SYS_CAP_RIGHTS_LIMIT = 533 // { int cap_rights_limit(int fd, \
- SYS_CAP_IOCTLS_LIMIT = 534 // { int cap_ioctls_limit(int fd, \
- SYS_CAP_IOCTLS_GET = 535 // { ssize_t cap_ioctls_get(int fd, \
- SYS_CAP_FCNTLS_LIMIT = 536 // { int cap_fcntls_limit(int fd, \
- SYS_CAP_FCNTLS_GET = 537 // { int cap_fcntls_get(int fd, \
+ SYS_WAIT6 = 532 // { int wait6(idtype_t idtype, id_t id, \
+ SYS_BINDAT = 538 // { int bindat(int fd, int s, caddr_t name, \
+ SYS_CONNECTAT = 539 // { int connectat(int fd, int s, caddr_t name, \
+ SYS_CHFLAGSAT = 540 // { int chflagsat(int fd, const char *path, \
+ SYS_ACCEPT4 = 541 // { int accept4(int s, \
+ SYS_PIPE2 = 542 // { int pipe2(int *fildes, int flags); }
+ SYS_PROCCTL = 544 // { int procctl(idtype_t idtype, id_t id, \
)
diff --git a/src/pkg/syscall/zsysnum_openbsd_386.go b/src/pkg/syscall/zsysnum_openbsd_386.go
index 82c98b90e..3b9ac4c94 100644
--- a/src/pkg/syscall/zsysnum_openbsd_386.go
+++ b/src/pkg/syscall/zsysnum_openbsd_386.go
@@ -10,10 +10,10 @@ const (
SYS_WRITE = 4 // { ssize_t sys_write(int fd, const void *buf, \
SYS_OPEN = 5 // { int sys_open(const char *path, \
SYS_CLOSE = 6 // { int sys_close(int fd); }
- SYS_WAIT4 = 7 // { pid_t sys_wait4(pid_t pid, int *status, int options, \
SYS___TFORK = 8 // { int sys___tfork(const struct __tfork *param, \
SYS_LINK = 9 // { int sys_link(const char *path, const char *link); }
SYS_UNLINK = 10 // { int sys_unlink(const char *path); }
+ SYS_WAIT4 = 11 // { pid_t sys_wait4(pid_t pid, int *status, \
SYS_CHDIR = 12 // { int sys_chdir(const char *path); }
SYS_FCHDIR = 13 // { int sys_fchdir(int fd); }
SYS_MKNOD = 14 // { int sys_mknod(const char *path, mode_t mode, \
@@ -21,6 +21,7 @@ const (
SYS_CHOWN = 16 // { int sys_chown(const char *path, uid_t uid, \
SYS_OBREAK = 17 // { int sys_obreak(char *nsize); } break
SYS_GETDTABLECOUNT = 18 // { int sys_getdtablecount(void); }
+ SYS_GETRUSAGE = 19 // { int sys_getrusage(int who, \
SYS_GETPID = 20 // { pid_t sys_getpid(void); }
SYS_MOUNT = 21 // { int sys_mount(const char *type, const char *path, \
SYS_UNMOUNT = 22 // { int sys_unmount(const char *path, int flags); }
@@ -39,8 +40,11 @@ const (
SYS_FCHFLAGS = 35 // { int sys_fchflags(int fd, u_int flags); }
SYS_SYNC = 36 // { void sys_sync(void); }
SYS_KILL = 37 // { int sys_kill(int pid, int signum); }
+ SYS_STAT = 38 // { int sys_stat(const char *path, struct stat *ub); }
SYS_GETPPID = 39 // { pid_t sys_getppid(void); }
+ SYS_LSTAT = 40 // { int sys_lstat(const char *path, struct stat *ub); }
SYS_DUP = 41 // { int sys_dup(int fd); }
+ SYS_FSTATAT = 42 // { int sys_fstatat(int fd, const char *path, \
SYS_GETEGID = 43 // { gid_t sys_getegid(void); }
SYS_PROFIL = 44 // { int sys_profil(caddr_t samples, size_t size, \
SYS_KTRACE = 45 // { int sys_ktrace(const char *fname, int ops, \
@@ -51,6 +55,7 @@ const (
SYS_SETLOGIN = 50 // { int sys_setlogin(const char *namebuf); }
SYS_ACCT = 51 // { int sys_acct(const char *path); }
SYS_SIGPENDING = 52 // { int sys_sigpending(void); }
+ SYS_FSTAT = 53 // { int sys_fstat(int fd, struct stat *sb); }
SYS_IOCTL = 54 // { int sys_ioctl(int fd, \
SYS_REBOOT = 55 // { int sys_reboot(int opt); }
SYS_REVOKE = 56 // { int sys_revoke(const char *path); }
@@ -59,36 +64,52 @@ const (
SYS_EXECVE = 59 // { int sys_execve(const char *path, \
SYS_UMASK = 60 // { mode_t sys_umask(mode_t newmask); }
SYS_CHROOT = 61 // { int sys_chroot(const char *path); }
+ SYS_GETFSSTAT = 62 // { int sys_getfsstat(struct statfs *buf, size_t bufsize, \
+ SYS_STATFS = 63 // { int sys_statfs(const char *path, \
+ SYS_FSTATFS = 64 // { int sys_fstatfs(int fd, struct statfs *buf); }
+ SYS_FHSTATFS = 65 // { int sys_fhstatfs(const fhandle_t *fhp, \
SYS_VFORK = 66 // { int sys_vfork(void); }
+ SYS_GETTIMEOFDAY = 67 // { int sys_gettimeofday(struct timeval *tp, \
+ SYS_SETTIMEOFDAY = 68 // { int sys_settimeofday(const struct timeval *tv, \
+ SYS_SETITIMER = 69 // { int sys_setitimer(int which, \
+ SYS_GETITIMER = 70 // { int sys_getitimer(int which, \
+ SYS_SELECT = 71 // { int sys_select(int nd, fd_set *in, fd_set *ou, \
+ SYS_KEVENT = 72 // { int sys_kevent(int fd, \
SYS_MUNMAP = 73 // { int sys_munmap(void *addr, size_t len); }
SYS_MPROTECT = 74 // { int sys_mprotect(void *addr, size_t len, \
SYS_MADVISE = 75 // { int sys_madvise(void *addr, size_t len, \
+ SYS_UTIMES = 76 // { int sys_utimes(const char *path, \
+ SYS_FUTIMES = 77 // { int sys_futimes(int fd, \
SYS_MINCORE = 78 // { int sys_mincore(void *addr, size_t len, \
SYS_GETGROUPS = 79 // { int sys_getgroups(int gidsetsize, \
SYS_SETGROUPS = 80 // { int sys_setgroups(int gidsetsize, \
SYS_GETPGRP = 81 // { int sys_getpgrp(void); }
SYS_SETPGID = 82 // { int sys_setpgid(pid_t pid, int pgid); }
- SYS_SETITIMER = 83 // { int sys_setitimer(int which, \
- SYS_GETITIMER = 86 // { int sys_getitimer(int which, \
+ SYS_UTIMENSAT = 84 // { int sys_utimensat(int fd, const char *path, \
+ SYS_FUTIMENS = 85 // { int sys_futimens(int fd, \
+ SYS_CLOCK_GETTIME = 87 // { int sys_clock_gettime(clockid_t clock_id, \
+ SYS_CLOCK_SETTIME = 88 // { int sys_clock_settime(clockid_t clock_id, \
+ SYS_CLOCK_GETRES = 89 // { int sys_clock_getres(clockid_t clock_id, \
SYS_DUP2 = 90 // { int sys_dup2(int from, int to); }
+ SYS_NANOSLEEP = 91 // { int sys_nanosleep(const struct timespec *rqtp, \
SYS_FCNTL = 92 // { int sys_fcntl(int fd, int cmd, ... void *arg); }
- SYS_SELECT = 93 // { int sys_select(int nd, fd_set *in, fd_set *ou, \
+ SYS___THRSLEEP = 94 // { int sys___thrsleep(const volatile void *ident, \
SYS_FSYNC = 95 // { int sys_fsync(int fd); }
SYS_SETPRIORITY = 96 // { int sys_setpriority(int which, id_t who, int prio); }
SYS_SOCKET = 97 // { int sys_socket(int domain, int type, int protocol); }
SYS_CONNECT = 98 // { int sys_connect(int s, const struct sockaddr *name, \
+ SYS_GETDENTS = 99 // { int sys_getdents(int fd, void *buf, size_t buflen); }
SYS_GETPRIORITY = 100 // { int sys_getpriority(int which, id_t who); }
SYS_SIGRETURN = 103 // { int sys_sigreturn(struct sigcontext *sigcntxp); }
SYS_BIND = 104 // { int sys_bind(int s, const struct sockaddr *name, \
SYS_SETSOCKOPT = 105 // { int sys_setsockopt(int s, int level, int name, \
SYS_LISTEN = 106 // { int sys_listen(int s, int backlog); }
+ SYS_PPOLL = 109 // { int sys_ppoll(struct pollfd *fds, \
+ SYS_PSELECT = 110 // { int sys_pselect(int nd, fd_set *in, fd_set *ou, \
SYS_SIGSUSPEND = 111 // { int sys_sigsuspend(int mask); }
- SYS_GETTIMEOFDAY = 116 // { int sys_gettimeofday(struct timeval *tp, \
- SYS_GETRUSAGE = 117 // { int sys_getrusage(int who, struct rusage *rusage); }
SYS_GETSOCKOPT = 118 // { int sys_getsockopt(int s, int level, int name, \
SYS_READV = 120 // { ssize_t sys_readv(int fd, \
SYS_WRITEV = 121 // { ssize_t sys_writev(int fd, \
- SYS_SETTIMEOFDAY = 122 // { int sys_settimeofday(const struct timeval *tv, \
SYS_FCHOWN = 123 // { int sys_fchown(int fd, uid_t uid, gid_t gid); }
SYS_FCHMOD = 124 // { int sys_fchmod(int fd, mode_t mode); }
SYS_SETREUID = 126 // { int sys_setreuid(uid_t ruid, uid_t euid); }
@@ -101,7 +122,6 @@ const (
SYS_SOCKETPAIR = 135 // { int sys_socketpair(int domain, int type, \
SYS_MKDIR = 136 // { int sys_mkdir(const char *path, mode_t mode); }
SYS_RMDIR = 137 // { int sys_rmdir(const char *path); }
- SYS_UTIMES = 138 // { int sys_utimes(const char *path, \
SYS_ADJTIME = 140 // { int sys_adjtime(const struct timeval *delta, \
SYS_SETSID = 147 // { int sys_setsid(void); }
SYS_QUOTACTL = 148 // { int sys_quotactl(const char *path, int cmd, \
@@ -122,21 +142,17 @@ const (
SYS_LSEEK = 199 // { off_t sys_lseek(int fd, int pad, off_t offset, \
SYS_TRUNCATE = 200 // { int sys_truncate(const char *path, int pad, \
SYS_FTRUNCATE = 201 // { int sys_ftruncate(int fd, int pad, off_t length); }
- SYS___SYSCTL = 202 // { int sys___sysctl(int *name, u_int namelen, \
+ SYS___SYSCTL = 202 // { int sys___sysctl(const int *name, u_int namelen, \
SYS_MLOCK = 203 // { int sys_mlock(const void *addr, size_t len); }
SYS_MUNLOCK = 204 // { int sys_munlock(const void *addr, size_t len); }
- SYS_FUTIMES = 206 // { int sys_futimes(int fd, \
SYS_GETPGID = 207 // { pid_t sys_getpgid(pid_t pid); }
+ SYS_UTRACE = 209 // { int sys_utrace(const char *label, const void *addr, \
SYS_SEMGET = 221 // { int sys_semget(key_t key, int nsems, int semflg); }
SYS_MSGGET = 225 // { int sys_msgget(key_t key, int msgflg); }
SYS_MSGSND = 226 // { int sys_msgsnd(int msqid, const void *msgp, size_t msgsz, \
SYS_MSGRCV = 227 // { int sys_msgrcv(int msqid, void *msgp, size_t msgsz, \
SYS_SHMAT = 228 // { void *sys_shmat(int shmid, const void *shmaddr, \
SYS_SHMDT = 230 // { int sys_shmdt(const void *shmaddr); }
- SYS_CLOCK_GETTIME = 232 // { int sys_clock_gettime(clockid_t clock_id, \
- SYS_CLOCK_SETTIME = 233 // { int sys_clock_settime(clockid_t clock_id, \
- SYS_CLOCK_GETRES = 234 // { int sys_clock_getres(clockid_t clock_id, \
- SYS_NANOSLEEP = 240 // { int sys_nanosleep(const struct timespec *rqtp, \
SYS_MINHERIT = 250 // { int sys_minherit(void *addr, size_t len, \
SYS_POLL = 252 // { int sys_poll(struct pollfd *fds, \
SYS_ISSETUGID = 253 // { int sys_issetugid(void); }
@@ -148,7 +164,6 @@ const (
SYS_PREADV = 267 // { ssize_t sys_preadv(int fd, \
SYS_PWRITEV = 268 // { ssize_t sys_pwritev(int fd, \
SYS_KQUEUE = 269 // { int sys_kqueue(void); }
- SYS_KEVENT = 270 // { int sys_kevent(int fd, \
SYS_MLOCKALL = 271 // { int sys_mlockall(int flags); }
SYS_MUNLOCKALL = 272 // { int sys_munlockall(void); }
SYS_GETRESUID = 281 // { int sys_getresuid(uid_t *ruid, uid_t *euid, \
@@ -160,32 +175,22 @@ const (
SYS_SIGALTSTACK = 288 // { int sys_sigaltstack(const struct sigaltstack *nss, \
SYS_SHMGET = 289 // { int sys_shmget(key_t key, size_t size, int shmflg); }
SYS_SEMOP = 290 // { int sys_semop(int semid, struct sembuf *sops, \
- SYS_STAT = 291 // { int sys_stat(const char *path, struct stat *ub); }
- SYS_FSTAT = 292 // { int sys_fstat(int fd, struct stat *sb); }
- SYS_LSTAT = 293 // { int sys_lstat(const char *path, struct stat *ub); }
SYS_FHSTAT = 294 // { int sys_fhstat(const fhandle_t *fhp, \
SYS___SEMCTL = 295 // { int sys___semctl(int semid, int semnum, int cmd, \
SYS_SHMCTL = 296 // { int sys_shmctl(int shmid, int cmd, \
SYS_MSGCTL = 297 // { int sys_msgctl(int msqid, int cmd, \
SYS_SCHED_YIELD = 298 // { int sys_sched_yield(void); }
SYS_GETTHRID = 299 // { pid_t sys_getthrid(void); }
- SYS___THRSLEEP = 300 // { int sys___thrsleep(const volatile void *ident, \
SYS___THRWAKEUP = 301 // { int sys___thrwakeup(const volatile void *ident, \
SYS___THREXIT = 302 // { void sys___threxit(pid_t *notdead); }
SYS___THRSIGDIVERT = 303 // { int sys___thrsigdivert(sigset_t sigmask, \
SYS___GETCWD = 304 // { int sys___getcwd(char *buf, size_t len); }
SYS_ADJFREQ = 305 // { int sys_adjfreq(const int64_t *freq, \
- SYS_GETFSSTAT = 306 // { int sys_getfsstat(struct statfs *buf, size_t bufsize, \
- SYS_STATFS = 307 // { int sys_statfs(const char *path, \
- SYS_FSTATFS = 308 // { int sys_fstatfs(int fd, struct statfs *buf); }
- SYS_FHSTATFS = 309 // { int sys_fhstatfs(const fhandle_t *fhp, \
SYS_SETRTABLE = 310 // { int sys_setrtable(int rtableid); }
SYS_GETRTABLE = 311 // { int sys_getrtable(void); }
- SYS_GETDIRENTRIES = 312 // { int sys_getdirentries(int fd, char *buf, \
SYS_FACCESSAT = 313 // { int sys_faccessat(int fd, const char *path, \
SYS_FCHMODAT = 314 // { int sys_fchmodat(int fd, const char *path, \
SYS_FCHOWNAT = 315 // { int sys_fchownat(int fd, const char *path, \
- SYS_FSTATAT = 316 // { int sys_fstatat(int fd, const char *path, \
SYS_LINKAT = 317 // { int sys_linkat(int fd1, const char *path1, int fd2, \
SYS_MKDIRAT = 318 // { int sys_mkdirat(int fd, const char *path, \
SYS_MKFIFOAT = 319 // { int sys_mkfifoat(int fd, const char *path, \
@@ -195,8 +200,6 @@ const (
SYS_RENAMEAT = 323 // { int sys_renameat(int fromfd, const char *from, \
SYS_SYMLINKAT = 324 // { int sys_symlinkat(const char *path, int fd, \
SYS_UNLINKAT = 325 // { int sys_unlinkat(int fd, const char *path, \
- SYS_UTIMENSAT = 326 // { int sys_utimensat(int fd, const char *path, \
- SYS_FUTIMENS = 327 // { int sys_futimens(int fd, \
SYS___SET_TCB = 329 // { void sys___set_tcb(void *tcb); }
SYS___GET_TCB = 330 // { void *sys___get_tcb(void); }
)
diff --git a/src/pkg/syscall/zsysnum_openbsd_amd64.go b/src/pkg/syscall/zsysnum_openbsd_amd64.go
index 82c98b90e..3b9ac4c94 100644
--- a/src/pkg/syscall/zsysnum_openbsd_amd64.go
+++ b/src/pkg/syscall/zsysnum_openbsd_amd64.go
@@ -10,10 +10,10 @@ const (
SYS_WRITE = 4 // { ssize_t sys_write(int fd, const void *buf, \
SYS_OPEN = 5 // { int sys_open(const char *path, \
SYS_CLOSE = 6 // { int sys_close(int fd); }
- SYS_WAIT4 = 7 // { pid_t sys_wait4(pid_t pid, int *status, int options, \
SYS___TFORK = 8 // { int sys___tfork(const struct __tfork *param, \
SYS_LINK = 9 // { int sys_link(const char *path, const char *link); }
SYS_UNLINK = 10 // { int sys_unlink(const char *path); }
+ SYS_WAIT4 = 11 // { pid_t sys_wait4(pid_t pid, int *status, \
SYS_CHDIR = 12 // { int sys_chdir(const char *path); }
SYS_FCHDIR = 13 // { int sys_fchdir(int fd); }
SYS_MKNOD = 14 // { int sys_mknod(const char *path, mode_t mode, \
@@ -21,6 +21,7 @@ const (
SYS_CHOWN = 16 // { int sys_chown(const char *path, uid_t uid, \
SYS_OBREAK = 17 // { int sys_obreak(char *nsize); } break
SYS_GETDTABLECOUNT = 18 // { int sys_getdtablecount(void); }
+ SYS_GETRUSAGE = 19 // { int sys_getrusage(int who, \
SYS_GETPID = 20 // { pid_t sys_getpid(void); }
SYS_MOUNT = 21 // { int sys_mount(const char *type, const char *path, \
SYS_UNMOUNT = 22 // { int sys_unmount(const char *path, int flags); }
@@ -39,8 +40,11 @@ const (
SYS_FCHFLAGS = 35 // { int sys_fchflags(int fd, u_int flags); }
SYS_SYNC = 36 // { void sys_sync(void); }
SYS_KILL = 37 // { int sys_kill(int pid, int signum); }
+ SYS_STAT = 38 // { int sys_stat(const char *path, struct stat *ub); }
SYS_GETPPID = 39 // { pid_t sys_getppid(void); }
+ SYS_LSTAT = 40 // { int sys_lstat(const char *path, struct stat *ub); }
SYS_DUP = 41 // { int sys_dup(int fd); }
+ SYS_FSTATAT = 42 // { int sys_fstatat(int fd, const char *path, \
SYS_GETEGID = 43 // { gid_t sys_getegid(void); }
SYS_PROFIL = 44 // { int sys_profil(caddr_t samples, size_t size, \
SYS_KTRACE = 45 // { int sys_ktrace(const char *fname, int ops, \
@@ -51,6 +55,7 @@ const (
SYS_SETLOGIN = 50 // { int sys_setlogin(const char *namebuf); }
SYS_ACCT = 51 // { int sys_acct(const char *path); }
SYS_SIGPENDING = 52 // { int sys_sigpending(void); }
+ SYS_FSTAT = 53 // { int sys_fstat(int fd, struct stat *sb); }
SYS_IOCTL = 54 // { int sys_ioctl(int fd, \
SYS_REBOOT = 55 // { int sys_reboot(int opt); }
SYS_REVOKE = 56 // { int sys_revoke(const char *path); }
@@ -59,36 +64,52 @@ const (
SYS_EXECVE = 59 // { int sys_execve(const char *path, \
SYS_UMASK = 60 // { mode_t sys_umask(mode_t newmask); }
SYS_CHROOT = 61 // { int sys_chroot(const char *path); }
+ SYS_GETFSSTAT = 62 // { int sys_getfsstat(struct statfs *buf, size_t bufsize, \
+ SYS_STATFS = 63 // { int sys_statfs(const char *path, \
+ SYS_FSTATFS = 64 // { int sys_fstatfs(int fd, struct statfs *buf); }
+ SYS_FHSTATFS = 65 // { int sys_fhstatfs(const fhandle_t *fhp, \
SYS_VFORK = 66 // { int sys_vfork(void); }
+ SYS_GETTIMEOFDAY = 67 // { int sys_gettimeofday(struct timeval *tp, \
+ SYS_SETTIMEOFDAY = 68 // { int sys_settimeofday(const struct timeval *tv, \
+ SYS_SETITIMER = 69 // { int sys_setitimer(int which, \
+ SYS_GETITIMER = 70 // { int sys_getitimer(int which, \
+ SYS_SELECT = 71 // { int sys_select(int nd, fd_set *in, fd_set *ou, \
+ SYS_KEVENT = 72 // { int sys_kevent(int fd, \
SYS_MUNMAP = 73 // { int sys_munmap(void *addr, size_t len); }
SYS_MPROTECT = 74 // { int sys_mprotect(void *addr, size_t len, \
SYS_MADVISE = 75 // { int sys_madvise(void *addr, size_t len, \
+ SYS_UTIMES = 76 // { int sys_utimes(const char *path, \
+ SYS_FUTIMES = 77 // { int sys_futimes(int fd, \
SYS_MINCORE = 78 // { int sys_mincore(void *addr, size_t len, \
SYS_GETGROUPS = 79 // { int sys_getgroups(int gidsetsize, \
SYS_SETGROUPS = 80 // { int sys_setgroups(int gidsetsize, \
SYS_GETPGRP = 81 // { int sys_getpgrp(void); }
SYS_SETPGID = 82 // { int sys_setpgid(pid_t pid, int pgid); }
- SYS_SETITIMER = 83 // { int sys_setitimer(int which, \
- SYS_GETITIMER = 86 // { int sys_getitimer(int which, \
+ SYS_UTIMENSAT = 84 // { int sys_utimensat(int fd, const char *path, \
+ SYS_FUTIMENS = 85 // { int sys_futimens(int fd, \
+ SYS_CLOCK_GETTIME = 87 // { int sys_clock_gettime(clockid_t clock_id, \
+ SYS_CLOCK_SETTIME = 88 // { int sys_clock_settime(clockid_t clock_id, \
+ SYS_CLOCK_GETRES = 89 // { int sys_clock_getres(clockid_t clock_id, \
SYS_DUP2 = 90 // { int sys_dup2(int from, int to); }
+ SYS_NANOSLEEP = 91 // { int sys_nanosleep(const struct timespec *rqtp, \
SYS_FCNTL = 92 // { int sys_fcntl(int fd, int cmd, ... void *arg); }
- SYS_SELECT = 93 // { int sys_select(int nd, fd_set *in, fd_set *ou, \
+ SYS___THRSLEEP = 94 // { int sys___thrsleep(const volatile void *ident, \
SYS_FSYNC = 95 // { int sys_fsync(int fd); }
SYS_SETPRIORITY = 96 // { int sys_setpriority(int which, id_t who, int prio); }
SYS_SOCKET = 97 // { int sys_socket(int domain, int type, int protocol); }
SYS_CONNECT = 98 // { int sys_connect(int s, const struct sockaddr *name, \
+ SYS_GETDENTS = 99 // { int sys_getdents(int fd, void *buf, size_t buflen); }
SYS_GETPRIORITY = 100 // { int sys_getpriority(int which, id_t who); }
SYS_SIGRETURN = 103 // { int sys_sigreturn(struct sigcontext *sigcntxp); }
SYS_BIND = 104 // { int sys_bind(int s, const struct sockaddr *name, \
SYS_SETSOCKOPT = 105 // { int sys_setsockopt(int s, int level, int name, \
SYS_LISTEN = 106 // { int sys_listen(int s, int backlog); }
+ SYS_PPOLL = 109 // { int sys_ppoll(struct pollfd *fds, \
+ SYS_PSELECT = 110 // { int sys_pselect(int nd, fd_set *in, fd_set *ou, \
SYS_SIGSUSPEND = 111 // { int sys_sigsuspend(int mask); }
- SYS_GETTIMEOFDAY = 116 // { int sys_gettimeofday(struct timeval *tp, \
- SYS_GETRUSAGE = 117 // { int sys_getrusage(int who, struct rusage *rusage); }
SYS_GETSOCKOPT = 118 // { int sys_getsockopt(int s, int level, int name, \
SYS_READV = 120 // { ssize_t sys_readv(int fd, \
SYS_WRITEV = 121 // { ssize_t sys_writev(int fd, \
- SYS_SETTIMEOFDAY = 122 // { int sys_settimeofday(const struct timeval *tv, \
SYS_FCHOWN = 123 // { int sys_fchown(int fd, uid_t uid, gid_t gid); }
SYS_FCHMOD = 124 // { int sys_fchmod(int fd, mode_t mode); }
SYS_SETREUID = 126 // { int sys_setreuid(uid_t ruid, uid_t euid); }
@@ -101,7 +122,6 @@ const (
SYS_SOCKETPAIR = 135 // { int sys_socketpair(int domain, int type, \
SYS_MKDIR = 136 // { int sys_mkdir(const char *path, mode_t mode); }
SYS_RMDIR = 137 // { int sys_rmdir(const char *path); }
- SYS_UTIMES = 138 // { int sys_utimes(const char *path, \
SYS_ADJTIME = 140 // { int sys_adjtime(const struct timeval *delta, \
SYS_SETSID = 147 // { int sys_setsid(void); }
SYS_QUOTACTL = 148 // { int sys_quotactl(const char *path, int cmd, \
@@ -122,21 +142,17 @@ const (
SYS_LSEEK = 199 // { off_t sys_lseek(int fd, int pad, off_t offset, \
SYS_TRUNCATE = 200 // { int sys_truncate(const char *path, int pad, \
SYS_FTRUNCATE = 201 // { int sys_ftruncate(int fd, int pad, off_t length); }
- SYS___SYSCTL = 202 // { int sys___sysctl(int *name, u_int namelen, \
+ SYS___SYSCTL = 202 // { int sys___sysctl(const int *name, u_int namelen, \
SYS_MLOCK = 203 // { int sys_mlock(const void *addr, size_t len); }
SYS_MUNLOCK = 204 // { int sys_munlock(const void *addr, size_t len); }
- SYS_FUTIMES = 206 // { int sys_futimes(int fd, \
SYS_GETPGID = 207 // { pid_t sys_getpgid(pid_t pid); }
+ SYS_UTRACE = 209 // { int sys_utrace(const char *label, const void *addr, \
SYS_SEMGET = 221 // { int sys_semget(key_t key, int nsems, int semflg); }
SYS_MSGGET = 225 // { int sys_msgget(key_t key, int msgflg); }
SYS_MSGSND = 226 // { int sys_msgsnd(int msqid, const void *msgp, size_t msgsz, \
SYS_MSGRCV = 227 // { int sys_msgrcv(int msqid, void *msgp, size_t msgsz, \
SYS_SHMAT = 228 // { void *sys_shmat(int shmid, const void *shmaddr, \
SYS_SHMDT = 230 // { int sys_shmdt(const void *shmaddr); }
- SYS_CLOCK_GETTIME = 232 // { int sys_clock_gettime(clockid_t clock_id, \
- SYS_CLOCK_SETTIME = 233 // { int sys_clock_settime(clockid_t clock_id, \
- SYS_CLOCK_GETRES = 234 // { int sys_clock_getres(clockid_t clock_id, \
- SYS_NANOSLEEP = 240 // { int sys_nanosleep(const struct timespec *rqtp, \
SYS_MINHERIT = 250 // { int sys_minherit(void *addr, size_t len, \
SYS_POLL = 252 // { int sys_poll(struct pollfd *fds, \
SYS_ISSETUGID = 253 // { int sys_issetugid(void); }
@@ -148,7 +164,6 @@ const (
SYS_PREADV = 267 // { ssize_t sys_preadv(int fd, \
SYS_PWRITEV = 268 // { ssize_t sys_pwritev(int fd, \
SYS_KQUEUE = 269 // { int sys_kqueue(void); }
- SYS_KEVENT = 270 // { int sys_kevent(int fd, \
SYS_MLOCKALL = 271 // { int sys_mlockall(int flags); }
SYS_MUNLOCKALL = 272 // { int sys_munlockall(void); }
SYS_GETRESUID = 281 // { int sys_getresuid(uid_t *ruid, uid_t *euid, \
@@ -160,32 +175,22 @@ const (
SYS_SIGALTSTACK = 288 // { int sys_sigaltstack(const struct sigaltstack *nss, \
SYS_SHMGET = 289 // { int sys_shmget(key_t key, size_t size, int shmflg); }
SYS_SEMOP = 290 // { int sys_semop(int semid, struct sembuf *sops, \
- SYS_STAT = 291 // { int sys_stat(const char *path, struct stat *ub); }
- SYS_FSTAT = 292 // { int sys_fstat(int fd, struct stat *sb); }
- SYS_LSTAT = 293 // { int sys_lstat(const char *path, struct stat *ub); }
SYS_FHSTAT = 294 // { int sys_fhstat(const fhandle_t *fhp, \
SYS___SEMCTL = 295 // { int sys___semctl(int semid, int semnum, int cmd, \
SYS_SHMCTL = 296 // { int sys_shmctl(int shmid, int cmd, \
SYS_MSGCTL = 297 // { int sys_msgctl(int msqid, int cmd, \
SYS_SCHED_YIELD = 298 // { int sys_sched_yield(void); }
SYS_GETTHRID = 299 // { pid_t sys_getthrid(void); }
- SYS___THRSLEEP = 300 // { int sys___thrsleep(const volatile void *ident, \
SYS___THRWAKEUP = 301 // { int sys___thrwakeup(const volatile void *ident, \
SYS___THREXIT = 302 // { void sys___threxit(pid_t *notdead); }
SYS___THRSIGDIVERT = 303 // { int sys___thrsigdivert(sigset_t sigmask, \
SYS___GETCWD = 304 // { int sys___getcwd(char *buf, size_t len); }
SYS_ADJFREQ = 305 // { int sys_adjfreq(const int64_t *freq, \
- SYS_GETFSSTAT = 306 // { int sys_getfsstat(struct statfs *buf, size_t bufsize, \
- SYS_STATFS = 307 // { int sys_statfs(const char *path, \
- SYS_FSTATFS = 308 // { int sys_fstatfs(int fd, struct statfs *buf); }
- SYS_FHSTATFS = 309 // { int sys_fhstatfs(const fhandle_t *fhp, \
SYS_SETRTABLE = 310 // { int sys_setrtable(int rtableid); }
SYS_GETRTABLE = 311 // { int sys_getrtable(void); }
- SYS_GETDIRENTRIES = 312 // { int sys_getdirentries(int fd, char *buf, \
SYS_FACCESSAT = 313 // { int sys_faccessat(int fd, const char *path, \
SYS_FCHMODAT = 314 // { int sys_fchmodat(int fd, const char *path, \
SYS_FCHOWNAT = 315 // { int sys_fchownat(int fd, const char *path, \
- SYS_FSTATAT = 316 // { int sys_fstatat(int fd, const char *path, \
SYS_LINKAT = 317 // { int sys_linkat(int fd1, const char *path1, int fd2, \
SYS_MKDIRAT = 318 // { int sys_mkdirat(int fd, const char *path, \
SYS_MKFIFOAT = 319 // { int sys_mkfifoat(int fd, const char *path, \
@@ -195,8 +200,6 @@ const (
SYS_RENAMEAT = 323 // { int sys_renameat(int fromfd, const char *from, \
SYS_SYMLINKAT = 324 // { int sys_symlinkat(const char *path, int fd, \
SYS_UNLINKAT = 325 // { int sys_unlinkat(int fd, const char *path, \
- SYS_UTIMENSAT = 326 // { int sys_utimensat(int fd, const char *path, \
- SYS_FUTIMENS = 327 // { int sys_futimens(int fd, \
SYS___SET_TCB = 329 // { void sys___set_tcb(void *tcb); }
SYS___GET_TCB = 330 // { void *sys___get_tcb(void); }
)
diff --git a/src/pkg/syscall/zsysnum_solaris_amd64.go b/src/pkg/syscall/zsysnum_solaris_amd64.go
new file mode 100644
index 000000000..43b3d8b40
--- /dev/null
+++ b/src/pkg/syscall/zsysnum_solaris_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 syscall
+
+// TODO(aram): remove these before Go 1.3.
+const (
+ SYS_EXECVE = 59
+ SYS_FCNTL = 62
+)
diff --git a/src/pkg/syscall/ztypes_dragonfly_386.go b/src/pkg/syscall/ztypes_dragonfly_386.go
index c467d8593..6b6ec1525 100644
--- a/src/pkg/syscall/ztypes_dragonfly_386.go
+++ b/src/pkg/syscall/ztypes_dragonfly_386.go
@@ -55,10 +55,6 @@ type Rlimit struct {
type _Gid_t uint32
const (
- F_DUPFD_CLOEXEC = 0
-)
-
-const (
S_IFMT = 0xf000
S_IFIFO = 0x1000
S_IFCHR = 0x2000
@@ -427,3 +423,13 @@ type BpfHdr struct {
Hdrlen uint16
Pad_cgo_0 [2]byte
}
+
+type Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed uint32
+ Ospeed uint32
+}
diff --git a/src/pkg/syscall/ztypes_dragonfly_amd64.go b/src/pkg/syscall/ztypes_dragonfly_amd64.go
index b71bf29f4..954ffd7ab 100644
--- a/src/pkg/syscall/ztypes_dragonfly_amd64.go
+++ b/src/pkg/syscall/ztypes_dragonfly_amd64.go
@@ -55,10 +55,6 @@ type Rlimit struct {
type _Gid_t uint32
const (
- F_DUPFD_CLOEXEC = 0
-)
-
-const (
S_IFMT = 0xf000
S_IFIFO = 0x1000
S_IFCHR = 0x2000
@@ -433,3 +429,13 @@ type BpfHdr struct {
Hdrlen uint16
Pad_cgo_0 [6]byte
}
+
+type Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed uint32
+ Ospeed uint32
+}
diff --git a/src/pkg/syscall/ztypes_freebsd_386.go b/src/pkg/syscall/ztypes_freebsd_386.go
index e77bd4b41..b809eea37 100644
--- a/src/pkg/syscall/ztypes_freebsd_386.go
+++ b/src/pkg/syscall/ztypes_freebsd_386.go
@@ -55,10 +55,6 @@ type Rlimit struct {
type _Gid_t uint32
const (
- O_CLOEXEC = 0
-)
-
-const (
S_IFMT = 0xf000
S_IFIFO = 0x1000
S_IFCHR = 0x2000
@@ -282,7 +278,9 @@ type FdSet struct {
}
const (
+ sizeofIfMsghdr = 0x64
SizeofIfMsghdr = 0x60
+ sizeofIfData = 0x54
SizeofIfData = 0x50
SizeofIfaMsghdr = 0x14
SizeofIfmaMsghdr = 0x10
@@ -291,6 +289,17 @@ const (
SizeofRtMetrics = 0x38
)
+type ifMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_cgo_0 [2]byte
+ Data ifData
+}
+
type IfMsghdr struct {
Msglen uint16
Version uint8
@@ -302,6 +311,34 @@ type IfMsghdr struct {
Data IfData
}
+type ifData struct {
+ Type uint8
+ Physical uint8
+ Addrlen uint8
+ Hdrlen uint8
+ Link_state uint8
+ Vhid uint8
+ Baudrate_pf uint8
+ Datalen uint8
+ Mtu uint32
+ Metric uint32
+ Baudrate uint32
+ Ipackets uint32
+ Ierrors uint32
+ Opackets uint32
+ Oerrors uint32
+ Collisions uint32
+ Ibytes uint32
+ Obytes uint32
+ Imcasts uint32
+ Omcasts uint32
+ Iqdrops uint32
+ Noproto uint32
+ Hwassist uint64
+ Epoch int32
+ Lastchange Timeval
+}
+
type IfData struct {
Type uint8
Physical uint8
@@ -443,3 +480,13 @@ type BpfZbufHeader struct {
User_gen uint32
X_bzh_pad [5]uint32
}
+
+type Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed uint32
+ Ospeed uint32
+}
diff --git a/src/pkg/syscall/ztypes_freebsd_amd64.go b/src/pkg/syscall/ztypes_freebsd_amd64.go
index 922de2ce5..a05908aed 100644
--- a/src/pkg/syscall/ztypes_freebsd_amd64.go
+++ b/src/pkg/syscall/ztypes_freebsd_amd64.go
@@ -55,10 +55,6 @@ type Rlimit struct {
type _Gid_t uint32
const (
- O_CLOEXEC = 0
-)
-
-const (
S_IFMT = 0xf000
S_IFIFO = 0x1000
S_IFCHR = 0x2000
@@ -284,7 +280,9 @@ type FdSet struct {
}
const (
+ sizeofIfMsghdr = 0xa8
SizeofIfMsghdr = 0xa8
+ sizeofIfData = 0x98
SizeofIfData = 0x98
SizeofIfaMsghdr = 0x14
SizeofIfmaMsghdr = 0x10
@@ -293,6 +291,17 @@ const (
SizeofRtMetrics = 0x70
)
+type ifMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_cgo_0 [2]byte
+ Data ifData
+}
+
type IfMsghdr struct {
Msglen uint16
Version uint8
@@ -304,6 +313,34 @@ type IfMsghdr struct {
Data IfData
}
+type ifData struct {
+ Type uint8
+ Physical uint8
+ Addrlen uint8
+ Hdrlen uint8
+ Link_state uint8
+ Vhid uint8
+ Baudrate_pf uint8
+ Datalen uint8
+ Mtu uint64
+ Metric uint64
+ Baudrate uint64
+ Ipackets uint64
+ Ierrors uint64
+ Opackets uint64
+ Oerrors uint64
+ Collisions uint64
+ Ibytes uint64
+ Obytes uint64
+ Imcasts uint64
+ Omcasts uint64
+ Iqdrops uint64
+ Noproto uint64
+ Hwassist uint64
+ Epoch int64
+ Lastchange Timeval
+}
+
type IfData struct {
Type uint8
Physical uint8
@@ -446,3 +483,13 @@ type BpfZbufHeader struct {
User_gen uint32
X_bzh_pad [5]uint32
}
+
+type Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed uint32
+ Ospeed uint32
+}
diff --git a/src/pkg/syscall/ztypes_freebsd_arm.go b/src/pkg/syscall/ztypes_freebsd_arm.go
index b1bf83b4c..9303816f9 100644
--- a/src/pkg/syscall/ztypes_freebsd_arm.go
+++ b/src/pkg/syscall/ztypes_freebsd_arm.go
@@ -1,5 +1,5 @@
// Created by cgo -godefs - DO NOT EDIT
-// cgo -godefs types_freebsd.go
+// cgo -godefs -- -fsigned-char types_freebsd.go
package syscall
@@ -19,13 +19,15 @@ type (
)
type Timespec struct {
- Sec int64
- Nsec int32
+ Sec int64
+ Nsec int32
+ Pad_cgo_0 [4]byte
}
type Timeval struct {
- Sec int64
- Usec int32
+ Sec int64
+ Usec int32
+ Pad_cgo_0 [4]byte
}
type Rusage struct {
@@ -55,10 +57,6 @@ type Rlimit struct {
type _Gid_t uint32
const (
- O_CLOEXEC = 0 // not supported
-)
-
-const (
S_IFMT = 0xf000
S_IFIFO = 0x1000
S_IFCHR = 0x2000
@@ -93,7 +91,6 @@ type Stat_t struct {
Gen uint32
Lspare int32
Birthtimespec Timespec
- Pad_cgo_0 [4]byte
}
type Statfs_t struct {
@@ -122,12 +119,13 @@ type Statfs_t struct {
}
type Flock_t struct {
- Start int64
- Len int64
- Pid int32
- Type int16
- Whence int16
- Sysid int32
+ Start int64
+ Len int64
+ Pid int32
+ Type int16
+ Whence int16
+ Sysid int32
+ Pad_cgo_0 [4]byte
}
type Dirent struct {
@@ -160,22 +158,20 @@ type RawSockaddrInet6 struct {
}
type RawSockaddrUnix struct {
- Len uint8
- Family uint8
- Path [104]int8
- Pad_cgo_0 [2]byte
+ Len uint8
+ Family uint8
+ Path [104]int8
}
type RawSockaddrDatalink struct {
- Len uint8
- Family uint8
- Index uint16
- Type uint8
- Nlen uint8
- Alen uint8
- Slen uint8
- Data [46]int8
- Pad_cgo_0 [2]byte
+ Len uint8
+ Family uint8
+ Index uint16
+ Type uint8
+ Nlen uint8
+ Alen uint8
+ Slen uint8
+ Data [46]int8
}
type RawSockaddr struct {
@@ -251,8 +247,8 @@ const (
SizeofSockaddrInet4 = 0x10
SizeofSockaddrInet6 = 0x1c
SizeofSockaddrAny = 0x6c
- SizeofSockaddrUnix = 0x6c
- SizeofSockaddrDatalink = 0x38
+ SizeofSockaddrUnix = 0x6a
+ SizeofSockaddrDatalink = 0x36
SizeofLinger = 0x8
SizeofIPMreq = 0x8
SizeofIPMreqn = 0xc
@@ -284,8 +280,10 @@ type FdSet struct {
}
const (
- SizeofIfMsghdr = 0x68
- SizeofIfData = 0x58
+ sizeofIfMsghdr = 0x70
+ SizeofIfMsghdr = 0x70
+ sizeofIfData = 0x60
+ SizeofIfData = 0x60
SizeofIfaMsghdr = 0x14
SizeofIfmaMsghdr = 0x10
SizeofIfAnnounceMsghdr = 0x18
@@ -293,6 +291,17 @@ const (
SizeofRtMetrics = 0x38
)
+type ifMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_cgo_0 [2]byte
+ Data ifData
+}
+
type IfMsghdr struct {
Msglen uint16
Version uint8
@@ -304,13 +313,41 @@ type IfMsghdr struct {
Data IfData
}
+type ifData struct {
+ Type uint8
+ Physical uint8
+ Addrlen uint8
+ Hdrlen uint8
+ Link_state uint8
+ Vhid uint8
+ Baudrate_pf uint8
+ Datalen uint8
+ Mtu uint32
+ Metric uint32
+ Baudrate uint32
+ Ipackets uint32
+ Ierrors uint32
+ Opackets uint32
+ Oerrors uint32
+ Collisions uint32
+ Ibytes uint32
+ Obytes uint32
+ Imcasts uint32
+ Omcasts uint32
+ Iqdrops uint32
+ Noproto uint32
+ Hwassist uint64
+ Epoch int64
+ Lastchange Timeval
+}
+
type IfData struct {
Type uint8
Physical uint8
Addrlen uint8
Hdrlen uint8
Link_state uint8
- Spare_char1 uint8 //Vhid uint8
+ Spare_char1 uint8
Spare_char2 uint8
Datalen uint8
Mtu uint32
@@ -328,6 +365,7 @@ type IfData struct {
Iqdrops uint32
Noproto uint32
Hwassist uint32
+ Pad_cgo_0 [4]byte
Epoch int64
Lastchange Timeval
}
@@ -399,7 +437,7 @@ const (
SizeofBpfZbuf = 0xc
SizeofBpfProgram = 0x8
SizeofBpfInsn = 0x8
- SizeofBpfHdr = 0x18
+ SizeofBpfHdr = 0x20
SizeofBpfZbufHeader = 0x20
)
@@ -436,7 +474,7 @@ type BpfHdr struct {
Caplen uint32
Datalen uint32
Hdrlen uint16
- Pad_cgo_0 [2]byte
+ Pad_cgo_0 [6]byte
}
type BpfZbufHeader struct {
@@ -445,3 +483,13 @@ type BpfZbufHeader struct {
User_gen uint32
X_bzh_pad [5]uint32
}
+
+type Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed uint32
+ Ospeed uint32
+}
diff --git a/src/pkg/syscall/ztypes_linux_386.go b/src/pkg/syscall/ztypes_linux_386.go
index 9abd647ac..daecb1ded 100644
--- a/src/pkg/syscall/ztypes_linux_386.go
+++ b/src/pkg/syscall/ztypes_linux_386.go
@@ -142,6 +142,14 @@ type Fsid struct {
X__val [2]int32
}
+type Flock_t struct {
+ Type int16
+ Whence int16
+ Start int64
+ Len int64
+ Pid int32
+}
+
type RawSockaddrInet4 struct {
Family uint16
Port uint16
diff --git a/src/pkg/syscall/ztypes_linux_amd64.go b/src/pkg/syscall/ztypes_linux_amd64.go
index 32da4e4b5..694fe1eac 100644
--- a/src/pkg/syscall/ztypes_linux_amd64.go
+++ b/src/pkg/syscall/ztypes_linux_amd64.go
@@ -142,6 +142,16 @@ type Fsid struct {
X__val [2]int32
}
+type Flock_t struct {
+ Type int16
+ Whence int16
+ Pad_cgo_0 [4]byte
+ Start int64
+ Len int64
+ Pid int32
+ Pad_cgo_1 [4]byte
+}
+
type RawSockaddrInet4 struct {
Family uint16
Port uint16
diff --git a/src/pkg/syscall/ztypes_linux_arm.go b/src/pkg/syscall/ztypes_linux_arm.go
index 4a918a8a7..5f21a948d 100644
--- a/src/pkg/syscall/ztypes_linux_arm.go
+++ b/src/pkg/syscall/ztypes_linux_arm.go
@@ -144,6 +144,16 @@ type Fsid struct {
X__val [2]int32
}
+type Flock_t struct {
+ Type int16
+ Whence int16
+ Pad_cgo_0 [4]byte
+ Start int64
+ Len int64
+ Pid int32
+ Pad_cgo_1 [4]byte
+}
+
type RawSockaddrInet4 struct {
Family uint16
Port uint16
diff --git a/src/pkg/syscall/ztypes_netbsd_386.go b/src/pkg/syscall/ztypes_netbsd_386.go
index 59314bad2..6add325a3 100644
--- a/src/pkg/syscall/ztypes_netbsd_386.go
+++ b/src/pkg/syscall/ztypes_netbsd_386.go
@@ -370,6 +370,16 @@ type BpfTimeval struct {
Usec int32
}
+type Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed int32
+ Ospeed int32
+}
+
type Sysctlnode struct {
Flags uint32
Num int32
diff --git a/src/pkg/syscall/ztypes_netbsd_amd64.go b/src/pkg/syscall/ztypes_netbsd_amd64.go
index a021a5738..4451fc1f0 100644
--- a/src/pkg/syscall/ztypes_netbsd_amd64.go
+++ b/src/pkg/syscall/ztypes_netbsd_amd64.go
@@ -377,6 +377,16 @@ type BpfTimeval struct {
Usec int64
}
+type Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed int32
+ Ospeed int32
+}
+
type Sysctlnode struct {
Flags uint32
Num int32
diff --git a/src/pkg/syscall/ztypes_netbsd_arm.go b/src/pkg/syscall/ztypes_netbsd_arm.go
index 59314bad2..4e853eaa2 100644
--- a/src/pkg/syscall/ztypes_netbsd_arm.go
+++ b/src/pkg/syscall/ztypes_netbsd_arm.go
@@ -19,13 +19,15 @@ type (
)
type Timespec struct {
- Sec int64
- Nsec int32
+ Sec int64
+ Nsec int32
+ Pad_cgo_0 [4]byte
}
type Timeval struct {
- Sec int64
- Usec int32
+ Sec int64
+ Usec int32
+ Pad_cgo_0 [4]byte
}
type Rusage struct {
@@ -57,10 +59,12 @@ type _Gid_t uint32
type Stat_t struct {
Dev uint64
Mode uint32
+ Pad_cgo_0 [4]byte
Ino uint64
Nlink uint32
Uid uint32
Gid uint32
+ Pad_cgo_1 [4]byte
Rdev uint64
Atimespec Timespec
Mtimespec Timespec
@@ -72,6 +76,7 @@ type Stat_t struct {
Flags uint32
Gen uint32
Spare [2]uint32
+ Pad_cgo_2 [4]byte
}
type Statfs_t [0]byte
@@ -217,12 +222,13 @@ const (
)
type Kevent_t struct {
- Ident uint32
- Filter uint32
- Flags uint32
- Fflags uint32
- Data int64
- Udata int32
+ Ident uint32
+ Filter uint32
+ Flags uint32
+ Fflags uint32
+ Data int64
+ Udata int32
+ Pad_cgo_0 [4]byte
}
type FdSet struct {
@@ -231,7 +237,7 @@ type FdSet struct {
const (
SizeofIfMsghdr = 0x98
- SizeofIfData = 0x84
+ SizeofIfData = 0x88
SizeofIfaMsghdr = 0x18
SizeofIfAnnounceMsghdr = 0x18
SizeofRtMsghdr = 0x78
@@ -247,7 +253,6 @@ type IfMsghdr struct {
Index uint16
Pad_cgo_0 [2]byte
Data IfData
- Pad_cgo_1 [4]byte
}
type IfData struct {
@@ -370,6 +375,16 @@ type BpfTimeval struct {
Usec int32
}
+type Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed int32
+ Ospeed int32
+}
+
type Sysctlnode struct {
Flags uint32
Num int32
diff --git a/src/pkg/syscall/ztypes_openbsd_386.go b/src/pkg/syscall/ztypes_openbsd_386.go
index 3c9cdf28b..2e4d9dd17 100644
--- a/src/pkg/syscall/ztypes_openbsd_386.go
+++ b/src/pkg/syscall/ztypes_openbsd_386.go
@@ -19,12 +19,12 @@ type (
)
type Timespec struct {
- Sec int32
+ Sec int64
Nsec int32
}
type Timeval struct {
- Sec int32
+ Sec int64
Usec int32
}
@@ -72,14 +72,13 @@ const (
)
type Stat_t struct {
- Dev int32
- Ino uint32
Mode uint32
+ Dev int32
+ Ino uint64
Nlink uint32
Uid uint32
Gid uint32
Rdev int32
- Lspare0 int32
Atim Timespec
Mtim Timespec
Ctim Timespec
@@ -88,9 +87,7 @@ type Stat_t struct {
Blksize uint32
Flags uint32
Gen uint32
- Lspare1 int32
X__st_birthtim Timespec
- Qspare [2]int64
}
type Statfs_t struct {
@@ -110,11 +107,12 @@ type Statfs_t struct {
F_fsid Fsid
F_namemax uint32
F_owner uint32
- F_ctime uint32
- F_spare [3]uint32
+ F_ctime uint64
F_fstypename [16]int8
F_mntonname [90]int8
F_mntfromname [90]int8
+ F_mntfromspec [90]int8
+ Pad_cgo_0 [2]byte
Mount_info [160]byte
}
@@ -127,11 +125,13 @@ type Flock_t struct {
}
type Dirent struct {
- Fileno uint32
- Reclen uint16
- Type uint8
- Namlen uint8
- Name [256]int8
+ Fileno uint64
+ Off int64
+ Reclen uint16
+ Type uint8
+ Namlen uint8
+ X__d_padding [4]uint8
+ Name [256]int8
}
type Fsid struct {
@@ -262,21 +262,21 @@ type Kevent_t struct {
Filter int16
Flags uint16
Fflags uint32
- Data int32
+ Data int64
Udata *byte
}
type FdSet struct {
- Bits [32]int32
+ Bits [32]uint32
}
const (
- SizeofIfMsghdr = 0xe8
- SizeofIfData = 0xd0
+ SizeofIfMsghdr = 0xec
+ SizeofIfData = 0xd4
SizeofIfaMsghdr = 0x18
SizeofIfAnnounceMsghdr = 0x1a
- SizeofRtMsghdr = 0x58
- SizeofRtMetrics = 0x30
+ SizeofRtMsghdr = 0x60
+ SizeofRtMetrics = 0x38
)
type IfMsghdr struct {
@@ -364,9 +364,9 @@ type RtMsghdr struct {
type RtMetrics struct {
Pksent uint64
+ Expire int64
Locks uint32
Mtu uint32
- Expire uint32
Refcnt uint32
Hopcount uint32
Recvpipe uint32
@@ -374,10 +374,11 @@ type RtMetrics struct {
Ssthresh uint32
Rtt uint32
Rttvar uint32
+ Pad uint32
}
type Mclpool struct {
- Grown uint32
+ Grown int32
Alive uint16
Hwm uint16
Cwm uint16
@@ -426,3 +427,13 @@ type BpfTimeval struct {
Sec uint32
Usec uint32
}
+
+type Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed int32
+ Ospeed int32
+}
diff --git a/src/pkg/syscall/ztypes_openbsd_amd64.go b/src/pkg/syscall/ztypes_openbsd_amd64.go
index 3a0ac96fa..f07bc714e 100644
--- a/src/pkg/syscall/ztypes_openbsd_amd64.go
+++ b/src/pkg/syscall/ztypes_openbsd_amd64.go
@@ -19,9 +19,8 @@ type (
)
type Timespec struct {
- Sec int32
- Pad_cgo_0 [4]byte
- Nsec int64
+ Sec int64
+ Nsec int64
}
type Timeval struct {
@@ -73,14 +72,13 @@ const (
)
type Stat_t struct {
- Dev int32
- Ino uint32
Mode uint32
+ Dev int32
+ Ino uint64
Nlink uint32
Uid uint32
Gid uint32
Rdev int32
- Lspare0 int32
Atim Timespec
Mtim Timespec
Ctim Timespec
@@ -89,9 +87,8 @@ type Stat_t struct {
Blksize uint32
Flags uint32
Gen uint32
- Lspare1 int32
+ Pad_cgo_0 [4]byte
X__st_birthtim Timespec
- Qspare [2]int64
}
type Statfs_t struct {
@@ -112,12 +109,12 @@ type Statfs_t struct {
F_fsid Fsid
F_namemax uint32
F_owner uint32
- F_ctime uint32
- F_spare [3]uint32
+ F_ctime uint64
F_fstypename [16]int8
F_mntonname [90]int8
F_mntfromname [90]int8
- Pad_cgo_1 [4]byte
+ F_mntfromspec [90]int8
+ Pad_cgo_1 [2]byte
Mount_info [160]byte
}
@@ -130,11 +127,13 @@ type Flock_t struct {
}
type Dirent struct {
- Fileno uint32
- Reclen uint16
- Type uint8
- Namlen uint8
- Name [256]int8
+ Fileno uint64
+ Off int64
+ Reclen uint16
+ Type uint8
+ Namlen uint8
+ X__d_padding [4]uint8
+ Name [256]int8
}
type Fsid struct {
@@ -263,16 +262,16 @@ const (
)
type Kevent_t struct {
- Ident uint32
+ Ident uint64
Filter int16
Flags uint16
Fflags uint32
- Data int32
+ Data int64
Udata *byte
}
type FdSet struct {
- Bits [32]int32
+ Bits [32]uint32
}
const (
@@ -280,8 +279,8 @@ const (
SizeofIfData = 0xe0
SizeofIfaMsghdr = 0x18
SizeofIfAnnounceMsghdr = 0x1a
- SizeofRtMsghdr = 0x58
- SizeofRtMetrics = 0x30
+ SizeofRtMsghdr = 0x60
+ SizeofRtMetrics = 0x38
)
type IfMsghdr struct {
@@ -371,9 +370,9 @@ type RtMsghdr struct {
type RtMetrics struct {
Pksent uint64
+ Expire int64
Locks uint32
Mtu uint32
- Expire uint32
Refcnt uint32
Hopcount uint32
Recvpipe uint32
@@ -381,10 +380,11 @@ type RtMetrics struct {
Ssthresh uint32
Rtt uint32
Rttvar uint32
+ Pad uint32
}
type Mclpool struct {
- Grown uint32
+ Grown int32
Alive uint16
Hwm uint16
Cwm uint16
@@ -434,3 +434,13 @@ type BpfTimeval struct {
Sec uint32
Usec uint32
}
+
+type Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed int32
+ Ospeed int32
+}
diff --git a/src/pkg/syscall/ztypes_solaris_amd64.go b/src/pkg/syscall/ztypes_solaris_amd64.go
new file mode 100644
index 000000000..77275a54e
--- /dev/null
+++ b/src/pkg/syscall/ztypes_solaris_amd64.go
@@ -0,0 +1,365 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_solaris.go
+
+package syscall
+
+const (
+ sizeofPtr = 0x8
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int64
+ _C_long_long int64
+)
+
+type Timespec struct {
+ Sec int64
+ Nsec int64
+}
+
+type Timeval struct {
+ Sec int64
+ Usec int64
+}
+
+type Timeval32 struct {
+ Sec int32
+ Usec int32
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int64
+ Ixrss int64
+ Idrss int64
+ Isrss int64
+ Minflt int64
+ Majflt int64
+ Nswap int64
+ Inblock int64
+ Oublock int64
+ Msgsnd int64
+ Msgrcv int64
+ Nsignals int64
+ Nvcsw int64
+ Nivcsw int64
+}
+
+type Rlimit struct {
+ Cur uint64
+ Max uint64
+}
+
+type _Gid_t uint32
+
+const (
+ S_IFMT = 0xf000
+ S_IFIFO = 0x1000
+ S_IFCHR = 0x2000
+ S_IFDIR = 0x4000
+ S_IFBLK = 0x6000
+ S_IFREG = 0x8000
+ S_IFLNK = 0xa000
+ S_IFSOCK = 0xc000
+ S_ISUID = 0x800
+ S_ISGID = 0x400
+ S_ISVTX = 0x200
+ S_IRUSR = 0x100
+ S_IWUSR = 0x80
+ S_IXUSR = 0x40
+)
+
+type Stat_t struct {
+ Dev uint64
+ Ino uint64
+ Mode uint32
+ Nlink uint32
+ Uid uint32
+ Gid uint32
+ Rdev uint64
+ Size int64
+ Atim Timespec
+ Mtim Timespec
+ Ctim Timespec
+ Blksize int32
+ Pad_cgo_0 [4]byte
+ Blocks int64
+ Fstype [16]int8
+}
+
+type Flock_t struct {
+ Type int16
+ Whence int16
+ Pad_cgo_0 [4]byte
+ Start int64
+ Len int64
+ Sysid int32
+ Pid int32
+ Pad [4]int64
+}
+
+type Dirent struct {
+ Ino uint64
+ Off int64
+ Reclen uint16
+ Name [1]int8
+ Pad_cgo_0 [5]byte
+}
+
+type RawSockaddrInet4 struct {
+ Family uint16
+ Port uint16
+ Addr [4]byte /* in_addr */
+ Zero [8]int8
+}
+
+type RawSockaddrInet6 struct {
+ Family uint16
+ Port uint16
+ Flowinfo uint32
+ Addr [16]byte /* in6_addr */
+ Scope_id uint32
+ X__sin6_src_id uint32
+}
+
+type RawSockaddrUnix struct {
+ Family uint16
+ Path [108]int8
+}
+
+type RawSockaddrDatalink struct {
+ Family uint16
+ Index uint16
+ Type uint8
+ Nlen uint8
+ Alen uint8
+ Slen uint8
+ Data [244]int8
+}
+
+type RawSockaddr struct {
+ Family uint16
+ Data [14]int8
+}
+
+type RawSockaddrAny struct {
+ Addr RawSockaddr
+ Pad [236]int8
+}
+
+type _Socklen uint32
+
+type Linger struct {
+ Onoff int32
+ Linger int32
+}
+
+type Iovec struct {
+ Base *int8
+ Len uint64
+}
+
+type IPMreq struct {
+ Multiaddr [4]byte /* in_addr */
+ Interface [4]byte /* in_addr */
+}
+
+type IPv6Mreq struct {
+ Multiaddr [16]byte /* in6_addr */
+ Interface uint32
+}
+
+type Msghdr struct {
+ Name *byte
+ Namelen uint32
+ Pad_cgo_0 [4]byte
+ Iov *Iovec
+ Iovlen int32
+ Pad_cgo_1 [4]byte
+ Accrights *int8
+ Accrightslen int32
+ Pad_cgo_2 [4]byte
+}
+
+type Cmsghdr struct {
+ Len uint32
+ Level int32
+ Type int32
+}
+
+type Inet6Pktinfo struct {
+ Addr [16]byte /* in6_addr */
+ Ifindex uint32
+}
+
+type IPv6MTUInfo struct {
+ Addr RawSockaddrInet6
+ Mtu uint32
+}
+
+type ICMPv6Filter struct {
+ X__icmp6_filt [8]uint32
+}
+
+const (
+ SizeofSockaddrInet4 = 0x10
+ SizeofSockaddrInet6 = 0x20
+ SizeofSockaddrAny = 0xfc
+ SizeofSockaddrUnix = 0x6e
+ SizeofSockaddrDatalink = 0xfc
+ SizeofLinger = 0x8
+ SizeofIPMreq = 0x8
+ SizeofIPv6Mreq = 0x14
+ SizeofMsghdr = 0x30
+ SizeofCmsghdr = 0xc
+ SizeofInet6Pktinfo = 0x14
+ SizeofIPv6MTUInfo = 0x24
+ SizeofICMPv6Filter = 0x20
+)
+
+type FdSet struct {
+ Bits [1024]int64
+}
+
+const (
+ SizeofIfMsghdr = 0x54
+ SizeofIfData = 0x44
+ SizeofIfaMsghdr = 0x14
+ SizeofRtMsghdr = 0x4c
+ SizeofRtMetrics = 0x28
+)
+
+type IfMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_cgo_0 [2]byte
+ Data IfData
+}
+
+type IfData struct {
+ Type uint8
+ Addrlen uint8
+ Hdrlen uint8
+ Pad_cgo_0 [1]byte
+ Mtu uint32
+ Metric uint32
+ Baudrate uint32
+ Ipackets uint32
+ Ierrors uint32
+ Opackets uint32
+ Oerrors uint32
+ Collisions uint32
+ Ibytes uint32
+ Obytes uint32
+ Imcasts uint32
+ Omcasts uint32
+ Iqdrops uint32
+ Noproto uint32
+ Lastchange Timeval32
+}
+
+type IfaMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_cgo_0 [2]byte
+ Metric int32
+}
+
+type RtMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Index uint16
+ Pad_cgo_0 [2]byte
+ Flags int32
+ Addrs int32
+ Pid int32
+ Seq int32
+ Errno int32
+ Use int32
+ Inits uint32
+ Rmx RtMetrics
+}
+
+type RtMetrics struct {
+ Locks uint32
+ Mtu uint32
+ Hopcount uint32
+ Expire uint32
+ Recvpipe uint32
+ Sendpipe uint32
+ Ssthresh uint32
+ Rtt uint32
+ Rttvar uint32
+ Pksent uint32
+}
+
+const (
+ SizeofBpfVersion = 0x4
+ SizeofBpfStat = 0x80
+ SizeofBpfProgram = 0x10
+ SizeofBpfInsn = 0x8
+ SizeofBpfHdr = 0x14
+)
+
+type BpfVersion struct {
+ Major uint16
+ Minor uint16
+}
+
+type BpfStat struct {
+ Recv uint64
+ Drop uint64
+ Capt uint64
+ Padding [13]uint64
+}
+
+type BpfProgram struct {
+ Len uint32
+ Pad_cgo_0 [4]byte
+ Insns *BpfInsn
+}
+
+type BpfInsn struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
+
+type BpfTimeval struct {
+ Sec int32
+ Usec int32
+}
+
+type BpfHdr struct {
+ Tstamp BpfTimeval
+ Caplen uint32
+ Datalen uint32
+ Hdrlen uint16
+ Pad_cgo_0 [2]byte
+}
+
+type Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [19]uint8
+ Pad_cgo_0 [1]byte
+}
diff --git a/src/pkg/syscall/ztypes_windows.go b/src/pkg/syscall/ztypes_windows.go
index a5681d700..a1d77e0b5 100644
--- a/src/pkg/syscall/ztypes_windows.go
+++ b/src/pkg/syscall/ztypes_windows.go
@@ -20,6 +20,7 @@ const (
ERROR_PROC_NOT_FOUND Errno = 127
ERROR_ALREADY_EXISTS Errno = 183
ERROR_ENVVAR_NOT_FOUND Errno = 203
+ ERROR_MORE_DATA Errno = 234
ERROR_OPERATION_ABORTED Errno = 995
ERROR_IO_PENDING Errno = 997
ERROR_NOT_FOUND Errno = 1168
@@ -514,9 +515,11 @@ const (
IOC_OUT = 0x40000000
IOC_IN = 0x80000000
+ IOC_VENDOR = 0x18000000
IOC_INOUT = IOC_IN | IOC_OUT
IOC_WS2 = 0x08000000
SIO_GET_EXTENSION_FUNCTION_POINTER = IOC_INOUT | IOC_WS2 | 6
+ SIO_KEEPALIVE_VALS = IOC_IN | IOC_VENDOR | 4
// cf. http://support.microsoft.com/default.aspx?scid=kb;en-us;257460
@@ -1033,3 +1036,9 @@ type WSAProtocolChain struct {
ChainLen int32
ChainEntries [MAX_PROTOCOL_CHAIN]uint32
}
+
+type TCPKeepalive struct {
+ OnOff uint32
+ Time uint32
+ Interval uint32
+}
diff --git a/src/pkg/testing/benchmark.go b/src/pkg/testing/benchmark.go
index 3473c5b2c..1fbf5c861 100644
--- a/src/pkg/testing/benchmark.go
+++ b/src/pkg/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 {
@@ -343,6 +350,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/src/pkg/testing/benchmark_test.go b/src/pkg/testing/benchmark_test.go
index 94e994dfa..f7ea64e7f 100644
--- a/src/pkg/testing/benchmark_test.go
+++ b/src/pkg/testing/benchmark_test.go
@@ -5,7 +5,11 @@
package testing_test
import (
+ "bytes"
+ "runtime"
+ "sync/atomic"
"testing"
+ "text/template"
)
var roundDownTests = []struct {
@@ -56,3 +60,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/src/pkg/testing/testing.go b/src/pkg/testing/testing.go
index 52dc166dd..8078ba7cc 100644
--- a/src/pkg/testing/testing.go
+++ b/src/pkg/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.")
@@ -43,6 +51,7 @@
//
// 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
@@ -143,10 +167,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
@@ -275,6 +300,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 +364,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 +406,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,6 +420,7 @@ 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
@@ -405,6 +437,7 @@ func Main(matchString func(pat, str string) (bool, error), tests []InternalTest,
stopAlarm()
if !testOk || !exampleOk {
fmt.Println("FAIL")
+ after()
os.Exit(1)
}
fmt.Println("PASS")
diff --git a/src/pkg/text/scanner/scanner.go b/src/pkg/text/scanner/scanner.go
index e0d86e343..db7ca73c6 100644
--- a/src/pkg/text/scanner/scanner.go
+++ b/src/pkg/text/scanner/scanner.go
@@ -240,6 +240,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 +251,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
diff --git a/src/pkg/text/scanner/scanner_test.go b/src/pkg/text/scanner/scanner_test.go
index 496eed4a3..7d3f597eb 100644
--- a/src/pkg/text/scanner/scanner_test.go
+++ b/src/pkg/text/scanner/scanner_test.go
@@ -360,7 +360,7 @@ func TestScanSelectedMask(t *testing.T) {
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 +402,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 +462,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 +518,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 +536,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 +548,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 +573,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/src/pkg/text/tabwriter/tabwriter.go b/src/pkg/text/tabwriter/tabwriter.go
index 722ac8d87..c0c32d5de 100644
--- a/src/pkg/text/tabwriter/tabwriter.go
+++ b/src/pkg/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/src/pkg/text/tabwriter/tabwriter_test.go b/src/pkg/text/tabwriter/tabwriter_test.go
index ace535647..9d3111e2c 100644
--- a/src/pkg/text/tabwriter/tabwriter_test.go
+++ b/src/pkg/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/src/pkg/text/template/doc.go b/src/pkg/text/template/doc.go
index f622ac7dc..7c6efd59c 100644
--- a/src/pkg/text/template/doc.go
+++ b/src/pkg/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".
diff --git a/src/pkg/text/template/exec.go b/src/pkg/text/template/exec.go
index 43b0b266e..2f3231264 100644
--- a/src/pkg/text/template/exec.go
+++ b/src/pkg/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)
@@ -594,6 +602,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:
diff --git a/src/pkg/text/template/exec_test.go b/src/pkg/text/template/exec_test.go
index f60702de8..868f2cb94 100644
--- a/src/pkg/text/template/exec_test.go
+++ b/src/pkg/text/template/exec_test.go
@@ -512,6 +512,8 @@ 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},
}
func zeroArgs() string {
@@ -546,6 +548,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 +587,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
diff --git a/src/pkg/text/template/multi_test.go b/src/pkg/text/template/multi_test.go
index 1f6ed5d8e..e4e804880 100644
--- a/src/pkg/text/template/multi_test.go
+++ b/src/pkg/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/src/pkg/text/template/template.go b/src/pkg/text/template/template.go
index a2b9062ad..249d0cbfb 100644
--- a/src/pkg/text/template/template.go
+++ b/src/pkg/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/src/pkg/time/format.go b/src/pkg/time/format.go
index 6f92c1262..9f210ea27 100644
--- a/src/pkg/time/format.go
+++ b/src/pkg/time/format.go
@@ -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 {
@@ -1037,8 +1037,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 +1240,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/src/pkg/time/format_test.go b/src/pkg/time/format_test.go
new file mode 100644
index 000000000..3bc8f4294
--- /dev/null
+++ b/src/pkg/time/format_test.go
@@ -0,0 +1,511 @@
+// 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 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) {
+ 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) {
+ 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)
+ }
+}
diff --git a/src/pkg/time/internal_test.go b/src/pkg/time/internal_test.go
index 87fdd3216..2243d3668 100644
--- a/src/pkg/time/internal_test.go
+++ b/src/pkg/time/internal_test.go
@@ -29,16 +29,20 @@ func CheckRuntimeTimerOverflow() error {
// 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.
+ switch runtime.GOOS {
+ // Allow more time for gobuilder to succeed.
+ case "windows":
timeout = Second
+ case "plan9":
+ // TODO(0intro): We don't know why it is needed.
+ timeout = 3 * Second
}
// Start a goroutine that should send on t.C before the timeout.
@@ -74,7 +78,15 @@ func CheckRuntimeTimerOverflow() error {
if Now().After(stop) {
return errors.New("runtime timer stuck: overflow in addtimer")
}
- runtime.Gosched()
+ // Issue 6874. This test previously called runtime.Gosched to try to yield
+ // to the goroutine servicing t, however the scheduler has a bias towards the
+ // previously running goroutine in an idle system. Combined with high load due
+ // to all CPUs busy running tests t's goroutine could be delayed beyond the
+ // timeout window.
+ //
+ // Calling runtime.GC() reduces the worst case lantency for scheduling t by 20x
+ // under the current Go 1.3 scheduler.
+ runtime.GC()
}
}
}
diff --git a/src/pkg/time/sleep.go b/src/pkg/time/sleep.go
index 4f55bebe6..6a03f417b 100644
--- a/src/pkg/time/sleep.go
+++ b/src/pkg/time/sleep.go
@@ -8,10 +8,8 @@ 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$
@@ -29,9 +27,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
}
@@ -92,7 +90,7 @@ func sendTime(now int64, c interface{}) {
// 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:
}
}
diff --git a/src/pkg/time/sleep_test.go b/src/pkg/time/sleep_test.go
index 468725950..03f8e732c 100644
--- a/src/pkg/time/sleep_test.go
+++ b/src/pkg/time/sleep_test.go
@@ -74,26 +74,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++ {
@@ -360,19 +347,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")
}
}
@@ -398,6 +384,9 @@ func TestIssue5745(t *testing.T) {
}
func TestOverflowRuntimeTimer(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping in short mode, see issue 6874")
+ }
if err := CheckRuntimeTimerOverflow(); err != nil {
t.Fatalf(err.Error())
}
diff --git a/src/pkg/time/sys_unix.go b/src/pkg/time/sys_unix.go
index 60a3ce08f..379e13d6a 100644
--- a/src/pkg/time/sys_unix.go
+++ b/src/pkg/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/src/pkg/time/tick.go b/src/pkg/time/tick.go
index b92c339c0..19007841e 100644
--- a/src/pkg/time/tick.go
+++ b/src/pkg/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/src/pkg/time/tick_test.go b/src/pkg/time/tick_test.go
index d8a086ceb..32f4740ad 100644
--- a/src/pkg/time/tick_test.go
+++ b/src/pkg/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/src/pkg/time/time.go b/src/pkg/time/time.go
index c504df740..0a2b09142 100644
--- a/src/pkg/time/time.go
+++ b/src/pkg/time/time.go
@@ -934,6 +934,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
diff --git a/src/pkg/time/time_test.go b/src/pkg/time/time_test.go
index 334c4b0cf..4ae7da5a4 100644
--- a/src/pkg/time/time_test.go
+++ b/src/pkg/time/time_test.go
@@ -12,8 +12,6 @@ import (
"math/big"
"math/rand"
"runtime"
- "strconv"
- "strings"
"testing"
"testing/quick"
. "time"
@@ -372,502 +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) {
- 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
@@ -1340,6 +842,7 @@ var parseDurationTests = []struct {
{"-.", false, 0},
{".s", false, 0},
{"+.s", false, 0},
+ {"3000000h", false, 0}, // overflow
}
func TestParseDuration(t *testing.T) {
@@ -1461,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/src/pkg/time/zoneinfo.go b/src/pkg/time/zoneinfo.go
index 1c6186258..c8e53a27c 100644
--- a/src/pkg/time/zoneinfo.go
+++ b/src/pkg/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/src/pkg/time/zoneinfo_plan9.go b/src/pkg/time/zoneinfo_plan9.go
index 0e8f3811b..4bb0cb390 100644
--- a/src/pkg/time/zoneinfo_plan9.go
+++ b/src/pkg/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/src/pkg/time/zoneinfo_read.go b/src/pkg/time/zoneinfo_read.go
index 7714aa9f5..de9ebb41c 100644
--- a/src/pkg/time/zoneinfo_read.go
+++ b/src/pkg/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/src/pkg/time/zoneinfo_test.go b/src/pkg/time/zoneinfo_test.go
new file mode 100644
index 000000000..4ca7fad93
--- /dev/null
+++ b/src/pkg/time/zoneinfo_test.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 time_test
+
+import (
+ "testing"
+ "time"
+)
+
+func TestVersion3(t *testing.T) {
+ 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) {
+ 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/src/pkg/time/zoneinfo_unix.go b/src/pkg/time/zoneinfo_unix.go
index fc5ae89fe..ab7e4612e 100644
--- a/src/pkg/time/zoneinfo_unix.go
+++ b/src/pkg/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/src/pkg/time/zoneinfo_windows.go b/src/pkg/time/zoneinfo_windows.go
index be4e5c13f..6046743e6 100644
--- a/src/pkg/time/zoneinfo_windows.go
+++ b/src/pkg/time/zoneinfo_windows.go
@@ -54,7 +54,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 +90,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 +165,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/src/pkg/unicode/letter.go b/src/pkg/unicode/letter.go
index fadaa57d8..977bd2b3b 100644
--- a/src/pkg/unicode/letter.go
+++ b/src/pkg/unicode/letter.go
@@ -74,7 +74,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 +316,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/src/pkg/unicode/letter_test.go b/src/pkg/unicode/letter_test.go
index e4d5572a0..4ee11fb36 100644
--- a/src/pkg/unicode/letter_test.go
+++ b/src/pkg/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/src/pkg/unicode/maketables.go b/src/pkg/unicode/maketables.go
index e5ed08b23..8116ab8a4 100644
--- a/src/pkg/unicode/maketables.go
+++ b/src/pkg/unicode/maketables.go
@@ -40,7 +40,7 @@ func main() {
var dataURL = flag.String("data", "", "full URL for UnicodeData.txt; defaults to --url/UnicodeData.txt")
var casefoldingURL = flag.String("casefolding", "", "full URL for CaseFolding.txt; defaults to --url/CaseFolding.txt")
var url = flag.String("url",
- "http://www.unicode.org/Public/6.2.0/ucd/",
+ "http://www.unicode.org/Public/6.3.0/ucd/",
"URL of Unicode database directory")
var tablelist = flag.String("tables",
"all",
@@ -386,7 +386,11 @@ func loadCasefold() {
}
}
-const progHeader = `// Generated by running
+const progHeader = `// 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=%s --data=%s --casefolding=%s
// DO NOT EDIT
diff --git a/src/pkg/unicode/script_test.go b/src/pkg/unicode/script_test.go
index 395cc71a0..e2ba0011a 100644
--- a/src/pkg/unicode/script_test.go
+++ b/src/pkg/unicode/script_test.go
@@ -182,7 +182,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/src/pkg/unicode/tables.go b/src/pkg/unicode/tables.go
index 939c41dc5..5670d1c5b 100644
--- a/src/pkg/unicode/tables.go
+++ b/src/pkg/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/6.3.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/6.3.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 = "6.3.0"
// Categories is the set of Unicode category tables.
var Categories = map[string]*RangeTable{
@@ -53,11 +57,12 @@ var _C = &RangeTable{
{0x007f, 0x009f, 1},
{0x00ad, 0x0600, 1363},
{0x0601, 0x0604, 1},
- {0x06dd, 0x070f, 50},
+ {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},
@@ -85,11 +90,12 @@ var _Cf = &RangeTable{
R16: []Range16{
{0x00ad, 0x0600, 1363},
{0x0601, 0x0604, 1},
- {0x06dd, 0x070f, 50},
+ {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},
},
@@ -1545,7 +1551,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},
@@ -1717,8 +1723,8 @@ 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},
@@ -2086,6 +2092,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},
@@ -2183,7 +2190,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},
@@ -2360,7 +2368,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},
@@ -2450,7 +2459,8 @@ var _S = &RangeTable{
{0x2141, 0x2144, 1},
{0x214a, 0x214d, 1},
{0x214f, 0x2190, 65},
- {0x2191, 0x2328, 1},
+ {0x2191, 0x2307, 1},
+ {0x230c, 0x2328, 1},
{0x232b, 0x23f3, 1},
{0x2400, 0x2426, 1},
{0x2440, 0x244a, 1},
@@ -2630,7 +2640,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},
@@ -2818,8 +2827,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 +2851,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 +2911,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/6.3.0/ucd/
// DO NOT EDIT
// Scripts is the set of Unicode script tables.
@@ -3016,6 +3025,7 @@ var _Arabic = &RangeTable{
{0x0600, 0x0604, 1},
{0x0606, 0x060b, 1},
{0x060d, 0x061a, 1},
+ {0x061c, 0x061c, 1},
{0x061e, 0x061e, 1},
{0x0620, 0x063f, 1},
{0x0641, 0x064a, 1},
@@ -3245,7 +3255,7 @@ 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},
@@ -3281,6 +3291,7 @@ var _Common = &RangeTable{
{0xa700, 0xa721, 1},
{0xa788, 0xa78a, 1},
{0xa830, 0xa839, 1},
+ {0xa9cf, 0xa9cf, 1},
{0xfd3e, 0xfd3f, 1},
{0xfdfd, 0xfdfd, 1},
{0xfe10, 0xfe19, 1},
@@ -3710,7 +3721,7 @@ var _Inscriptional_Parthian = &RangeTable{
var _Javanese = &RangeTable{
R16: []Range16{
{0xa980, 0xa9cd, 1},
- {0xa9cf, 0xa9d9, 1},
+ {0xa9d0, 0xa9d9, 1},
{0xa9de, 0xa9df, 1},
},
}
@@ -4403,7 +4414,7 @@ var (
)
// 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/6.3.0/ucd/
// DO NOT EDIT
// Properties is the set of Unicode property tables.
@@ -4453,8 +4464,10 @@ var _ASCII_Hex_Digit = &RangeTable{
var _Bidi_Control = &RangeTable{
R16: []Range16{
+ {0x061c, 0x061c, 1},
{0x200e, 0x200f, 1},
{0x202a, 0x202e, 1},
+ {0x2066, 0x2069, 1},
},
}
@@ -4931,7 +4944,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},
@@ -5053,6 +5066,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},
@@ -5440,7 +5454,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 +5500,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/6.3.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/6.3.0/ucd/CaseFolding.txt
// DO NOT EDIT
// CaseRanges is the table describing case mappings for all letters with
@@ -6372,7 +6385,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: 3471 16-bit, 832 32-bit, 4303 total.
+// Range bytes: 20826 16-bit, 9984 32-bit, 30810 total.
// Fold orbit bytes: 63 pairs, 252 bytes
diff --git a/src/pkg/unicode/utf16/utf16.go b/src/pkg/unicode/utf16/utf16.go
index 903e4012a..c0e47c535 100644
--- a/src/pkg/unicode/utf16/utf16.go
+++ b/src/pkg/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/src/pkg/unicode/utf16/utf16_test.go b/src/pkg/unicode/utf16/utf16_test.go
index ee16a303d..3dca472bb 100644
--- a/src/pkg/unicode/utf16/utf16_test.go
+++ b/src/pkg/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/src/pkg/unicode/utf8/example_test.go b/src/pkg/unicode/utf8/example_test.go
index fe2037336..7b3e7ac74 100644
--- a/src/pkg/unicode/utf8/example_test.go
+++ b/src/pkg/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/src/pkg/unicode/utf8/utf8.go b/src/pkg/unicode/utf8/utf8.go
index 93d0be5e0..0dc859a04 100644
--- a/src/pkg/unicode/utf8/utf8.go
+++ b/src/pkg/unicode/utf8/utf8.go
@@ -329,37 +329,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